From 1859ae1061baa4a70c4ffb5db8a776b365db396e Mon Sep 17 00:00:00 2001 From: Teddy Zhang Date: Thu, 8 May 2025 01:54:40 -0700 Subject: [PATCH 01/41] outlines bot.py and necessary/relevant changes to report.py. In bot.py, fills out the interaction between the report class and the DMing user during the report process, and describes a format for communication of reporting data. Adds some relevant state and functions to report.py to match, and suggests a structure for report.py. Outlines TODOs for moderator flow implementation using reactions. --- DiscordBot/bot.py | 90 ++++++++++++++++++++++++++++++++++++++++---- DiscordBot/report.py | 50 +++++++++++++++++++++--- 2 files changed, 126 insertions(+), 14 deletions(-) diff --git a/DiscordBot/bot.py b/DiscordBot/bot.py index ec5dddb6..75c6e606 100644 --- a/DiscordBot/bot.py +++ b/DiscordBot/bot.py @@ -26,6 +26,9 @@ discord_token = tokens['discord'] +MOD_TODO_START = "TODO" + + class ModBot(discord.Client): def __init__(self): intents = discord.Intents.default() @@ -89,26 +92,96 @@ async def handle_dm(self, message): if author_id not in self.reports: self.reports[author_id] = Report(self) - # Let the report class handle this message; forward all the messages it returns to uss + # If we are starting a report responses = await self.reports[author_id].handle_message(message) - for r in responses: - await message.channel.send(r) + + if self.reports[author_id].awaiting_message(): + reply = responses[0] + await message.channel.send(reply) + + if self.reports[author_id].message_identified(): + reply = responses[0] + reported_name = responses[1] + reported_content = responses[2] + await message.channel.send(reply) + + if self.reports[author_id].category_identified(): + reply = responses[0] + category = responses[1] + await message.channel.send(reply) + + if self.reports[author_id].type_identified(): + reply = responses[0] + type_ = responses[1] + await message.channel.send(reply) + + if self.reports[author_id].subtype_identified(): + reply = responses[0] + subtype = responses[1] + await message.channel.send(reply) + + if self.reports[author_id].harm_identified(): + reply = responses[0] + harm = responses[1] + if harm: + # TODO escalate (or simulate it) + print("Escalating report") + await message.channel.send(reply) + + if self.reports[author_id].block_step(): + reply = responses[0] + block = responses[1] + if block: + # TODO block user (or simulate it) + print("Blocking user") + await message.channel.send(reply) # If the report is complete or cancelled, remove it from our map if self.reports[author_id].report_complete(): self.reports.pop(author_id) + # Put the report in the mod channel + mod_channel = self.mod_channels[message.guild.id] + report_info_msg = MOD_TODO_START + "User " + message.author.name + "reported user" + reported_name + "'s message.\n" + report_info_msg += "Here is the content of the post: " + str(reported_content) + ".\n" #not sure if str() protects from code injection? + report_info_msg += "Category: " + str(category) + "\n" + report_info_msg += "Type: " + str(type_) + "\n" + report_info_msg += "Subtype: " + str(subtype) + "\n" + await mod_channel.send(report_info_msg) + + # ------ starter code relevant to MILESTONE 3: -------------- + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------- + + async def handle_channel_message(self, message): - # Only handle messages sent in the "group-#" channel + if not message.channel.name == f'group-{self.group_num}': return - # Forward the message to the mod channel + # ----- teddy: commented out to reduce clutter for milestone 2 since we are not doing auto flagging ------------ + # # Forward the message to the mod channel + # mod_channel = self.mod_channels[message.guild.id] + # await mod_channel.send(f'Forwarded message:\n{message.author.name}: "{message.content}"') + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------------------------------------------------------ + return + + async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): + # see https://discordpy.readthedocs.io/en/latest/api.html?highlight=on_reaction_add#discord.RawReactionActionEvent mod_channel = self.mod_channels[message.guild.id] - await mod_channel.send(f'Forwarded message:\n{message.author.name}: "{message.content}"') - scores = self.eval_text(message.content) - await mod_channel.send(self.code_format(scores)) + message = await mod_channel.fetch_message(payload.message_id) + + # Ignore messages that are not the bot's moderator to-do messages + if message.author.id != self.user.id or (not message.content.startswith(MOD_TODO_START)): + return + + # TODO IMPLEMENT MODERATOR FLOW HERE + + return def eval_text(self, message): '''' @@ -124,6 +197,7 @@ def code_format(self, text): evaluated, insert your code here for formatting the string to be shown in the mod channel. ''' + #teddy: not sure if we need this function return "Evaluated: '" + text+ "'" diff --git a/DiscordBot/report.py b/DiscordBot/report.py index d2bba994..0c2c5bf3 100644 --- a/DiscordBot/report.py +++ b/DiscordBot/report.py @@ -6,6 +6,13 @@ class State(Enum): REPORT_START = auto() AWAITING_MESSAGE = auto() MESSAGE_IDENTIFIED = auto() + + CATEGORY_IDENTIFIED = auto() #disinformation, nudity, etc + TYPE_IDENTIFIED = auto() #political disinfo, health disinfo + SUBTYPE_IDENTIFIED = auto() #vaccines, cures and treatments + HARM_IDENTIFIED = auto() + BLOCK_STEP = auto() + REPORT_COMPLETE = auto() class Report: @@ -55,14 +62,45 @@ async def handle_message(self, message): # Here we've found the message - it's up to you to decide what to do next! self.state = State.MESSAGE_IDENTIFIED - return ["I found this message:", "```" + message.author.name + ": " + message.content + "```", \ - "This is all I know how to do right now - it's up to you to build out the rest of my reporting flow!"] - - if self.state == State.MESSAGE_IDENTIFIED: - return [""] + return ["I found this message:```" + message.author.name + ": " + message.content + "```\n", + message.author.name, + message.content] - return [] + # TODO fill out the rest of the user reporting flow + # seems like readme wants us to use this: https://discordpy.readthedocs.io/en/latest/api.html?highlight=on_reaction_add#discord.on_raw_reaction_add + if self.state == State.MESSAGE_IDENTIFIED: + # get value based on reacts + self.state = State.CATEGORY_IDENTIFIED + return ["[PLACEHOLDER] What category does this content fall under?\n1 = disinformation\n2 = other reporting flow"] + + #etc etc + # return based on expected format outlined in bot.py, + # where 0th element is the appropriate messaage and the rest are data + if self.state == State.BLOCK_STEP: + # if user wants to block then block + user_wants_to_block = True + return [user_wants_to_block] + + return [] + + + def report_start(self): + return self.state == State.REPORT_START + def awaiting_message(self): + return self.state == State.AWAITING_MESSAGE + def message_identified(self): + return self.state == State.MESSAGE_IDENTIFIED + def category_identified(self): + return self.state == State.CATEGORY_IDENTIFIED + def type_identified(self): + return self.state == State.TYPE_IDENTIFIED + def subtype_identified(self): + return self.state == State.SUBTYPE_IDENTIFIED + def harm_identified(self): + return self.state == State.HARM_IDENTIFIED + def block_step(self): + return self.state == State.BLOCK_STEP def report_complete(self): return self.state == State.REPORT_COMPLETE From 116c28e47e9186852d972c21475a1d0d9d86093a Mon Sep 17 00:00:00 2001 From: oburay Date: Thu, 8 May 2025 03:52:08 -0700 Subject: [PATCH 02/41] User flow implementation --- DiscordBot/report.py | 182 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 180 insertions(+), 2 deletions(-) diff --git a/DiscordBot/report.py b/DiscordBot/report.py index d2bba994..5b3ee3d4 100644 --- a/DiscordBot/report.py +++ b/DiscordBot/report.py @@ -7,6 +7,10 @@ class State(Enum): AWAITING_MESSAGE = auto() MESSAGE_IDENTIFIED = auto() REPORT_COMPLETE = auto() + AWAITING_REASON = auto() + AWAITING_DISINFORMATION_TYPE = auto() + AWAITING_POLITICAL_DISINFORMATION_TYPE =auto() + AWAITING_FILTER_ACTION = auto() class Report: START_KEYWORD = "report" @@ -17,6 +21,10 @@ def __init__(self, client): self.state = State.REPORT_START self.client = client self.message = None + self.report_type = None + self.disinfo_type = None + self.political_disinfo_type = None + self.filter = False async def handle_message(self, message): ''' @@ -59,14 +67,184 @@ async def handle_message(self, message): "This is all I know how to do right now - it's up to you to build out the rest of my reporting flow!"] if self.state == State.MESSAGE_IDENTIFIED: - return [""] + # Ask the user to select a reason for reporting the message + self.state = State.AWAITING_REASON + return [ + "Please select the reason for reporting this message by typing the corresponding number:", + "1. Disinformation", + "2. Hate Speech", + "3. Harassment", + "4. Spam" + ] + + if self.state == State.AWAITING_REASON: + # Process user's report reason + + if message.content == "1": + # Handling disinformation + self.report_type = "Disinformation" + self.state = State.AWAITING_DISINFORMATION_TYPE + return[ + "Please select the type of disinformation by typing the corresponding number:", + "1. Political Disinformation", + "2. Health Disinformation", + "3. Other Disinformation" + ] + + elif message.content == "2" : + # Handling hate speech + self.report_type = "Hate Speech" + self.state = State.REPORT_COMPLETE + return [" Thank you for reporting" + self.report_type + " content. Our content moderation team will review the message and take action which may result in content or account removal."] + + elif message.content == "3" : + # Handling Harassment + self.report_type = "Harassment" + self.state = State.REPORT_COMPLETE + return [" Thank you for reporting" + self.report_type + " content. Our content moderation team will review the message and take action which may result in content or account removal."] + + + elif message.content == "4" : + # Handling Spam + self.report_type = "Spam" + self.state = State.REPORT_COMPLETE + return [" Thank you for reporting" + self.report_type + " content. Our content moderation team will review the message and take action which may result in content or account removal."] + + else: + # Handling wrong report reason + return [ "Kindly enter a valid report reason by selecting the correponding number:", + "1. Disinformation", + "2. Hate Speech", + "3. Harassment", + "4. Spam", + "Please try again or say `cancel` to cancel." + ] + + if self.state == State.AWAITING_DISINFORMATION_TYPE : + # Process Disinformation options + + if message.content == "1": + # Handle political disinformation + self.state = State.AWAITING_POLITICAL_DISINFORMATION_TYPE + self.disinfo_type = "Political Disinformation" + return [ "Please select the type of political Disinformation by typing the corresponding number:", + "1. Conspiracy Theory", + "2. Distorted Information", + "3. False Claim", + "4. Election/Campaign Misinformation" + ] + + elif message.content == "2" : + # Handle Health Disinformation + self.state = State.AWAITING_FILTER_ACTION + self.disinfo_type = "Health Disinformation" + return [ "Would you like to filter content from this account on your feed? Select the correponding number:", + "1. Yes", + "2. No" + ] + + + elif message.content == "3" : + # Handle other Disinformation + self.state = State.AWAITING_FILTER_ACTION + self.disinfo_type = "Other Disinformation" + return [ "Would you like to filter content from this account on your feed? Select the correponding number:", + "1. Yes", + "2. No" + ] + + else : + # Handling wrong disinformation type + return [ "Kindly enter a valid disinformation type by selecting the correponding number:", + "1. Political Disinformation", + "2. Health Disinformation", + "3. Other Disinformation", + "Please try again or say `cancel` to cancel." + ] + if self.state == State.AWAITING_POLITICAL_DISINFORMATION_TYPE : + # Process political disinformation options + + if message.content == "1": + # Handling Conspiracy Theory + self.political_disinfo_type = "Conspiracy Theory" + self.state = State.AWAITING_FILTER_ACTION + return [ "Would you like to filter content from this account on your feed? Select the correponding number:", + "1. Yes", + "2. No" + ] + + elif message.content == "2": + # Handling Distorted Information + self.political_disinfo_type = "Distorted Information" + self.state = State.AWAITING_FILTER_ACTION + return [ "Would you like to filter content from this account on your feed? Select the correponding number:", + "1. Yes", + "2. No" + ] + + elif message.content == "3": + # Handling False Claim + self.political_disinfo_type = "False Claim" + self.state = State.AWAITING_FILTER_ACTION + return [ "Would you like to filter content from this account on your feed? Select the correponding number:", + "1. Yes", + "2. No" + ] + + elif message.content == "4": + # Handling Election/Campaign Misinformation + self.political_disinfo_type = "Election/Campaign Misinformation" + self.state = State.AWAITING_FILTER_ACTION + return [ "Would you like to filter content from this account on your feed? Select the correponding number:", + "1. Yes", + "2. No" + ] + + + else : + # Handling + return [ "Please select the type of political Disinformation by typing the corresponding number:", + "1. Conspiracy Theory", + "2. Distorted Information", + "3. False Claim", + "4. Election/Campaign Misinformation", + "Please try again or say `cancel` to cancel." + ] + + if self.state == State.AWAITING_FILTER_ACTION: + # Handling responses to filter account content + + if message.content == "1": + # Handle content filtering + self.filter = True + self.state = State.REPORT_COMPLETE + return [ "This account’s posts have been restricted from appearing on your feed.", + " Thank you for reporting" + self.report_type + " content. Our content moderation team will review the message and take action which may result in content or account removal." + ] + + elif message.content == "2": + # Handle no content filtering action + self.state = State.REPORT_COMPLETE + return [ "This account’s posts have been restricted from appearing on your feed.", + " Thank you for reporting" + self.report_type + " content. Our content moderation team will review the message and take action which may result in content or account removal." + ] + + else : + # wrong option for account filtering prompt + return [ "Would you like to filter content from this account on your feed? Select the correponding number:", + "1. Yes", + "2. No", + "Please try again or say `cancel` to cancel." + ] + + return [] def report_complete(self): return self.state == State.REPORT_COMPLETE - +# when self.state == report.coplte what should we do ? From 4fc10fd6bd300791d38b9f891b372bd246438d02 Mon Sep 17 00:00:00 2001 From: Teddy Zhang Date: Thu, 8 May 2025 18:10:03 -0700 Subject: [PATCH 03/41] integrated mine and raymond's code and some small formatting fixes --- DiscordBot/bot.py | 110 ++++++++++------- DiscordBot/report.py | 282 ++++++++++++++++++++++++------------------- 2 files changed, 223 insertions(+), 169 deletions(-) diff --git a/DiscordBot/bot.py b/DiscordBot/bot.py index 75c6e606..2749c84b 100644 --- a/DiscordBot/bot.py +++ b/DiscordBot/bot.py @@ -26,7 +26,7 @@ discord_token = tokens['discord'] -MOD_TODO_START = "TODO" +MOD_TODO_START = "---------------------------\nTODO" class ModBot(discord.Client): @@ -95,60 +95,69 @@ async def handle_dm(self, message): # If we are starting a report responses = await self.reports[author_id].handle_message(message) - if self.reports[author_id].awaiting_message(): - reply = responses[0] - await message.channel.send(reply) - - if self.reports[author_id].message_identified(): - reply = responses[0] - reported_name = responses[1] - reported_content = responses[2] - await message.channel.send(reply) + ## report.py updates state, and below, we route our response based on that state - if self.reports[author_id].category_identified(): - reply = responses[0] - category = responses[1] - await message.channel.send(reply) + if self.reports[author_id].is_awaiting_message(): + for r in responses: + await message.channel.send(r) - if self.reports[author_id].type_identified(): - reply = responses[0] - type_ = responses[1] - await message.channel.send(reply) + if self.reports[author_id].is_awaiting_reason(): + for r in responses: + await message.channel.send(r) - if self.reports[author_id].subtype_identified(): - reply = responses[0] - subtype = responses[1] - await message.channel.send(reply) + if self.reports[author_id].is_awaiting_disinformation_type(): + for r in responses: + await message.channel.send(r) - if self.reports[author_id].harm_identified(): - reply = responses[0] - harm = responses[1] - if harm: - # TODO escalate (or simulate it) - print("Escalating report") - await message.channel.send(reply) + if self.reports[author_id].is_awaiting_political_disinformation_type(): + for r in responses: + await message.channel.send(r) - if self.reports[author_id].block_step(): - reply = responses[0] - block = responses[1] - if block: - # TODO block user (or simulate it) - print("Blocking user") - await message.channel.send(reply) + if self.reports[author_id].is_awaiting_filter_action(): + for r in responses: + await message.channel.send(r) + + # if self.reports[author_id].harm_identified(): + # reply = responses[0] + # harm = responses[1] + # if harm: + # # TODO escalate (or simulate it) + # print("Escalating report") + # await message.channel.send(reply) + + # if self.reports[author_id].block_step(): + # reply = responses[0] + # block = responses[1] + # if block: + # # TODO block user (or simulate it) + # print("Blocking user") + # await message.channel.send(reply) # If the report is complete or cancelled, remove it from our map - if self.reports[author_id].report_complete(): - self.reports.pop(author_id) + if self.reports[author_id].is_report_complete(): + + reported_author = self.reports[author_id].get_reported_author() + reported_content = self.reports[author_id].get_reported_content() + report_type = self.reports[author_id].get_report_type() + disinfo_type = self.reports[author_id].get_disinfo_type() + disinfo_subtype = self.reports[author_id].get_disinfo_subtype() + + for r in responses: + await message.channel.send(r) # Put the report in the mod channel - mod_channel = self.mod_channels[message.guild.id] - report_info_msg = MOD_TODO_START + "User " + message.author.name + "reported user" + reported_name + "'s message.\n" - report_info_msg += "Here is the content of the post: " + str(reported_content) + ".\n" #not sure if str() protects from code injection? - report_info_msg += "Category: " + str(category) + "\n" - report_info_msg += "Type: " + str(type_) + "\n" - report_info_msg += "Subtype: " + str(subtype) + "\n" + mod_channel = self.mod_channels[self.reports[author_id].get_message_guild_id()] + # todo are we worried about code injection via author name or content? + report_info_msg = MOD_TODO_START + " User " + message.author.name + " reported user " + str(reported_author) + "'s message.\n" + report_info_msg += "Here is the message: \n```" + str(reported_content) + "\n```" + report_info_msg += "Category: " + str(report_type) + " > " + str(disinfo_type) + " > " + str(disinfo_subtype) + "\n" + report_info_msg += "react to this message in order to moderate it\n" + await mod_channel.send(report_info_msg) + # remove + self.reports.pop(author_id) + # ------ starter code relevant to MILESTONE 3: -------------- # scores = self.eval_text(message.content) # await mod_channel.send(self.code_format(scores)) @@ -199,6 +208,19 @@ def code_format(self, text): ''' #teddy: not sure if we need this function return "Evaluated: '" + text+ "'" + + # def process_response(self, responses): + + # reply = responses["reply"] + # if not isinstance(reply, str): # just in case i forget brackets in report.py + # reply = [reply] + # del responses["reply"] + + # for key, value in responses.items(): # go through data (not including reply) + # if key not in self.current_report: # don't allow overwriting + # self.current_report[key] = value + + # return reply client = ModBot() diff --git a/DiscordBot/report.py b/DiscordBot/report.py index 1acbf705..559c032a 100644 --- a/DiscordBot/report.py +++ b/DiscordBot/report.py @@ -5,20 +5,14 @@ class State(Enum): REPORT_START = auto() AWAITING_MESSAGE = auto() - MESSAGE_IDENTIFIED = auto() -# CATEGORY_IDENTIFIED = auto() #disinformation, nudity, etc -# TYPE_IDENTIFIED = auto() #political disinfo, health disinfo -# SUBTYPE_IDENTIFIED = auto() #vaccines, cures and treatments -# HARM_IDENTIFIED = auto() -# BLOCK_STEP = auto() - - REPORT_COMPLETE = auto() AWAITING_REASON = auto() AWAITING_DISINFORMATION_TYPE = auto() AWAITING_POLITICAL_DISINFORMATION_TYPE =auto() AWAITING_FILTER_ACTION = auto() + REPORT_COMPLETE = auto() + class Report: START_KEYWORD = "report" CANCEL_KEYWORD = "cancel" @@ -28,9 +22,13 @@ def __init__(self, client): self.state = State.REPORT_START self.client = client self.message = None + + self.message_guild_id = None + self.reported_author = None + self.reported_content = None self.report_type = None self.disinfo_type = None - self.political_disinfo_type = None + self.disinfo_subtype = None self.filter = False async def handle_message(self, message): @@ -57,35 +55,35 @@ async def handle_message(self, message): m = re.search('/(\d+)/(\d+)/(\d+)', message.content) if not m: return ["I'm sorry, I couldn't read that link. Please try again or say `cancel` to cancel."] + guild = self.client.get_guild(int(m.group(1))) if not guild: return ["I cannot accept reports of messages from guilds that I'm not in. Please have the guild owner add me to the guild and try again."] + channel = guild.get_channel(int(m.group(2))) if not channel: return ["It seems this channel was deleted or never existed. Please try again or say `cancel` to cancel."] + try: message = await channel.fetch_message(int(m.group(3))) except discord.errors.NotFound: return ["It seems this message was deleted or never existed. Please try again or say `cancel` to cancel."] - # Here we've found the message - it's up to you to decide what to do next! - self.state = State.MESSAGE_IDENTIFIED -# return ["I found this message:", "```" + message.author.name + ": " + message.content + "```", \ -# "This is all I know how to do right now - it's up to you to build out the rest of my reporting flow!"] - return ["I found this message:```" + message.author.name + ": " + message.content + "```\n", - message.author.name, - message.content] - - if self.state == State.MESSAGE_IDENTIFIED: - # Ask the user to select a reason for reporting the message self.state = State.AWAITING_REASON - return [ - "Please select the reason for reporting this message by typing the corresponding number:", - "1. Disinformation", - "2. Hate Speech", - "3. Harassment", - "4. Spam" - ] + + # add guild ID so we know where to send the moderation todo + self.message_guild_id = message.guild.id + + self.reported_author = message.author.name + self.reported_content = message.content + + reply = "I found this message:```" + message.author.name + ": " + message.content + "```\n" + reply += "Please select the reason for reporting this message by typing the corresponding number:\n" + reply += "1. Disinformation\n" + reply += "2. Hate Speech\n" + reply += "3. Harassment\n" + reply += "4. Spam\n" + return [reply] if self.state == State.AWAITING_REASON: # Process user's report reason @@ -94,41 +92,57 @@ async def handle_message(self, message): # Handling disinformation self.report_type = "Disinformation" self.state = State.AWAITING_DISINFORMATION_TYPE - return[ - "Please select the type of disinformation by typing the corresponding number:", - "1. Political Disinformation", - "2. Health Disinformation", - "3. Other Disinformation" - ] + + reply = "You have selected " + self.report_type + ".\n" + reply += "Please select the type of disinformation by typing the corresponding number:\n" + reply += "1. Political Disinformation\n" + reply += "2. Health Disinformation\n" + reply += "3. Other Disinformation\n" + return [reply] elif message.content == "2" : # Handling hate speech self.report_type = "Hate Speech" + self.disinfo_type = "[out of scope of project]" + self.disinfo_subtype = "[out of scope of project]" self.state = State.REPORT_COMPLETE - return [" Thank you for reporting" + self.report_type + " content. Our content moderation team will review the message and take action which may result in content or account removal."] + return [ + "Thank you for reporting " + self.report_type + " content.", + "Our content moderation team will review the message and take action which may result in content or account removal." + ] elif message.content == "3" : # Handling Harassment self.report_type = "Harassment" + self.disinfo_type = "[out of scope of project]" + self.disinfo_subtype = "[out of scope of project]" self.state = State.REPORT_COMPLETE - return [" Thank you for reporting" + self.report_type + " content. Our content moderation team will review the message and take action which may result in content or account removal."] + return [ + "Thank you for reporting " + self.report_type + " content.", + "Our content moderation team will review the message and take action which may result in content or account removal." + ] elif message.content == "4" : # Handling Spam self.report_type = "Spam" + self.disinfo_type = "[out of scope of project]" + self.disinfo_subtype = "[out of scope of project]" self.state = State.REPORT_COMPLETE - return [" Thank you for reporting" + self.report_type + " content. Our content moderation team will review the message and take action which may result in content or account removal."] + return [ + "Thank you for reporting " + self.report_type + " content", + "Our content moderation team will review the message and take action which may result in content or account removal." + ] else: # Handling wrong report reason - return [ "Kindly enter a valid report reason by selecting the correponding number:", - "1. Disinformation", - "2. Hate Speech", - "3. Harassment", - "4. Spam", - "Please try again or say `cancel` to cancel." - ] + reply = "Kindly enter a valid report reason by selecting the correponding number:\n" + reply += "1. Disinformation\n" + reply += "2. Hate Speech\n" + reply += "3. Harassment\n" + reply += "4. Spam\n" + reply += "Please try again or say `cancel` to cancel.\n" + return [reply] if self.state == State.AWAITING_DISINFORMATION_TYPE : # Process Disinformation options @@ -137,90 +151,98 @@ async def handle_message(self, message): # Handle political disinformation self.state = State.AWAITING_POLITICAL_DISINFORMATION_TYPE self.disinfo_type = "Political Disinformation" - return [ "Please select the type of political Disinformation by typing the corresponding number:", - "1. Conspiracy Theory", - "2. Distorted Information", - "3. False Claim", - "4. Election/Campaign Misinformation" - ] + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Please select the type of political Disinformation by typing the corresponding number:\n" + reply += "1. Conspiracy Theory\n" + reply += "2. Distorted Information\n" + reply += "3. False Claim\n" + reply += "4. Election/Campaign Misinformation" + return [reply] elif message.content == "2" : # Handle Health Disinformation self.state = State.AWAITING_FILTER_ACTION self.disinfo_type = "Health Disinformation" - return [ "Would you like to filter content from this account on your feed? Select the correponding number:", - "1. Yes", - "2. No" - ] + self.disinfo_subtype = "[out of scope of project]" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Would you like to filter content from this account on your feed? Select the correponding number:\n" + reply += "1. Yes\n" + reply += "2. No\n" + return [reply] elif message.content == "3" : # Handle other Disinformation self.state = State.AWAITING_FILTER_ACTION self.disinfo_type = "Other Disinformation" - return [ "Would you like to filter content from this account on your feed? Select the correponding number:", - "1. Yes", - "2. No" - ] + self.disinfo_subtype = "[out of scope of project]" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Would you like to filter content from this account on your feed? Select the correponding number:\n" + reply += "1. Yes\n" + reply += "2. No\n" + return [reply] else : # Handling wrong disinformation type - return [ "Kindly enter a valid disinformation type by selecting the correponding number:", - "1. Political Disinformation", - "2. Health Disinformation", - "3. Other Disinformation", - "Please try again or say `cancel` to cancel." - ] + reply = "Kindly enter a valid disinformation type by selecting the correponding number:", + reply += "1. Political Disinformation", + reply += "2. Health Disinformation", + reply += "3. Other Disinformation", + reply += "Please try again or say `cancel` to cancel." + return [reply] if self.state == State.AWAITING_POLITICAL_DISINFORMATION_TYPE : # Process political disinformation options if message.content == "1": # Handling Conspiracy Theory - self.political_disinfo_type = "Conspiracy Theory" + self.disinfo_subtype = "Conspiracy Theory" self.state = State.AWAITING_FILTER_ACTION - return [ "Would you like to filter content from this account on your feed? Select the correponding number:", - "1. Yes", - "2. No" - ] + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Would you like to filter content from this account on your feed? Select the correponding number:\n" + reply += "1. Yes\n" + reply += "2. No\n" + return [reply] elif message.content == "2": # Handling Distorted Information - self.political_disinfo_type = "Distorted Information" + self.disinfo_subtype = "Distorted Information" self.state = State.AWAITING_FILTER_ACTION - return [ "Would you like to filter content from this account on your feed? Select the correponding number:", - "1. Yes", - "2. No" - ] + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Would you like to filter content from this account on your feed? Select the correponding number:\n" + reply += "1. Yes\n" + reply += "2. No\n" + return [reply] elif message.content == "3": # Handling False Claim - self.political_disinfo_type = "False Claim" + self.disinfo_subtype = "False Claim" self.state = State.AWAITING_FILTER_ACTION - return [ "Would you like to filter content from this account on your feed? Select the correponding number:", - "1. Yes", - "2. No" - ] + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Would you like to filter content from this account on your feed? Select the correponding number:\n" + reply += "1. Yes\n" + reply += "2. No\n" + return [reply] elif message.content == "4": # Handling Election/Campaign Misinformation - self.political_disinfo_type = "Election/Campaign Misinformation" + self.disinfo_subtype = "Election/Campaign Misinformation" self.state = State.AWAITING_FILTER_ACTION - return [ "Would you like to filter content from this account on your feed? Select the correponding number:", - "1. Yes", - "2. No" - ] + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Would you like to filter content from this account on your feed? Select the correponding number:\n" + reply += "1. Yes\n" + reply += "2. No\n" + return [reply] - else : # Handling - return [ "Please select the type of political Disinformation by typing the corresponding number:", - "1. Conspiracy Theory", - "2. Distorted Information", - "3. False Claim", - "4. Election/Campaign Misinformation", - "Please try again or say `cancel` to cancel." - ] + reply = "Please select the type of political Disinformation by typing the corresponding number:\n" + reply += "1. Conspiracy Theory\n" + reply += "2. Distorted Information\n" + reply += "3. False Claim\n" + reply += "4. Election/Campaign Misinformation\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] if self.state == State.AWAITING_FILTER_ACTION: # Handling responses to filter account content @@ -229,56 +251,66 @@ async def handle_message(self, message): # Handle content filtering self.filter = True self.state = State.REPORT_COMPLETE - return [ "This account’s posts have been restricted from appearing on your feed.", - " Thank you for reporting" + self.report_type + " content. Our content moderation team will review the message and take action which may result in content or account removal." + return [ + "This account’s posts have been restricted from appearing on your feed.", + "Thank you for reporting" + self.report_type + " content.", + "Our content moderation team will review the message and take action which may result in content or account removal." ] elif message.content == "2": # Handle no content filtering action self.state = State.REPORT_COMPLETE - return [ "This account’s posts have been restricted from appearing on your feed.", - " Thank you for reporting" + self.report_type + " content. Our content moderation team will review the message and take action which may result in content or account removal." + return [ + "This account’s posts have been restricted from appearing on your feed.", + " Thank you for reporting" + self.report_type + " content.", + "Our content moderation team will review the message and take action which may result in content or account removal." ] - else : + else: # wrong option for account filtering prompt - return [ "Would you like to filter content from this account on your feed? Select the correponding number:", - "1. Yes", - "2. No", - "Please try again or say `cancel` to cancel." - ] - - - return [] + reply = "Would you like to filter content from this account on your feed? Select the correponding number:\n" + reply += "1. Yes\n" + reply += "2. No\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] # if self.state == State.BLOCK_STEP: # # if user wants to block then block # user_wants_to_block = True # return [user_wants_to_block] - - return [] + + return {} + #getters for state + def get_message_guild_id(self): + return self.message_guild_id + def get_reported_author(self): + return self.reported_author + def get_reported_content(self): + return self.reported_content + def get_report_type(self): + return self.report_type + def get_disinfo_type(self): + return self.disinfo_type + def get_disinfo_subtype(self): + return self.disinfo_subtype + def get_filter(self): + return self.filter - def report_start(self): + def is_report_start(self): return self.state == State.REPORT_START - def awaiting_message(self): + def is_awaiting_message(self): return self.state == State.AWAITING_MESSAGE - def message_identified(self): - return self.state == State.MESSAGE_IDENTIFIED - def category_identified(self): - return self.state == State.CATEGORY_IDENTIFIED - def type_identified(self): - return self.state == State.TYPE_IDENTIFIED - def subtype_identified(self): - return self.state == State.SUBTYPE_IDENTIFIED - def harm_identified(self): - return self.state == State.HARM_IDENTIFIED - def block_step(self): - return self.state == State.BLOCK_STEP - def report_complete(self): - return self.state == State.REPORT_COMPLETE - - -# when self.state == report.coplte what should we do ? - + def is_awaiting_reason(self): + return self.state == State.AWAITING_REASON + def is_awaiting_disinformation_type(self): + return self.state == State.AWAITING_DISINFORMATION_TYPE + def is_awaiting_political_disinformation_type(self): + return self.state == State.AWAITING_POLITICAL_DISINFORMATION_TYPE + def is_awaiting_filter_action(self): + return self.state == State.AWAITING_FILTER_ACTION + # def block_step(self): + # return self.state == State.BLOCK_STEP + def is_report_complete(self): + return self.state == State.REPORT_COMPLETE From 43ebbc47b3c69119991a3a7653906eca1d24037a Mon Sep 17 00:00:00 2001 From: oburay Date: Thu, 8 May 2025 21:01:18 -0700 Subject: [PATCH 04/41] Update : AWAITING_MESSAGE Workflow --- DiscordBot/report.py | 68 ++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/DiscordBot/report.py b/DiscordBot/report.py index 559c032a..dfa52c59 100644 --- a/DiscordBot/report.py +++ b/DiscordBot/report.py @@ -9,6 +9,7 @@ class State(Enum): AWAITING_REASON = auto() AWAITING_DISINFORMATION_TYPE = auto() AWAITING_POLITICAL_DISINFORMATION_TYPE =auto() + AWAITING_HEALTHL_DISINFORMATION_TYPE =auto() AWAITING_FILTER_ACTION = auto() REPORT_COMPLETE = auto() @@ -80,9 +81,7 @@ async def handle_message(self, message): reply = "I found this message:```" + message.author.name + ": " + message.content + "```\n" reply += "Please select the reason for reporting this message by typing the corresponding number:\n" reply += "1. Disinformation\n" - reply += "2. Hate Speech\n" - reply += "3. Harassment\n" - reply += "4. Spam\n" + reply += "2. Other\n" return [reply] if self.state == State.AWAITING_REASON: @@ -101,46 +100,47 @@ async def handle_message(self, message): return [reply] elif message.content == "2" : - # Handling hate speech - self.report_type = "Hate Speech" - self.disinfo_type = "[out of scope of project]" - self.disinfo_subtype = "[out of scope of project]" + # Handling Other Abuse types + self.report_type = "Other" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" self.state = State.REPORT_COMPLETE - return [ - "Thank you for reporting " + self.report_type + " content.", - "Our content moderation team will review the message and take action which may result in content or account removal." - ] + # return [ + # "Thank you for reporting " + self.report_type + " content.", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] - elif message.content == "3" : - # Handling Harassment - self.report_type = "Harassment" - self.disinfo_type = "[out of scope of project]" - self.disinfo_subtype = "[out of scope of project]" - self.state = State.REPORT_COMPLETE - return [ - "Thank you for reporting " + self.report_type + " content.", - "Our content moderation team will review the message and take action which may result in content or account removal." - ] + # elif message.content == "3" : + # # Handling Harassment + # self.report_type = "Harassment" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + # self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content.", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] - elif message.content == "4" : - # Handling Spam - self.report_type = "Spam" - self.disinfo_type = "[out of scope of project]" - self.disinfo_subtype = "[out of scope of project]" - self.state = State.REPORT_COMPLETE - return [ - "Thank you for reporting " + self.report_type + " content", - "Our content moderation team will review the message and take action which may result in content or account removal." - ] + # elif message.content == "4" : + # # Handling Spam + # self.report_type = "Spam" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + # self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] else: # Handling wrong report reason reply = "Kindly enter a valid report reason by selecting the correponding number:\n" reply += "1. Disinformation\n" - reply += "2. Hate Speech\n" - reply += "3. Harassment\n" - reply += "4. Spam\n" + reply += "2. Other\n" reply += "Please try again or say `cancel` to cancel.\n" return [reply] From 0c8d432e665338156e2b5b0a40f779a4806a4b09 Mon Sep 17 00:00:00 2001 From: oburay Date: Thu, 8 May 2025 21:25:07 -0700 Subject: [PATCH 05/41] Update : AWAITING_DISINFORMATION_TYPE Workflow --- DiscordBot/report.py | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/DiscordBot/report.py b/DiscordBot/report.py index dfa52c59..2ff29520 100644 --- a/DiscordBot/report.py +++ b/DiscordBot/report.py @@ -11,6 +11,7 @@ class State(Enum): AWAITING_POLITICAL_DISINFORMATION_TYPE =auto() AWAITING_HEALTHL_DISINFORMATION_TYPE =auto() AWAITING_FILTER_ACTION = auto() + AWAITING_HARMFUL_CONTENT_STATUS = auto() REPORT_COMPLETE = auto() @@ -153,42 +154,45 @@ async def handle_message(self, message): self.disinfo_type = "Political Disinformation" reply = "You have selected " + self.disinfo_type + ".\n" reply += "Please select the type of political Disinformation by typing the corresponding number:\n" - reply += "1. Conspiracy Theory\n" - reply += "2. Distorted Information\n" - reply += "3. False Claim\n" - reply += "4. Election/Campaign Misinformation" + reply += "1. Election/Campaign Misinformation\n" + reply += "2. Government/Civic Services\n" + reply += "3. Manipulated Photos/Video\n" + reply += "4. Other\n" return [reply] elif message.content == "2" : # Handle Health Disinformation - self.state = State.AWAITING_FILTER_ACTION + self.state = State.AWAITING_HEALTHL_DISINFORMATION_TYPE self.disinfo_type = "Health Disinformation" - self.disinfo_subtype = "[out of scope of project]" reply = "You have selected " + self.disinfo_type + ".\n" - reply += "Would you like to filter content from this account on your feed? Select the correponding number:\n" - reply += "1. Yes\n" - reply += "2. No\n" + reply += "Please select the type of health disinformation by typing the corresponding number:\n" + reply += "1. Vaccines\n" + reply += "2. Cures and Treatments\n" + reply += "3. Mental Health\n" + reply += "4. Other\n" return [reply] elif message.content == "3" : # Handle other Disinformation - self.state = State.AWAITING_FILTER_ACTION + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS self.disinfo_type = "Other Disinformation" self.disinfo_subtype = "[out of scope of project]" reply = "You have selected " + self.disinfo_type + ".\n" - reply += "Would you like to filter content from this account on your feed? Select the correponding number:\n" - reply += "1. Yes\n" - reply += "2. No\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" return [reply] else : # Handling wrong disinformation type reply = "Kindly enter a valid disinformation type by selecting the correponding number:", - reply += "1. Political Disinformation", - reply += "2. Health Disinformation", - reply += "3. Other Disinformation", - reply += "Please try again or say `cancel` to cancel." + reply += "1. Political Disinformation\n", + reply += "2. Health Disinformation\n", + reply += "3. Other Disinformation\n", + reply += "Please try again or say `cancel` to cancel.\n" return [reply] if self.state == State.AWAITING_POLITICAL_DISINFORMATION_TYPE : From e23d7ea98462970ed07a09f0bb1e5d204069a61f Mon Sep 17 00:00:00 2001 From: oburay Date: Thu, 8 May 2025 21:32:18 -0700 Subject: [PATCH 06/41] Update : AWAITING_POLITICAL_DISINFORMATION_TYPE Workflow --- DiscordBot/report.py | 74 ++++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/DiscordBot/report.py b/DiscordBot/report.py index 2ff29520..f1fe1f45 100644 --- a/DiscordBot/report.py +++ b/DiscordBot/report.py @@ -199,52 +199,60 @@ async def handle_message(self, message): # Process political disinformation options if message.content == "1": - # Handling Conspiracy Theory - self.disinfo_subtype = "Conspiracy Theory" - self.state = State.AWAITING_FILTER_ACTION - reply = "You have selected " + self.disinfo_subtype + ".\n" - reply += "Would you like to filter content from this account on your feed? Select the correponding number:\n" - reply += "1. Yes\n" - reply += "2. No\n" + # Handling Election/Campaign Misinformation + self.disinfo_subtype = "Election/Campaign Misinformation" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" return [reply] elif message.content == "2": - # Handling Distorted Information - self.disinfo_subtype = "Distorted Information" - self.state = State.AWAITING_FILTER_ACTION - reply = "You have selected " + self.disinfo_subtype + ".\n" - reply += "Would you like to filter content from this account on your feed? Select the correponding number:\n" - reply += "1. Yes\n" - reply += "2. No\n" + # Handling Government/Civic Services + self.disinfo_subtype = "Government/Civic Services" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" return [reply] elif message.content == "3": - # Handling False Claim - self.disinfo_subtype = "False Claim" - self.state = State.AWAITING_FILTER_ACTION - reply = "You have selected " + self.disinfo_subtype + ".\n" - reply += "Would you like to filter content from this account on your feed? Select the correponding number:\n" - reply += "1. Yes\n" - reply += "2. No\n" + # Handling Manipulated Photos/Video + self.disinfo_subtype = "Manipulated Photos/Video" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" return [reply] elif message.content == "4": - # Handling Election/Campaign Misinformation - self.disinfo_subtype = "Election/Campaign Misinformation" - self.state = State.AWAITING_FILTER_ACTION - reply = "You have selected " + self.disinfo_subtype + ".\n" - reply += "Would you like to filter content from this account on your feed? Select the correponding number:\n" - reply += "1. Yes\n" - reply += "2. No\n" + # Handling Other + self.disinfo_subtype = "Other" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" return [reply] else : - # Handling + # Handling wrong political disinformation type reply = "Please select the type of political Disinformation by typing the corresponding number:\n" - reply += "1. Conspiracy Theory\n" - reply += "2. Distorted Information\n" - reply += "3. False Claim\n" - reply += "4. Election/Campaign Misinformation\n" + reply += "1. Election/Campaign Misinformation\n" + reply += "2. Government/Civic Services\n" + reply += "3. Manipulated Photos/Video\n" + reply += "4. Other\n" reply += "Please try again or say `cancel` to cancel." return [reply] From 56f5667786407d47e79dee4b943b892b9d0947d6 Mon Sep 17 00:00:00 2001 From: oburay Date: Thu, 8 May 2025 21:39:25 -0700 Subject: [PATCH 07/41] Update : AWAITING_HEALTHL_DISINFORMATION_TYPE Workflow --- DiscordBot/report.py | 61 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/DiscordBot/report.py b/DiscordBot/report.py index f1fe1f45..fd3a505e 100644 --- a/DiscordBot/report.py +++ b/DiscordBot/report.py @@ -255,7 +255,68 @@ async def handle_message(self, message): reply += "4. Other\n" reply += "Please try again or say `cancel` to cancel." return [reply] + + if self.state == State.AWAITING_HEALTHL_DISINFORMATION_TYPE: + # Process health disinformation options + + if message.content == "1": + # Handling Vaccines + self.disinfo_subtype = "Vaccines" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + elif message.content == "2": + # Handling Cures and Treatments + self.disinfo_subtype = "Cures and Treatments" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "3": + # Handling Mental Health + self.disinfo_subtype = "Mental Health" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "4": + # Handling Other + self.disinfo_subtype = "Other" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong health disinformation type + reply = "Please select the type of health Disinformation by typing the corresponding number:\n" + reply += "1. Vaccines\n" + reply += "2. Cures and Treatments\n" + reply += "3. Mental Health\n" + reply += "4. Other\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + if self.state == State.AWAITING_FILTER_ACTION: # Handling responses to filter account content From 0d23d2e43885324b8f073d8f53a7c631fe30c37a Mon Sep 17 00:00:00 2001 From: oburay Date: Thu, 8 May 2025 21:51:07 -0700 Subject: [PATCH 08/41] Update : AWAITING_HARMFUL_CONTENT_STATUS Workflow --- DiscordBot/report.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/DiscordBot/report.py b/DiscordBot/report.py index fd3a505e..cf81eded 100644 --- a/DiscordBot/report.py +++ b/DiscordBot/report.py @@ -32,6 +32,7 @@ def __init__(self, client): self.disinfo_type = None self.disinfo_subtype = None self.filter = False + self.harmful = False async def handle_message(self, message): ''' @@ -317,6 +318,26 @@ async def handle_message(self, message): reply += "Please try again or say `cancel` to cancel." return [reply] + if self.state == State.AWAITING_HARMFUL_CONTENT_STATUS: + # Handle decision making on whether content is harmful + + if message.content == "1" : + # No harmful content + self.state == State.AWAITING_FILTER_ACTION + reply = "Please indicate if you would like to block content from this account on your feed. Select the correponding number:\n" + reply += "1. No \n" + reply += "2. Yes \n" + return [reply] + + elif message.content in ["2", "3", "4"] : + # Harmful content + self.harmful = True + self.state == State.AWAITING_FILTER_ACTION + reply = "Thank you. Our team has been notified.\n" + reply += "Please indicate if you would like to block content from this account on your feed. Select the correponding number:\n" + reply += "1. No \n" + reply += "2. Yes \n" + if self.state == State.AWAITING_FILTER_ACTION: # Handling responses to filter account content From 27d4d66d534f49306b718b5c13bd8dec856d3eb1 Mon Sep 17 00:00:00 2001 From: oburay Date: Thu, 8 May 2025 21:57:03 -0700 Subject: [PATCH 09/41] Update : AWAITING_FILTER_ACTION Workflow --- DiscordBot/report.py | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/DiscordBot/report.py b/DiscordBot/report.py index cf81eded..f1dfb161 100644 --- a/DiscordBot/report.py +++ b/DiscordBot/report.py @@ -338,27 +338,33 @@ async def handle_message(self, message): reply += "1. No \n" reply += "2. Yes \n" + else: + # Handle wrong response to harmful prompt + reply = "Kindly indicate if this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + if self.state == State.AWAITING_FILTER_ACTION: # Handling responses to filter account content if message.content == "1": - # Handle content filtering - self.filter = True + # Handle no content filtering action self.state = State.REPORT_COMPLETE - return [ - "This account’s posts have been restricted from appearing on your feed.", - "Thank you for reporting" + self.report_type + " content.", - "Our content moderation team will review the message and take action which may result in content or account removal." - ] + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] elif message.content == "2": - # Handle no content filtering action + # Handle content filtering action + self.filter = True self.state = State.REPORT_COMPLETE - return [ - "This account’s posts have been restricted from appearing on your feed.", - " Thank you for reporting" + self.report_type + " content.", - "Our content moderation team will review the message and take action which may result in content or account removal." - ] + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] else: # wrong option for account filtering prompt From 936840dacb5f8a709744f9d5ebfdf3967d0a7ef3 Mon Sep 17 00:00:00 2001 From: andrewzian <69400346+andrewzian@users.noreply.github.com> Date: Thu, 8 May 2025 23:00:50 -0700 Subject: [PATCH 10/41] updated all state, bug fixes in user flow --- DiscordBot/bot.py | 8 ++++++++ DiscordBot/report.py | 34 ++++++++++++++++++++-------------- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/DiscordBot/bot.py b/DiscordBot/bot.py index 2749c84b..7a3b8d79 100644 --- a/DiscordBot/bot.py +++ b/DiscordBot/bot.py @@ -112,6 +112,14 @@ async def handle_dm(self, message): if self.reports[author_id].is_awaiting_political_disinformation_type(): for r in responses: await message.channel.send(r) + + if self.reports[author_id].is_awaiting_healthl_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_harmful_content_status(): + for r in responses: + await message.channel.send(r) if self.reports[author_id].is_awaiting_filter_action(): for r in responses: diff --git a/DiscordBot/report.py b/DiscordBot/report.py index f1dfb161..a516a2a1 100644 --- a/DiscordBot/report.py +++ b/DiscordBot/report.py @@ -189,10 +189,10 @@ async def handle_message(self, message): else : # Handling wrong disinformation type - reply = "Kindly enter a valid disinformation type by selecting the correponding number:", - reply += "1. Political Disinformation\n", - reply += "2. Health Disinformation\n", - reply += "3. Other Disinformation\n", + reply = "Kindly enter a valid disinformation type by selecting the correponding number:\n" + reply += "1. Political Disinformation\n" + reply += "2. Health Disinformation\n" + reply += "3. Other Disinformation\n" reply += "Please try again or say `cancel` to cancel.\n" return [reply] @@ -203,7 +203,7 @@ async def handle_message(self, message): # Handling Election/Campaign Misinformation self.disinfo_subtype = "Election/Campaign Misinformation" self.state = State.AWAITING_HARMFUL_CONTENT_STATUS - reply = "You have selected " + self.disinfo_type + ".\n" + reply = "You have selected " + self.disinfo_subtype + ".\n" reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" reply += "1. No.\n" reply += "2. Yes, physical harm.\n" @@ -215,7 +215,7 @@ async def handle_message(self, message): # Handling Government/Civic Services self.disinfo_subtype = "Government/Civic Services" self.state = State.AWAITING_HARMFUL_CONTENT_STATUS - reply = "You have selected " + self.disinfo_type + ".\n" + reply = "You have selected " + self.disinfo_subtype + ".\n" reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" reply += "1. No.\n" reply += "2. Yes, physical harm.\n" @@ -227,7 +227,7 @@ async def handle_message(self, message): # Handling Manipulated Photos/Video self.disinfo_subtype = "Manipulated Photos/Video" self.state = State.AWAITING_HARMFUL_CONTENT_STATUS - reply = "You have selected " + self.disinfo_type + ".\n" + reply = "You have selected " + self.disinfo_subtype + ".\n" reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" reply += "1. No.\n" reply += "2. Yes, physical harm.\n" @@ -239,7 +239,7 @@ async def handle_message(self, message): # Handling Other self.disinfo_subtype = "Other" self.state = State.AWAITING_HARMFUL_CONTENT_STATUS - reply = "You have selected " + self.disinfo_type + ".\n" + reply = "You have selected " + self.disinfo_subtype + ".\n" reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" reply += "1. No.\n" reply += "2. Yes, physical harm.\n" @@ -264,7 +264,7 @@ async def handle_message(self, message): # Handling Vaccines self.disinfo_subtype = "Vaccines" self.state = State.AWAITING_HARMFUL_CONTENT_STATUS - reply = "You have selected " + self.disinfo_type + ".\n" + reply = "You have selected " + self.disinfo_subtype + ".\n" reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" reply += "1. No.\n" reply += "2. Yes, physical harm.\n" @@ -276,7 +276,7 @@ async def handle_message(self, message): # Handling Cures and Treatments self.disinfo_subtype = "Cures and Treatments" self.state = State.AWAITING_HARMFUL_CONTENT_STATUS - reply = "You have selected " + self.disinfo_type + ".\n" + reply = "You have selected " + self.disinfo_subtype + ".\n" reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" reply += "1. No.\n" reply += "2. Yes, physical harm.\n" @@ -288,7 +288,7 @@ async def handle_message(self, message): # Handling Mental Health self.disinfo_subtype = "Mental Health" self.state = State.AWAITING_HARMFUL_CONTENT_STATUS - reply = "You have selected " + self.disinfo_type + ".\n" + reply = "You have selected " + self.disinfo_subtype + ".\n" reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" reply += "1. No.\n" reply += "2. Yes, physical harm.\n" @@ -300,7 +300,7 @@ async def handle_message(self, message): # Handling Other self.disinfo_subtype = "Other" self.state = State.AWAITING_HARMFUL_CONTENT_STATUS - reply = "You have selected " + self.disinfo_type + ".\n" + reply = "You have selected " + self.disinfo_subtype + ".\n" reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" reply += "1. No.\n" reply += "2. Yes, physical harm.\n" @@ -323,7 +323,7 @@ async def handle_message(self, message): if message.content == "1" : # No harmful content - self.state == State.AWAITING_FILTER_ACTION + self.state = State.AWAITING_FILTER_ACTION reply = "Please indicate if you would like to block content from this account on your feed. Select the correponding number:\n" reply += "1. No \n" reply += "2. Yes \n" @@ -332,11 +332,12 @@ async def handle_message(self, message): elif message.content in ["2", "3", "4"] : # Harmful content self.harmful = True - self.state == State.AWAITING_FILTER_ACTION + self.state = State.AWAITING_FILTER_ACTION reply = "Thank you. Our team has been notified.\n" reply += "Please indicate if you would like to block content from this account on your feed. Select the correponding number:\n" reply += "1. No \n" reply += "2. Yes \n" + return [reply] else: # Handle wrong response to harmful prompt @@ -345,6 +346,7 @@ async def handle_message(self, message): reply += "2. Yes, physical harm.\n" reply += "3. Yes, mental harm.\n" reply += "4. Yes, financial or property harm.\n" + reply += "Please try again or say `cancel` to cancel." return [reply] @@ -407,6 +409,10 @@ def is_awaiting_disinformation_type(self): return self.state == State.AWAITING_DISINFORMATION_TYPE def is_awaiting_political_disinformation_type(self): return self.state == State.AWAITING_POLITICAL_DISINFORMATION_TYPE + def is_awaiting_healthl_disinformation_type(self): + return self.state == State.AWAITING_HEALTHL_DISINFORMATION_TYPE + def is_awaiting_harmful_content_status(self): + return self.state == State.AWAITING_HARMFUL_CONTENT_STATUS def is_awaiting_filter_action(self): return self.state == State.AWAITING_FILTER_ACTION # def block_step(self): From c9c77a3a99d96caf988cd7cd5621c4360d4885b9 Mon Sep 17 00:00:00 2001 From: andrewzian <69400346+andrewzian@users.noreply.github.com> Date: Thu, 8 May 2025 23:16:09 -0700 Subject: [PATCH 11/41] message on double report --- DiscordBot/report.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/DiscordBot/report.py b/DiscordBot/report.py index a516a2a1..c391b916 100644 --- a/DiscordBot/report.py +++ b/DiscordBot/report.py @@ -52,6 +52,10 @@ async def handle_message(self, message): reply += "You can obtain this link by right-clicking the message and clicking `Copy Message Link`." self.state = State.AWAITING_MESSAGE return [reply] + else: + if message.content == self.START_KEYWORD: + reply = "You currently have an active report open, the state is " + self.state.name + "." + return [reply] if self.state == State.AWAITING_MESSAGE: # Parse out the three ID strings from the message link From 3bf9939686091225a9641eb9675543ded18921b0 Mon Sep 17 00:00:00 2001 From: andrewzian <69400346+andrewzian@users.noreply.github.com> Date: Fri, 9 May 2025 13:41:54 -0700 Subject: [PATCH 12/41] forgot to commit initially --- DiscordBot/bot.py | 21 ++++++++++++++++++++- DiscordBot/report.py | 21 ++++++++++++++++++--- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/DiscordBot/bot.py b/DiscordBot/bot.py index 7a3b8d79..842b93ab 100644 --- a/DiscordBot/bot.py +++ b/DiscordBot/bot.py @@ -7,6 +7,7 @@ import re import requests from report import Report +from report_queue import SubmittedReport, PriorityReportQueue import pdb # Set up logging to the console @@ -37,6 +38,9 @@ def __init__(self): self.group_num = None self.mod_channels = {} # Map from guild to the mod channel id for that guild self.reports = {} # Map from user IDs to the state of their report + self.report_id_counter = 0 + # should equal the number of distinct priorities defined in Report.get_priority + self.report_queue = PriorityReportQueue(3, ["Imminent physical/mental harm", "Imminent financial/property harm", "Non-imminent"]) async def on_ready(self): print(f'{self.user.name} has connected to Discord! It is these guilds:') @@ -149,6 +153,10 @@ async def handle_dm(self, message): report_type = self.reports[author_id].get_report_type() disinfo_type = self.reports[author_id].get_disinfo_type() disinfo_subtype = self.reports[author_id].get_disinfo_subtype() + imminent = self.reports[author_id].get_imminent() + priority = self.reports[author_id].get_priority() + id = self.report_id_counter + id += 1 for r in responses: await message.channel.send(r) @@ -159,7 +167,10 @@ async def handle_dm(self, message): report_info_msg = MOD_TODO_START + " User " + message.author.name + " reported user " + str(reported_author) + "'s message.\n" report_info_msg += "Here is the message: \n```" + str(reported_content) + "\n```" report_info_msg += "Category: " + str(report_type) + " > " + str(disinfo_type) + " > " + str(disinfo_subtype) + "\n" - report_info_msg += "react to this message in order to moderate it\n" + if imminent: + report_info_msg += "FLAG: Imminent " + imminent + " harm reported." + submitted_report = SubmittedReport(id, reported_author, reported_content, report_type, disinfo_type, disinfo_subtype) + self.report_queue.enqueue(submitted_report, priority) await mod_channel.send(report_info_msg) @@ -177,6 +188,14 @@ async def handle_channel_message(self, message): if not message.channel.name == f'group-{self.group_num}': return + # moderator commands + if message.channel.name == f'group-{self.group_num}-mod': + if message.content == "report summary": + message.channel.send(self.report_queue.summary()) + elif message.content == "report display": + message.channel.send(self.report_queue.display()) + + # ----- teddy: commented out to reduce clutter for milestone 2 since we are not doing auto flagging ------------ # # Forward the message to the mod channel # mod_channel = self.mod_channels[message.guild.id] diff --git a/DiscordBot/report.py b/DiscordBot/report.py index c391b916..01d75064 100644 --- a/DiscordBot/report.py +++ b/DiscordBot/report.py @@ -32,7 +32,7 @@ def __init__(self, client): self.disinfo_type = None self.disinfo_subtype = None self.filter = False - self.harmful = False + self.imminent = None async def handle_message(self, message): ''' @@ -54,7 +54,8 @@ async def handle_message(self, message): return [reply] else: if message.content == self.START_KEYWORD: - reply = "You currently have an active report open, the state is " + self.state.name + "." + reply = "You currently have an active report open, the status is " + self.state.name + ". " + reply += "Please continue this report or say `cancel` to cancel.\n" return [reply] if self.state == State.AWAITING_MESSAGE: @@ -335,7 +336,12 @@ async def handle_message(self, message): elif message.content in ["2", "3", "4"] : # Harmful content - self.harmful = True + harm_dict = { + "2": "physical", + "3": "mental", + "4": "financial" + } + self.imminent = harm_dict[message.content] self.state = State.AWAITING_FILTER_ACTION reply = "Thank you. Our team has been notified.\n" reply += "Please indicate if you would like to block content from this account on your feed. Select the correponding number:\n" @@ -400,6 +406,15 @@ def get_disinfo_type(self): return self.disinfo_type def get_disinfo_subtype(self): return self.disinfo_subtype + def get_imminent(self): + return self.imminent + def get_priority(self): # defining priorities, can be changed + if self.imminent in ["physical", "mental"]: + return 0 + elif self.imminent == "financial": + return 1 + else: + return 2 def get_filter(self): return self.filter From e60065798826962457da552b871e3fed5058dfe6 Mon Sep 17 00:00:00 2001 From: andrewzian <69400346+andrewzian@users.noreply.github.com> Date: Fri, 9 May 2025 13:43:57 -0700 Subject: [PATCH 13/41] forgot to commit initially --- .history/DiscordBot/bot_20250508222458.py | 235 + .history/DiscordBot/bot_20250509124520.py | 237 + .history/DiscordBot/bot_20250509125037.py | 238 + .history/DiscordBot/bot_20250509125209.py | 238 + .history/DiscordBot/bot_20250509125348.py | 239 + .history/DiscordBot/bot_20250509125707.py | 241 + .history/DiscordBot/bot_20250509131012.py | 242 + .history/DiscordBot/bot_20250509131355.py | 242 + .history/DiscordBot/bot_20250509131440.py | 242 + .history/DiscordBot/bot_20250509131607.py | 243 + .history/DiscordBot/bot_20250509131821.py | 245 + .history/DiscordBot/bot_20250509132756.py | 253 + .history/DiscordBot/bot_20250509133441.py | 253 + .history/DiscordBot/bot_20250509133536.py | 254 + .history/DiscordBot/report_20250508231525.py | 426 + .history/DiscordBot/report_20250509105254.py | 427 + .history/DiscordBot/report_20250509105318.py | 427 + .history/DiscordBot/report_20250509124520.py | 429 + .history/DiscordBot/report_20250509124544.py | 429 + .history/DiscordBot/report_20250509124556.py | 429 + .history/DiscordBot/report_20250509124712.py | 434 + .history/DiscordBot/report_20250509124922.py | 434 + .history/DiscordBot/report_20250509124933.py | 434 + .history/DiscordBot/report_20250509131005.py | 441 + .../DiscordBot/report_queue_20250509131250.py | 30 + .../DiscordBot/report_queue_20250509131330.py | 30 + .../DiscordBot/report_queue_20250509131820.py | 34 + .../DiscordBot/report_queue_20250509132041.py | 34 + .../DiscordBot/report_queue_20250509132223.py | 37 + .../DiscordBot/report_queue_20250509132453.py | 45 + .../DiscordBot/report_queue_20250509133058.py | 61 + .../DiscordBot/report_queue_20250509133229.py | 60 + .../DiscordBot/report_queue_20250509133302.py | 62 + .../DiscordBot/report_queue_20250509133440.py | 62 + .../submitted_report_20250509124230.py | 0 .../submitted_report_20250509125057.py | 7 + .../submitted_report_20250509131251.py | 30 + DiscordBot/report_queue.py | 62 + venv/bin/Activate.ps1 | 247 + venv/bin/activate | 70 + venv/bin/activate.csh | 27 + venv/bin/activate.fish | 69 + venv/bin/normalizer | 10 + venv/bin/pip | 10 + venv/bin/pip3 | 10 + venv/bin/pip3.12 | 10 + venv/bin/python | 1 + venv/bin/python3 | 1 + venv/bin/python3.12 | 1 + .../INSTALLER | 1 + .../aiohappyeyeballs-2.6.1.dist-info/LICENSE | 279 + .../aiohappyeyeballs-2.6.1.dist-info/METADATA | 123 + .../aiohappyeyeballs-2.6.1.dist-info/RECORD | 16 + .../aiohappyeyeballs-2.6.1.dist-info/WHEEL | 4 + .../aiohappyeyeballs/__init__.py | 14 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 542 bytes .../__pycache__/_staggered.cpython-312.pyc | Bin 0 -> 8041 bytes .../__pycache__/impl.cpython-312.pyc | Bin 0 -> 10155 bytes .../__pycache__/types.cpython-312.pyc | Bin 0 -> 638 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 3750 bytes .../aiohappyeyeballs/_staggered.py | 207 + .../site-packages/aiohappyeyeballs/impl.py | 259 + .../site-packages/aiohappyeyeballs/py.typed | 0 .../site-packages/aiohappyeyeballs/types.py | 17 + .../site-packages/aiohappyeyeballs/utils.py | 97 + .../aiohttp-3.11.18.dist-info/INSTALLER | 1 + .../aiohttp-3.11.18.dist-info/METADATA | 251 + .../aiohttp-3.11.18.dist-info/RECORD | 131 + .../aiohttp-3.11.18.dist-info/WHEEL | 5 + .../licenses/LICENSE.txt | 13 + .../aiohttp-3.11.18.dist-info/top_level.txt | 1 + .../aiohttp/.hash/_cparser.pxd.hash | 1 + .../aiohttp/.hash/_find_header.pxd.hash | 1 + .../aiohttp/.hash/_http_parser.pyx.hash | 1 + .../aiohttp/.hash/_http_writer.pyx.hash | 1 + .../site-packages/aiohttp/.hash/hdrs.py.hash | 1 + .../site-packages/aiohttp/__init__.py | 264 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 5018 bytes .../aiohttp/__pycache__/abc.cpython-312.pyc | Bin 0 -> 11708 bytes .../__pycache__/base_protocol.cpython-312.pyc | Bin 0 -> 4555 bytes .../__pycache__/client.cpython-312.pyc | Bin 0 -> 53109 bytes .../client_exceptions.cpython-312.pyc | Bin 0 -> 18013 bytes .../__pycache__/client_proto.cpython-312.pyc | Bin 0 -> 11686 bytes .../__pycache__/client_reqrep.cpython-312.pyc | Bin 0 -> 56420 bytes .../__pycache__/client_ws.cpython-312.pyc | Bin 0 -> 22539 bytes .../compression_utils.cpython-312.pyc | Bin 0 -> 8991 bytes .../__pycache__/connector.cpython-312.pyc | Bin 0 -> 69312 bytes .../__pycache__/cookiejar.cpython-312.pyc | Bin 0 -> 20509 bytes .../__pycache__/formdata.cpython-312.pyc | Bin 0 -> 7762 bytes .../aiohttp/__pycache__/hdrs.cpython-312.pyc | Bin 0 -> 8519 bytes .../__pycache__/helpers.cpython-312.pyc | Bin 0 -> 41759 bytes .../aiohttp/__pycache__/http.cpython-312.pyc | Bin 0 -> 1720 bytes .../http_exceptions.cpython-312.pyc | Bin 0 -> 6190 bytes .../__pycache__/http_parser.cpython-312.pyc | Bin 0 -> 35666 bytes .../http_websocket.cpython-312.pyc | Bin 0 -> 1008 bytes .../__pycache__/http_writer.cpython-312.pyc | Bin 0 -> 10840 bytes .../aiohttp/__pycache__/log.cpython-312.pyc | Bin 0 -> 757 bytes .../__pycache__/multipart.cpython-312.pyc | Bin 0 -> 49693 bytes .../__pycache__/payload.cpython-312.pyc | Bin 0 -> 24914 bytes .../payload_streamer.cpython-312.pyc | Bin 0 -> 4445 bytes .../__pycache__/pytest_plugin.cpython-312.pyc | Bin 0 -> 18293 bytes .../__pycache__/resolver.cpython-312.pyc | Bin 0 -> 7645 bytes .../__pycache__/streams.cpython-312.pyc | Bin 0 -> 30991 bytes .../__pycache__/tcp_helpers.cpython-312.pyc | Bin 0 -> 1816 bytes .../__pycache__/test_utils.cpython-312.pyc | Bin 0 -> 34840 bytes .../__pycache__/tracing.cpython-312.pyc | Bin 0 -> 22588 bytes .../__pycache__/typedefs.cpython-312.pyc | Bin 0 -> 2309 bytes .../aiohttp/__pycache__/web.cpython-312.pyc | Bin 0 -> 16595 bytes .../__pycache__/web_app.cpython-312.pyc | Bin 0 -> 27368 bytes .../web_exceptions.cpython-312.pyc | Bin 0 -> 15041 bytes .../web_fileresponse.cpython-312.pyc | Bin 0 -> 17229 bytes .../__pycache__/web_log.cpython-312.pyc | Bin 0 -> 10713 bytes .../web_middlewares.cpython-312.pyc | Bin 0 -> 5662 bytes .../__pycache__/web_protocol.cpython-312.pyc | Bin 0 -> 31295 bytes .../__pycache__/web_request.cpython-312.pyc | Bin 0 -> 38650 bytes .../__pycache__/web_response.cpython-312.pyc | Bin 0 -> 38550 bytes .../__pycache__/web_routedef.cpython-312.pyc | Bin 0 -> 11936 bytes .../__pycache__/web_runner.cpython-312.pyc | Bin 0 -> 19064 bytes .../__pycache__/web_server.cpython-312.pyc | Bin 0 -> 4944 bytes .../web_urldispatcher.cpython-312.pyc | Bin 0 -> 68617 bytes .../__pycache__/web_ws.cpython-312.pyc | Bin 0 -> 31380 bytes .../__pycache__/worker.cpython-312.pyc | Bin 0 -> 12096 bytes .../site-packages/aiohttp/_cparser.pxd | 158 + .../site-packages/aiohttp/_find_header.pxd | 2 + .../site-packages/aiohttp/_headers.pxi | 83 + .../_http_parser.cpython-312-darwin.so | Bin 0 -> 388096 bytes .../site-packages/aiohttp/_http_parser.pyx | 837 + .../_http_writer.cpython-312-darwin.so | Bin 0 -> 99216 bytes .../site-packages/aiohttp/_http_writer.pyx | 160 + .../aiohttp/_websocket/.hash/mask.pxd.hash | 1 + .../aiohttp/_websocket/.hash/mask.pyx.hash | 1 + .../_websocket/.hash/reader_c.pxd.hash | 1 + .../aiohttp/_websocket/__init__.py | 1 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 280 bytes .../__pycache__/helpers.cpython-312.pyc | Bin 0 -> 6022 bytes .../__pycache__/models.cpython-312.pyc | Bin 0 -> 3490 bytes .../__pycache__/reader.cpython-312.pyc | Bin 0 -> 776 bytes .../__pycache__/reader_c.cpython-312.pyc | Bin 0 -> 17639 bytes .../__pycache__/reader_py.cpython-312.pyc | Bin 0 -> 17640 bytes .../__pycache__/writer.cpython-312.pyc | Bin 0 -> 6390 bytes .../aiohttp/_websocket/helpers.py | 147 + .../_websocket/mask.cpython-312-darwin.so | Bin 0 -> 79832 bytes .../site-packages/aiohttp/_websocket/mask.pxd | 3 + .../site-packages/aiohttp/_websocket/mask.pyx | 48 + .../aiohttp/_websocket/models.py | 84 + .../aiohttp/_websocket/reader.py | 31 + .../_websocket/reader_c.cpython-312-darwin.so | Bin 0 -> 225616 bytes .../aiohttp/_websocket/reader_c.pxd | 110 + .../aiohttp/_websocket/reader_c.py | 468 + .../aiohttp/_websocket/reader_py.py | 468 + .../aiohttp/_websocket/writer.py | 177 + .../python3.12/site-packages/aiohttp/abc.py | 253 + .../site-packages/aiohttp/base_protocol.py | 100 + .../site-packages/aiohttp/client.py | 1550 ++ .../aiohttp/client_exceptions.py | 421 + .../site-packages/aiohttp/client_proto.py | 308 + .../site-packages/aiohttp/client_reqrep.py | 1315 ++ .../site-packages/aiohttp/client_ws.py | 428 + .../aiohttp/compression_utils.py | 173 + .../site-packages/aiohttp/connector.py | 1658 ++ .../site-packages/aiohttp/cookiejar.py | 495 + .../site-packages/aiohttp/formdata.py | 182 + .../python3.12/site-packages/aiohttp/hdrs.py | 121 + .../site-packages/aiohttp/helpers.py | 958 ++ .../python3.12/site-packages/aiohttp/http.py | 72 + .../site-packages/aiohttp/http_exceptions.py | 112 + .../site-packages/aiohttp/http_parser.py | 1046 ++ .../site-packages/aiohttp/http_websocket.py | 36 + .../site-packages/aiohttp/http_writer.py | 249 + .../python3.12/site-packages/aiohttp/log.py | 8 + .../site-packages/aiohttp/multipart.py | 1071 ++ .../site-packages/aiohttp/payload.py | 519 + .../site-packages/aiohttp/payload_streamer.py | 78 + .../python3.12/site-packages/aiohttp/py.typed | 1 + .../site-packages/aiohttp/pytest_plugin.py | 436 + .../site-packages/aiohttp/resolver.py | 190 + .../site-packages/aiohttp/streams.py | 727 + .../site-packages/aiohttp/tcp_helpers.py | 37 + .../site-packages/aiohttp/test_utils.py | 774 + .../site-packages/aiohttp/tracing.py | 470 + .../site-packages/aiohttp/typedefs.py | 69 + .../python3.12/site-packages/aiohttp/web.py | 605 + .../site-packages/aiohttp/web_app.py | 620 + .../site-packages/aiohttp/web_exceptions.py | 452 + .../site-packages/aiohttp/web_fileresponse.py | 418 + .../site-packages/aiohttp/web_log.py | 216 + .../site-packages/aiohttp/web_middlewares.py | 121 + .../site-packages/aiohttp/web_protocol.py | 792 + .../site-packages/aiohttp/web_request.py | 914 ++ .../site-packages/aiohttp/web_response.py | 838 + .../site-packages/aiohttp/web_routedef.py | 214 + .../site-packages/aiohttp/web_runner.py | 399 + .../site-packages/aiohttp/web_server.py | 84 + .../aiohttp/web_urldispatcher.py | 1303 ++ .../site-packages/aiohttp/web_ws.py | 627 + .../site-packages/aiohttp/worker.py | 255 + .../aiosignal-1.3.2.dist-info/INSTALLER | 1 + .../aiosignal-1.3.2.dist-info/LICENSE | 201 + .../aiosignal-1.3.2.dist-info/METADATA | 123 + .../aiosignal-1.3.2.dist-info/RECORD | 10 + .../aiosignal-1.3.2.dist-info/WHEEL | 6 + .../aiosignal-1.3.2.dist-info/top_level.txt | 1 + .../site-packages/aiosignal/__init__.py | 36 + .../site-packages/aiosignal/__init__.pyi | 12 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1702 bytes .../site-packages/aiosignal/py.typed | 0 .../python3.12/site-packages/attr/__init__.py | 104 + .../site-packages/attr/__init__.pyi | 389 + .../attr/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 2651 bytes .../attr/__pycache__/_cmp.cpython-312.pyc | Bin 0 -> 5115 bytes .../attr/__pycache__/_compat.cpython-312.pyc | Bin 0 -> 3541 bytes .../attr/__pycache__/_config.cpython-312.pyc | Bin 0 -> 1147 bytes .../attr/__pycache__/_funcs.cpython-312.pyc | Bin 0 -> 13670 bytes .../attr/__pycache__/_make.cpython-312.pyc | Bin 0 -> 99525 bytes .../__pycache__/_next_gen.cpython-312.pyc | Bin 0 -> 24393 bytes .../__pycache__/_version_info.cpython-312.pyc | Bin 0 -> 3161 bytes .../__pycache__/converters.cpython-312.pyc | Bin 0 -> 4665 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 3618 bytes .../attr/__pycache__/filters.cpython-312.pyc | Bin 0 -> 3032 bytes .../attr/__pycache__/setters.cpython-312.pyc | Bin 0 -> 1952 bytes .../__pycache__/validators.cpython-312.pyc | Bin 0 -> 26262 bytes .../lib/python3.12/site-packages/attr/_cmp.py | 160 + .../python3.12/site-packages/attr/_cmp.pyi | 13 + .../python3.12/site-packages/attr/_compat.py | 94 + .../python3.12/site-packages/attr/_config.py | 31 + .../python3.12/site-packages/attr/_funcs.py | 468 + .../python3.12/site-packages/attr/_make.py | 3123 ++++ .../site-packages/attr/_next_gen.py | 623 + .../site-packages/attr/_typing_compat.pyi | 15 + .../site-packages/attr/_version_info.py | 86 + .../site-packages/attr/_version_info.pyi | 9 + .../site-packages/attr/converters.py | 162 + .../site-packages/attr/converters.pyi | 19 + .../site-packages/attr/exceptions.py | 95 + .../site-packages/attr/exceptions.pyi | 17 + .../python3.12/site-packages/attr/filters.py | 72 + .../python3.12/site-packages/attr/filters.pyi | 6 + .../python3.12/site-packages/attr/py.typed | 0 .../python3.12/site-packages/attr/setters.py | 79 + .../python3.12/site-packages/attr/setters.pyi | 20 + .../site-packages/attr/validators.py | 710 + .../site-packages/attr/validators.pyi | 86 + .../attrs-25.3.0.dist-info/INSTALLER | 1 + .../attrs-25.3.0.dist-info/METADATA | 232 + .../attrs-25.3.0.dist-info/RECORD | 55 + .../attrs-25.3.0.dist-info/WHEEL | 4 + .../attrs-25.3.0.dist-info/licenses/LICENSE | 21 + .../site-packages/attrs/__init__.py | 69 + .../site-packages/attrs/__init__.pyi | 263 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1171 bytes .../__pycache__/converters.cpython-312.pyc | Bin 0 -> 256 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 256 bytes .../attrs/__pycache__/filters.cpython-312.pyc | Bin 0 -> 250 bytes .../attrs/__pycache__/setters.cpython-312.pyc | Bin 0 -> 250 bytes .../__pycache__/validators.cpython-312.pyc | Bin 0 -> 256 bytes .../site-packages/attrs/converters.py | 3 + .../site-packages/attrs/exceptions.py | 3 + .../python3.12/site-packages/attrs/filters.py | 3 + .../python3.12/site-packages/attrs/py.typed | 0 .../python3.12/site-packages/attrs/setters.py | 3 + .../site-packages/attrs/validators.py | 3 + .../certifi-2025.4.26.dist-info/INSTALLER | 1 + .../certifi-2025.4.26.dist-info/METADATA | 78 + .../certifi-2025.4.26.dist-info/RECORD | 14 + .../certifi-2025.4.26.dist-info/WHEEL | 5 + .../licenses/LICENSE | 20 + .../certifi-2025.4.26.dist-info/top_level.txt | 1 + .../site-packages/certifi/__init__.py | 4 + .../site-packages/certifi/__main__.py | 12 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 344 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 659 bytes .../certifi/__pycache__/core.cpython-312.pyc | Bin 0 -> 3229 bytes .../site-packages/certifi/cacert.pem | 4676 ++++++ .../python3.12/site-packages/certifi/core.py | 114 + .../python3.12/site-packages/certifi/py.typed | 0 .../INSTALLER | 1 + .../METADATA | 731 + .../charset_normalizer-3.4.2.dist-info/RECORD | 35 + .../charset_normalizer-3.4.2.dist-info/WHEEL | 6 + .../entry_points.txt | 2 + .../licenses/LICENSE | 21 + .../top_level.txt | 1 + .../charset_normalizer/__init__.py | 48 + .../charset_normalizer/__main__.py | 6 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1810 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 385 bytes .../__pycache__/api.cpython-312.pyc | Bin 0 -> 18199 bytes .../__pycache__/cd.cpython-312.pyc | Bin 0 -> 13326 bytes .../__pycache__/constant.cpython-312.pyc | Bin 0 -> 40840 bytes .../__pycache__/legacy.cpython-312.pyc | Bin 0 -> 2810 bytes .../__pycache__/md.cpython-312.pyc | Bin 0 -> 24377 bytes .../__pycache__/models.cpython-312.pyc | Bin 0 -> 17157 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 13786 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 412 bytes .../site-packages/charset_normalizer/api.py | 668 + .../site-packages/charset_normalizer/cd.py | 395 + .../charset_normalizer/cli/__init__.py | 8 + .../charset_normalizer/cli/__main__.py | 381 + .../cli/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 373 bytes .../cli/__pycache__/__main__.cpython-312.pyc | Bin 0 -> 14434 bytes .../charset_normalizer/constant.py | 2015 +++ .../charset_normalizer/legacy.py | 64 + .../md.cpython-312-darwin.so | Bin 0 -> 115744 bytes .../site-packages/charset_normalizer/md.py | 635 + .../md__mypyc.cpython-312-darwin.so | Bin 0 -> 482040 bytes .../charset_normalizer/models.py | 360 + .../site-packages/charset_normalizer/py.typed | 0 .../site-packages/charset_normalizer/utils.py | 414 + .../charset_normalizer/version.py | 8 + .../site-packages/discord/__init__.py | 96 + .../site-packages/discord/__main__.py | 357 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 2812 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 15355 bytes .../__pycache__/_types.cpython-312.pyc | Bin 0 -> 1664 bytes .../discord/__pycache__/abc.cpython-312.pyc | Bin 0 -> 82878 bytes .../__pycache__/activity.cpython-312.pyc | Bin 0 -> 36624 bytes .../__pycache__/appinfo.cpython-312.pyc | Bin 0 -> 25283 bytes .../discord/__pycache__/asset.cpython-312.pyc | Bin 0 -> 21287 bytes .../__pycache__/audit_logs.cpython-312.pyc | Bin 0 -> 47442 bytes .../__pycache__/automod.cpython-312.pyc | Bin 0 -> 32556 bytes .../__pycache__/backoff.cpython-312.pyc | Bin 0 -> 5005 bytes .../__pycache__/channel.cpython-312.pyc | Bin 0 -> 152117 bytes .../__pycache__/client.cpython-312.pyc | Bin 0 -> 124214 bytes .../__pycache__/colour.cpython-312.pyc | Bin 0 -> 20306 bytes .../__pycache__/components.cpython-312.pyc | Bin 0 -> 26296 bytes .../context_managers.cpython-312.pyc | Bin 0 -> 5237 bytes .../__pycache__/embeds.cpython-312.pyc | Bin 0 -> 29628 bytes .../discord/__pycache__/emoji.cpython-312.pyc | Bin 0 -> 14152 bytes .../discord/__pycache__/enums.cpython-312.pyc | Bin 0 -> 35509 bytes .../__pycache__/errors.cpython-312.pyc | Bin 0 -> 12946 bytes .../discord/__pycache__/file.cpython-312.pyc | Bin 0 -> 6418 bytes .../discord/__pycache__/flags.cpython-312.pyc | Bin 0 -> 87706 bytes .../__pycache__/gateway.cpython-312.pyc | Bin 0 -> 52022 bytes .../discord/__pycache__/guild.cpython-312.pyc | Bin 0 -> 196033 bytes .../discord/__pycache__/http.cpython-312.pyc | Bin 0 -> 116102 bytes .../__pycache__/integrations.cpython-312.pyc | Bin 0 -> 16226 bytes .../__pycache__/interactions.cpython-312.pyc | Bin 0 -> 62855 bytes .../__pycache__/invite.cpython-312.pyc | Bin 0 -> 24199 bytes .../__pycache__/member.cpython-312.pyc | Bin 0 -> 54627 bytes .../__pycache__/mentions.cpython-312.pyc | Bin 0 -> 7074 bytes .../__pycache__/message.cpython-312.pyc | Bin 0 -> 134855 bytes .../__pycache__/mixins.cpython-312.pyc | Bin 0 -> 2326 bytes .../__pycache__/object.cpython-312.pyc | Bin 0 -> 4896 bytes .../__pycache__/oggparse.cpython-312.pyc | Bin 0 -> 5363 bytes .../discord/__pycache__/opus.cpython-312.pyc | Bin 0 -> 23494 bytes .../__pycache__/partial_emoji.cpython-312.pyc | Bin 0 -> 11167 bytes .../__pycache__/permissions.cpython-312.pyc | Bin 0 -> 39775 bytes .../__pycache__/player.cpython-312.pyc | Bin 0 -> 39928 bytes .../discord/__pycache__/poll.cpython-312.pyc | Bin 0 -> 26053 bytes .../__pycache__/presences.cpython-312.pyc | Bin 0 -> 8327 bytes .../__pycache__/raw_models.cpython-312.pyc | Bin 0 -> 22992 bytes .../__pycache__/reaction.cpython-312.pyc | Bin 0 -> 11932 bytes .../discord/__pycache__/role.cpython-312.pyc | Bin 0 -> 28037 bytes .../scheduled_event.cpython-312.pyc | Bin 0 -> 27709 bytes .../discord/__pycache__/shard.cpython-312.pyc | Bin 0 -> 33942 bytes .../discord/__pycache__/sku.cpython-312.pyc | Bin 0 -> 15192 bytes .../__pycache__/soundboard.cpython-312.pyc | Bin 0 -> 13521 bytes .../stage_instance.cpython-312.pyc | Bin 0 -> 7840 bytes .../discord/__pycache__/state.cpython-312.pyc | Bin 0 -> 111286 bytes .../__pycache__/sticker.cpython-312.pyc | Bin 0 -> 21318 bytes .../__pycache__/subscription.cpython-312.pyc | Bin 0 -> 5215 bytes .../discord/__pycache__/team.cpython-312.pyc | Bin 0 -> 6700 bytes .../__pycache__/template.cpython-312.pyc | Bin 0 -> 13242 bytes .../__pycache__/threads.cpython-312.pyc | Bin 0 -> 40321 bytes .../discord/__pycache__/user.cpython-312.pyc | Bin 0 -> 24067 bytes .../discord/__pycache__/utils.cpython-312.pyc | Bin 0 -> 64183 bytes .../__pycache__/voice_client.cpython-312.pyc | Bin 0 -> 27890 bytes .../__pycache__/voice_state.cpython-312.pyc | Bin 0 -> 39339 bytes .../welcome_screen.cpython-312.pyc | Bin 0 -> 9392 bytes .../__pycache__/widget.cpython-312.pyc | Bin 0 -> 13388 bytes .../site-packages/discord/_types.py | 34 + .../python3.12/site-packages/discord/abc.py | 2001 +++ .../site-packages/discord/activity.py | 870 + .../discord/app_commands/__init__.py | 21 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 683 bytes .../__pycache__/checks.cpython-312.pyc | Bin 0 -> 22079 bytes .../__pycache__/commands.cpython-312.pyc | Bin 0 -> 116506 bytes .../__pycache__/errors.cpython-312.pyc | Bin 0 -> 24666 bytes .../__pycache__/installs.cpython-312.pyc | Bin 0 -> 10724 bytes .../__pycache__/models.cpython-312.pyc | Bin 0 -> 48714 bytes .../__pycache__/namespace.cpython-312.pyc | Bin 0 -> 14461 bytes .../__pycache__/transformers.cpython-312.pyc | Bin 0 -> 41852 bytes .../__pycache__/translator.cpython-312.pyc | Bin 0 -> 13297 bytes .../__pycache__/tree.cpython-312.pyc | Bin 0 -> 56503 bytes .../discord/app_commands/checks.py | 537 + .../discord/app_commands/commands.py | 2886 ++++ .../discord/app_commands/errors.py | 519 + .../discord/app_commands/installs.py | 207 + .../discord/app_commands/models.py | 1124 ++ .../discord/app_commands/namespace.py | 263 + .../discord/app_commands/transformers.py | 878 ++ .../discord/app_commands/translator.py | 305 + .../discord/app_commands/tree.py | 1317 ++ .../site-packages/discord/appinfo.py | 645 + .../python3.12/site-packages/discord/asset.py | 536 + .../site-packages/discord/audit_logs.py | 938 ++ .../site-packages/discord/automod.py | 672 + .../site-packages/discord/backoff.py | 108 + .../discord/bin/libopus-0.x64.dll | Bin 0 -> 441856 bytes .../discord/bin/libopus-0.x86.dll | Bin 0 -> 366080 bytes .../site-packages/discord/channel.py | 3611 +++++ .../site-packages/discord/client.py | 3289 ++++ .../site-packages/discord/colour.py | 526 + .../site-packages/discord/components.py | 663 + .../site-packages/discord/context_managers.py | 92 + .../site-packages/discord/embeds.py | 779 + .../python3.12/site-packages/discord/emoji.py | 302 + .../python3.12/site-packages/discord/enums.py | 881 ++ .../site-packages/discord/errors.py | 305 + .../discord/ext/commands/__init__.py | 21 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 677 bytes .../__pycache__/_types.cpython-312.pyc | Bin 0 -> 3408 bytes .../commands/__pycache__/bot.cpython-312.pyc | Bin 0 -> 62915 bytes .../commands/__pycache__/cog.cpython-312.pyc | Bin 0 -> 34685 bytes .../__pycache__/context.cpython-312.pyc | Bin 0 -> 45708 bytes .../__pycache__/converter.cpython-312.pyc | Bin 0 -> 63045 bytes .../__pycache__/cooldowns.cpython-312.pyc | Bin 0 -> 15008 bytes .../commands/__pycache__/core.cpython-312.pyc | Bin 0 -> 108410 bytes .../__pycache__/errors.cpython-312.pyc | Bin 0 -> 49006 bytes .../__pycache__/flags.cpython-312.pyc | Bin 0 -> 27897 bytes .../commands/__pycache__/help.cpython-312.pyc | Bin 0 -> 73862 bytes .../__pycache__/hybrid.cpython-312.pyc | Bin 0 -> 45938 bytes .../__pycache__/parameters.cpython-312.pyc | Bin 0 -> 11347 bytes .../commands/__pycache__/view.cpython-312.pyc | Bin 0 -> 8075 bytes .../discord/ext/commands/_types.py | 73 + .../site-packages/discord/ext/commands/bot.py | 1530 ++ .../site-packages/discord/ext/commands/cog.py | 809 + .../discord/ext/commands/context.py | 1089 ++ .../discord/ext/commands/converter.py | 1444 ++ .../discord/ext/commands/cooldowns.py | 285 + .../discord/ext/commands/core.py | 2640 ++++ .../discord/ext/commands/errors.py | 1226 ++ .../discord/ext/commands/flags.py | 670 + .../discord/ext/commands/help.py | 1583 ++ .../discord/ext/commands/hybrid.py | 954 ++ .../discord/ext/commands/parameters.py | 322 + .../discord/ext/commands/view.py | 196 + .../discord/ext/tasks/__init__.py | 842 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 38045 bytes .../python3.12/site-packages/discord/file.py | 159 + .../python3.12/site-packages/discord/flags.py | 2399 +++ .../site-packages/discord/gateway.py | 1046 ++ .../python3.12/site-packages/discord/guild.py | 4791 ++++++ .../python3.12/site-packages/discord/http.py | 2773 ++++ .../site-packages/discord/integrations.py | 417 + .../site-packages/discord/interactions.py | 1498 ++ .../site-packages/discord/invite.py | 571 + .../site-packages/discord/member.py | 1187 ++ .../site-packages/discord/mentions.py | 153 + .../site-packages/discord/message.py | 3049 ++++ .../site-packages/discord/mixins.py | 46 + .../site-packages/discord/object.py | 117 + .../site-packages/discord/oggparse.py | 117 + .../python3.12/site-packages/discord/opus.py | 506 + .../site-packages/discord/partial_emoji.py | 269 + .../site-packages/discord/permissions.py | 993 ++ .../site-packages/discord/player.py | 836 + .../python3.12/site-packages/discord/poll.py | 672 + .../site-packages/discord/presences.py | 150 + .../python3.12/site-packages/discord/py.typed | 0 .../site-packages/discord/raw_models.py | 555 + .../site-packages/discord/reaction.py | 286 + .../python3.12/site-packages/discord/role.py | 651 + .../site-packages/discord/scheduled_event.py | 682 + .../python3.12/site-packages/discord/shard.py | 638 + .../python3.12/site-packages/discord/sku.py | 359 + .../site-packages/discord/soundboard.py | 325 + .../site-packages/discord/stage_instance.py | 192 + .../python3.12/site-packages/discord/state.py | 1983 +++ .../site-packages/discord/sticker.py | 521 + .../site-packages/discord/subscription.py | 107 + .../python3.12/site-packages/discord/team.py | 152 + .../site-packages/discord/template.py | 313 + .../site-packages/discord/threads.py | 976 ++ .../site-packages/discord/types/__init__.py | 10 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 382 bytes .../__pycache__/activity.cpython-312.pyc | Bin 0 -> 4556 bytes .../types/__pycache__/appinfo.cpython-312.pyc | Bin 0 -> 4244 bytes .../__pycache__/audit_log.cpython-312.pyc | Bin 0 -> 11359 bytes .../types/__pycache__/automod.cpython-312.pyc | Bin 0 -> 6289 bytes .../types/__pycache__/channel.cpython-312.pyc | Bin 0 -> 9108 bytes .../types/__pycache__/command.cpython-312.pyc | Bin 0 -> 8840 bytes .../__pycache__/components.cpython-312.pyc | Bin 0 -> 5292 bytes .../types/__pycache__/embed.cpython-312.pyc | Bin 0 -> 3482 bytes .../types/__pycache__/emoji.cpython-312.pyc | Bin 0 -> 2434 bytes .../types/__pycache__/gateway.cpython-312.pyc | Bin 0 -> 15879 bytes .../types/__pycache__/guild.cpython-312.pyc | Bin 0 -> 8531 bytes .../__pycache__/integration.cpython-312.pyc | Bin 0 -> 3515 bytes .../__pycache__/interactions.cpython-312.pyc | Bin 0 -> 13760 bytes .../types/__pycache__/invite.cpython-312.pyc | Bin 0 -> 4125 bytes .../types/__pycache__/member.cpython-312.pyc | Bin 0 -> 3349 bytes .../types/__pycache__/message.cpython-312.pyc | Bin 0 -> 8572 bytes .../types/__pycache__/poll.cpython-312.pyc | Bin 0 -> 3653 bytes .../types/__pycache__/role.cpython-312.pyc | Bin 0 -> 2465 bytes .../scheduled_event.cpython-312.pyc | Bin 0 -> 5083 bytes .../types/__pycache__/sku.cpython-312.pyc | Bin 0 -> 2350 bytes .../__pycache__/snowflake.cpython-312.pyc | Bin 0 -> 1467 bytes .../__pycache__/soundboard.cpython-312.pyc | Bin 0 -> 2490 bytes .../types/__pycache__/sticker.cpython-312.pyc | Bin 0 -> 3647 bytes .../__pycache__/subscription.cpython-312.pyc | Bin 0 -> 2119 bytes .../types/__pycache__/team.cpython-312.pyc | Bin 0 -> 2252 bytes .../__pycache__/template.cpython-312.pyc | Bin 0 -> 2326 bytes .../types/__pycache__/threads.cpython-312.pyc | Bin 0 -> 3654 bytes .../types/__pycache__/user.cpython-312.pyc | Bin 0 -> 2651 bytes .../types/__pycache__/voice.cpython-312.pyc | Bin 0 -> 3807 bytes .../types/__pycache__/webhook.cpython-312.pyc | Bin 0 -> 3083 bytes .../welcome_screen.cpython-312.pyc | Bin 0 -> 2110 bytes .../types/__pycache__/widget.cpython-312.pyc | Bin 0 -> 3035 bytes .../site-packages/discord/types/activity.py | 106 + .../site-packages/discord/types/appinfo.py | 91 + .../site-packages/discord/types/audit_log.py | 360 + .../site-packages/discord/types/automod.py | 133 + .../site-packages/discord/types/channel.py | 209 + .../site-packages/discord/types/command.py | 222 + .../site-packages/discord/types/components.py | 122 + .../site-packages/discord/types/embed.py | 78 + .../site-packages/discord/types/emoji.py | 48 + .../site-packages/discord/types/gateway.py | 381 + .../site-packages/discord/types/guild.py | 196 + .../discord/types/integration.py | 82 + .../discord/types/interactions.py | 337 + .../site-packages/discord/types/invite.py | 95 + .../site-packages/discord/types/member.py | 70 + .../site-packages/discord/types/message.py | 239 + .../site-packages/discord/types/poll.py | 88 + .../site-packages/discord/types/role.py | 54 + .../discord/types/scheduled_event.py | 111 + .../site-packages/discord/types/sku.py | 53 + .../site-packages/discord/types/snowflake.py | 28 + .../site-packages/discord/types/soundboard.py | 49 + .../site-packages/discord/types/sticker.py | 83 + .../discord/types/subscription.py | 43 + .../site-packages/discord/types/team.py | 46 + .../site-packages/discord/types/template.py | 49 + .../site-packages/discord/types/threads.py | 80 + .../site-packages/discord/types/user.py | 56 + .../site-packages/discord/types/voice.py | 89 + .../site-packages/discord/types/webhook.py | 67 + .../discord/types/welcome_screen.py | 40 + .../site-packages/discord/types/widget.py | 65 + .../site-packages/discord/ui/__init__.py | 18 + .../ui/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 542 bytes .../ui/__pycache__/button.cpython-312.pyc | Bin 0 -> 15089 bytes .../ui/__pycache__/dynamic.cpython-312.pyc | Bin 0 -> 11478 bytes .../ui/__pycache__/item.cpython-312.pyc | Bin 0 -> 7206 bytes .../ui/__pycache__/modal.cpython-312.pyc | Bin 0 -> 9235 bytes .../ui/__pycache__/select.cpython-312.pyc | Bin 0 -> 49616 bytes .../ui/__pycache__/text_input.cpython-312.pyc | Bin 0 -> 11669 bytes .../ui/__pycache__/view.cpython-312.pyc | Bin 0 -> 34895 bytes .../site-packages/discord/ui/button.py | 330 + .../site-packages/discord/ui/dynamic.py | 216 + .../site-packages/discord/ui/item.py | 168 + .../site-packages/discord/ui/modal.py | 209 + .../site-packages/discord/ui/select.py | 1109 ++ .../site-packages/discord/ui/text_input.py | 251 + .../site-packages/discord/ui/view.py | 747 + .../python3.12/site-packages/discord/user.py | 570 + .../python3.12/site-packages/discord/utils.py | 1542 ++ .../site-packages/discord/voice_client.py | 591 + .../site-packages/discord/voice_state.py | 688 + .../site-packages/discord/webhook/__init__.py | 13 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 426 bytes .../__pycache__/async_.cpython-312.pyc | Bin 0 -> 79262 bytes .../webhook/__pycache__/sync.cpython-312.pyc | Bin 0 -> 48246 bytes .../site-packages/discord/webhook/async_.py | 2105 +++ .../site-packages/discord/webhook/sync.py | 1270 ++ .../site-packages/discord/welcome_screen.py | 217 + .../site-packages/discord/widget.py | 325 + .../discord_py-2.5.2.dist-info/INSTALLER | 1 + .../discord_py-2.5.2.dist-info/LICENSE | 21 + .../discord_py-2.5.2.dist-info/METADATA | 206 + .../discord_py-2.5.2.dist-info/RECORD | 266 + .../discord_py-2.5.2.dist-info/REQUESTED | 0 .../discord_py-2.5.2.dist-info/WHEEL | 5 + .../discord_py-2.5.2.dist-info/top_level.txt | 1 + .../frozenlist-1.6.0.dist-info/INSTALLER | 1 + .../frozenlist-1.6.0.dist-info/METADATA | 545 + .../frozenlist-1.6.0.dist-info/RECORD | 13 + .../frozenlist-1.6.0.dist-info/WHEEL | 6 + .../licenses/LICENSE | 201 + .../frozenlist-1.6.0.dist-info/top_level.txt | 1 + .../site-packages/frozenlist/__init__.py | 86 + .../site-packages/frozenlist/__init__.pyi | 47 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4097 bytes .../site-packages/frozenlist/_frozenlist.cpp | 13052 ++++++++++++++++ .../_frozenlist.cpython-312-darwin.so | Bin 0 -> 128720 bytes .../site-packages/frozenlist/_frozenlist.pyx | 126 + .../site-packages/frozenlist/py.typed | 1 + .../idna-3.10.dist-info/INSTALLER | 1 + .../idna-3.10.dist-info/LICENSE.md | 31 + .../idna-3.10.dist-info/METADATA | 250 + .../site-packages/idna-3.10.dist-info/RECORD | 22 + .../site-packages/idna-3.10.dist-info/WHEEL | 4 + .../python3.12/site-packages/idna/__init__.py | 45 + .../idna/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 912 bytes .../idna/__pycache__/codec.cpython-312.pyc | Bin 0 -> 5012 bytes .../idna/__pycache__/compat.cpython-312.pyc | Bin 0 -> 916 bytes .../idna/__pycache__/core.cpython-312.pyc | Bin 0 -> 16202 bytes .../idna/__pycache__/idnadata.cpython-312.pyc | Bin 0 -> 99502 bytes .../__pycache__/intranges.cpython-312.pyc | Bin 0 -> 2664 bytes .../__pycache__/package_data.cpython-312.pyc | Bin 0 -> 243 bytes .../__pycache__/uts46data.cpython-312.pyc | Bin 0 -> 158872 bytes .../python3.12/site-packages/idna/codec.py | 122 + .../python3.12/site-packages/idna/compat.py | 15 + .../lib/python3.12/site-packages/idna/core.py | 437 + .../python3.12/site-packages/idna/idnadata.py | 4243 +++++ .../site-packages/idna/intranges.py | 57 + .../site-packages/idna/package_data.py | 1 + .../python3.12/site-packages/idna/py.typed | 0 .../site-packages/idna/uts46data.py | 8681 ++++++++++ .../multidict-6.4.3.dist-info/INSTALLER | 1 + .../multidict-6.4.3.dist-info/METADATA | 149 + .../multidict-6.4.3.dist-info/RECORD | 16 + .../multidict-6.4.3.dist-info/WHEEL | 6 + .../licenses/LICENSE | 13 + .../multidict-6.4.3.dist-info/top_level.txt | 1 + .../site-packages/multidict/__init__.py | 59 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1428 bytes .../__pycache__/_abc.cpython-312.pyc | Bin 0 -> 5301 bytes .../__pycache__/_compat.cpython-312.pyc | Bin 0 -> 691 bytes .../__pycache__/_multidict_py.cpython-312.pyc | Bin 0 -> 45522 bytes .../site-packages/multidict/_abc.py | 69 + .../site-packages/multidict/_compat.py | 15 + .../_multidict.cpython-312-darwin.so | Bin 0 -> 104432 bytes .../site-packages/multidict/_multidict_py.py | 888 ++ .../site-packages/multidict/py.typed | 1 + .../pip-24.0.dist-info/AUTHORS.txt | 760 + .../pip-24.0.dist-info/INSTALLER | 1 + .../pip-24.0.dist-info/LICENSE.txt | 20 + .../site-packages/pip-24.0.dist-info/METADATA | 88 + .../site-packages/pip-24.0.dist-info/RECORD | 1024 ++ .../pip-24.0.dist-info/REQUESTED | 0 .../site-packages/pip-24.0.dist-info/WHEEL | 5 + .../pip-24.0.dist-info/entry_points.txt | 4 + .../pip-24.0.dist-info/top_level.txt | 1 + .../python3.12/site-packages/pip/__init__.py | 13 + .../python3.12/site-packages/pip/__main__.py | 24 + .../site-packages/pip/__pip-runner__.py | 50 + .../pip/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 722 bytes .../pip/__pycache__/__main__.cpython-312.pyc | Bin 0 -> 878 bytes .../__pip-runner__.cpython-312.pyc | Bin 0 -> 2236 bytes .../site-packages/pip/_internal/__init__.py | 18 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 824 bytes .../__pycache__/build_env.cpython-312.pyc | Bin 0 -> 14328 bytes .../__pycache__/cache.cpython-312.pyc | Bin 0 -> 12697 bytes .../__pycache__/configuration.cpython-312.pyc | Bin 0 -> 17694 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 33312 bytes .../__pycache__/main.cpython-312.pyc | Bin 0 -> 707 bytes .../__pycache__/pyproject.cpython-312.pyc | Bin 0 -> 5002 bytes .../self_outdated_check.cpython-312.pyc | Bin 0 -> 10589 bytes .../__pycache__/wheel_builder.cpython-312.pyc | Bin 0 -> 13662 bytes .../site-packages/pip/_internal/build_env.py | 311 + .../site-packages/pip/_internal/cache.py | 290 + .../pip/_internal/cli/__init__.py | 4 + .../cli/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 315 bytes .../autocompletion.cpython-312.pyc | Bin 0 -> 8502 bytes .../__pycache__/base_command.cpython-312.pyc | Bin 0 -> 10486 bytes .../__pycache__/cmdoptions.cpython-312.pyc | Bin 0 -> 30411 bytes .../command_context.cpython-312.pyc | Bin 0 -> 1812 bytes .../cli/__pycache__/main.cpython-312.pyc | Bin 0 -> 2335 bytes .../__pycache__/main_parser.cpython-312.pyc | Bin 0 -> 4942 bytes .../cli/__pycache__/parser.cpython-312.pyc | Bin 0 -> 15039 bytes .../__pycache__/progress_bars.cpython-312.pyc | Bin 0 -> 2654 bytes .../__pycache__/req_command.cpython-312.pyc | Bin 0 -> 18874 bytes .../cli/__pycache__/spinners.cpython-312.pyc | Bin 0 -> 7871 bytes .../__pycache__/status_codes.cpython-312.pyc | Bin 0 -> 412 bytes .../pip/_internal/cli/autocompletion.py | 172 + .../pip/_internal/cli/base_command.py | 236 + .../pip/_internal/cli/cmdoptions.py | 1074 ++ .../pip/_internal/cli/command_context.py | 27 + .../site-packages/pip/_internal/cli/main.py | 79 + .../pip/_internal/cli/main_parser.py | 134 + .../site-packages/pip/_internal/cli/parser.py | 294 + .../pip/_internal/cli/progress_bars.py | 68 + .../pip/_internal/cli/req_command.py | 505 + .../pip/_internal/cli/spinners.py | 159 + .../pip/_internal/cli/status_codes.py | 6 + .../pip/_internal/commands/__init__.py | 132 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4039 bytes .../__pycache__/cache.cpython-312.pyc | Bin 0 -> 9748 bytes .../__pycache__/check.cpython-312.pyc | Bin 0 -> 2127 bytes .../__pycache__/completion.cpython-312.pyc | Bin 0 -> 5229 bytes .../__pycache__/configuration.cpython-312.pyc | Bin 0 -> 13249 bytes .../__pycache__/debug.cpython-312.pyc | Bin 0 -> 10195 bytes .../__pycache__/download.cpython-312.pyc | Bin 0 -> 7623 bytes .../__pycache__/freeze.cpython-312.pyc | Bin 0 -> 4393 bytes .../commands/__pycache__/hash.cpython-312.pyc | Bin 0 -> 3020 bytes .../commands/__pycache__/help.cpython-312.pyc | Bin 0 -> 1710 bytes .../__pycache__/index.cpython-312.pyc | Bin 0 -> 6757 bytes .../__pycache__/inspect.cpython-312.pyc | Bin 0 -> 4012 bytes .../__pycache__/install.cpython-312.pyc | Bin 0 -> 28942 bytes .../commands/__pycache__/list.cpython-312.pyc | Bin 0 -> 15437 bytes .../__pycache__/search.cpython-312.pyc | Bin 0 -> 7655 bytes .../commands/__pycache__/show.cpython-312.pyc | Bin 0 -> 9765 bytes .../__pycache__/uninstall.cpython-312.pyc | Bin 0 -> 4763 bytes .../__pycache__/wheel.cpython-312.pyc | Bin 0 -> 8987 bytes .../pip/_internal/commands/cache.py | 225 + .../pip/_internal/commands/check.py | 54 + .../pip/_internal/commands/completion.py | 130 + .../pip/_internal/commands/configuration.py | 280 + .../pip/_internal/commands/debug.py | 201 + .../pip/_internal/commands/download.py | 147 + .../pip/_internal/commands/freeze.py | 108 + .../pip/_internal/commands/hash.py | 59 + .../pip/_internal/commands/help.py | 41 + .../pip/_internal/commands/index.py | 139 + .../pip/_internal/commands/inspect.py | 92 + .../pip/_internal/commands/install.py | 774 + .../pip/_internal/commands/list.py | 368 + .../pip/_internal/commands/search.py | 174 + .../pip/_internal/commands/show.py | 189 + .../pip/_internal/commands/uninstall.py | 113 + .../pip/_internal/commands/wheel.py | 183 + .../pip/_internal/configuration.py | 383 + .../pip/_internal/distributions/__init__.py | 21 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 978 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 2899 bytes .../__pycache__/installed.cpython-312.pyc | Bin 0 -> 1734 bytes .../__pycache__/sdist.cpython-312.pyc | Bin 0 -> 8511 bytes .../__pycache__/wheel.cpython-312.pyc | Bin 0 -> 2280 bytes .../pip/_internal/distributions/base.py | 51 + .../pip/_internal/distributions/installed.py | 29 + .../pip/_internal/distributions/sdist.py | 156 + .../pip/_internal/distributions/wheel.py | 40 + .../site-packages/pip/_internal/exceptions.py | 728 + .../pip/_internal/index/__init__.py | 2 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 269 bytes .../__pycache__/collector.cpython-312.pyc | Bin 0 -> 21920 bytes .../package_finder.cpython-312.pyc | Bin 0 -> 40757 bytes .../index/__pycache__/sources.cpython-312.pyc | Bin 0 -> 12641 bytes .../pip/_internal/index/collector.py | 507 + .../pip/_internal/index/package_finder.py | 1027 ++ .../pip/_internal/index/sources.py | 285 + .../pip/_internal/locations/__init__.py | 467 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 16813 bytes .../__pycache__/_distutils.cpython-312.pyc | Bin 0 -> 6885 bytes .../__pycache__/_sysconfig.cpython-312.pyc | Bin 0 -> 8048 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 3818 bytes .../pip/_internal/locations/_distutils.py | 172 + .../pip/_internal/locations/_sysconfig.py | 213 + .../pip/_internal/locations/base.py | 81 + .../site-packages/pip/_internal/main.py | 12 + .../pip/_internal/metadata/__init__.py | 128 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 5919 bytes .../__pycache__/_json.cpython-312.pyc | Bin 0 -> 2912 bytes .../metadata/__pycache__/base.cpython-312.pyc | Bin 0 -> 35749 bytes .../__pycache__/pkg_resources.cpython-312.pyc | Bin 0 -> 15824 bytes .../pip/_internal/metadata/_json.py | 84 + .../pip/_internal/metadata/base.py | 702 + .../_internal/metadata/importlib/__init__.py | 6 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 395 bytes .../__pycache__/_compat.cpython-312.pyc | Bin 0 -> 3370 bytes .../__pycache__/_dists.cpython-312.pyc | Bin 0 -> 13462 bytes .../__pycache__/_envs.cpython-312.pyc | Bin 0 -> 11217 bytes .../_internal/metadata/importlib/_compat.py | 55 + .../_internal/metadata/importlib/_dists.py | 227 + .../pip/_internal/metadata/importlib/_envs.py | 189 + .../pip/_internal/metadata/pkg_resources.py | 278 + .../pip/_internal/models/__init__.py | 2 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 303 bytes .../__pycache__/candidate.cpython-312.pyc | Bin 0 -> 1942 bytes .../__pycache__/direct_url.cpython-312.pyc | Bin 0 -> 11233 bytes .../format_control.cpython-312.pyc | Bin 0 -> 4264 bytes .../models/__pycache__/index.cpython-312.pyc | Bin 0 -> 1731 bytes .../installation_report.cpython-312.pyc | Bin 0 -> 2306 bytes .../models/__pycache__/link.cpython-312.pyc | Bin 0 -> 26037 bytes .../models/__pycache__/scheme.cpython-312.pyc | Bin 0 -> 1206 bytes .../__pycache__/search_scope.cpython-312.pyc | Bin 0 -> 5125 bytes .../selection_prefs.cpython-312.pyc | Bin 0 -> 1888 bytes .../__pycache__/target_python.cpython-312.pyc | Bin 0 -> 4991 bytes .../models/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 5817 bytes .../pip/_internal/models/candidate.py | 30 + .../pip/_internal/models/direct_url.py | 235 + .../pip/_internal/models/format_control.py | 78 + .../pip/_internal/models/index.py | 28 + .../_internal/models/installation_report.py | 56 + .../pip/_internal/models/link.py | 579 + .../pip/_internal/models/scheme.py | 31 + .../pip/_internal/models/search_scope.py | 132 + .../pip/_internal/models/selection_prefs.py | 51 + .../pip/_internal/models/target_python.py | 122 + .../pip/_internal/models/wheel.py | 92 + .../pip/_internal/network/__init__.py | 2 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 291 bytes .../network/__pycache__/auth.cpython-312.pyc | Bin 0 -> 22025 bytes .../network/__pycache__/cache.cpython-312.pyc | Bin 0 -> 6552 bytes .../__pycache__/download.cpython-312.pyc | Bin 0 -> 8584 bytes .../__pycache__/lazy_wheel.cpython-312.pyc | Bin 0 -> 11697 bytes .../__pycache__/session.cpython-312.pyc | Bin 0 -> 18811 bytes .../network/__pycache__/utils.cpython-312.pyc | Bin 0 -> 2290 bytes .../__pycache__/xmlrpc.cpython-312.pyc | Bin 0 -> 2981 bytes .../pip/_internal/network/auth.py | 561 + .../pip/_internal/network/cache.py | 106 + .../pip/_internal/network/download.py | 186 + .../pip/_internal/network/lazy_wheel.py | 210 + .../pip/_internal/network/session.py | 520 + .../pip/_internal/network/utils.py | 96 + .../pip/_internal/network/xmlrpc.py | 62 + .../pip/_internal/operations/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 234 bytes .../__pycache__/check.cpython-312.pyc | Bin 0 -> 7616 bytes .../__pycache__/freeze.cpython-312.pyc | Bin 0 -> 10151 bytes .../__pycache__/prepare.cpython-312.pyc | Bin 0 -> 25740 bytes .../_internal/operations/build/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 240 bytes .../__pycache__/build_tracker.cpython-312.pyc | Bin 0 -> 7851 bytes .../__pycache__/metadata.cpython-312.pyc | Bin 0 -> 1917 bytes .../metadata_editable.cpython-312.pyc | Bin 0 -> 1951 bytes .../metadata_legacy.cpython-312.pyc | Bin 0 -> 3102 bytes .../build/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 1718 bytes .../wheel_editable.cpython-312.pyc | Bin 0 -> 2059 bytes .../__pycache__/wheel_legacy.cpython-312.pyc | Bin 0 -> 3966 bytes .../operations/build/build_tracker.py | 139 + .../_internal/operations/build/metadata.py | 39 + .../operations/build/metadata_editable.py | 41 + .../operations/build/metadata_legacy.py | 74 + .../pip/_internal/operations/build/wheel.py | 37 + .../operations/build/wheel_editable.py | 46 + .../operations/build/wheel_legacy.py | 102 + .../pip/_internal/operations/check.py | 187 + .../pip/_internal/operations/freeze.py | 255 + .../_internal/operations/install/__init__.py | 2 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 303 bytes .../editable_legacy.cpython-312.pyc | Bin 0 -> 1854 bytes .../install/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 33890 bytes .../operations/install/editable_legacy.py | 46 + .../pip/_internal/operations/install/wheel.py | 734 + .../pip/_internal/operations/prepare.py | 730 + .../site-packages/pip/_internal/pyproject.py | 179 + .../pip/_internal/req/__init__.py | 92 + .../req/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 3778 bytes .../__pycache__/constructors.cpython-312.pyc | Bin 0 -> 21618 bytes .../req/__pycache__/req_file.cpython-312.pyc | Bin 0 -> 21489 bytes .../__pycache__/req_install.cpython-312.pyc | Bin 0 -> 38363 bytes .../req/__pycache__/req_set.cpython-312.pyc | Bin 0 -> 7249 bytes .../__pycache__/req_uninstall.cpython-312.pyc | Bin 0 -> 33006 bytes .../pip/_internal/req/constructors.py | 576 + .../pip/_internal/req/req_file.py | 554 + .../pip/_internal/req/req_install.py | 923 ++ .../pip/_internal/req/req_set.py | 119 + .../pip/_internal/req/req_uninstall.py | 649 + .../pip/_internal/resolution/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 234 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 1222 bytes .../pip/_internal/resolution/base.py | 20 + .../_internal/resolution/legacy/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 241 bytes .../__pycache__/resolver.cpython-312.pyc | Bin 0 -> 22461 bytes .../_internal/resolution/legacy/resolver.py | 598 + .../resolution/resolvelib/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 245 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 8374 bytes .../__pycache__/candidates.cpython-312.pyc | Bin 0 -> 30414 bytes .../__pycache__/factory.cpython-312.pyc | Bin 0 -> 32138 bytes .../found_candidates.cpython-312.pyc | Bin 0 -> 6245 bytes .../__pycache__/provider.cpython-312.pyc | Bin 0 -> 10415 bytes .../__pycache__/reporter.cpython-312.pyc | Bin 0 -> 4972 bytes .../__pycache__/requirements.cpython-312.pyc | Bin 0 -> 11450 bytes .../__pycache__/resolver.cpython-312.pyc | Bin 0 -> 12380 bytes .../_internal/resolution/resolvelib/base.py | 141 + .../resolution/resolvelib/candidates.py | 597 + .../resolution/resolvelib/factory.py | 812 + .../resolution/resolvelib/found_candidates.py | 155 + .../resolution/resolvelib/provider.py | 255 + .../resolution/resolvelib/reporter.py | 80 + .../resolution/resolvelib/requirements.py | 166 + .../resolution/resolvelib/resolver.py | 317 + .../pip/_internal/self_outdated_check.py | 248 + .../pip/_internal/utils/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 229 bytes .../__pycache__/_jaraco_text.cpython-312.pyc | Bin 0 -> 4570 bytes .../utils/__pycache__/_log.cpython-312.pyc | Bin 0 -> 1900 bytes .../utils/__pycache__/appdirs.cpython-312.pyc | Bin 0 -> 2444 bytes .../utils/__pycache__/compat.cpython-312.pyc | Bin 0 -> 2247 bytes .../compatibility_tags.cpython-312.pyc | Bin 0 -> 5595 bytes .../__pycache__/datetime.cpython-312.pyc | Bin 0 -> 718 bytes .../__pycache__/deprecation.cpython-312.pyc | Bin 0 -> 4220 bytes .../direct_url_helpers.cpython-312.pyc | Bin 0 -> 3587 bytes .../__pycache__/egg_link.cpython-312.pyc | Bin 0 -> 3260 bytes .../__pycache__/encoding.cpython-312.pyc | Bin 0 -> 2189 bytes .../__pycache__/entrypoints.cpython-312.pyc | Bin 0 -> 4027 bytes .../__pycache__/filesystem.cpython-312.pyc | Bin 0 -> 7489 bytes .../__pycache__/filetypes.cpython-312.pyc | Bin 0 -> 1198 bytes .../utils/__pycache__/glibc.cpython-312.pyc | Bin 0 -> 2376 bytes .../utils/__pycache__/hashes.cpython-312.pyc | Bin 0 -> 7588 bytes .../utils/__pycache__/logging.cpython-312.pyc | Bin 0 -> 13583 bytes .../utils/__pycache__/misc.cpython-312.pyc | Bin 0 -> 34155 bytes .../utils/__pycache__/models.cpython-312.pyc | Bin 0 -> 2746 bytes .../__pycache__/packaging.cpython-312.pyc | Bin 0 -> 2617 bytes .../setuptools_build.cpython-312.pyc | Bin 0 -> 4581 bytes .../__pycache__/subprocess.cpython-312.pyc | Bin 0 -> 8744 bytes .../__pycache__/temp_dir.cpython-312.pyc | Bin 0 -> 12090 bytes .../__pycache__/unpacking.cpython-312.pyc | Bin 0 -> 11140 bytes .../utils/__pycache__/urls.cpython-312.pyc | Bin 0 -> 2434 bytes .../__pycache__/virtualenv.cpython-312.pyc | Bin 0 -> 4514 bytes .../utils/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 5960 bytes .../pip/_internal/utils/_jaraco_text.py | 109 + .../site-packages/pip/_internal/utils/_log.py | 38 + .../pip/_internal/utils/appdirs.py | 52 + .../pip/_internal/utils/compat.py | 63 + .../pip/_internal/utils/compatibility_tags.py | 165 + .../pip/_internal/utils/datetime.py | 11 + .../pip/_internal/utils/deprecation.py | 120 + .../pip/_internal/utils/direct_url_helpers.py | 87 + .../pip/_internal/utils/egg_link.py | 80 + .../pip/_internal/utils/encoding.py | 36 + .../pip/_internal/utils/entrypoints.py | 84 + .../pip/_internal/utils/filesystem.py | 153 + .../pip/_internal/utils/filetypes.py | 27 + .../pip/_internal/utils/glibc.py | 88 + .../pip/_internal/utils/hashes.py | 151 + .../pip/_internal/utils/logging.py | 348 + .../site-packages/pip/_internal/utils/misc.py | 783 + .../pip/_internal/utils/models.py | 39 + .../pip/_internal/utils/packaging.py | 57 + .../pip/_internal/utils/setuptools_build.py | 146 + .../pip/_internal/utils/subprocess.py | 260 + .../pip/_internal/utils/temp_dir.py | 296 + .../pip/_internal/utils/unpacking.py | 257 + .../site-packages/pip/_internal/utils/urls.py | 62 + .../pip/_internal/utils/virtualenv.py | 104 + .../pip/_internal/utils/wheel.py | 134 + .../pip/_internal/vcs/__init__.py | 15 + .../vcs/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 568 bytes .../vcs/__pycache__/bazaar.cpython-312.pyc | Bin 0 -> 5060 bytes .../vcs/__pycache__/git.cpython-312.pyc | Bin 0 -> 19024 bytes .../vcs/__pycache__/mercurial.cpython-312.pyc | Bin 0 -> 7649 bytes .../__pycache__/subversion.cpython-312.pyc | Bin 0 -> 12515 bytes .../versioncontrol.cpython-312.pyc | Bin 0 -> 29047 bytes .../site-packages/pip/_internal/vcs/bazaar.py | 112 + .../site-packages/pip/_internal/vcs/git.py | 526 + .../pip/_internal/vcs/mercurial.py | 163 + .../pip/_internal/vcs/subversion.py | 324 + .../pip/_internal/vcs/versioncontrol.py | 705 + .../pip/_internal/wheel_builder.py | 354 + .../site-packages/pip/_vendor/__init__.py | 121 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4730 bytes .../_vendor/__pycache__/six.cpython-312.pyc | Bin 0 -> 41307 bytes .../typing_extensions.cpython-312.pyc | Bin 0 -> 122075 bytes .../pip/_vendor/cachecontrol/__init__.py | 28 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 940 bytes .../__pycache__/_cmd.cpython-312.pyc | Bin 0 -> 2684 bytes .../__pycache__/adapter.cpython-312.pyc | Bin 0 -> 6499 bytes .../__pycache__/cache.cpython-312.pyc | Bin 0 -> 3847 bytes .../__pycache__/controller.cpython-312.pyc | Bin 0 -> 16181 bytes .../__pycache__/filewrapper.cpython-312.pyc | Bin 0 -> 4385 bytes .../__pycache__/heuristics.cpython-312.pyc | Bin 0 -> 6729 bytes .../__pycache__/serialize.cpython-312.pyc | Bin 0 -> 6443 bytes .../__pycache__/wrapper.cpython-312.pyc | Bin 0 -> 1712 bytes .../pip/_vendor/cachecontrol/_cmd.py | 70 + .../pip/_vendor/cachecontrol/adapter.py | 161 + .../pip/_vendor/cachecontrol/cache.py | 74 + .../_vendor/cachecontrol/caches/__init__.py | 8 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 473 bytes .../__pycache__/file_cache.cpython-312.pyc | Bin 0 -> 7748 bytes .../__pycache__/redis_cache.cpython-312.pyc | Bin 0 -> 2776 bytes .../_vendor/cachecontrol/caches/file_cache.py | 181 + .../cachecontrol/caches/redis_cache.py | 48 + .../pip/_vendor/cachecontrol/controller.py | 494 + .../pip/_vendor/cachecontrol/filewrapper.py | 119 + .../pip/_vendor/cachecontrol/heuristics.py | 154 + .../pip/_vendor/cachecontrol/py.typed | 0 .../pip/_vendor/cachecontrol/serialize.py | 206 + .../pip/_vendor/cachecontrol/wrapper.py | 43 + .../pip/_vendor/certifi/__init__.py | 4 + .../pip/_vendor/certifi/__main__.py | 12 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 356 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 683 bytes .../certifi/__pycache__/core.cpython-312.pyc | Bin 0 -> 2887 bytes .../pip/_vendor/certifi/cacert.pem | 4635 ++++++ .../site-packages/pip/_vendor/certifi/core.py | 108 + .../pip/_vendor/certifi/py.typed | 0 .../pip/_vendor/chardet/__init__.py | 115 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4606 bytes .../__pycache__/big5freq.cpython-312.pyc | Bin 0 -> 27237 bytes .../__pycache__/big5prober.cpython-312.pyc | Bin 0 -> 1425 bytes .../chardistribution.cpython-312.pyc | Bin 0 -> 9676 bytes .../charsetgroupprober.cpython-312.pyc | Bin 0 -> 4160 bytes .../__pycache__/charsetprober.cpython-312.pyc | Bin 0 -> 5056 bytes .../codingstatemachine.cpython-312.pyc | Bin 0 -> 3916 bytes .../codingstatemachinedict.cpython-312.pyc | Bin 0 -> 827 bytes .../__pycache__/cp949prober.cpython-312.pyc | Bin 0 -> 1434 bytes .../chardet/__pycache__/enums.cpython-312.pyc | Bin 0 -> 3034 bytes .../__pycache__/escprober.cpython-312.pyc | Bin 0 -> 4604 bytes .../chardet/__pycache__/escsm.cpython-312.pyc | Bin 0 -> 15348 bytes .../__pycache__/eucjpprober.cpython-312.pyc | Bin 0 -> 4412 bytes .../__pycache__/euckrfreq.cpython-312.pyc | Bin 0 -> 12120 bytes .../__pycache__/euckrprober.cpython-312.pyc | Bin 0 -> 1428 bytes .../__pycache__/euctwfreq.cpython-312.pyc | Bin 0 -> 27242 bytes .../__pycache__/euctwprober.cpython-312.pyc | Bin 0 -> 1428 bytes .../__pycache__/gb2312freq.cpython-312.pyc | Bin 0 -> 19164 bytes .../__pycache__/gb2312prober.cpython-312.pyc | Bin 0 -> 1441 bytes .../__pycache__/hebrewprober.cpython-312.pyc | Bin 0 -> 5848 bytes .../__pycache__/jisfreq.cpython-312.pyc | Bin 0 -> 22193 bytes .../__pycache__/johabfreq.cpython-312.pyc | Bin 0 -> 83041 bytes .../__pycache__/johabprober.cpython-312.pyc | Bin 0 -> 1432 bytes .../__pycache__/jpcntx.cpython-312.pyc | Bin 0 -> 39587 bytes .../langbulgarianmodel.cpython-312.pyc | Bin 0 -> 83160 bytes .../langgreekmodel.cpython-312.pyc | Bin 0 -> 77026 bytes .../langhebrewmodel.cpython-312.pyc | Bin 0 -> 77537 bytes .../langhungarianmodel.cpython-312.pyc | Bin 0 -> 83114 bytes .../langrussianmodel.cpython-312.pyc | Bin 0 -> 105289 bytes .../__pycache__/langthaimodel.cpython-312.pyc | Bin 0 -> 77715 bytes .../langturkishmodel.cpython-312.pyc | Bin 0 -> 77554 bytes .../__pycache__/latin1prober.cpython-312.pyc | Bin 0 -> 7040 bytes .../macromanprober.cpython-312.pyc | Bin 0 -> 7220 bytes .../mbcharsetprober.cpython-312.pyc | Bin 0 -> 3932 bytes .../mbcsgroupprober.cpython-312.pyc | Bin 0 -> 1626 bytes .../__pycache__/mbcssm.cpython-312.pyc | Bin 0 -> 38683 bytes .../__pycache__/resultdict.cpython-312.pyc | Bin 0 -> 670 bytes .../sbcharsetprober.cpython-312.pyc | Bin 0 -> 6425 bytes .../sbcsgroupprober.cpython-312.pyc | Bin 0 -> 2395 bytes .../__pycache__/sjisprober.cpython-312.pyc | Bin 0 -> 4524 bytes .../universaldetector.cpython-312.pyc | Bin 0 -> 12304 bytes .../__pycache__/utf1632prober.cpython-312.pyc | Bin 0 -> 10017 bytes .../__pycache__/utf8prober.cpython-312.pyc | Bin 0 -> 3213 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 526 bytes .../pip/_vendor/chardet/big5freq.py | 386 + .../pip/_vendor/chardet/big5prober.py | 47 + .../pip/_vendor/chardet/chardistribution.py | 261 + .../pip/_vendor/chardet/charsetgroupprober.py | 106 + .../pip/_vendor/chardet/charsetprober.py | 147 + .../pip/_vendor/chardet/cli/__init__.py | 0 .../cli/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 233 bytes .../__pycache__/chardetect.cpython-312.pyc | Bin 0 -> 4050 bytes .../pip/_vendor/chardet/cli/chardetect.py | 112 + .../pip/_vendor/chardet/codingstatemachine.py | 90 + .../_vendor/chardet/codingstatemachinedict.py | 19 + .../pip/_vendor/chardet/cp949prober.py | 49 + .../pip/_vendor/chardet/enums.py | 85 + .../pip/_vendor/chardet/escprober.py | 102 + .../pip/_vendor/chardet/escsm.py | 261 + .../pip/_vendor/chardet/eucjpprober.py | 102 + .../pip/_vendor/chardet/euckrfreq.py | 196 + .../pip/_vendor/chardet/euckrprober.py | 47 + .../pip/_vendor/chardet/euctwfreq.py | 388 + .../pip/_vendor/chardet/euctwprober.py | 47 + .../pip/_vendor/chardet/gb2312freq.py | 284 + .../pip/_vendor/chardet/gb2312prober.py | 47 + .../pip/_vendor/chardet/hebrewprober.py | 316 + .../pip/_vendor/chardet/jisfreq.py | 325 + .../pip/_vendor/chardet/johabfreq.py | 2382 +++ .../pip/_vendor/chardet/johabprober.py | 47 + .../pip/_vendor/chardet/jpcntx.py | 238 + .../pip/_vendor/chardet/langbulgarianmodel.py | 4649 ++++++ .../pip/_vendor/chardet/langgreekmodel.py | 4397 ++++++ .../pip/_vendor/chardet/langhebrewmodel.py | 4380 ++++++ .../pip/_vendor/chardet/langhungarianmodel.py | 4649 ++++++ .../pip/_vendor/chardet/langrussianmodel.py | 5725 +++++++ .../pip/_vendor/chardet/langthaimodel.py | 4380 ++++++ .../pip/_vendor/chardet/langturkishmodel.py | 4380 ++++++ .../pip/_vendor/chardet/latin1prober.py | 147 + .../pip/_vendor/chardet/macromanprober.py | 162 + .../pip/_vendor/chardet/mbcharsetprober.py | 95 + .../pip/_vendor/chardet/mbcsgroupprober.py | 57 + .../pip/_vendor/chardet/mbcssm.py | 661 + .../pip/_vendor/chardet/metadata/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 238 bytes .../__pycache__/languages.cpython-312.pyc | Bin 0 -> 9793 bytes .../pip/_vendor/chardet/metadata/languages.py | 352 + .../pip/_vendor/chardet/py.typed | 0 .../pip/_vendor/chardet/resultdict.py | 16 + .../pip/_vendor/chardet/sbcharsetprober.py | 162 + .../pip/_vendor/chardet/sbcsgroupprober.py | 88 + .../pip/_vendor/chardet/sjisprober.py | 105 + .../pip/_vendor/chardet/universaldetector.py | 362 + .../pip/_vendor/chardet/utf1632prober.py | 225 + .../pip/_vendor/chardet/utf8prober.py | 82 + .../pip/_vendor/chardet/version.py | 9 + .../pip/_vendor/colorama/__init__.py | 7 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 530 bytes .../colorama/__pycache__/ansi.cpython-312.pyc | Bin 0 -> 3988 bytes .../__pycache__/ansitowin32.cpython-312.pyc | Bin 0 -> 16459 bytes .../__pycache__/initialise.cpython-312.pyc | Bin 0 -> 3588 bytes .../__pycache__/win32.cpython-312.pyc | Bin 0 -> 8164 bytes .../__pycache__/winterm.cpython-312.pyc | Bin 0 -> 9126 bytes .../pip/_vendor/colorama/ansi.py | 102 + .../pip/_vendor/colorama/ansitowin32.py | 277 + .../pip/_vendor/colorama/initialise.py | 121 + .../pip/_vendor/colorama/tests/__init__.py | 1 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 236 bytes .../__pycache__/ansi_test.cpython-312.pyc | Bin 0 -> 5505 bytes .../ansitowin32_test.cpython-312.pyc | Bin 0 -> 18141 bytes .../initialise_test.cpython-312.pyc | Bin 0 -> 11786 bytes .../__pycache__/isatty_test.cpython-312.pyc | Bin 0 -> 4942 bytes .../tests/__pycache__/utils.cpython-312.pyc | Bin 0 -> 2526 bytes .../__pycache__/winterm_test.cpython-312.pyc | Bin 0 -> 6650 bytes .../pip/_vendor/colorama/tests/ansi_test.py | 76 + .../colorama/tests/ansitowin32_test.py | 294 + .../_vendor/colorama/tests/initialise_test.py | 189 + .../pip/_vendor/colorama/tests/isatty_test.py | 57 + .../pip/_vendor/colorama/tests/utils.py | 49 + .../_vendor/colorama/tests/winterm_test.py | 131 + .../pip/_vendor/colorama/win32.py | 180 + .../pip/_vendor/colorama/winterm.py | 195 + .../pip/_vendor/distlib/__init__.py | 33 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1307 bytes .../__pycache__/compat.cpython-312.pyc | Bin 0 -> 45640 bytes .../__pycache__/database.cpython-312.pyc | Bin 0 -> 66065 bytes .../distlib/__pycache__/index.cpython-312.pyc | Bin 0 -> 24404 bytes .../__pycache__/locators.cpython-312.pyc | Bin 0 -> 60193 bytes .../__pycache__/manifest.cpython-312.pyc | Bin 0 -> 15154 bytes .../__pycache__/markers.cpython-312.pyc | Bin 0 -> 7717 bytes .../__pycache__/metadata.cpython-312.pyc | Bin 0 -> 41831 bytes .../__pycache__/resources.cpython-312.pyc | Bin 0 -> 17363 bytes .../__pycache__/scripts.cpython-312.pyc | Bin 0 -> 19618 bytes .../distlib/__pycache__/util.cpython-312.pyc | Bin 0 -> 88254 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 30401 bytes .../distlib/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 51897 bytes .../pip/_vendor/distlib/compat.py | 1138 ++ .../pip/_vendor/distlib/database.py | 1359 ++ .../pip/_vendor/distlib/index.py | 508 + .../pip/_vendor/distlib/locators.py | 1303 ++ .../pip/_vendor/distlib/manifest.py | 384 + .../pip/_vendor/distlib/markers.py | 167 + .../pip/_vendor/distlib/metadata.py | 1068 ++ .../pip/_vendor/distlib/resources.py | 358 + .../pip/_vendor/distlib/scripts.py | 452 + .../site-packages/pip/_vendor/distlib/t32.exe | Bin 0 -> 97792 bytes .../pip/_vendor/distlib/t64-arm.exe | Bin 0 -> 182784 bytes .../site-packages/pip/_vendor/distlib/t64.exe | Bin 0 -> 108032 bytes .../site-packages/pip/_vendor/distlib/util.py | 2025 +++ .../pip/_vendor/distlib/version.py | 751 + .../site-packages/pip/_vendor/distlib/w32.exe | Bin 0 -> 91648 bytes .../pip/_vendor/distlib/w64-arm.exe | Bin 0 -> 168448 bytes .../site-packages/pip/_vendor/distlib/w64.exe | Bin 0 -> 101888 bytes .../pip/_vendor/distlib/wheel.py | 1099 ++ .../pip/_vendor/distro/__init__.py | 54 + .../pip/_vendor/distro/__main__.py | 4 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 998 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 330 bytes .../distro/__pycache__/distro.cpython-312.pyc | Bin 0 -> 53790 bytes .../pip/_vendor/distro/distro.py | 1399 ++ .../site-packages/pip/_vendor/distro/py.typed | 0 .../pip/_vendor/idna/__init__.py | 44 + .../idna/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 919 bytes .../idna/__pycache__/codec.cpython-312.pyc | Bin 0 -> 4671 bytes .../idna/__pycache__/compat.cpython-312.pyc | Bin 0 -> 925 bytes .../idna/__pycache__/core.cpython-312.pyc | Bin 0 -> 16320 bytes .../idna/__pycache__/idnadata.cpython-312.pyc | Bin 0 -> 38420 bytes .../__pycache__/intranges.cpython-312.pyc | Bin 0 -> 2676 bytes .../__pycache__/package_data.cpython-312.pyc | Bin 0 -> 254 bytes .../__pycache__/uts46data.cpython-312.pyc | Bin 0 -> 158908 bytes .../site-packages/pip/_vendor/idna/codec.py | 112 + .../site-packages/pip/_vendor/idna/compat.py | 13 + .../site-packages/pip/_vendor/idna/core.py | 400 + .../pip/_vendor/idna/idnadata.py | 2151 +++ .../pip/_vendor/idna/intranges.py | 54 + .../pip/_vendor/idna/package_data.py | 2 + .../site-packages/pip/_vendor/idna/py.typed | 0 .../pip/_vendor/idna/uts46data.py | 8600 ++++++++++ .../pip/_vendor/msgpack/__init__.py | 57 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1869 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 2063 bytes .../msgpack/__pycache__/ext.cpython-312.pyc | Bin 0 -> 8706 bytes .../__pycache__/fallback.cpython-312.pyc | Bin 0 -> 43600 bytes .../pip/_vendor/msgpack/exceptions.py | 48 + .../site-packages/pip/_vendor/msgpack/ext.py | 193 + .../pip/_vendor/msgpack/fallback.py | 1010 ++ .../pip/_vendor/packaging/__about__.py | 26 + .../pip/_vendor/packaging/__init__.py | 25 + .../__pycache__/__about__.cpython-312.pyc | Bin 0 -> 668 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 504 bytes .../__pycache__/_manylinux.cpython-312.pyc | Bin 0 -> 12111 bytes .../__pycache__/_musllinux.cpython-312.pyc | Bin 0 -> 6945 bytes .../__pycache__/_structures.cpython-312.pyc | Bin 0 -> 3279 bytes .../__pycache__/markers.cpython-312.pyc | Bin 0 -> 14087 bytes .../__pycache__/requirements.cpython-312.pyc | Bin 0 -> 6984 bytes .../__pycache__/specifiers.cpython-312.pyc | Bin 0 -> 31285 bytes .../__pycache__/tags.cpython-312.pyc | Bin 0 -> 18994 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 5906 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 19977 bytes .../pip/_vendor/packaging/_manylinux.py | 301 + .../pip/_vendor/packaging/_musllinux.py | 136 + .../pip/_vendor/packaging/_structures.py | 61 + .../pip/_vendor/packaging/markers.py | 304 + .../pip/_vendor/packaging/py.typed | 0 .../pip/_vendor/packaging/requirements.py | 146 + .../pip/_vendor/packaging/specifiers.py | 802 + .../pip/_vendor/packaging/tags.py | 487 + .../pip/_vendor/packaging/utils.py | 136 + .../pip/_vendor/packaging/version.py | 504 + .../pip/_vendor/pkg_resources/__init__.py | 3361 ++++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 146512 bytes .../pip/_vendor/platformdirs/__init__.py | 566 + .../pip/_vendor/platformdirs/__main__.py | 53 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 18067 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 1984 bytes .../__pycache__/android.cpython-312.pyc | Bin 0 -> 9482 bytes .../__pycache__/api.cpython-312.pyc | Bin 0 -> 9710 bytes .../__pycache__/macos.cpython-312.pyc | Bin 0 -> 5675 bytes .../__pycache__/unix.cpython-312.pyc | Bin 0 -> 12479 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 349 bytes .../__pycache__/windows.cpython-312.pyc | Bin 0 -> 13037 bytes .../pip/_vendor/platformdirs/android.py | 210 + .../pip/_vendor/platformdirs/api.py | 223 + .../pip/_vendor/platformdirs/macos.py | 91 + .../pip/_vendor/platformdirs/py.typed | 0 .../pip/_vendor/platformdirs/unix.py | 223 + .../pip/_vendor/platformdirs/version.py | 4 + .../pip/_vendor/platformdirs/windows.py | 255 + .../pip/_vendor/pygments/__init__.py | 82 + .../pip/_vendor/pygments/__main__.py | 17 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 3527 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 773 bytes .../__pycache__/cmdline.cpython-312.pyc | Bin 0 -> 26644 bytes .../__pycache__/console.cpython-312.pyc | Bin 0 -> 2665 bytes .../__pycache__/filter.cpython-312.pyc | Bin 0 -> 3271 bytes .../__pycache__/formatter.cpython-312.pyc | Bin 0 -> 4608 bytes .../__pycache__/lexer.cpython-312.pyc | Bin 0 -> 38339 bytes .../__pycache__/modeline.cpython-312.pyc | Bin 0 -> 1607 bytes .../__pycache__/plugin.cpython-312.pyc | Bin 0 -> 3435 bytes .../__pycache__/regexopt.cpython-312.pyc | Bin 0 -> 4120 bytes .../__pycache__/scanner.cpython-312.pyc | Bin 0 -> 4795 bytes .../__pycache__/sphinxext.cpython-312.pyc | Bin 0 -> 11085 bytes .../__pycache__/style.cpython-312.pyc | Bin 0 -> 6711 bytes .../__pycache__/token.cpython-312.pyc | Bin 0 -> 8181 bytes .../__pycache__/unistring.cpython-312.pyc | Bin 0 -> 33027 bytes .../pygments/__pycache__/util.cpython-312.pyc | Bin 0 -> 14020 bytes .../pip/_vendor/pygments/cmdline.py | 668 + .../pip/_vendor/pygments/console.py | 70 + .../pip/_vendor/pygments/filter.py | 71 + .../pip/_vendor/pygments/filters/__init__.py | 940 ++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 37975 bytes .../pip/_vendor/pygments/formatter.py | 124 + .../_vendor/pygments/formatters/__init__.py | 158 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 6965 bytes .../__pycache__/_mapping.cpython-312.pyc | Bin 0 -> 4254 bytes .../__pycache__/bbcode.cpython-312.pyc | Bin 0 -> 4233 bytes .../__pycache__/groff.cpython-312.pyc | Bin 0 -> 7303 bytes .../__pycache__/html.cpython-312.pyc | Bin 0 -> 40611 bytes .../__pycache__/img.cpython-312.pyc | Bin 0 -> 27082 bytes .../__pycache__/irc.cpython-312.pyc | Bin 0 -> 6104 bytes .../__pycache__/latex.cpython-312.pyc | Bin 0 -> 19993 bytes .../__pycache__/other.cpython-312.pyc | Bin 0 -> 6923 bytes .../__pycache__/pangomarkup.cpython-312.pyc | Bin 0 -> 2969 bytes .../__pycache__/rtf.cpython-312.pyc | Bin 0 -> 6165 bytes .../__pycache__/svg.cpython-312.pyc | Bin 0 -> 9105 bytes .../__pycache__/terminal.cpython-312.pyc | Bin 0 -> 5868 bytes .../__pycache__/terminal256.cpython-312.pyc | Bin 0 -> 15196 bytes .../_vendor/pygments/formatters/_mapping.py | 23 + .../pip/_vendor/pygments/formatters/bbcode.py | 108 + .../pip/_vendor/pygments/formatters/groff.py | 170 + .../pip/_vendor/pygments/formatters/html.py | 989 ++ .../pip/_vendor/pygments/formatters/img.py | 645 + .../pip/_vendor/pygments/formatters/irc.py | 154 + .../pip/_vendor/pygments/formatters/latex.py | 521 + .../pip/_vendor/pygments/formatters/other.py | 161 + .../pygments/formatters/pangomarkup.py | 83 + .../pip/_vendor/pygments/formatters/rtf.py | 146 + .../pip/_vendor/pygments/formatters/svg.py | 188 + .../_vendor/pygments/formatters/terminal.py | 127 + .../pygments/formatters/terminal256.py | 338 + .../pip/_vendor/pygments/lexer.py | 943 ++ .../pip/_vendor/pygments/lexers/__init__.py | 362 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 14691 bytes .../__pycache__/_mapping.cpython-312.pyc | Bin 0 -> 64443 bytes .../lexers/__pycache__/python.cpython-312.pyc | Bin 0 -> 42678 bytes .../pip/_vendor/pygments/lexers/_mapping.py | 559 + .../pip/_vendor/pygments/lexers/python.py | 1198 ++ .../pip/_vendor/pygments/modeline.py | 43 + .../pip/_vendor/pygments/plugin.py | 88 + .../pip/_vendor/pygments/regexopt.py | 91 + .../pip/_vendor/pygments/scanner.py | 104 + .../pip/_vendor/pygments/sphinxext.py | 217 + .../pip/_vendor/pygments/style.py | 197 + .../pip/_vendor/pygments/styles/__init__.py | 103 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4487 bytes .../pip/_vendor/pygments/token.py | 213 + .../pip/_vendor/pygments/unistring.py | 153 + .../pip/_vendor/pygments/util.py | 330 + .../pip/_vendor/pyparsing/__init__.py | 322 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 7950 bytes .../__pycache__/actions.cpython-312.pyc | Bin 0 -> 8434 bytes .../__pycache__/common.cpython-312.pyc | Bin 0 -> 13453 bytes .../__pycache__/core.cpython-312.pyc | Bin 0 -> 267747 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 13033 bytes .../__pycache__/helpers.cpython-312.pyc | Bin 0 -> 48540 bytes .../__pycache__/results.cpython-312.pyc | Bin 0 -> 34149 bytes .../__pycache__/testing.cpython-312.pyc | Bin 0 -> 17227 bytes .../__pycache__/unicode.cpython-312.pyc | Bin 0 -> 13223 bytes .../__pycache__/util.cpython-312.pyc | Bin 0 -> 14943 bytes .../pip/_vendor/pyparsing/actions.py | 217 + .../pip/_vendor/pyparsing/common.py | 432 + .../pip/_vendor/pyparsing/core.py | 6115 ++++++++ .../pip/_vendor/pyparsing/diagram/__init__.py | 656 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 26852 bytes .../pip/_vendor/pyparsing/exceptions.py | 299 + .../pip/_vendor/pyparsing/helpers.py | 1100 ++ .../pip/_vendor/pyparsing/py.typed | 0 .../pip/_vendor/pyparsing/results.py | 796 + .../pip/_vendor/pyparsing/testing.py | 331 + .../pip/_vendor/pyparsing/unicode.py | 361 + .../pip/_vendor/pyparsing/util.py | 284 + .../pip/_vendor/pyproject_hooks/__init__.py | 23 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 652 bytes .../__pycache__/_compat.cpython-312.pyc | Bin 0 -> 413 bytes .../__pycache__/_impl.cpython-312.pyc | Bin 0 -> 14764 bytes .../pip/_vendor/pyproject_hooks/_compat.py | 8 + .../pip/_vendor/pyproject_hooks/_impl.py | 330 + .../pyproject_hooks/_in_process/__init__.py | 18 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1119 bytes .../__pycache__/_in_process.cpython-312.pyc | Bin 0 -> 14436 bytes .../_in_process/_in_process.py | 353 + .../pip/_vendor/requests/__init__.py | 182 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 5485 bytes .../__pycache__/__version__.cpython-312.pyc | Bin 0 -> 623 bytes .../_internal_utils.cpython-312.pyc | Bin 0 -> 2060 bytes .../__pycache__/adapters.cpython-312.pyc | Bin 0 -> 21319 bytes .../requests/__pycache__/api.cpython-312.pyc | Bin 0 -> 7243 bytes .../requests/__pycache__/auth.cpython-312.pyc | Bin 0 -> 13962 bytes .../__pycache__/certs.cpython-312.pyc | Bin 0 -> 961 bytes .../__pycache__/compat.cpython-312.pyc | Bin 0 -> 1546 bytes .../__pycache__/cookies.cpython-312.pyc | Bin 0 -> 25285 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 7086 bytes .../requests/__pycache__/help.cpython-312.pyc | Bin 0 -> 4351 bytes .../__pycache__/hooks.cpython-312.pyc | Bin 0 -> 1091 bytes .../__pycache__/models.cpython-312.pyc | Bin 0 -> 35487 bytes .../__pycache__/packages.cpython-312.pyc | Bin 0 -> 811 bytes .../__pycache__/sessions.cpython-312.pyc | Bin 0 -> 27796 bytes .../__pycache__/status_codes.cpython-312.pyc | Bin 0 -> 5998 bytes .../__pycache__/structures.cpython-312.pyc | Bin 0 -> 5656 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 36308 bytes .../pip/_vendor/requests/__version__.py | 14 + .../pip/_vendor/requests/_internal_utils.py | 50 + .../pip/_vendor/requests/adapters.py | 538 + .../site-packages/pip/_vendor/requests/api.py | 157 + .../pip/_vendor/requests/auth.py | 315 + .../pip/_vendor/requests/certs.py | 24 + .../pip/_vendor/requests/compat.py | 67 + .../pip/_vendor/requests/cookies.py | 561 + .../pip/_vendor/requests/exceptions.py | 141 + .../pip/_vendor/requests/help.py | 131 + .../pip/_vendor/requests/hooks.py | 33 + .../pip/_vendor/requests/models.py | 1034 ++ .../pip/_vendor/requests/packages.py | 16 + .../pip/_vendor/requests/sessions.py | 833 + .../pip/_vendor/requests/status_codes.py | 128 + .../pip/_vendor/requests/structures.py | 99 + .../pip/_vendor/requests/utils.py | 1094 ++ .../pip/_vendor/resolvelib/__init__.py | 26 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 673 bytes .../__pycache__/providers.cpython-312.pyc | Bin 0 -> 6890 bytes .../__pycache__/reporters.cpython-312.pyc | Bin 0 -> 2693 bytes .../__pycache__/resolvers.cpython-312.pyc | Bin 0 -> 25936 bytes .../__pycache__/structs.cpython-312.pyc | Bin 0 -> 10545 bytes .../pip/_vendor/resolvelib/compat/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 239 bytes .../collections_abc.cpython-312.pyc | Bin 0 -> 459 bytes .../resolvelib/compat/collections_abc.py | 6 + .../pip/_vendor/resolvelib/providers.py | 133 + .../pip/_vendor/resolvelib/py.typed | 0 .../pip/_vendor/resolvelib/reporters.py | 43 + .../pip/_vendor/resolvelib/resolvers.py | 547 + .../pip/_vendor/resolvelib/structs.py | 170 + .../pip/_vendor/rich/__init__.py | 177 + .../pip/_vendor/rich/__main__.py | 274 + .../rich/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 7054 bytes .../rich/__pycache__/__main__.cpython-312.pyc | Bin 0 -> 10343 bytes .../__pycache__/_cell_widths.cpython-312.pyc | Bin 0 -> 7860 bytes .../__pycache__/_emoji_codes.cpython-312.pyc | Bin 0 -> 206015 bytes .../_emoji_replace.cpython-312.pyc | Bin 0 -> 1768 bytes .../_export_format.cpython-312.pyc | Bin 0 -> 2360 bytes .../__pycache__/_extension.cpython-312.pyc | Bin 0 -> 576 bytes .../rich/__pycache__/_fileno.cpython-312.pyc | Bin 0 -> 894 bytes .../rich/__pycache__/_inspect.cpython-312.pyc | Bin 0 -> 12116 bytes .../__pycache__/_log_render.cpython-312.pyc | Bin 0 -> 4186 bytes .../rich/__pycache__/_loop.cpython-312.pyc | Bin 0 -> 1924 bytes .../__pycache__/_null_file.cpython-312.pyc | Bin 0 -> 3659 bytes .../__pycache__/_palettes.cpython-312.pyc | Bin 0 -> 5199 bytes .../rich/__pycache__/_pick.cpython-312.pyc | Bin 0 -> 763 bytes .../rich/__pycache__/_ratio.cpython-312.pyc | Bin 0 -> 6616 bytes .../__pycache__/_spinners.cpython-312.pyc | Bin 0 -> 13218 bytes .../rich/__pycache__/_stack.cpython-312.pyc | Bin 0 -> 1004 bytes .../rich/__pycache__/_timer.cpython-312.pyc | Bin 0 -> 904 bytes .../_win32_console.cpython-312.pyc | Bin 0 -> 29006 bytes .../rich/__pycache__/_windows.cpython-312.pyc | Bin 0 -> 2529 bytes .../_windows_renderer.cpython-312.pyc | Bin 0 -> 3612 bytes .../rich/__pycache__/_wrap.cpython-312.pyc | Bin 0 -> 2399 bytes .../rich/__pycache__/abc.cpython-312.pyc | Bin 0 -> 1647 bytes .../rich/__pycache__/align.cpython-312.pyc | Bin 0 -> 12361 bytes .../rich/__pycache__/ansi.cpython-312.pyc | Bin 0 -> 9145 bytes .../rich/__pycache__/bar.cpython-312.pyc | Bin 0 -> 4311 bytes .../rich/__pycache__/box.cpython-312.pyc | Bin 0 -> 11897 bytes .../rich/__pycache__/cells.cpython-312.pyc | Bin 0 -> 5657 bytes .../rich/__pycache__/color.cpython-312.pyc | Bin 0 -> 26564 bytes .../__pycache__/color_triplet.cpython-312.pyc | Bin 0 -> 1740 bytes .../rich/__pycache__/columns.cpython-312.pyc | Bin 0 -> 8626 bytes .../rich/__pycache__/console.cpython-312.pyc | Bin 0 -> 113823 bytes .../__pycache__/constrain.cpython-312.pyc | Bin 0 -> 2297 bytes .../__pycache__/containers.cpython-312.pyc | Bin 0 -> 9265 bytes .../rich/__pycache__/control.cpython-312.pyc | Bin 0 -> 10968 bytes .../default_styles.cpython-312.pyc | Bin 0 -> 10412 bytes .../rich/__pycache__/diagnose.cpython-312.pyc | Bin 0 -> 1526 bytes .../rich/__pycache__/emoji.cpython-312.pyc | Bin 0 -> 4248 bytes .../rich/__pycache__/errors.cpython-312.pyc | Bin 0 -> 1884 bytes .../__pycache__/file_proxy.cpython-312.pyc | Bin 0 -> 3616 bytes .../rich/__pycache__/filesize.cpython-312.pyc | Bin 0 -> 3121 bytes .../__pycache__/highlighter.cpython-312.pyc | Bin 0 -> 9937 bytes .../rich/__pycache__/json.cpython-312.pyc | Bin 0 -> 6074 bytes .../rich/__pycache__/jupyter.cpython-312.pyc | Bin 0 -> 5248 bytes .../rich/__pycache__/layout.cpython-312.pyc | Bin 0 -> 20259 bytes .../rich/__pycache__/live.cpython-312.pyc | Bin 0 -> 19179 bytes .../__pycache__/live_render.cpython-312.pyc | Bin 0 -> 4933 bytes .../rich/__pycache__/logging.cpython-312.pyc | Bin 0 -> 13587 bytes .../rich/__pycache__/markup.cpython-312.pyc | Bin 0 -> 9337 bytes .../rich/__pycache__/measure.cpython-312.pyc | Bin 0 -> 6415 bytes .../rich/__pycache__/padding.cpython-312.pyc | Bin 0 -> 7173 bytes .../rich/__pycache__/pager.cpython-312.pyc | Bin 0 -> 1859 bytes .../rich/__pycache__/palette.cpython-312.pyc | Bin 0 -> 5353 bytes .../rich/__pycache__/panel.cpython-312.pyc | Bin 0 -> 12136 bytes .../rich/__pycache__/pretty.cpython-312.pyc | Bin 0 -> 40081 bytes .../rich/__pycache__/progress.cpython-312.pyc | Bin 0 -> 75114 bytes .../__pycache__/progress_bar.cpython-312.pyc | Bin 0 -> 10428 bytes .../rich/__pycache__/prompt.cpython-312.pyc | Bin 0 -> 14817 bytes .../rich/__pycache__/protocol.cpython-312.pyc | Bin 0 -> 1831 bytes .../rich/__pycache__/region.cpython-312.pyc | Bin 0 -> 606 bytes .../rich/__pycache__/repr.cpython-312.pyc | Bin 0 -> 6665 bytes .../rich/__pycache__/rule.cpython-312.pyc | Bin 0 -> 6607 bytes .../rich/__pycache__/scope.cpython-312.pyc | Bin 0 -> 3869 bytes .../rich/__pycache__/screen.cpython-312.pyc | Bin 0 -> 2523 bytes .../rich/__pycache__/segment.cpython-312.pyc | Bin 0 -> 28200 bytes .../rich/__pycache__/spinner.cpython-312.pyc | Bin 0 -> 6103 bytes .../rich/__pycache__/status.cpython-312.pyc | Bin 0 -> 6107 bytes .../rich/__pycache__/style.cpython-312.pyc | Bin 0 -> 33553 bytes .../rich/__pycache__/styled.cpython-312.pyc | Bin 0 -> 2178 bytes .../rich/__pycache__/syntax.cpython-312.pyc | Bin 0 -> 39649 bytes .../rich/__pycache__/table.cpython-312.pyc | Bin 0 -> 43623 bytes .../terminal_theme.cpython-312.pyc | Bin 0 -> 3387 bytes .../rich/__pycache__/text.cpython-312.pyc | Bin 0 -> 58988 bytes .../rich/__pycache__/theme.cpython-312.pyc | Bin 0 -> 6379 bytes .../rich/__pycache__/themes.cpython-312.pyc | Bin 0 -> 353 bytes .../__pycache__/traceback.cpython-312.pyc | Bin 0 -> 31583 bytes .../rich/__pycache__/tree.cpython-312.pyc | Bin 0 -> 11478 bytes .../pip/_vendor/rich/_cell_widths.py | 451 + .../pip/_vendor/rich/_emoji_codes.py | 3610 +++++ .../pip/_vendor/rich/_emoji_replace.py | 32 + .../pip/_vendor/rich/_export_format.py | 76 + .../pip/_vendor/rich/_extension.py | 10 + .../site-packages/pip/_vendor/rich/_fileno.py | 24 + .../pip/_vendor/rich/_inspect.py | 270 + .../pip/_vendor/rich/_log_render.py | 94 + .../site-packages/pip/_vendor/rich/_loop.py | 43 + .../pip/_vendor/rich/_null_file.py | 69 + .../pip/_vendor/rich/_palettes.py | 309 + .../site-packages/pip/_vendor/rich/_pick.py | 17 + .../site-packages/pip/_vendor/rich/_ratio.py | 160 + .../pip/_vendor/rich/_spinners.py | 482 + .../site-packages/pip/_vendor/rich/_stack.py | 16 + .../site-packages/pip/_vendor/rich/_timer.py | 19 + .../pip/_vendor/rich/_win32_console.py | 662 + .../pip/_vendor/rich/_windows.py | 72 + .../pip/_vendor/rich/_windows_renderer.py | 56 + .../site-packages/pip/_vendor/rich/_wrap.py | 56 + .../site-packages/pip/_vendor/rich/abc.py | 33 + .../site-packages/pip/_vendor/rich/align.py | 311 + .../site-packages/pip/_vendor/rich/ansi.py | 240 + .../site-packages/pip/_vendor/rich/bar.py | 94 + .../site-packages/pip/_vendor/rich/box.py | 517 + .../site-packages/pip/_vendor/rich/cells.py | 154 + .../site-packages/pip/_vendor/rich/color.py | 622 + .../pip/_vendor/rich/color_triplet.py | 38 + .../site-packages/pip/_vendor/rich/columns.py | 187 + .../site-packages/pip/_vendor/rich/console.py | 2633 ++++ .../pip/_vendor/rich/constrain.py | 37 + .../pip/_vendor/rich/containers.py | 167 + .../site-packages/pip/_vendor/rich/control.py | 225 + .../pip/_vendor/rich/default_styles.py | 190 + .../pip/_vendor/rich/diagnose.py | 37 + .../site-packages/pip/_vendor/rich/emoji.py | 96 + .../site-packages/pip/_vendor/rich/errors.py | 34 + .../pip/_vendor/rich/file_proxy.py | 57 + .../pip/_vendor/rich/filesize.py | 89 + .../pip/_vendor/rich/highlighter.py | 232 + .../site-packages/pip/_vendor/rich/json.py | 140 + .../site-packages/pip/_vendor/rich/jupyter.py | 101 + .../site-packages/pip/_vendor/rich/layout.py | 443 + .../site-packages/pip/_vendor/rich/live.py | 375 + .../pip/_vendor/rich/live_render.py | 113 + .../site-packages/pip/_vendor/rich/logging.py | 289 + .../site-packages/pip/_vendor/rich/markup.py | 246 + .../site-packages/pip/_vendor/rich/measure.py | 151 + .../site-packages/pip/_vendor/rich/padding.py | 141 + .../site-packages/pip/_vendor/rich/pager.py | 34 + .../site-packages/pip/_vendor/rich/palette.py | 100 + .../site-packages/pip/_vendor/rich/panel.py | 308 + .../site-packages/pip/_vendor/rich/pretty.py | 994 ++ .../pip/_vendor/rich/progress.py | 1702 ++ .../pip/_vendor/rich/progress_bar.py | 224 + .../site-packages/pip/_vendor/rich/prompt.py | 376 + .../pip/_vendor/rich/protocol.py | 42 + .../site-packages/pip/_vendor/rich/py.typed | 0 .../site-packages/pip/_vendor/rich/region.py | 10 + .../site-packages/pip/_vendor/rich/repr.py | 149 + .../site-packages/pip/_vendor/rich/rule.py | 130 + .../site-packages/pip/_vendor/rich/scope.py | 86 + .../site-packages/pip/_vendor/rich/screen.py | 54 + .../site-packages/pip/_vendor/rich/segment.py | 739 + .../site-packages/pip/_vendor/rich/spinner.py | 137 + .../site-packages/pip/_vendor/rich/status.py | 132 + .../site-packages/pip/_vendor/rich/style.py | 796 + .../site-packages/pip/_vendor/rich/styled.py | 42 + .../site-packages/pip/_vendor/rich/syntax.py | 948 ++ .../site-packages/pip/_vendor/rich/table.py | 1002 ++ .../pip/_vendor/rich/terminal_theme.py | 153 + .../site-packages/pip/_vendor/rich/text.py | 1307 ++ .../site-packages/pip/_vendor/rich/theme.py | 115 + .../site-packages/pip/_vendor/rich/themes.py | 5 + .../pip/_vendor/rich/traceback.py | 756 + .../site-packages/pip/_vendor/rich/tree.py | 251 + .../site-packages/pip/_vendor/six.py | 998 ++ .../pip/_vendor/tenacity/__init__.py | 608 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 27125 bytes .../__pycache__/_asyncio.cpython-312.pyc | Bin 0 -> 4845 bytes .../__pycache__/_utils.cpython-312.pyc | Bin 0 -> 2354 bytes .../__pycache__/after.cpython-312.pyc | Bin 0 -> 1663 bytes .../__pycache__/before.cpython-312.pyc | Bin 0 -> 1503 bytes .../__pycache__/before_sleep.cpython-312.pyc | Bin 0 -> 2341 bytes .../tenacity/__pycache__/nap.cpython-312.pyc | Bin 0 -> 1451 bytes .../__pycache__/retry.cpython-312.pyc | Bin 0 -> 14320 bytes .../tenacity/__pycache__/stop.cpython-312.pyc | Bin 0 -> 5607 bytes .../__pycache__/tornadoweb.cpython-312.pyc | Bin 0 -> 2625 bytes .../tenacity/__pycache__/wait.cpython-312.pyc | Bin 0 -> 12452 bytes .../pip/_vendor/tenacity/_asyncio.py | 94 + .../pip/_vendor/tenacity/_utils.py | 76 + .../pip/_vendor/tenacity/after.py | 51 + .../pip/_vendor/tenacity/before.py | 46 + .../pip/_vendor/tenacity/before_sleep.py | 71 + .../site-packages/pip/_vendor/tenacity/nap.py | 43 + .../pip/_vendor/tenacity/py.typed | 0 .../pip/_vendor/tenacity/retry.py | 272 + .../pip/_vendor/tenacity/stop.py | 103 + .../pip/_vendor/tenacity/tornadoweb.py | 59 + .../pip/_vendor/tenacity/wait.py | 228 + .../pip/_vendor/tomli/__init__.py | 11 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 423 bytes .../tomli/__pycache__/_parser.cpython-312.pyc | Bin 0 -> 26966 bytes .../tomli/__pycache__/_re.cpython-312.pyc | Bin 0 -> 3947 bytes .../tomli/__pycache__/_types.cpython-312.pyc | Bin 0 -> 405 bytes .../pip/_vendor/tomli/_parser.py | 691 + .../site-packages/pip/_vendor/tomli/_re.py | 107 + .../site-packages/pip/_vendor/tomli/_types.py | 10 + .../site-packages/pip/_vendor/tomli/py.typed | 1 + .../pip/_vendor/truststore/__init__.py | 13 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 657 bytes .../__pycache__/_api.cpython-312.pyc | Bin 0 -> 15836 bytes .../__pycache__/_macos.cpython-312.pyc | Bin 0 -> 16701 bytes .../__pycache__/_openssl.cpython-312.pyc | Bin 0 -> 2254 bytes .../_ssl_constants.cpython-312.pyc | Bin 0 -> 1138 bytes .../__pycache__/_windows.cpython-312.pyc | Bin 0 -> 15545 bytes .../pip/_vendor/truststore/_api.py | 302 + .../pip/_vendor/truststore/_macos.py | 501 + .../pip/_vendor/truststore/_openssl.py | 66 + .../pip/_vendor/truststore/_ssl_constants.py | 31 + .../pip/_vendor/truststore/_windows.py | 554 + .../pip/_vendor/truststore/py.typed | 0 .../pip/_vendor/typing_extensions.py | 3072 ++++ .../pip/_vendor/urllib3/__init__.py | 102 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 3444 bytes .../__pycache__/_collections.cpython-312.pyc | Bin 0 -> 15970 bytes .../__pycache__/_version.cpython-312.pyc | Bin 0 -> 257 bytes .../__pycache__/connection.cpython-312.pyc | Bin 0 -> 20446 bytes .../connectionpool.cpython-312.pyc | Bin 0 -> 36318 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 13532 bytes .../__pycache__/fields.cpython-312.pyc | Bin 0 -> 10452 bytes .../__pycache__/filepost.cpython-312.pyc | Bin 0 -> 4057 bytes .../__pycache__/poolmanager.cpython-312.pyc | Bin 0 -> 20341 bytes .../__pycache__/request.cpython-312.pyc | Bin 0 -> 7333 bytes .../__pycache__/response.cpython-312.pyc | Bin 0 -> 34005 bytes .../pip/_vendor/urllib3/_collections.py | 337 + .../pip/_vendor/urllib3/_version.py | 2 + .../pip/_vendor/urllib3/connection.py | 572 + .../pip/_vendor/urllib3/connectionpool.py | 1132 ++ .../pip/_vendor/urllib3/contrib/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 237 bytes .../_appengine_environ.cpython-312.pyc | Bin 0 -> 1887 bytes .../__pycache__/appengine.cpython-312.pyc | Bin 0 -> 11603 bytes .../__pycache__/ntlmpool.cpython-312.pyc | Bin 0 -> 5758 bytes .../__pycache__/pyopenssl.cpython-312.pyc | Bin 0 -> 24489 bytes .../securetransport.cpython-312.pyc | Bin 0 -> 35583 bytes .../contrib/__pycache__/socks.cpython-312.pyc | Bin 0 -> 7550 bytes .../urllib3/contrib/_appengine_environ.py | 36 + .../contrib/_securetransport/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 254 bytes .../__pycache__/bindings.cpython-312.pyc | Bin 0 -> 17466 bytes .../__pycache__/low_level.cpython-312.pyc | Bin 0 -> 14840 bytes .../contrib/_securetransport/bindings.py | 519 + .../contrib/_securetransport/low_level.py | 397 + .../pip/_vendor/urllib3/contrib/appengine.py | 314 + .../pip/_vendor/urllib3/contrib/ntlmpool.py | 130 + .../pip/_vendor/urllib3/contrib/pyopenssl.py | 518 + .../urllib3/contrib/securetransport.py | 921 ++ .../pip/_vendor/urllib3/contrib/socks.py | 216 + .../pip/_vendor/urllib3/exceptions.py | 323 + .../pip/_vendor/urllib3/fields.py | 274 + .../pip/_vendor/urllib3/filepost.py | 98 + .../pip/_vendor/urllib3/packages/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 238 bytes .../packages/__pycache__/six.cpython-312.pyc | Bin 0 -> 41358 bytes .../urllib3/packages/backports/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 248 bytes .../__pycache__/makefile.cpython-312.pyc | Bin 0 -> 1859 bytes .../weakref_finalize.cpython-312.pyc | Bin 0 -> 7367 bytes .../urllib3/packages/backports/makefile.py | 51 + .../packages/backports/weakref_finalize.py | 155 + .../pip/_vendor/urllib3/packages/six.py | 1076 ++ .../pip/_vendor/urllib3/poolmanager.py | 537 + .../pip/_vendor/urllib3/request.py | 191 + .../pip/_vendor/urllib3/response.py | 879 ++ .../pip/_vendor/urllib3/util/__init__.py | 49 + .../util/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1185 bytes .../__pycache__/connection.cpython-312.pyc | Bin 0 -> 4795 bytes .../util/__pycache__/proxy.cpython-312.pyc | Bin 0 -> 1591 bytes .../util/__pycache__/queue.cpython-312.pyc | Bin 0 -> 1391 bytes .../util/__pycache__/request.cpython-312.pyc | Bin 0 -> 4222 bytes .../util/__pycache__/response.cpython-312.pyc | Bin 0 -> 3028 bytes .../util/__pycache__/retry.cpython-312.pyc | Bin 0 -> 21736 bytes .../util/__pycache__/ssl_.cpython-312.pyc | Bin 0 -> 15142 bytes .../ssl_match_hostname.cpython-312.pyc | Bin 0 -> 5110 bytes .../__pycache__/ssltransport.cpython-312.pyc | Bin 0 -> 10806 bytes .../util/__pycache__/timeout.cpython-312.pyc | Bin 0 -> 11178 bytes .../util/__pycache__/url.cpython-312.pyc | Bin 0 -> 15834 bytes .../util/__pycache__/wait.cpython-312.pyc | Bin 0 -> 4442 bytes .../pip/_vendor/urllib3/util/connection.py | 149 + .../pip/_vendor/urllib3/util/proxy.py | 57 + .../pip/_vendor/urllib3/util/queue.py | 22 + .../pip/_vendor/urllib3/util/request.py | 137 + .../pip/_vendor/urllib3/util/response.py | 107 + .../pip/_vendor/urllib3/util/retry.py | 620 + .../pip/_vendor/urllib3/util/ssl_.py | 495 + .../urllib3/util/ssl_match_hostname.py | 159 + .../pip/_vendor/urllib3/util/ssltransport.py | 221 + .../pip/_vendor/urllib3/util/timeout.py | 271 + .../pip/_vendor/urllib3/util/url.py | 435 + .../pip/_vendor/urllib3/util/wait.py | 152 + .../site-packages/pip/_vendor/vendor.txt | 24 + .../pip/_vendor/webencodings/__init__.py | 342 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 12034 bytes .../__pycache__/labels.cpython-312.pyc | Bin 0 -> 7171 bytes .../__pycache__/mklabels.cpython-312.pyc | Bin 0 -> 2735 bytes .../__pycache__/tests.cpython-312.pyc | Bin 0 -> 9078 bytes .../x_user_defined.cpython-312.pyc | Bin 0 -> 3334 bytes .../pip/_vendor/webencodings/labels.py | 231 + .../pip/_vendor/webencodings/mklabels.py | 59 + .../pip/_vendor/webencodings/tests.py | 153 + .../_vendor/webencodings/x_user_defined.py | 325 + .../lib/python3.12/site-packages/pip/py.typed | 4 + .../propcache-0.3.1.dist-info/INSTALLER | 1 + .../propcache-0.3.1.dist-info/METADATA | 337 + .../propcache-0.3.1.dist-info/RECORD | 18 + .../propcache-0.3.1.dist-info/WHEEL | 6 + .../licenses/LICENSE | 202 + .../propcache-0.3.1.dist-info/licenses/NOTICE | 13 + .../propcache-0.3.1.dist-info/top_level.txt | 1 + .../site-packages/propcache/__init__.py | 32 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1317 bytes .../__pycache__/_helpers.cpython-312.pyc | Bin 0 -> 1060 bytes .../__pycache__/_helpers_py.cpython-312.pyc | Bin 0 -> 3219 bytes .../propcache/__pycache__/api.cpython-312.pyc | Bin 0 -> 378 bytes .../site-packages/propcache/_helpers.py | 39 + .../_helpers_c.cpython-312-darwin.so | Bin 0 -> 124496 bytes .../site-packages/propcache/_helpers_c.pyx | 86 + .../site-packages/propcache/_helpers_py.py | 60 + .../python3.12/site-packages/propcache/api.py | 8 + .../site-packages/propcache/py.typed | 1 + .../requests-2.32.3.dist-info/INSTALLER | 1 + .../requests-2.32.3.dist-info/LICENSE | 175 + .../requests-2.32.3.dist-info/METADATA | 119 + .../requests-2.32.3.dist-info/RECORD | 43 + .../requests-2.32.3.dist-info/REQUESTED | 0 .../requests-2.32.3.dist-info/WHEEL | 5 + .../requests-2.32.3.dist-info/top_level.txt | 1 + .../site-packages/requests/__init__.py | 184 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 5440 bytes .../__pycache__/__version__.cpython-312.pyc | Bin 0 -> 611 bytes .../_internal_utils.cpython-312.pyc | Bin 0 -> 2048 bytes .../__pycache__/adapters.cpython-312.pyc | Bin 0 -> 28391 bytes .../requests/__pycache__/api.cpython-312.pyc | Bin 0 -> 7231 bytes .../requests/__pycache__/auth.cpython-312.pyc | Bin 0 -> 13950 bytes .../__pycache__/certs.cpython-312.pyc | Bin 0 -> 693 bytes .../__pycache__/compat.cpython-312.pyc | Bin 0 -> 2112 bytes .../__pycache__/cookies.cpython-312.pyc | Bin 0 -> 25303 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 7612 bytes .../requests/__pycache__/help.cpython-312.pyc | Bin 0 -> 4354 bytes .../__pycache__/hooks.cpython-312.pyc | Bin 0 -> 1079 bytes .../__pycache__/models.cpython-312.pyc | Bin 0 -> 35433 bytes .../__pycache__/packages.cpython-312.pyc | Bin 0 -> 1166 bytes .../__pycache__/sessions.cpython-312.pyc | Bin 0 -> 27909 bytes .../__pycache__/status_codes.cpython-312.pyc | Bin 0 -> 6058 bytes .../__pycache__/structures.cpython-312.pyc | Bin 0 -> 5644 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 36457 bytes .../site-packages/requests/__version__.py | 14 + .../site-packages/requests/_internal_utils.py | 50 + .../site-packages/requests/adapters.py | 719 + .../python3.12/site-packages/requests/api.py | 157 + .../python3.12/site-packages/requests/auth.py | 314 + .../site-packages/requests/certs.py | 17 + .../site-packages/requests/compat.py | 94 + .../site-packages/requests/cookies.py | 561 + .../site-packages/requests/exceptions.py | 151 + .../python3.12/site-packages/requests/help.py | 134 + .../site-packages/requests/hooks.py | 33 + .../site-packages/requests/models.py | 1037 ++ .../site-packages/requests/packages.py | 23 + .../site-packages/requests/sessions.py | 831 + .../site-packages/requests/status_codes.py | 128 + .../site-packages/requests/structures.py | 99 + .../site-packages/requests/utils.py | 1096 ++ .../urllib3-2.4.0.dist-info/INSTALLER | 1 + .../urllib3-2.4.0.dist-info/METADATA | 154 + .../urllib3-2.4.0.dist-info/RECORD | 79 + .../urllib3-2.4.0.dist-info/WHEEL | 4 + .../licenses/LICENSE.txt | 21 + .../site-packages/urllib3/__init__.py | 211 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 7342 bytes .../_base_connection.cpython-312.pyc | Bin 0 -> 6880 bytes .../__pycache__/_collections.cpython-312.pyc | Bin 0 -> 22599 bytes .../_request_methods.cpython-312.pyc | Bin 0 -> 10634 bytes .../__pycache__/_version.cpython-312.pyc | Bin 0 -> 678 bytes .../__pycache__/connection.cpython-312.pyc | Bin 0 -> 36193 bytes .../connectionpool.cpython-312.pyc | Bin 0 -> 39767 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 16643 bytes .../__pycache__/fields.cpython-312.pyc | Bin 0 -> 12054 bytes .../__pycache__/filepost.cpython-312.pyc | Bin 0 -> 3521 bytes .../__pycache__/poolmanager.cpython-312.pyc | Bin 0 -> 24106 bytes .../__pycache__/response.cpython-312.pyc | Bin 0 -> 51097 bytes .../site-packages/urllib3/_base_connection.py | 165 + .../site-packages/urllib3/_collections.py | 479 + .../site-packages/urllib3/_request_methods.py | 278 + .../site-packages/urllib3/_version.py | 21 + .../site-packages/urllib3/connection.py | 1044 ++ .../site-packages/urllib3/connectionpool.py | 1178 ++ .../site-packages/urllib3/contrib/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 225 bytes .../__pycache__/pyopenssl.cpython-312.pyc | Bin 0 -> 28248 bytes .../contrib/__pycache__/socks.cpython-312.pyc | Bin 0 -> 8203 bytes .../urllib3/contrib/emscripten/__init__.py | 16 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 933 bytes .../__pycache__/connection.cpython-312.pyc | Bin 0 -> 10274 bytes .../__pycache__/fetch.cpython-312.pyc | Bin 0 -> 28145 bytes .../__pycache__/request.cpython-312.pyc | Bin 0 -> 1453 bytes .../__pycache__/response.cpython-312.pyc | Bin 0 -> 12247 bytes .../urllib3/contrib/emscripten/connection.py | 255 + .../emscripten/emscripten_fetch_worker.js | 110 + .../urllib3/contrib/emscripten/fetch.py | 708 + .../urllib3/contrib/emscripten/request.py | 22 + .../urllib3/contrib/emscripten/response.py | 277 + .../urllib3/contrib/pyopenssl.py | 564 + .../site-packages/urllib3/contrib/socks.py | 228 + .../site-packages/urllib3/exceptions.py | 335 + .../site-packages/urllib3/fields.py | 341 + .../site-packages/urllib3/filepost.py | 89 + .../site-packages/urllib3/http2/__init__.py | 53 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1778 bytes .../__pycache__/connection.cpython-312.pyc | Bin 0 -> 17082 bytes .../http2/__pycache__/probe.cpython-312.pyc | Bin 0 -> 3726 bytes .../site-packages/urllib3/http2/connection.py | 356 + .../site-packages/urllib3/http2/probe.py | 87 + .../site-packages/urllib3/poolmanager.py | 637 + .../python3.12/site-packages/urllib3/py.typed | 2 + .../site-packages/urllib3/response.py | 1278 ++ .../site-packages/urllib3/util/__init__.py | 42 + .../util/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1038 bytes .../__pycache__/connection.cpython-312.pyc | Bin 0 -> 4728 bytes .../util/__pycache__/proxy.cpython-312.pyc | Bin 0 -> 1250 bytes .../util/__pycache__/request.cpython-312.pyc | Bin 0 -> 8205 bytes .../util/__pycache__/response.cpython-312.pyc | Bin 0 -> 2906 bytes .../util/__pycache__/retry.cpython-312.pyc | Bin 0 -> 20319 bytes .../util/__pycache__/ssl_.cpython-312.pyc | Bin 0 -> 17202 bytes .../ssl_match_hostname.cpython-312.pyc | Bin 0 -> 5590 bytes .../__pycache__/ssltransport.cpython-312.pyc | Bin 0 -> 13352 bytes .../util/__pycache__/timeout.cpython-312.pyc | Bin 0 -> 11722 bytes .../util/__pycache__/url.cpython-312.pyc | Bin 0 -> 16259 bytes .../util/__pycache__/util.cpython-312.pyc | Bin 0 -> 2027 bytes .../util/__pycache__/wait.cpython-312.pyc | Bin 0 -> 3473 bytes .../site-packages/urllib3/util/connection.py | 137 + .../site-packages/urllib3/util/proxy.py | 43 + .../site-packages/urllib3/util/request.py | 258 + .../site-packages/urllib3/util/response.py | 101 + .../site-packages/urllib3/util/retry.py | 533 + .../site-packages/urllib3/util/ssl_.py | 524 + .../urllib3/util/ssl_match_hostname.py | 159 + .../urllib3/util/ssltransport.py | 271 + .../site-packages/urllib3/util/timeout.py | 275 + .../site-packages/urllib3/util/url.py | 469 + .../site-packages/urllib3/util/util.py | 42 + .../site-packages/urllib3/util/wait.py | 124 + .../yarl-1.20.0.dist-info/INSTALLER | 1 + .../yarl-1.20.0.dist-info/METADATA | 2383 +++ .../yarl-1.20.0.dist-info/RECORD | 26 + .../site-packages/yarl-1.20.0.dist-info/WHEEL | 6 + .../yarl-1.20.0.dist-info/licenses/LICENSE | 202 + .../yarl-1.20.0.dist-info/licenses/NOTICE | 13 + .../yarl-1.20.0.dist-info/top_level.txt | 1 + .../python3.12/site-packages/yarl/__init__.py | 14 + .../yarl/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 494 bytes .../yarl/__pycache__/_parse.cpython-312.pyc | Bin 0 -> 6991 bytes .../yarl/__pycache__/_path.cpython-312.pyc | Bin 0 -> 1448 bytes .../yarl/__pycache__/_query.cpython-312.pyc | Bin 0 -> 4815 bytes .../yarl/__pycache__/_quoters.cpython-312.pyc | Bin 0 -> 2029 bytes .../yarl/__pycache__/_quoting.cpython-312.pyc | Bin 0 -> 788 bytes .../__pycache__/_quoting_py.cpython-312.pyc | Bin 0 -> 8961 bytes .../yarl/__pycache__/_url.cpython-312.pyc | Bin 0 -> 60589 bytes .../python3.12/site-packages/yarl/_parse.py | 203 + .../python3.12/site-packages/yarl/_path.py | 41 + .../python3.12/site-packages/yarl/_query.py | 114 + .../python3.12/site-packages/yarl/_quoters.py | 33 + .../python3.12/site-packages/yarl/_quoting.py | 19 + .../yarl/_quoting_c.cpython-312-darwin.so | Bin 0 -> 161648 bytes .../site-packages/yarl/_quoting_c.pyx | 453 + .../site-packages/yarl/_quoting_py.py | 213 + .../lib/python3.12/site-packages/yarl/_url.py | 1604 ++ .../python3.12/site-packages/yarl/py.typed | 1 + venv/pyvenv.cfg | 5 + 1814 files changed, 378464 insertions(+) create mode 100644 .history/DiscordBot/bot_20250508222458.py create mode 100644 .history/DiscordBot/bot_20250509124520.py create mode 100644 .history/DiscordBot/bot_20250509125037.py create mode 100644 .history/DiscordBot/bot_20250509125209.py create mode 100644 .history/DiscordBot/bot_20250509125348.py create mode 100644 .history/DiscordBot/bot_20250509125707.py create mode 100644 .history/DiscordBot/bot_20250509131012.py create mode 100644 .history/DiscordBot/bot_20250509131355.py create mode 100644 .history/DiscordBot/bot_20250509131440.py create mode 100644 .history/DiscordBot/bot_20250509131607.py create mode 100644 .history/DiscordBot/bot_20250509131821.py create mode 100644 .history/DiscordBot/bot_20250509132756.py create mode 100644 .history/DiscordBot/bot_20250509133441.py create mode 100644 .history/DiscordBot/bot_20250509133536.py create mode 100644 .history/DiscordBot/report_20250508231525.py create mode 100644 .history/DiscordBot/report_20250509105254.py create mode 100644 .history/DiscordBot/report_20250509105318.py create mode 100644 .history/DiscordBot/report_20250509124520.py create mode 100644 .history/DiscordBot/report_20250509124544.py create mode 100644 .history/DiscordBot/report_20250509124556.py create mode 100644 .history/DiscordBot/report_20250509124712.py create mode 100644 .history/DiscordBot/report_20250509124922.py create mode 100644 .history/DiscordBot/report_20250509124933.py create mode 100644 .history/DiscordBot/report_20250509131005.py create mode 100644 .history/DiscordBot/report_queue_20250509131250.py create mode 100644 .history/DiscordBot/report_queue_20250509131330.py create mode 100644 .history/DiscordBot/report_queue_20250509131820.py create mode 100644 .history/DiscordBot/report_queue_20250509132041.py create mode 100644 .history/DiscordBot/report_queue_20250509132223.py create mode 100644 .history/DiscordBot/report_queue_20250509132453.py create mode 100644 .history/DiscordBot/report_queue_20250509133058.py create mode 100644 .history/DiscordBot/report_queue_20250509133229.py create mode 100644 .history/DiscordBot/report_queue_20250509133302.py create mode 100644 .history/DiscordBot/report_queue_20250509133440.py create mode 100644 .history/DiscordBot/submitted_report_20250509124230.py create mode 100644 .history/DiscordBot/submitted_report_20250509125057.py create mode 100644 .history/DiscordBot/submitted_report_20250509131251.py create mode 100644 DiscordBot/report_queue.py create mode 100644 venv/bin/Activate.ps1 create mode 100644 venv/bin/activate create mode 100644 venv/bin/activate.csh create mode 100644 venv/bin/activate.fish create mode 100755 venv/bin/normalizer create mode 100755 venv/bin/pip create mode 100755 venv/bin/pip3 create mode 100755 venv/bin/pip3.12 create mode 120000 venv/bin/python create mode 120000 venv/bin/python3 create mode 120000 venv/bin/python3.12 create mode 100644 venv/lib/python3.12/site-packages/aiohappyeyeballs-2.6.1.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/aiohappyeyeballs-2.6.1.dist-info/LICENSE create mode 100644 venv/lib/python3.12/site-packages/aiohappyeyeballs-2.6.1.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/aiohappyeyeballs-2.6.1.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/aiohappyeyeballs-2.6.1.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/aiohappyeyeballs/__init__.py create mode 100644 venv/lib/python3.12/site-packages/aiohappyeyeballs/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohappyeyeballs/__pycache__/_staggered.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohappyeyeballs/__pycache__/impl.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohappyeyeballs/__pycache__/types.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohappyeyeballs/__pycache__/utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohappyeyeballs/_staggered.py create mode 100644 venv/lib/python3.12/site-packages/aiohappyeyeballs/impl.py create mode 100644 venv/lib/python3.12/site-packages/aiohappyeyeballs/py.typed create mode 100644 venv/lib/python3.12/site-packages/aiohappyeyeballs/types.py create mode 100644 venv/lib/python3.12/site-packages/aiohappyeyeballs/utils.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp-3.11.18.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/aiohttp-3.11.18.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/aiohttp-3.11.18.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/aiohttp-3.11.18.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/aiohttp-3.11.18.dist-info/licenses/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/aiohttp-3.11.18.dist-info/top_level.txt create mode 100644 venv/lib/python3.12/site-packages/aiohttp/.hash/_cparser.pxd.hash create mode 100644 venv/lib/python3.12/site-packages/aiohttp/.hash/_find_header.pxd.hash create mode 100644 venv/lib/python3.12/site-packages/aiohttp/.hash/_http_parser.pyx.hash create mode 100644 venv/lib/python3.12/site-packages/aiohttp/.hash/_http_writer.pyx.hash create mode 100644 venv/lib/python3.12/site-packages/aiohttp/.hash/hdrs.py.hash create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__init__.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/abc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/base_protocol.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/client.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/client_exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/client_proto.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/client_reqrep.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/client_ws.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/compression_utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/connector.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/cookiejar.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/formdata.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/hdrs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/helpers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/http.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/http_exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/http_parser.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/http_websocket.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/http_writer.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/log.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/multipart.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/payload.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/payload_streamer.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/pytest_plugin.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/resolver.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/streams.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/tcp_helpers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/test_utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/tracing.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/typedefs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/web.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_app.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_fileresponse.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_log.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_middlewares.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_protocol.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_request.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_response.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_routedef.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_runner.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_server.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_urldispatcher.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_ws.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/__pycache__/worker.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/_cparser.pxd create mode 100644 venv/lib/python3.12/site-packages/aiohttp/_find_header.pxd create mode 100644 venv/lib/python3.12/site-packages/aiohttp/_headers.pxi create mode 100755 venv/lib/python3.12/site-packages/aiohttp/_http_parser.cpython-312-darwin.so create mode 100644 venv/lib/python3.12/site-packages/aiohttp/_http_parser.pyx create mode 100755 venv/lib/python3.12/site-packages/aiohttp/_http_writer.cpython-312-darwin.so create mode 100644 venv/lib/python3.12/site-packages/aiohttp/_http_writer.pyx create mode 100644 venv/lib/python3.12/site-packages/aiohttp/_websocket/.hash/mask.pxd.hash create mode 100644 venv/lib/python3.12/site-packages/aiohttp/_websocket/.hash/mask.pyx.hash create mode 100644 venv/lib/python3.12/site-packages/aiohttp/_websocket/.hash/reader_c.pxd.hash create mode 100644 venv/lib/python3.12/site-packages/aiohttp/_websocket/__init__.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/_websocket/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/_websocket/__pycache__/helpers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/_websocket/__pycache__/models.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/_websocket/__pycache__/reader.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/_websocket/__pycache__/reader_c.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/_websocket/__pycache__/reader_py.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/_websocket/__pycache__/writer.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiohttp/_websocket/helpers.py create mode 100755 venv/lib/python3.12/site-packages/aiohttp/_websocket/mask.cpython-312-darwin.so create mode 100644 venv/lib/python3.12/site-packages/aiohttp/_websocket/mask.pxd create mode 100644 venv/lib/python3.12/site-packages/aiohttp/_websocket/mask.pyx create mode 100644 venv/lib/python3.12/site-packages/aiohttp/_websocket/models.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/_websocket/reader.py create mode 100755 venv/lib/python3.12/site-packages/aiohttp/_websocket/reader_c.cpython-312-darwin.so create mode 100644 venv/lib/python3.12/site-packages/aiohttp/_websocket/reader_c.pxd create mode 100644 venv/lib/python3.12/site-packages/aiohttp/_websocket/reader_c.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/_websocket/reader_py.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/_websocket/writer.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/abc.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/base_protocol.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/client.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/client_exceptions.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/client_proto.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/client_reqrep.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/client_ws.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/compression_utils.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/connector.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/cookiejar.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/formdata.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/hdrs.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/helpers.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/http.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/http_exceptions.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/http_parser.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/http_websocket.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/http_writer.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/log.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/multipart.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/payload.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/payload_streamer.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/py.typed create mode 100644 venv/lib/python3.12/site-packages/aiohttp/pytest_plugin.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/resolver.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/streams.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/tcp_helpers.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/test_utils.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/tracing.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/typedefs.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/web.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/web_app.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/web_exceptions.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/web_fileresponse.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/web_log.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/web_middlewares.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/web_protocol.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/web_request.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/web_response.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/web_routedef.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/web_runner.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/web_server.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/web_urldispatcher.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/web_ws.py create mode 100644 venv/lib/python3.12/site-packages/aiohttp/worker.py create mode 100644 venv/lib/python3.12/site-packages/aiosignal-1.3.2.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/aiosignal-1.3.2.dist-info/LICENSE create mode 100644 venv/lib/python3.12/site-packages/aiosignal-1.3.2.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/aiosignal-1.3.2.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/aiosignal-1.3.2.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/aiosignal-1.3.2.dist-info/top_level.txt create mode 100644 venv/lib/python3.12/site-packages/aiosignal/__init__.py create mode 100644 venv/lib/python3.12/site-packages/aiosignal/__init__.pyi create mode 100644 venv/lib/python3.12/site-packages/aiosignal/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/aiosignal/py.typed create mode 100644 venv/lib/python3.12/site-packages/attr/__init__.py create mode 100644 venv/lib/python3.12/site-packages/attr/__init__.pyi create mode 100644 venv/lib/python3.12/site-packages/attr/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/attr/__pycache__/_cmp.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/attr/__pycache__/_compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/attr/__pycache__/_config.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/attr/__pycache__/_funcs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/attr/__pycache__/_make.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/attr/__pycache__/_next_gen.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/attr/__pycache__/_version_info.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/attr/__pycache__/converters.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/attr/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/attr/__pycache__/filters.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/attr/__pycache__/setters.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/attr/__pycache__/validators.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/attr/_cmp.py create mode 100644 venv/lib/python3.12/site-packages/attr/_cmp.pyi create mode 100644 venv/lib/python3.12/site-packages/attr/_compat.py create mode 100644 venv/lib/python3.12/site-packages/attr/_config.py create mode 100644 venv/lib/python3.12/site-packages/attr/_funcs.py create mode 100644 venv/lib/python3.12/site-packages/attr/_make.py create mode 100644 venv/lib/python3.12/site-packages/attr/_next_gen.py create mode 100644 venv/lib/python3.12/site-packages/attr/_typing_compat.pyi create mode 100644 venv/lib/python3.12/site-packages/attr/_version_info.py create mode 100644 venv/lib/python3.12/site-packages/attr/_version_info.pyi create mode 100644 venv/lib/python3.12/site-packages/attr/converters.py create mode 100644 venv/lib/python3.12/site-packages/attr/converters.pyi create mode 100644 venv/lib/python3.12/site-packages/attr/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/attr/exceptions.pyi create mode 100644 venv/lib/python3.12/site-packages/attr/filters.py create mode 100644 venv/lib/python3.12/site-packages/attr/filters.pyi create mode 100644 venv/lib/python3.12/site-packages/attr/py.typed create mode 100644 venv/lib/python3.12/site-packages/attr/setters.py create mode 100644 venv/lib/python3.12/site-packages/attr/setters.pyi create mode 100644 venv/lib/python3.12/site-packages/attr/validators.py create mode 100644 venv/lib/python3.12/site-packages/attr/validators.pyi create mode 100644 venv/lib/python3.12/site-packages/attrs-25.3.0.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/attrs-25.3.0.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/attrs-25.3.0.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/attrs-25.3.0.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/attrs-25.3.0.dist-info/licenses/LICENSE create mode 100644 venv/lib/python3.12/site-packages/attrs/__init__.py create mode 100644 venv/lib/python3.12/site-packages/attrs/__init__.pyi create mode 100644 venv/lib/python3.12/site-packages/attrs/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/attrs/__pycache__/converters.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/attrs/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/attrs/__pycache__/filters.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/attrs/__pycache__/setters.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/attrs/__pycache__/validators.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/attrs/converters.py create mode 100644 venv/lib/python3.12/site-packages/attrs/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/attrs/filters.py create mode 100644 venv/lib/python3.12/site-packages/attrs/py.typed create mode 100644 venv/lib/python3.12/site-packages/attrs/setters.py create mode 100644 venv/lib/python3.12/site-packages/attrs/validators.py create mode 100644 venv/lib/python3.12/site-packages/certifi-2025.4.26.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/certifi-2025.4.26.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/certifi-2025.4.26.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/certifi-2025.4.26.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/certifi-2025.4.26.dist-info/licenses/LICENSE create mode 100644 venv/lib/python3.12/site-packages/certifi-2025.4.26.dist-info/top_level.txt create mode 100644 venv/lib/python3.12/site-packages/certifi/__init__.py create mode 100644 venv/lib/python3.12/site-packages/certifi/__main__.py create mode 100644 venv/lib/python3.12/site-packages/certifi/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/certifi/__pycache__/__main__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/certifi/__pycache__/core.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/certifi/cacert.pem create mode 100644 venv/lib/python3.12/site-packages/certifi/core.py create mode 100644 venv/lib/python3.12/site-packages/certifi/py.typed create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/entry_points.txt create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/licenses/LICENSE create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/top_level.txt create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer/__init__.py create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer/__main__.py create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/__main__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/api.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/cd.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/constant.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/legacy.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/md.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/models.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/version.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer/api.py create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer/cd.py create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer/cli/__init__.py create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer/cli/__main__.py create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer/cli/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer/cli/__pycache__/__main__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer/constant.py create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer/legacy.py create mode 100755 venv/lib/python3.12/site-packages/charset_normalizer/md.cpython-312-darwin.so create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer/md.py create mode 100755 venv/lib/python3.12/site-packages/charset_normalizer/md__mypyc.cpython-312-darwin.so create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer/models.py create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer/py.typed create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer/utils.py create mode 100644 venv/lib/python3.12/site-packages/charset_normalizer/version.py create mode 100644 venv/lib/python3.12/site-packages/discord/__init__.py create mode 100644 venv/lib/python3.12/site-packages/discord/__main__.py create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/__main__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/_types.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/abc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/activity.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/appinfo.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/asset.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/audit_logs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/automod.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/backoff.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/channel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/client.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/colour.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/components.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/context_managers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/embeds.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/emoji.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/enums.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/errors.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/file.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/flags.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/gateway.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/guild.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/http.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/integrations.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/interactions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/invite.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/member.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/mentions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/message.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/mixins.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/object.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/oggparse.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/opus.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/partial_emoji.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/permissions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/player.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/poll.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/presences.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/raw_models.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/reaction.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/role.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/scheduled_event.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/shard.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/sku.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/soundboard.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/stage_instance.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/state.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/sticker.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/subscription.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/team.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/template.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/threads.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/user.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/voice_client.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/voice_state.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/welcome_screen.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/__pycache__/widget.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/_types.py create mode 100644 venv/lib/python3.12/site-packages/discord/abc.py create mode 100644 venv/lib/python3.12/site-packages/discord/activity.py create mode 100644 venv/lib/python3.12/site-packages/discord/app_commands/__init__.py create mode 100644 venv/lib/python3.12/site-packages/discord/app_commands/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/app_commands/__pycache__/checks.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/app_commands/__pycache__/commands.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/app_commands/__pycache__/errors.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/app_commands/__pycache__/installs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/app_commands/__pycache__/models.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/app_commands/__pycache__/namespace.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/app_commands/__pycache__/transformers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/app_commands/__pycache__/translator.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/app_commands/__pycache__/tree.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/app_commands/checks.py create mode 100644 venv/lib/python3.12/site-packages/discord/app_commands/commands.py create mode 100644 venv/lib/python3.12/site-packages/discord/app_commands/errors.py create mode 100644 venv/lib/python3.12/site-packages/discord/app_commands/installs.py create mode 100644 venv/lib/python3.12/site-packages/discord/app_commands/models.py create mode 100644 venv/lib/python3.12/site-packages/discord/app_commands/namespace.py create mode 100644 venv/lib/python3.12/site-packages/discord/app_commands/transformers.py create mode 100644 venv/lib/python3.12/site-packages/discord/app_commands/translator.py create mode 100644 venv/lib/python3.12/site-packages/discord/app_commands/tree.py create mode 100644 venv/lib/python3.12/site-packages/discord/appinfo.py create mode 100644 venv/lib/python3.12/site-packages/discord/asset.py create mode 100644 venv/lib/python3.12/site-packages/discord/audit_logs.py create mode 100644 venv/lib/python3.12/site-packages/discord/automod.py create mode 100644 venv/lib/python3.12/site-packages/discord/backoff.py create mode 100644 venv/lib/python3.12/site-packages/discord/bin/libopus-0.x64.dll create mode 100644 venv/lib/python3.12/site-packages/discord/bin/libopus-0.x86.dll create mode 100644 venv/lib/python3.12/site-packages/discord/channel.py create mode 100644 venv/lib/python3.12/site-packages/discord/client.py create mode 100644 venv/lib/python3.12/site-packages/discord/colour.py create mode 100644 venv/lib/python3.12/site-packages/discord/components.py create mode 100644 venv/lib/python3.12/site-packages/discord/context_managers.py create mode 100644 venv/lib/python3.12/site-packages/discord/embeds.py create mode 100644 venv/lib/python3.12/site-packages/discord/emoji.py create mode 100644 venv/lib/python3.12/site-packages/discord/enums.py create mode 100644 venv/lib/python3.12/site-packages/discord/errors.py create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/__init__.py create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/_types.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/bot.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/cog.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/context.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/converter.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/cooldowns.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/core.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/errors.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/flags.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/help.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/hybrid.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/parameters.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/view.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/_types.py create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/bot.py create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/cog.py create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/context.py create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/converter.py create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/cooldowns.py create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/core.py create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/errors.py create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/flags.py create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/help.py create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/hybrid.py create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/parameters.py create mode 100644 venv/lib/python3.12/site-packages/discord/ext/commands/view.py create mode 100644 venv/lib/python3.12/site-packages/discord/ext/tasks/__init__.py create mode 100644 venv/lib/python3.12/site-packages/discord/ext/tasks/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/file.py create mode 100644 venv/lib/python3.12/site-packages/discord/flags.py create mode 100644 venv/lib/python3.12/site-packages/discord/gateway.py create mode 100644 venv/lib/python3.12/site-packages/discord/guild.py create mode 100644 venv/lib/python3.12/site-packages/discord/http.py create mode 100644 venv/lib/python3.12/site-packages/discord/integrations.py create mode 100644 venv/lib/python3.12/site-packages/discord/interactions.py create mode 100644 venv/lib/python3.12/site-packages/discord/invite.py create mode 100644 venv/lib/python3.12/site-packages/discord/member.py create mode 100644 venv/lib/python3.12/site-packages/discord/mentions.py create mode 100644 venv/lib/python3.12/site-packages/discord/message.py create mode 100644 venv/lib/python3.12/site-packages/discord/mixins.py create mode 100644 venv/lib/python3.12/site-packages/discord/object.py create mode 100644 venv/lib/python3.12/site-packages/discord/oggparse.py create mode 100644 venv/lib/python3.12/site-packages/discord/opus.py create mode 100644 venv/lib/python3.12/site-packages/discord/partial_emoji.py create mode 100644 venv/lib/python3.12/site-packages/discord/permissions.py create mode 100644 venv/lib/python3.12/site-packages/discord/player.py create mode 100644 venv/lib/python3.12/site-packages/discord/poll.py create mode 100644 venv/lib/python3.12/site-packages/discord/presences.py create mode 100644 venv/lib/python3.12/site-packages/discord/py.typed create mode 100644 venv/lib/python3.12/site-packages/discord/raw_models.py create mode 100644 venv/lib/python3.12/site-packages/discord/reaction.py create mode 100644 venv/lib/python3.12/site-packages/discord/role.py create mode 100644 venv/lib/python3.12/site-packages/discord/scheduled_event.py create mode 100644 venv/lib/python3.12/site-packages/discord/shard.py create mode 100644 venv/lib/python3.12/site-packages/discord/sku.py create mode 100644 venv/lib/python3.12/site-packages/discord/soundboard.py create mode 100644 venv/lib/python3.12/site-packages/discord/stage_instance.py create mode 100644 venv/lib/python3.12/site-packages/discord/state.py create mode 100644 venv/lib/python3.12/site-packages/discord/sticker.py create mode 100644 venv/lib/python3.12/site-packages/discord/subscription.py create mode 100644 venv/lib/python3.12/site-packages/discord/team.py create mode 100644 venv/lib/python3.12/site-packages/discord/template.py create mode 100644 venv/lib/python3.12/site-packages/discord/threads.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/__init__.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/activity.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/appinfo.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/audit_log.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/automod.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/channel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/command.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/components.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/embed.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/emoji.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/gateway.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/guild.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/integration.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/interactions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/invite.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/member.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/message.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/poll.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/role.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/scheduled_event.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/sku.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/snowflake.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/soundboard.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/sticker.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/subscription.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/team.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/template.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/threads.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/user.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/voice.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/webhook.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/welcome_screen.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/__pycache__/widget.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/types/activity.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/appinfo.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/audit_log.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/automod.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/channel.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/command.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/components.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/embed.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/emoji.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/gateway.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/guild.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/integration.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/interactions.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/invite.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/member.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/message.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/poll.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/role.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/scheduled_event.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/sku.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/snowflake.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/soundboard.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/sticker.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/subscription.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/team.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/template.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/threads.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/user.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/voice.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/webhook.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/welcome_screen.py create mode 100644 venv/lib/python3.12/site-packages/discord/types/widget.py create mode 100644 venv/lib/python3.12/site-packages/discord/ui/__init__.py create mode 100644 venv/lib/python3.12/site-packages/discord/ui/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/ui/__pycache__/button.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/ui/__pycache__/dynamic.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/ui/__pycache__/item.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/ui/__pycache__/modal.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/ui/__pycache__/select.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/ui/__pycache__/text_input.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/ui/__pycache__/view.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/ui/button.py create mode 100644 venv/lib/python3.12/site-packages/discord/ui/dynamic.py create mode 100644 venv/lib/python3.12/site-packages/discord/ui/item.py create mode 100644 venv/lib/python3.12/site-packages/discord/ui/modal.py create mode 100644 venv/lib/python3.12/site-packages/discord/ui/select.py create mode 100644 venv/lib/python3.12/site-packages/discord/ui/text_input.py create mode 100644 venv/lib/python3.12/site-packages/discord/ui/view.py create mode 100644 venv/lib/python3.12/site-packages/discord/user.py create mode 100644 venv/lib/python3.12/site-packages/discord/utils.py create mode 100644 venv/lib/python3.12/site-packages/discord/voice_client.py create mode 100644 venv/lib/python3.12/site-packages/discord/voice_state.py create mode 100644 venv/lib/python3.12/site-packages/discord/webhook/__init__.py create mode 100644 venv/lib/python3.12/site-packages/discord/webhook/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/webhook/__pycache__/async_.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/webhook/__pycache__/sync.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/discord/webhook/async_.py create mode 100644 venv/lib/python3.12/site-packages/discord/webhook/sync.py create mode 100644 venv/lib/python3.12/site-packages/discord/welcome_screen.py create mode 100644 venv/lib/python3.12/site-packages/discord/widget.py create mode 100644 venv/lib/python3.12/site-packages/discord_py-2.5.2.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/discord_py-2.5.2.dist-info/LICENSE create mode 100644 venv/lib/python3.12/site-packages/discord_py-2.5.2.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/discord_py-2.5.2.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/discord_py-2.5.2.dist-info/REQUESTED create mode 100644 venv/lib/python3.12/site-packages/discord_py-2.5.2.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/discord_py-2.5.2.dist-info/top_level.txt create mode 100644 venv/lib/python3.12/site-packages/frozenlist-1.6.0.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/frozenlist-1.6.0.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/frozenlist-1.6.0.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/frozenlist-1.6.0.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/frozenlist-1.6.0.dist-info/licenses/LICENSE create mode 100644 venv/lib/python3.12/site-packages/frozenlist-1.6.0.dist-info/top_level.txt create mode 100644 venv/lib/python3.12/site-packages/frozenlist/__init__.py create mode 100644 venv/lib/python3.12/site-packages/frozenlist/__init__.pyi create mode 100644 venv/lib/python3.12/site-packages/frozenlist/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/frozenlist/_frozenlist.cpp create mode 100755 venv/lib/python3.12/site-packages/frozenlist/_frozenlist.cpython-312-darwin.so create mode 100644 venv/lib/python3.12/site-packages/frozenlist/_frozenlist.pyx create mode 100644 venv/lib/python3.12/site-packages/frozenlist/py.typed create mode 100644 venv/lib/python3.12/site-packages/idna-3.10.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/idna-3.10.dist-info/LICENSE.md create mode 100644 venv/lib/python3.12/site-packages/idna-3.10.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/idna-3.10.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/idna-3.10.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/idna/__init__.py create mode 100644 venv/lib/python3.12/site-packages/idna/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/idna/__pycache__/codec.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/idna/__pycache__/compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/idna/__pycache__/core.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/idna/__pycache__/idnadata.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/idna/__pycache__/intranges.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/idna/__pycache__/package_data.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/idna/__pycache__/uts46data.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/idna/codec.py create mode 100644 venv/lib/python3.12/site-packages/idna/compat.py create mode 100644 venv/lib/python3.12/site-packages/idna/core.py create mode 100644 venv/lib/python3.12/site-packages/idna/idnadata.py create mode 100644 venv/lib/python3.12/site-packages/idna/intranges.py create mode 100644 venv/lib/python3.12/site-packages/idna/package_data.py create mode 100644 venv/lib/python3.12/site-packages/idna/py.typed create mode 100644 venv/lib/python3.12/site-packages/idna/uts46data.py create mode 100644 venv/lib/python3.12/site-packages/multidict-6.4.3.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/multidict-6.4.3.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/multidict-6.4.3.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/multidict-6.4.3.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/multidict-6.4.3.dist-info/licenses/LICENSE create mode 100644 venv/lib/python3.12/site-packages/multidict-6.4.3.dist-info/top_level.txt create mode 100644 venv/lib/python3.12/site-packages/multidict/__init__.py create mode 100644 venv/lib/python3.12/site-packages/multidict/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/multidict/__pycache__/_abc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/multidict/__pycache__/_compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/multidict/__pycache__/_multidict_py.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/multidict/_abc.py create mode 100644 venv/lib/python3.12/site-packages/multidict/_compat.py create mode 100755 venv/lib/python3.12/site-packages/multidict/_multidict.cpython-312-darwin.so create mode 100644 venv/lib/python3.12/site-packages/multidict/_multidict_py.py create mode 100644 venv/lib/python3.12/site-packages/multidict/py.typed create mode 100644 venv/lib/python3.12/site-packages/pip-24.0.dist-info/AUTHORS.txt create mode 100644 venv/lib/python3.12/site-packages/pip-24.0.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/pip-24.0.dist-info/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/pip-24.0.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/pip-24.0.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/pip-24.0.dist-info/REQUESTED create mode 100644 venv/lib/python3.12/site-packages/pip-24.0.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/pip-24.0.dist-info/entry_points.txt create mode 100644 venv/lib/python3.12/site-packages/pip-24.0.dist-info/top_level.txt create mode 100644 venv/lib/python3.12/site-packages/pip/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/__main__.py create mode 100644 venv/lib/python3.12/site-packages/pip/__pip-runner__.py create mode 100644 venv/lib/python3.12/site-packages/pip/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/__pycache__/__main__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/__pycache__/__pip-runner__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/build_env.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/cache.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/configuration.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/main.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/pyproject.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/self_outdated_check.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/wheel_builder.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/build_env.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cache.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/autocompletion.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/base_command.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/cmdoptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/command_context.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/main.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/main_parser.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/parser.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/progress_bars.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/req_command.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/spinners.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/status_codes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/autocompletion.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/base_command.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/cmdoptions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/command_context.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/main.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/main_parser.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/parser.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/progress_bars.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/req_command.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/spinners.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/status_codes.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/cache.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/check.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/completion.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/debug.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/download.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/freeze.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/hash.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/help.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/index.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/inspect.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/install.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/list.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/search.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/show.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/cache.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/check.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/completion.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/configuration.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/debug.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/download.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/freeze.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/hash.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/help.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/index.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/inspect.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/install.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/list.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/search.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/show.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/uninstall.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/configuration.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/base.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/installed.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/sdist.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/base.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/installed.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/sdist.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/collector.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/package_finder.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/sources.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/collector.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/package_finder.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/sources.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/_distutils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/_sysconfig.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/base.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/_distutils.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/_sysconfig.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/base.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/main.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/_json.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/base.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/pkg_resources.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/_json.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/base.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_dists.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_envs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/_compat.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/_dists.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/_envs.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/pkg_resources.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/candidate.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/direct_url.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/format_control.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/index.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/installation_report.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/link.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/scheme.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/search_scope.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/selection_prefs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/target_python.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/candidate.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/direct_url.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/format_control.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/index.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/installation_report.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/link.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/scheme.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/search_scope.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/selection_prefs.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/target_python.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/auth.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/cache.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/download.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/lazy_wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/session.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/xmlrpc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/auth.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/cache.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/download.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/lazy_wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/session.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/utils.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/xmlrpc.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/check.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/build_tracker.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata_editable.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel_editable.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/build_tracker.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/metadata.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/metadata_editable.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/metadata_legacy.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/wheel_editable.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/wheel_legacy.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/check.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/freeze.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/install/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/editable_legacy.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/install/editable_legacy.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/install/wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/prepare.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/pyproject.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/constructors.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_file.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_install.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_set.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_uninstall.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/constructors.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/req_file.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/req_install.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/req_set.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/req_uninstall.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/__pycache__/base.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/base.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/legacy/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/legacy/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/legacy/__pycache__/resolver.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/legacy/resolver.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/base.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/found_candidates.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/reporter.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/base.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/candidates.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/factory.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/provider.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/reporter.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/requirements.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/resolver.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/self_outdated_check.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/_jaraco_text.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/_log.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/appdirs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/compatibility_tags.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/datetime.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/deprecation.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/direct_url_helpers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/egg_link.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/encoding.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/entrypoints.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/filesystem.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/filetypes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/glibc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/logging.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/misc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/models.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/subprocess.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/temp_dir.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/unpacking.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/urls.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/virtualenv.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/_jaraco_text.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/_log.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/appdirs.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/compat.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/compatibility_tags.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/datetime.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/deprecation.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/direct_url_helpers.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/egg_link.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/encoding.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/entrypoints.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/filesystem.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/filetypes.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/glibc.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/hashes.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/logging.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/misc.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/models.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/packaging.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/setuptools_build.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/subprocess.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/temp_dir.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/unpacking.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/urls.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/virtualenv.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/bazaar.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/git.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/mercurial.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/subversion.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/versioncontrol.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/bazaar.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/git.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/mercurial.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/subversion.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/versioncontrol.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/wheel_builder.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/__pycache__/six.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/__pycache__/typing_extensions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/adapter.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/cache.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/controller.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/serialize.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/_cmd.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/adapter.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/cache.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/file_cache.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/redis_cache.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/controller.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/filewrapper.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/heuristics.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/py.typed create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/serialize.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/wrapper.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/certifi/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/certifi/__main__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/certifi/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/certifi/__pycache__/__main__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/certifi/__pycache__/core.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/certifi/cacert.pem create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/certifi/core.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/certifi/py.typed create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/big5freq.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/big5prober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/chardistribution.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/charsetgroupprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/charsetprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/codingstatemachine.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/codingstatemachinedict.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/cp949prober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/enums.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/escprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/escsm.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/eucjpprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/euckrfreq.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/euckrprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/euctwfreq.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/euctwprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/gb2312freq.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/gb2312prober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/hebrewprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/jisfreq.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/johabfreq.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/johabprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/jpcntx.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/langbulgarianmodel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/langgreekmodel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/langhebrewmodel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/langhungarianmodel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/langrussianmodel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/langthaimodel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/langturkishmodel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/latin1prober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/macromanprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/mbcharsetprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/mbcsgroupprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/mbcssm.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/resultdict.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/sbcharsetprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/sbcsgroupprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/sjisprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/universaldetector.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/utf1632prober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/utf8prober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/version.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/big5freq.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/big5prober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/chardistribution.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/charsetgroupprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/charsetprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/cli/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/cli/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/cli/__pycache__/chardetect.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/cli/chardetect.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/codingstatemachine.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/codingstatemachinedict.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/cp949prober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/enums.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/escprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/escsm.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/eucjpprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/euckrfreq.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/euckrprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/euctwfreq.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/euctwprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/gb2312freq.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/gb2312prober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/hebrewprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/jisfreq.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/johabfreq.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/johabprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/jpcntx.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/langbulgarianmodel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/langgreekmodel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/langhebrewmodel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/langhungarianmodel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/langrussianmodel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/langthaimodel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/langturkishmodel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/latin1prober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/macromanprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/mbcharsetprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/mbcsgroupprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/mbcssm.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/metadata/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/metadata/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/metadata/__pycache__/languages.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/metadata/languages.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/py.typed create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/resultdict.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/sbcharsetprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/sbcsgroupprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/sjisprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/universaldetector.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/utf1632prober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/utf8prober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/version.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/__pycache__/ansi.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/__pycache__/ansitowin32.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/__pycache__/initialise.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/__pycache__/win32.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/__pycache__/winterm.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/ansi.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/ansitowin32.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/initialise.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/__pycache__/ansi_test.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/__pycache__/ansitowin32_test.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/__pycache__/initialise_test.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/__pycache__/isatty_test.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/__pycache__/utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/__pycache__/winterm_test.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/ansi_test.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/ansitowin32_test.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/initialise_test.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/isatty_test.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/utils.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/winterm_test.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/win32.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/winterm.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/database.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/index.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/locators.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/manifest.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/markers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/metadata.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/resources.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/scripts.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/util.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/version.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/compat.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/database.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/index.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/locators.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/manifest.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/markers.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/metadata.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/resources.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/scripts.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/t32.exe create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/t64-arm.exe create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/t64.exe create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/util.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/version.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/w32.exe create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/w64-arm.exe create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/w64.exe create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distro/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distro/__main__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distro/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distro/__pycache__/__main__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distro/__pycache__/distro.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distro/distro.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distro/py.typed create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/codec.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/core.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/idnadata.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/intranges.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/package_data.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/uts46data.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/codec.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/compat.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/core.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/idnadata.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/intranges.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/package_data.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/py.typed create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/uts46data.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/ext.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/fallback.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/msgpack/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/msgpack/ext.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/msgpack/fallback.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__about__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/__about__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_manylinux.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_musllinux.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_structures.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/markers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/requirements.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/specifiers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/tags.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/version.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/_manylinux.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/_musllinux.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/_structures.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/markers.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/py.typed create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/requirements.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/specifiers.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/tags.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/utils.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/version.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pkg_resources/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pkg_resources/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__main__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/__main__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/android.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/api.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/macos.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/unix.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/version.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/windows.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/android.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/api.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/macos.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/py.typed create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/unix.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/version.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/windows.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__main__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/__main__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/cmdline.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/console.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/filter.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/formatter.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/lexer.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/modeline.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/plugin.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/regexopt.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/scanner.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/sphinxext.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/style.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/token.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/unistring.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/util.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/cmdline.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/console.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/filter.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/filters/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/filters/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatter.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/_mapping.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/bbcode.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/groff.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/html.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/img.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/irc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/latex.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/other.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/pangomarkup.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/rtf.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/svg.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal256.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/_mapping.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/bbcode.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/groff.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/html.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/img.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/irc.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/latex.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/other.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/pangomarkup.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/rtf.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/svg.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/terminal.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/terminal256.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexer.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/_mapping.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/python.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/_mapping.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/python.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/modeline.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/plugin.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/regexopt.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/scanner.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/sphinxext.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/style.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/styles/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/styles/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/token.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/unistring.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/util.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/actions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/common.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/core.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/helpers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/results.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/testing.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/unicode.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/util.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/actions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/common.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/core.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/diagram/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/diagram/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/helpers.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/py.typed create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/results.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/testing.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/unicode.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/util.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_impl.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_compat.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_impl.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/_in_process.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/__version__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/_internal_utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/adapters.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/api.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/auth.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/certs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/cookies.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/help.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/hooks.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/models.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/packages.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/sessions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/status_codes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/structures.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__version__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/_internal_utils.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/adapters.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/api.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/auth.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/certs.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/compat.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/cookies.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/help.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/hooks.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/models.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/packages.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/sessions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/status_codes.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/structures.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/utils.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/providers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/reporters.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/resolvers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/structs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/__pycache__/collections_abc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/collections_abc.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/providers.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/py.typed create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/reporters.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/resolvers.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/structs.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__main__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/__main__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_cell_widths.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_emoji_codes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_emoji_replace.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_export_format.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_extension.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_fileno.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_inspect.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_log_render.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_loop.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_null_file.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_palettes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_pick.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_ratio.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_spinners.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_stack.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_timer.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_win32_console.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_windows.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_windows_renderer.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_wrap.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/abc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/align.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/ansi.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/bar.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/box.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/cells.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/color.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/color_triplet.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/columns.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/console.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/constrain.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/containers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/control.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/default_styles.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/diagnose.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/emoji.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/errors.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/file_proxy.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/filesize.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/highlighter.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/json.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/jupyter.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/layout.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/live.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/live_render.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/logging.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/markup.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/measure.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/padding.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/pager.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/palette.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/panel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/pretty.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/progress.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/progress_bar.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/prompt.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/protocol.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/region.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/repr.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/rule.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/scope.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/screen.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/segment.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/spinner.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/status.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/style.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/styled.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/syntax.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/table.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/terminal_theme.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/text.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/theme.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/themes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/traceback.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/tree.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_cell_widths.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_emoji_codes.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_emoji_replace.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_export_format.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_extension.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_fileno.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_inspect.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_log_render.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_loop.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_null_file.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_palettes.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_pick.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_ratio.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_spinners.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_stack.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_timer.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_win32_console.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_windows.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_windows_renderer.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_wrap.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/abc.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/align.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/ansi.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/bar.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/box.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/cells.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/color.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/color_triplet.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/columns.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/console.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/constrain.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/containers.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/control.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/default_styles.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/diagnose.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/emoji.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/errors.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/file_proxy.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/filesize.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/highlighter.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/json.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/jupyter.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/layout.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/live.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/live_render.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/logging.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/markup.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/measure.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/padding.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/pager.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/palette.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/panel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/pretty.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/progress.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/progress_bar.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/prompt.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/protocol.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/py.typed create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/region.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/repr.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/rule.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/scope.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/screen.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/segment.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/spinner.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/status.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/style.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/styled.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/syntax.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/table.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/terminal_theme.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/text.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/theme.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/themes.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/traceback.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/tree.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/six.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/_asyncio.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/_utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/after.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/before.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/before_sleep.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/nap.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/retry.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/stop.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/tornadoweb.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/wait.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/_asyncio.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/_utils.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/after.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/before.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/before_sleep.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/nap.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/py.typed create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/retry.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/stop.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/tornadoweb.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/wait.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/_parser.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/_re.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/_types.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli/_parser.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli/_re.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli/_types.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli/py.typed create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/truststore/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_api.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_macos.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_openssl.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_ssl_constants.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_windows.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/truststore/_api.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/truststore/_macos.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/truststore/_openssl.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/truststore/_ssl_constants.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/truststore/_windows.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/truststore/py.typed create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/typing_extensions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/_collections.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/_version.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/connection.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/connectionpool.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/fields.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/filepost.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/poolmanager.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/request.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/response.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/_collections.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/_version.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/connection.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/connectionpool.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_appengine_environ.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/appengine.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/ntlmpool.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/securetransport.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/socks.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/fields.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/filepost.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/__pycache__/six.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/weakref_finalize.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/weakref_finalize.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/six.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/poolmanager.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/request.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/response.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/connection.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/proxy.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/queue.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/request.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/response.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/retry.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/ssltransport.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/timeout.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/url.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/wait.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/connection.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/proxy.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/queue.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/request.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/response.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/retry.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/ssl_.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/ssl_match_hostname.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/ssltransport.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/timeout.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/url.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/wait.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/vendor.txt create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/__pycache__/labels.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/__pycache__/mklabels.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/__pycache__/tests.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/__pycache__/x_user_defined.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/labels.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/mklabels.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/tests.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/x_user_defined.py create mode 100644 venv/lib/python3.12/site-packages/pip/py.typed create mode 100644 venv/lib/python3.12/site-packages/propcache-0.3.1.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/propcache-0.3.1.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/propcache-0.3.1.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/propcache-0.3.1.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/propcache-0.3.1.dist-info/licenses/LICENSE create mode 100644 venv/lib/python3.12/site-packages/propcache-0.3.1.dist-info/licenses/NOTICE create mode 100644 venv/lib/python3.12/site-packages/propcache-0.3.1.dist-info/top_level.txt create mode 100644 venv/lib/python3.12/site-packages/propcache/__init__.py create mode 100644 venv/lib/python3.12/site-packages/propcache/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/propcache/__pycache__/_helpers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/propcache/__pycache__/_helpers_py.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/propcache/__pycache__/api.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/propcache/_helpers.py create mode 100755 venv/lib/python3.12/site-packages/propcache/_helpers_c.cpython-312-darwin.so create mode 100644 venv/lib/python3.12/site-packages/propcache/_helpers_c.pyx create mode 100644 venv/lib/python3.12/site-packages/propcache/_helpers_py.py create mode 100644 venv/lib/python3.12/site-packages/propcache/api.py create mode 100644 venv/lib/python3.12/site-packages/propcache/py.typed create mode 100644 venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/LICENSE create mode 100644 venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/REQUESTED create mode 100644 venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/top_level.txt create mode 100644 venv/lib/python3.12/site-packages/requests/__init__.py create mode 100644 venv/lib/python3.12/site-packages/requests/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/requests/__pycache__/__version__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/requests/__pycache__/_internal_utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/requests/__pycache__/adapters.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/requests/__pycache__/api.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/requests/__pycache__/auth.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/requests/__pycache__/certs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/requests/__pycache__/compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/requests/__pycache__/cookies.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/requests/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/requests/__pycache__/help.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/requests/__pycache__/hooks.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/requests/__pycache__/models.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/requests/__pycache__/packages.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/requests/__pycache__/sessions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/requests/__pycache__/status_codes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/requests/__pycache__/structures.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/requests/__pycache__/utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/requests/__version__.py create mode 100644 venv/lib/python3.12/site-packages/requests/_internal_utils.py create mode 100644 venv/lib/python3.12/site-packages/requests/adapters.py create mode 100644 venv/lib/python3.12/site-packages/requests/api.py create mode 100644 venv/lib/python3.12/site-packages/requests/auth.py create mode 100644 venv/lib/python3.12/site-packages/requests/certs.py create mode 100644 venv/lib/python3.12/site-packages/requests/compat.py create mode 100644 venv/lib/python3.12/site-packages/requests/cookies.py create mode 100644 venv/lib/python3.12/site-packages/requests/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/requests/help.py create mode 100644 venv/lib/python3.12/site-packages/requests/hooks.py create mode 100644 venv/lib/python3.12/site-packages/requests/models.py create mode 100644 venv/lib/python3.12/site-packages/requests/packages.py create mode 100644 venv/lib/python3.12/site-packages/requests/sessions.py create mode 100644 venv/lib/python3.12/site-packages/requests/status_codes.py create mode 100644 venv/lib/python3.12/site-packages/requests/structures.py create mode 100644 venv/lib/python3.12/site-packages/requests/utils.py create mode 100644 venv/lib/python3.12/site-packages/urllib3-2.4.0.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/urllib3-2.4.0.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/urllib3-2.4.0.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/urllib3-2.4.0.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/urllib3-2.4.0.dist-info/licenses/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/urllib3/__init__.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/__pycache__/_base_connection.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/__pycache__/_collections.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/__pycache__/_request_methods.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/__pycache__/_version.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/__pycache__/connection.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/__pycache__/connectionpool.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/__pycache__/fields.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/__pycache__/filepost.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/__pycache__/poolmanager.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/__pycache__/response.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/_base_connection.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/_collections.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/_request_methods.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/_version.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/connection.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/connectionpool.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/contrib/__init__.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/contrib/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/contrib/__pycache__/socks.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/__init__.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/__pycache__/connection.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/__pycache__/fetch.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/__pycache__/request.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/__pycache__/response.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/connection.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/emscripten_fetch_worker.js create mode 100644 venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/fetch.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/request.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/response.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/contrib/pyopenssl.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/contrib/socks.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/fields.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/filepost.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/http2/__init__.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/http2/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/http2/__pycache__/connection.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/http2/__pycache__/probe.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/http2/connection.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/http2/probe.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/poolmanager.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/py.typed create mode 100644 venv/lib/python3.12/site-packages/urllib3/response.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/util/__init__.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/util/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/util/__pycache__/connection.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/util/__pycache__/proxy.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/util/__pycache__/request.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/util/__pycache__/response.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/util/__pycache__/retry.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/util/__pycache__/ssl_.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/util/__pycache__/ssltransport.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/util/__pycache__/timeout.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/util/__pycache__/url.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/util/__pycache__/util.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/util/__pycache__/wait.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/urllib3/util/connection.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/util/proxy.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/util/request.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/util/response.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/util/retry.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/util/ssl_.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/util/ssl_match_hostname.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/util/ssltransport.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/util/timeout.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/util/url.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/util/util.py create mode 100644 venv/lib/python3.12/site-packages/urllib3/util/wait.py create mode 100644 venv/lib/python3.12/site-packages/yarl-1.20.0.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/yarl-1.20.0.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/yarl-1.20.0.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/yarl-1.20.0.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/yarl-1.20.0.dist-info/licenses/LICENSE create mode 100644 venv/lib/python3.12/site-packages/yarl-1.20.0.dist-info/licenses/NOTICE create mode 100644 venv/lib/python3.12/site-packages/yarl-1.20.0.dist-info/top_level.txt create mode 100644 venv/lib/python3.12/site-packages/yarl/__init__.py create mode 100644 venv/lib/python3.12/site-packages/yarl/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/yarl/__pycache__/_parse.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/yarl/__pycache__/_path.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/yarl/__pycache__/_query.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/yarl/__pycache__/_quoters.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/yarl/__pycache__/_quoting.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/yarl/__pycache__/_quoting_py.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/yarl/__pycache__/_url.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/yarl/_parse.py create mode 100644 venv/lib/python3.12/site-packages/yarl/_path.py create mode 100644 venv/lib/python3.12/site-packages/yarl/_query.py create mode 100644 venv/lib/python3.12/site-packages/yarl/_quoters.py create mode 100644 venv/lib/python3.12/site-packages/yarl/_quoting.py create mode 100755 venv/lib/python3.12/site-packages/yarl/_quoting_c.cpython-312-darwin.so create mode 100644 venv/lib/python3.12/site-packages/yarl/_quoting_c.pyx create mode 100644 venv/lib/python3.12/site-packages/yarl/_quoting_py.py create mode 100644 venv/lib/python3.12/site-packages/yarl/_url.py create mode 100644 venv/lib/python3.12/site-packages/yarl/py.typed create mode 100644 venv/pyvenv.cfg diff --git a/.history/DiscordBot/bot_20250508222458.py b/.history/DiscordBot/bot_20250508222458.py new file mode 100644 index 00000000..7a3b8d79 --- /dev/null +++ b/.history/DiscordBot/bot_20250508222458.py @@ -0,0 +1,235 @@ +# bot.py +import discord +from discord.ext import commands +import os +import json +import logging +import re +import requests +from report import Report +import pdb + +# Set up logging to the console +logger = logging.getLogger('discord') +logger.setLevel(logging.DEBUG) +handler = logging.FileHandler(filename='discord.log', encoding='utf-8', mode='w') +handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s')) +logger.addHandler(handler) + +# There should be a file called 'tokens.json' inside the same folder as this file +token_path = 'tokens.json' +if not os.path.isfile(token_path): + raise Exception(f"{token_path} not found!") +with open(token_path) as f: + # If you get an error here, it means your token is formatted incorrectly. Did you put it in quotes? + tokens = json.load(f) + discord_token = tokens['discord'] + + +MOD_TODO_START = "---------------------------\nTODO" + + +class ModBot(discord.Client): + def __init__(self): + intents = discord.Intents.default() + intents.message_content = True + super().__init__(command_prefix='.', intents=intents) + self.group_num = None + self.mod_channels = {} # Map from guild to the mod channel id for that guild + self.reports = {} # Map from user IDs to the state of their report + + async def on_ready(self): + print(f'{self.user.name} has connected to Discord! It is these guilds:') + for guild in self.guilds: + print(f' - {guild.name}') + print('Press Ctrl-C to quit.') + + # Parse the group number out of the bot's name + match = re.search('[gG]roup (\d+) [bB]ot', self.user.name) + if match: + self.group_num = match.group(1) + else: + raise Exception("Group number not found in bot's name. Name format should be \"Group # Bot\".") + + # Find the mod channel in each guild that this bot should report to + for guild in self.guilds: + for channel in guild.text_channels: + if channel.name == f'group-{self.group_num}-mod': + self.mod_channels[guild.id] = channel + + + async def on_message(self, message): + ''' + This function is called whenever a message is sent in a channel that the bot can see (including DMs). + Currently the bot is configured to only handle messages that are sent over DMs or in your group's "group-#" channel. + ''' + # Ignore messages from the bot + if message.author.id == self.user.id: + return + + # Check if this message was sent in a server ("guild") or if it's a DM + if message.guild: + await self.handle_channel_message(message) + else: + await self.handle_dm(message) + + async def handle_dm(self, message): + # Handle a help message + if message.content == Report.HELP_KEYWORD: + reply = "Use the `report` command to begin the reporting process.\n" + reply += "Use the `cancel` command to cancel the report process.\n" + await message.channel.send(reply) + return + + author_id = message.author.id + responses = [] + + # Only respond to messages if they're part of a reporting flow + if author_id not in self.reports and not message.content.startswith(Report.START_KEYWORD): + return + + # If we don't currently have an active report for this user, add one + if author_id not in self.reports: + self.reports[author_id] = Report(self) + + # If we are starting a report + responses = await self.reports[author_id].handle_message(message) + + ## report.py updates state, and below, we route our response based on that state + + if self.reports[author_id].is_awaiting_message(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_reason(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_political_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_healthl_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_harmful_content_status(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_filter_action(): + for r in responses: + await message.channel.send(r) + + # if self.reports[author_id].harm_identified(): + # reply = responses[0] + # harm = responses[1] + # if harm: + # # TODO escalate (or simulate it) + # print("Escalating report") + # await message.channel.send(reply) + + # if self.reports[author_id].block_step(): + # reply = responses[0] + # block = responses[1] + # if block: + # # TODO block user (or simulate it) + # print("Blocking user") + # await message.channel.send(reply) + + # If the report is complete or cancelled, remove it from our map + if self.reports[author_id].is_report_complete(): + + reported_author = self.reports[author_id].get_reported_author() + reported_content = self.reports[author_id].get_reported_content() + report_type = self.reports[author_id].get_report_type() + disinfo_type = self.reports[author_id].get_disinfo_type() + disinfo_subtype = self.reports[author_id].get_disinfo_subtype() + + for r in responses: + await message.channel.send(r) + + # Put the report in the mod channel + mod_channel = self.mod_channels[self.reports[author_id].get_message_guild_id()] + # todo are we worried about code injection via author name or content? + report_info_msg = MOD_TODO_START + " User " + message.author.name + " reported user " + str(reported_author) + "'s message.\n" + report_info_msg += "Here is the message: \n```" + str(reported_content) + "\n```" + report_info_msg += "Category: " + str(report_type) + " > " + str(disinfo_type) + " > " + str(disinfo_subtype) + "\n" + report_info_msg += "react to this message in order to moderate it\n" + + await mod_channel.send(report_info_msg) + + # remove + self.reports.pop(author_id) + + # ------ starter code relevant to MILESTONE 3: -------------- + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------- + + + async def handle_channel_message(self, message): + + if not message.channel.name == f'group-{self.group_num}': + return + + # ----- teddy: commented out to reduce clutter for milestone 2 since we are not doing auto flagging ------------ + # # Forward the message to the mod channel + # mod_channel = self.mod_channels[message.guild.id] + # await mod_channel.send(f'Forwarded message:\n{message.author.name}: "{message.content}"') + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------------------------------------------------------ + return + + async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): + # see https://discordpy.readthedocs.io/en/latest/api.html?highlight=on_reaction_add#discord.RawReactionActionEvent + mod_channel = self.mod_channels[message.guild.id] + + message = await mod_channel.fetch_message(payload.message_id) + + # Ignore messages that are not the bot's moderator to-do messages + if message.author.id != self.user.id or (not message.content.startswith(MOD_TODO_START)): + return + + # TODO IMPLEMENT MODERATOR FLOW HERE + + return + + def eval_text(self, message): + '''' + TODO: Once you know how you want to evaluate messages in your channel, + insert your code here! This will primarily be used in Milestone 3. + ''' + return message + + + def code_format(self, text): + '''' + TODO: Once you know how you want to show that a message has been + evaluated, insert your code here for formatting the string to be + shown in the mod channel. + ''' + #teddy: not sure if we need this function + return "Evaluated: '" + text+ "'" + + # def process_response(self, responses): + + # reply = responses["reply"] + # if not isinstance(reply, str): # just in case i forget brackets in report.py + # reply = [reply] + # del responses["reply"] + + # for key, value in responses.items(): # go through data (not including reply) + # if key not in self.current_report: # don't allow overwriting + # self.current_report[key] = value + + # return reply + + +client = ModBot() +client.run(discord_token) \ No newline at end of file diff --git a/.history/DiscordBot/bot_20250509124520.py b/.history/DiscordBot/bot_20250509124520.py new file mode 100644 index 00000000..e8ebdafb --- /dev/null +++ b/.history/DiscordBot/bot_20250509124520.py @@ -0,0 +1,237 @@ +# bot.py +import discord +from discord.ext import commands +import os +import json +import logging +import re +import requests +from report import Report +import pdb + +# Set up logging to the console +logger = logging.getLogger('discord') +logger.setLevel(logging.DEBUG) +handler = logging.FileHandler(filename='discord.log', encoding='utf-8', mode='w') +handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s')) +logger.addHandler(handler) + +# There should be a file called 'tokens.json' inside the same folder as this file +token_path = 'tokens.json' +if not os.path.isfile(token_path): + raise Exception(f"{token_path} not found!") +with open(token_path) as f: + # If you get an error here, it means your token is formatted incorrectly. Did you put it in quotes? + tokens = json.load(f) + discord_token = tokens['discord'] + + +MOD_TODO_START = "---------------------------\nTODO" + + +class ModBot(discord.Client): + def __init__(self): + intents = discord.Intents.default() + intents.message_content = True + super().__init__(command_prefix='.', intents=intents) + self.group_num = None + self.mod_channels = {} # Map from guild to the mod channel id for that guild + self.reports = {} # Map from user IDs to the state of their report + self.report_queue = [] + + async def on_ready(self): + print(f'{self.user.name} has connected to Discord! It is these guilds:') + for guild in self.guilds: + print(f' - {guild.name}') + print('Press Ctrl-C to quit.') + + # Parse the group number out of the bot's name + match = re.search('[gG]roup (\d+) [bB]ot', self.user.name) + if match: + self.group_num = match.group(1) + else: + raise Exception("Group number not found in bot's name. Name format should be \"Group # Bot\".") + + # Find the mod channel in each guild that this bot should report to + for guild in self.guilds: + for channel in guild.text_channels: + if channel.name == f'group-{self.group_num}-mod': + self.mod_channels[guild.id] = channel + + + async def on_message(self, message): + ''' + This function is called whenever a message is sent in a channel that the bot can see (including DMs). + Currently the bot is configured to only handle messages that are sent over DMs or in your group's "group-#" channel. + ''' + # Ignore messages from the bot + if message.author.id == self.user.id: + return + + # Check if this message was sent in a server ("guild") or if it's a DM + if message.guild: + await self.handle_channel_message(message) + else: + await self.handle_dm(message) + + async def handle_dm(self, message): + # Handle a help message + if message.content == Report.HELP_KEYWORD: + reply = "Use the `report` command to begin the reporting process.\n" + reply += "Use the `cancel` command to cancel the report process.\n" + await message.channel.send(reply) + return + + author_id = message.author.id + responses = [] + + # Only respond to messages if they're part of a reporting flow + if author_id not in self.reports and not message.content.startswith(Report.START_KEYWORD): + return + + # If we don't currently have an active report for this user, add one + if author_id not in self.reports: + self.reports[author_id] = Report(self) + + # If we are starting a report + responses = await self.reports[author_id].handle_message(message) + + ## report.py updates state, and below, we route our response based on that state + + if self.reports[author_id].is_awaiting_message(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_reason(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_political_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_healthl_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_harmful_content_status(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_filter_action(): + for r in responses: + await message.channel.send(r) + + # if self.reports[author_id].harm_identified(): + # reply = responses[0] + # harm = responses[1] + # if harm: + # # TODO escalate (or simulate it) + # print("Escalating report") + # await message.channel.send(reply) + + # if self.reports[author_id].block_step(): + # reply = responses[0] + # block = responses[1] + # if block: + # # TODO block user (or simulate it) + # print("Blocking user") + # await message.channel.send(reply) + + # If the report is complete or cancelled, remove it from our map + if self.reports[author_id].is_report_complete(): + + reported_author = self.reports[author_id].get_reported_author() + reported_content = self.reports[author_id].get_reported_content() + report_type = self.reports[author_id].get_report_type() + disinfo_type = self.reports[author_id].get_disinfo_type() + disinfo_subtype = self.reports[author_id].get_disinfo_subtype() + imminent_harm = self.reports[author_id].get_harmful() + + for r in responses: + await message.channel.send(r) + + # Put the report in the mod channel + mod_channel = self.mod_channels[self.reports[author_id].get_message_guild_id()] + # todo are we worried about code injection via author name or content? + report_info_msg = MOD_TODO_START + " User " + message.author.name + " reported user " + str(reported_author) + "'s message.\n" + report_info_msg += "Here is the message: \n```" + str(reported_content) + "\n```" + report_info_msg += "Category: " + str(report_type) + " > " + str(disinfo_type) + " > " + str(disinfo_subtype) + "\n" + self.report_queue.append(SubmittedReport()) + + await mod_channel.send(report_info_msg) + + # remove + self.reports.pop(author_id) + + # ------ starter code relevant to MILESTONE 3: -------------- + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------- + + + async def handle_channel_message(self, message): + + if not message.channel.name == f'group-{self.group_num}': + return + + # ----- teddy: commented out to reduce clutter for milestone 2 since we are not doing auto flagging ------------ + # # Forward the message to the mod channel + # mod_channel = self.mod_channels[message.guild.id] + # await mod_channel.send(f'Forwarded message:\n{message.author.name}: "{message.content}"') + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------------------------------------------------------ + return + + async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): + # see https://discordpy.readthedocs.io/en/latest/api.html?highlight=on_reaction_add#discord.RawReactionActionEvent + mod_channel = self.mod_channels[message.guild.id] + + message = await mod_channel.fetch_message(payload.message_id) + + # Ignore messages that are not the bot's moderator to-do messages + if message.author.id != self.user.id or (not message.content.startswith(MOD_TODO_START)): + return + + # TODO IMPLEMENT MODERATOR FLOW HERE + + return + + def eval_text(self, message): + '''' + TODO: Once you know how you want to evaluate messages in your channel, + insert your code here! This will primarily be used in Milestone 3. + ''' + return message + + + def code_format(self, text): + '''' + TODO: Once you know how you want to show that a message has been + evaluated, insert your code here for formatting the string to be + shown in the mod channel. + ''' + #teddy: not sure if we need this function + return "Evaluated: '" + text+ "'" + + # def process_response(self, responses): + + # reply = responses["reply"] + # if not isinstance(reply, str): # just in case i forget brackets in report.py + # reply = [reply] + # del responses["reply"] + + # for key, value in responses.items(): # go through data (not including reply) + # if key not in self.current_report: # don't allow overwriting + # self.current_report[key] = value + + # return reply + + +client = ModBot() +client.run(discord_token) \ No newline at end of file diff --git a/.history/DiscordBot/bot_20250509125037.py b/.history/DiscordBot/bot_20250509125037.py new file mode 100644 index 00000000..6b73c0e7 --- /dev/null +++ b/.history/DiscordBot/bot_20250509125037.py @@ -0,0 +1,238 @@ +# bot.py +import discord +from discord.ext import commands +import os +import json +import logging +import re +import requests +from report import Report +from submitted_report import SubmittedReport +import pdb + +# Set up logging to the console +logger = logging.getLogger('discord') +logger.setLevel(logging.DEBUG) +handler = logging.FileHandler(filename='discord.log', encoding='utf-8', mode='w') +handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s')) +logger.addHandler(handler) + +# There should be a file called 'tokens.json' inside the same folder as this file +token_path = 'tokens.json' +if not os.path.isfile(token_path): + raise Exception(f"{token_path} not found!") +with open(token_path) as f: + # If you get an error here, it means your token is formatted incorrectly. Did you put it in quotes? + tokens = json.load(f) + discord_token = tokens['discord'] + + +MOD_TODO_START = "---------------------------\nTODO" + + +class ModBot(discord.Client): + def __init__(self): + intents = discord.Intents.default() + intents.message_content = True + super().__init__(command_prefix='.', intents=intents) + self.group_num = None + self.mod_channels = {} # Map from guild to the mod channel id for that guild + self.reports = {} # Map from user IDs to the state of their report + self.report_queue = [] + + async def on_ready(self): + print(f'{self.user.name} has connected to Discord! It is these guilds:') + for guild in self.guilds: + print(f' - {guild.name}') + print('Press Ctrl-C to quit.') + + # Parse the group number out of the bot's name + match = re.search('[gG]roup (\d+) [bB]ot', self.user.name) + if match: + self.group_num = match.group(1) + else: + raise Exception("Group number not found in bot's name. Name format should be \"Group # Bot\".") + + # Find the mod channel in each guild that this bot should report to + for guild in self.guilds: + for channel in guild.text_channels: + if channel.name == f'group-{self.group_num}-mod': + self.mod_channels[guild.id] = channel + + + async def on_message(self, message): + ''' + This function is called whenever a message is sent in a channel that the bot can see (including DMs). + Currently the bot is configured to only handle messages that are sent over DMs or in your group's "group-#" channel. + ''' + # Ignore messages from the bot + if message.author.id == self.user.id: + return + + # Check if this message was sent in a server ("guild") or if it's a DM + if message.guild: + await self.handle_channel_message(message) + else: + await self.handle_dm(message) + + async def handle_dm(self, message): + # Handle a help message + if message.content == Report.HELP_KEYWORD: + reply = "Use the `report` command to begin the reporting process.\n" + reply += "Use the `cancel` command to cancel the report process.\n" + await message.channel.send(reply) + return + + author_id = message.author.id + responses = [] + + # Only respond to messages if they're part of a reporting flow + if author_id not in self.reports and not message.content.startswith(Report.START_KEYWORD): + return + + # If we don't currently have an active report for this user, add one + if author_id not in self.reports: + self.reports[author_id] = Report(self) + + # If we are starting a report + responses = await self.reports[author_id].handle_message(message) + + ## report.py updates state, and below, we route our response based on that state + + if self.reports[author_id].is_awaiting_message(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_reason(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_political_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_healthl_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_harmful_content_status(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_filter_action(): + for r in responses: + await message.channel.send(r) + + # if self.reports[author_id].harm_identified(): + # reply = responses[0] + # harm = responses[1] + # if harm: + # # TODO escalate (or simulate it) + # print("Escalating report") + # await message.channel.send(reply) + + # if self.reports[author_id].block_step(): + # reply = responses[0] + # block = responses[1] + # if block: + # # TODO block user (or simulate it) + # print("Blocking user") + # await message.channel.send(reply) + + # If the report is complete or cancelled, remove it from our map + if self.reports[author_id].is_report_complete(): + + reported_author = self.reports[author_id].get_reported_author() + reported_content = self.reports[author_id].get_reported_content() + report_type = self.reports[author_id].get_report_type() + disinfo_type = self.reports[author_id].get_disinfo_type() + disinfo_subtype = self.reports[author_id].get_disinfo_subtype() + imminent = self.reports[author_id].get_imminent() + + for r in responses: + await message.channel.send(r) + + # Put the report in the mod channel + mod_channel = self.mod_channels[self.reports[author_id].get_message_guild_id()] + # todo are we worried about code injection via author name or content? + report_info_msg = MOD_TODO_START + " User " + message.author.name + " reported user " + str(reported_author) + "'s message.\n" + report_info_msg += "Here is the message: \n```" + str(reported_content) + "\n```" + report_info_msg += "Category: " + str(report_type) + " > " + str(disinfo_type) + " > " + str(disinfo_subtype) + "\n" + self.report_queue.append(SubmittedReport()) + + await mod_channel.send(report_info_msg) + + # remove + self.reports.pop(author_id) + + # ------ starter code relevant to MILESTONE 3: -------------- + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------- + + + async def handle_channel_message(self, message): + + if not message.channel.name == f'group-{self.group_num}': + return + + # ----- teddy: commented out to reduce clutter for milestone 2 since we are not doing auto flagging ------------ + # # Forward the message to the mod channel + # mod_channel = self.mod_channels[message.guild.id] + # await mod_channel.send(f'Forwarded message:\n{message.author.name}: "{message.content}"') + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------------------------------------------------------ + return + + async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): + # see https://discordpy.readthedocs.io/en/latest/api.html?highlight=on_reaction_add#discord.RawReactionActionEvent + mod_channel = self.mod_channels[message.guild.id] + + message = await mod_channel.fetch_message(payload.message_id) + + # Ignore messages that are not the bot's moderator to-do messages + if message.author.id != self.user.id or (not message.content.startswith(MOD_TODO_START)): + return + + # TODO IMPLEMENT MODERATOR FLOW HERE + + return + + def eval_text(self, message): + '''' + TODO: Once you know how you want to evaluate messages in your channel, + insert your code here! This will primarily be used in Milestone 3. + ''' + return message + + + def code_format(self, text): + '''' + TODO: Once you know how you want to show that a message has been + evaluated, insert your code here for formatting the string to be + shown in the mod channel. + ''' + #teddy: not sure if we need this function + return "Evaluated: '" + text+ "'" + + # def process_response(self, responses): + + # reply = responses["reply"] + # if not isinstance(reply, str): # just in case i forget brackets in report.py + # reply = [reply] + # del responses["reply"] + + # for key, value in responses.items(): # go through data (not including reply) + # if key not in self.current_report: # don't allow overwriting + # self.current_report[key] = value + + # return reply + + +client = ModBot() +client.run(discord_token) \ No newline at end of file diff --git a/.history/DiscordBot/bot_20250509125209.py b/.history/DiscordBot/bot_20250509125209.py new file mode 100644 index 00000000..20591c52 --- /dev/null +++ b/.history/DiscordBot/bot_20250509125209.py @@ -0,0 +1,238 @@ +# bot.py +import discord +from discord.ext import commands +import os +import json +import logging +import re +import requests +from report import Report +from submitted_report import SubmittedReport +import pdb + +# Set up logging to the console +logger = logging.getLogger('discord') +logger.setLevel(logging.DEBUG) +handler = logging.FileHandler(filename='discord.log', encoding='utf-8', mode='w') +handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s')) +logger.addHandler(handler) + +# There should be a file called 'tokens.json' inside the same folder as this file +token_path = 'tokens.json' +if not os.path.isfile(token_path): + raise Exception(f"{token_path} not found!") +with open(token_path) as f: + # If you get an error here, it means your token is formatted incorrectly. Did you put it in quotes? + tokens = json.load(f) + discord_token = tokens['discord'] + + +MOD_TODO_START = "---------------------------\nTODO" + + +class ModBot(discord.Client): + def __init__(self): + intents = discord.Intents.default() + intents.message_content = True + super().__init__(command_prefix='.', intents=intents) + self.group_num = None + self.mod_channels = {} # Map from guild to the mod channel id for that guild + self.reports = {} # Map from user IDs to the state of their report + self.report_queue = [] + + async def on_ready(self): + print(f'{self.user.name} has connected to Discord! It is these guilds:') + for guild in self.guilds: + print(f' - {guild.name}') + print('Press Ctrl-C to quit.') + + # Parse the group number out of the bot's name + match = re.search('[gG]roup (\d+) [bB]ot', self.user.name) + if match: + self.group_num = match.group(1) + else: + raise Exception("Group number not found in bot's name. Name format should be \"Group # Bot\".") + + # Find the mod channel in each guild that this bot should report to + for guild in self.guilds: + for channel in guild.text_channels: + if channel.name == f'group-{self.group_num}-mod': + self.mod_channels[guild.id] = channel + + + async def on_message(self, message): + ''' + This function is called whenever a message is sent in a channel that the bot can see (including DMs). + Currently the bot is configured to only handle messages that are sent over DMs or in your group's "group-#" channel. + ''' + # Ignore messages from the bot + if message.author.id == self.user.id: + return + + # Check if this message was sent in a server ("guild") or if it's a DM + if message.guild: + await self.handle_channel_message(message) + else: + await self.handle_dm(message) + + async def handle_dm(self, message): + # Handle a help message + if message.content == Report.HELP_KEYWORD: + reply = "Use the `report` command to begin the reporting process.\n" + reply += "Use the `cancel` command to cancel the report process.\n" + await message.channel.send(reply) + return + + author_id = message.author.id + responses = [] + + # Only respond to messages if they're part of a reporting flow + if author_id not in self.reports and not message.content.startswith(Report.START_KEYWORD): + return + + # If we don't currently have an active report for this user, add one + if author_id not in self.reports: + self.reports[author_id] = Report(self) + + # If we are starting a report + responses = await self.reports[author_id].handle_message(message) + + ## report.py updates state, and below, we route our response based on that state + + if self.reports[author_id].is_awaiting_message(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_reason(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_political_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_healthl_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_harmful_content_status(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_filter_action(): + for r in responses: + await message.channel.send(r) + + # if self.reports[author_id].harm_identified(): + # reply = responses[0] + # harm = responses[1] + # if harm: + # # TODO escalate (or simulate it) + # print("Escalating report") + # await message.channel.send(reply) + + # if self.reports[author_id].block_step(): + # reply = responses[0] + # block = responses[1] + # if block: + # # TODO block user (or simulate it) + # print("Blocking user") + # await message.channel.send(reply) + + # If the report is complete or cancelled, remove it from our map + if self.reports[author_id].is_report_complete(): + + reported_author = self.reports[author_id].get_reported_author() + reported_content = self.reports[author_id].get_reported_content() + report_type = self.reports[author_id].get_report_type() + disinfo_type = self.reports[author_id].get_disinfo_type() + disinfo_subtype = self.reports[author_id].get_disinfo_subtype() + imminent = self.reports[author_id].get_imminent() + + for r in responses: + await message.channel.send(r) + + # Put the report in the mod channel + mod_channel = self.mod_channels[self.reports[author_id].get_message_guild_id()] + # todo are we worried about code injection via author name or content? + report_info_msg = MOD_TODO_START + " User " + message.author.name + " reported user " + str(reported_author) + "'s message.\n" + report_info_msg += "Here is the message: \n```" + str(reported_content) + "\n```" + report_info_msg += "Category: " + str(report_type) + " > " + str(disinfo_type) + " > " + str(disinfo_subtype) + "\n" + self.report_queue.append(SubmittedReport(reported_author, reported_content, report_type, disinfo_type, disinfo_subtype, imminent)) + + await mod_channel.send(report_info_msg) + + # remove + self.reports.pop(author_id) + + # ------ starter code relevant to MILESTONE 3: -------------- + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------- + + + async def handle_channel_message(self, message): + + if not message.channel.name == f'group-{self.group_num}': + return + + # ----- teddy: commented out to reduce clutter for milestone 2 since we are not doing auto flagging ------------ + # # Forward the message to the mod channel + # mod_channel = self.mod_channels[message.guild.id] + # await mod_channel.send(f'Forwarded message:\n{message.author.name}: "{message.content}"') + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------------------------------------------------------ + return + + async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): + # see https://discordpy.readthedocs.io/en/latest/api.html?highlight=on_reaction_add#discord.RawReactionActionEvent + mod_channel = self.mod_channels[message.guild.id] + + message = await mod_channel.fetch_message(payload.message_id) + + # Ignore messages that are not the bot's moderator to-do messages + if message.author.id != self.user.id or (not message.content.startswith(MOD_TODO_START)): + return + + # TODO IMPLEMENT MODERATOR FLOW HERE + + return + + def eval_text(self, message): + '''' + TODO: Once you know how you want to evaluate messages in your channel, + insert your code here! This will primarily be used in Milestone 3. + ''' + return message + + + def code_format(self, text): + '''' + TODO: Once you know how you want to show that a message has been + evaluated, insert your code here for formatting the string to be + shown in the mod channel. + ''' + #teddy: not sure if we need this function + return "Evaluated: '" + text+ "'" + + # def process_response(self, responses): + + # reply = responses["reply"] + # if not isinstance(reply, str): # just in case i forget brackets in report.py + # reply = [reply] + # del responses["reply"] + + # for key, value in responses.items(): # go through data (not including reply) + # if key not in self.current_report: # don't allow overwriting + # self.current_report[key] = value + + # return reply + + +client = ModBot() +client.run(discord_token) \ No newline at end of file diff --git a/.history/DiscordBot/bot_20250509125348.py b/.history/DiscordBot/bot_20250509125348.py new file mode 100644 index 00000000..46d9c3b2 --- /dev/null +++ b/.history/DiscordBot/bot_20250509125348.py @@ -0,0 +1,239 @@ +# bot.py +import discord +from discord.ext import commands +import os +import json +import logging +import re +import requests +from report import Report +from submitted_report import SubmittedReport +import pdb + +# Set up logging to the console +logger = logging.getLogger('discord') +logger.setLevel(logging.DEBUG) +handler = logging.FileHandler(filename='discord.log', encoding='utf-8', mode='w') +handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s')) +logger.addHandler(handler) + +# There should be a file called 'tokens.json' inside the same folder as this file +token_path = 'tokens.json' +if not os.path.isfile(token_path): + raise Exception(f"{token_path} not found!") +with open(token_path) as f: + # If you get an error here, it means your token is formatted incorrectly. Did you put it in quotes? + tokens = json.load(f) + discord_token = tokens['discord'] + + +MOD_TODO_START = "---------------------------\nTODO" + + +class ModBot(discord.Client): + def __init__(self): + intents = discord.Intents.default() + intents.message_content = True + super().__init__(command_prefix='.', intents=intents) + self.group_num = None + self.mod_channels = {} # Map from guild to the mod channel id for that guild + self.reports = {} # Map from user IDs to the state of their report + self.report_queue = [] + + async def on_ready(self): + print(f'{self.user.name} has connected to Discord! It is these guilds:') + for guild in self.guilds: + print(f' - {guild.name}') + print('Press Ctrl-C to quit.') + + # Parse the group number out of the bot's name + match = re.search('[gG]roup (\d+) [bB]ot', self.user.name) + if match: + self.group_num = match.group(1) + else: + raise Exception("Group number not found in bot's name. Name format should be \"Group # Bot\".") + + # Find the mod channel in each guild that this bot should report to + for guild in self.guilds: + for channel in guild.text_channels: + if channel.name == f'group-{self.group_num}-mod': + self.mod_channels[guild.id] = channel + + + async def on_message(self, message): + ''' + This function is called whenever a message is sent in a channel that the bot can see (including DMs). + Currently the bot is configured to only handle messages that are sent over DMs or in your group's "group-#" channel. + ''' + # Ignore messages from the bot + if message.author.id == self.user.id: + return + + # Check if this message was sent in a server ("guild") or if it's a DM + if message.guild: + await self.handle_channel_message(message) + else: + await self.handle_dm(message) + + async def handle_dm(self, message): + # Handle a help message + if message.content == Report.HELP_KEYWORD: + reply = "Use the `report` command to begin the reporting process.\n" + reply += "Use the `cancel` command to cancel the report process.\n" + await message.channel.send(reply) + return + + author_id = message.author.id + responses = [] + + # Only respond to messages if they're part of a reporting flow + if author_id not in self.reports and not message.content.startswith(Report.START_KEYWORD): + return + + # If we don't currently have an active report for this user, add one + if author_id not in self.reports: + self.reports[author_id] = Report(self) + + # If we are starting a report + responses = await self.reports[author_id].handle_message(message) + + ## report.py updates state, and below, we route our response based on that state + + if self.reports[author_id].is_awaiting_message(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_reason(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_political_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_healthl_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_harmful_content_status(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_filter_action(): + for r in responses: + await message.channel.send(r) + + # if self.reports[author_id].harm_identified(): + # reply = responses[0] + # harm = responses[1] + # if harm: + # # TODO escalate (or simulate it) + # print("Escalating report") + # await message.channel.send(reply) + + # if self.reports[author_id].block_step(): + # reply = responses[0] + # block = responses[1] + # if block: + # # TODO block user (or simulate it) + # print("Blocking user") + # await message.channel.send(reply) + + # If the report is complete or cancelled, remove it from our map + if self.reports[author_id].is_report_complete(): + + reported_author = self.reports[author_id].get_reported_author() + reported_content = self.reports[author_id].get_reported_content() + report_type = self.reports[author_id].get_report_type() + disinfo_type = self.reports[author_id].get_disinfo_type() + disinfo_subtype = self.reports[author_id].get_disinfo_subtype() + imminent = self.reports[author_id].get_imminent() + + for r in responses: + await message.channel.send(r) + + # Put the report in the mod channel + mod_channel = self.mod_channels[self.reports[author_id].get_message_guild_id()] + # todo are we worried about code injection via author name or content? + report_info_msg = MOD_TODO_START + " User " + message.author.name + " reported user " + str(reported_author) + "'s message.\n" + report_info_msg += "Here is the message: \n```" + str(reported_content) + "\n```" + report_info_msg += "Category: " + str(report_type) + " > " + str(disinfo_type) + " > " + str(disinfo_subtype) + "\n" + submitted_report = SubmittedReport(reported_author, reported_content, report_type, disinfo_type, disinfo_subtype, imminent) + self.report_queue.append(submitted_report) + + await mod_channel.send(report_info_msg) + + # remove + self.reports.pop(author_id) + + # ------ starter code relevant to MILESTONE 3: -------------- + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------- + + + async def handle_channel_message(self, message): + + if not message.channel.name == f'group-{self.group_num}': + return + + # ----- teddy: commented out to reduce clutter for milestone 2 since we are not doing auto flagging ------------ + # # Forward the message to the mod channel + # mod_channel = self.mod_channels[message.guild.id] + # await mod_channel.send(f'Forwarded message:\n{message.author.name}: "{message.content}"') + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------------------------------------------------------ + return + + async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): + # see https://discordpy.readthedocs.io/en/latest/api.html?highlight=on_reaction_add#discord.RawReactionActionEvent + mod_channel = self.mod_channels[message.guild.id] + + message = await mod_channel.fetch_message(payload.message_id) + + # Ignore messages that are not the bot's moderator to-do messages + if message.author.id != self.user.id or (not message.content.startswith(MOD_TODO_START)): + return + + # TODO IMPLEMENT MODERATOR FLOW HERE + + return + + def eval_text(self, message): + '''' + TODO: Once you know how you want to evaluate messages in your channel, + insert your code here! This will primarily be used in Milestone 3. + ''' + return message + + + def code_format(self, text): + '''' + TODO: Once you know how you want to show that a message has been + evaluated, insert your code here for formatting the string to be + shown in the mod channel. + ''' + #teddy: not sure if we need this function + return "Evaluated: '" + text+ "'" + + # def process_response(self, responses): + + # reply = responses["reply"] + # if not isinstance(reply, str): # just in case i forget brackets in report.py + # reply = [reply] + # del responses["reply"] + + # for key, value in responses.items(): # go through data (not including reply) + # if key not in self.current_report: # don't allow overwriting + # self.current_report[key] = value + + # return reply + + +client = ModBot() +client.run(discord_token) \ No newline at end of file diff --git a/.history/DiscordBot/bot_20250509125707.py b/.history/DiscordBot/bot_20250509125707.py new file mode 100644 index 00000000..404e7ac4 --- /dev/null +++ b/.history/DiscordBot/bot_20250509125707.py @@ -0,0 +1,241 @@ +# bot.py +import discord +from discord.ext import commands +import os +import json +import logging +import re +import requests +from report import Report +from submitted_report import SubmittedReport +import pdb + +# Set up logging to the console +logger = logging.getLogger('discord') +logger.setLevel(logging.DEBUG) +handler = logging.FileHandler(filename='discord.log', encoding='utf-8', mode='w') +handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s')) +logger.addHandler(handler) + +# There should be a file called 'tokens.json' inside the same folder as this file +token_path = 'tokens.json' +if not os.path.isfile(token_path): + raise Exception(f"{token_path} not found!") +with open(token_path) as f: + # If you get an error here, it means your token is formatted incorrectly. Did you put it in quotes? + tokens = json.load(f) + discord_token = tokens['discord'] + + +MOD_TODO_START = "---------------------------\nTODO" + + +class ModBot(discord.Client): + def __init__(self): + intents = discord.Intents.default() + intents.message_content = True + super().__init__(command_prefix='.', intents=intents) + self.group_num = None + self.mod_channels = {} # Map from guild to the mod channel id for that guild + self.reports = {} # Map from user IDs to the state of their report + self.report_queue = [] + + async def on_ready(self): + print(f'{self.user.name} has connected to Discord! It is these guilds:') + for guild in self.guilds: + print(f' - {guild.name}') + print('Press Ctrl-C to quit.') + + # Parse the group number out of the bot's name + match = re.search('[gG]roup (\d+) [bB]ot', self.user.name) + if match: + self.group_num = match.group(1) + else: + raise Exception("Group number not found in bot's name. Name format should be \"Group # Bot\".") + + # Find the mod channel in each guild that this bot should report to + for guild in self.guilds: + for channel in guild.text_channels: + if channel.name == f'group-{self.group_num}-mod': + self.mod_channels[guild.id] = channel + + + async def on_message(self, message): + ''' + This function is called whenever a message is sent in a channel that the bot can see (including DMs). + Currently the bot is configured to only handle messages that are sent over DMs or in your group's "group-#" channel. + ''' + # Ignore messages from the bot + if message.author.id == self.user.id: + return + + # Check if this message was sent in a server ("guild") or if it's a DM + if message.guild: + await self.handle_channel_message(message) + else: + await self.handle_dm(message) + + async def handle_dm(self, message): + # Handle a help message + if message.content == Report.HELP_KEYWORD: + reply = "Use the `report` command to begin the reporting process.\n" + reply += "Use the `cancel` command to cancel the report process.\n" + await message.channel.send(reply) + return + + author_id = message.author.id + responses = [] + + # Only respond to messages if they're part of a reporting flow + if author_id not in self.reports and not message.content.startswith(Report.START_KEYWORD): + return + + # If we don't currently have an active report for this user, add one + if author_id not in self.reports: + self.reports[author_id] = Report(self) + + # If we are starting a report + responses = await self.reports[author_id].handle_message(message) + + ## report.py updates state, and below, we route our response based on that state + + if self.reports[author_id].is_awaiting_message(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_reason(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_political_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_healthl_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_harmful_content_status(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_filter_action(): + for r in responses: + await message.channel.send(r) + + # if self.reports[author_id].harm_identified(): + # reply = responses[0] + # harm = responses[1] + # if harm: + # # TODO escalate (or simulate it) + # print("Escalating report") + # await message.channel.send(reply) + + # if self.reports[author_id].block_step(): + # reply = responses[0] + # block = responses[1] + # if block: + # # TODO block user (or simulate it) + # print("Blocking user") + # await message.channel.send(reply) + + # If the report is complete or cancelled, remove it from our map + if self.reports[author_id].is_report_complete(): + + reported_author = self.reports[author_id].get_reported_author() + reported_content = self.reports[author_id].get_reported_content() + report_type = self.reports[author_id].get_report_type() + disinfo_type = self.reports[author_id].get_disinfo_type() + disinfo_subtype = self.reports[author_id].get_disinfo_subtype() + imminent = self.reports[author_id].get_imminent() + + for r in responses: + await message.channel.send(r) + + # Put the report in the mod channel + mod_channel = self.mod_channels[self.reports[author_id].get_message_guild_id()] + # todo are we worried about code injection via author name or content? + report_info_msg = MOD_TODO_START + " User " + message.author.name + " reported user " + str(reported_author) + "'s message.\n" + report_info_msg += "Here is the message: \n```" + str(reported_content) + "\n```" + report_info_msg += "Category: " + str(report_type) + " > " + str(disinfo_type) + " > " + str(disinfo_subtype) + "\n" + if imminent: + report_info_msg += "FLAG: Imminent " + imminent + " harm reported." + submitted_report = SubmittedReport(reported_author, reported_content, report_type, disinfo_type, disinfo_subtype, imminent) + self.report_queue.append(submitted_report) + + await mod_channel.send(report_info_msg) + + # remove + self.reports.pop(author_id) + + # ------ starter code relevant to MILESTONE 3: -------------- + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------- + + + async def handle_channel_message(self, message): + + if not message.channel.name == f'group-{self.group_num}': + return + + # ----- teddy: commented out to reduce clutter for milestone 2 since we are not doing auto flagging ------------ + # # Forward the message to the mod channel + # mod_channel = self.mod_channels[message.guild.id] + # await mod_channel.send(f'Forwarded message:\n{message.author.name}: "{message.content}"') + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------------------------------------------------------ + return + + async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): + # see https://discordpy.readthedocs.io/en/latest/api.html?highlight=on_reaction_add#discord.RawReactionActionEvent + mod_channel = self.mod_channels[message.guild.id] + + message = await mod_channel.fetch_message(payload.message_id) + + # Ignore messages that are not the bot's moderator to-do messages + if message.author.id != self.user.id or (not message.content.startswith(MOD_TODO_START)): + return + + # TODO IMPLEMENT MODERATOR FLOW HERE + + return + + def eval_text(self, message): + '''' + TODO: Once you know how you want to evaluate messages in your channel, + insert your code here! This will primarily be used in Milestone 3. + ''' + return message + + + def code_format(self, text): + '''' + TODO: Once you know how you want to show that a message has been + evaluated, insert your code here for formatting the string to be + shown in the mod channel. + ''' + #teddy: not sure if we need this function + return "Evaluated: '" + text+ "'" + + # def process_response(self, responses): + + # reply = responses["reply"] + # if not isinstance(reply, str): # just in case i forget brackets in report.py + # reply = [reply] + # del responses["reply"] + + # for key, value in responses.items(): # go through data (not including reply) + # if key not in self.current_report: # don't allow overwriting + # self.current_report[key] = value + + # return reply + + +client = ModBot() +client.run(discord_token) \ No newline at end of file diff --git a/.history/DiscordBot/bot_20250509131012.py b/.history/DiscordBot/bot_20250509131012.py new file mode 100644 index 00000000..cec09d7b --- /dev/null +++ b/.history/DiscordBot/bot_20250509131012.py @@ -0,0 +1,242 @@ +# bot.py +import discord +from discord.ext import commands +import os +import json +import logging +import re +import requests +from report import Report +from submitted_report import SubmittedReport +import pdb + +# Set up logging to the console +logger = logging.getLogger('discord') +logger.setLevel(logging.DEBUG) +handler = logging.FileHandler(filename='discord.log', encoding='utf-8', mode='w') +handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s')) +logger.addHandler(handler) + +# There should be a file called 'tokens.json' inside the same folder as this file +token_path = 'tokens.json' +if not os.path.isfile(token_path): + raise Exception(f"{token_path} not found!") +with open(token_path) as f: + # If you get an error here, it means your token is formatted incorrectly. Did you put it in quotes? + tokens = json.load(f) + discord_token = tokens['discord'] + + +MOD_TODO_START = "---------------------------\nTODO" + + +class ModBot(discord.Client): + def __init__(self): + intents = discord.Intents.default() + intents.message_content = True + super().__init__(command_prefix='.', intents=intents) + self.group_num = None + self.mod_channels = {} # Map from guild to the mod channel id for that guild + self.reports = {} # Map from user IDs to the state of their report + self.report_queue = [] + + async def on_ready(self): + print(f'{self.user.name} has connected to Discord! It is these guilds:') + for guild in self.guilds: + print(f' - {guild.name}') + print('Press Ctrl-C to quit.') + + # Parse the group number out of the bot's name + match = re.search('[gG]roup (\d+) [bB]ot', self.user.name) + if match: + self.group_num = match.group(1) + else: + raise Exception("Group number not found in bot's name. Name format should be \"Group # Bot\".") + + # Find the mod channel in each guild that this bot should report to + for guild in self.guilds: + for channel in guild.text_channels: + if channel.name == f'group-{self.group_num}-mod': + self.mod_channels[guild.id] = channel + + + async def on_message(self, message): + ''' + This function is called whenever a message is sent in a channel that the bot can see (including DMs). + Currently the bot is configured to only handle messages that are sent over DMs or in your group's "group-#" channel. + ''' + # Ignore messages from the bot + if message.author.id == self.user.id: + return + + # Check if this message was sent in a server ("guild") or if it's a DM + if message.guild: + await self.handle_channel_message(message) + else: + await self.handle_dm(message) + + async def handle_dm(self, message): + # Handle a help message + if message.content == Report.HELP_KEYWORD: + reply = "Use the `report` command to begin the reporting process.\n" + reply += "Use the `cancel` command to cancel the report process.\n" + await message.channel.send(reply) + return + + author_id = message.author.id + responses = [] + + # Only respond to messages if they're part of a reporting flow + if author_id not in self.reports and not message.content.startswith(Report.START_KEYWORD): + return + + # If we don't currently have an active report for this user, add one + if author_id not in self.reports: + self.reports[author_id] = Report(self) + + # If we are starting a report + responses = await self.reports[author_id].handle_message(message) + + ## report.py updates state, and below, we route our response based on that state + + if self.reports[author_id].is_awaiting_message(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_reason(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_political_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_healthl_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_harmful_content_status(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_filter_action(): + for r in responses: + await message.channel.send(r) + + # if self.reports[author_id].harm_identified(): + # reply = responses[0] + # harm = responses[1] + # if harm: + # # TODO escalate (or simulate it) + # print("Escalating report") + # await message.channel.send(reply) + + # if self.reports[author_id].block_step(): + # reply = responses[0] + # block = responses[1] + # if block: + # # TODO block user (or simulate it) + # print("Blocking user") + # await message.channel.send(reply) + + # If the report is complete or cancelled, remove it from our map + if self.reports[author_id].is_report_complete(): + + reported_author = self.reports[author_id].get_reported_author() + reported_content = self.reports[author_id].get_reported_content() + report_type = self.reports[author_id].get_report_type() + disinfo_type = self.reports[author_id].get_disinfo_type() + disinfo_subtype = self.reports[author_id].get_disinfo_subtype() + imminent = self.reports[author_id].get_imminent() + priority = self.reports[author_id].get_priority() + + for r in responses: + await message.channel.send(r) + + # Put the report in the mod channel + mod_channel = self.mod_channels[self.reports[author_id].get_message_guild_id()] + # todo are we worried about code injection via author name or content? + report_info_msg = MOD_TODO_START + " User " + message.author.name + " reported user " + str(reported_author) + "'s message.\n" + report_info_msg += "Here is the message: \n```" + str(reported_content) + "\n```" + report_info_msg += "Category: " + str(report_type) + " > " + str(disinfo_type) + " > " + str(disinfo_subtype) + "\n" + if imminent: + report_info_msg += "FLAG: Imminent " + imminent + " harm reported." + submitted_report = SubmittedReport(reported_author, reported_content, report_type, disinfo_type, disinfo_subtype) + self.report_queue.enqueue(submitted_report, priority) + + await mod_channel.send(report_info_msg) + + # remove + self.reports.pop(author_id) + + # ------ starter code relevant to MILESTONE 3: -------------- + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------- + + + async def handle_channel_message(self, message): + + if not message.channel.name == f'group-{self.group_num}': + return + + # ----- teddy: commented out to reduce clutter for milestone 2 since we are not doing auto flagging ------------ + # # Forward the message to the mod channel + # mod_channel = self.mod_channels[message.guild.id] + # await mod_channel.send(f'Forwarded message:\n{message.author.name}: "{message.content}"') + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------------------------------------------------------ + return + + async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): + # see https://discordpy.readthedocs.io/en/latest/api.html?highlight=on_reaction_add#discord.RawReactionActionEvent + mod_channel = self.mod_channels[message.guild.id] + + message = await mod_channel.fetch_message(payload.message_id) + + # Ignore messages that are not the bot's moderator to-do messages + if message.author.id != self.user.id or (not message.content.startswith(MOD_TODO_START)): + return + + # TODO IMPLEMENT MODERATOR FLOW HERE + + return + + def eval_text(self, message): + '''' + TODO: Once you know how you want to evaluate messages in your channel, + insert your code here! This will primarily be used in Milestone 3. + ''' + return message + + + def code_format(self, text): + '''' + TODO: Once you know how you want to show that a message has been + evaluated, insert your code here for formatting the string to be + shown in the mod channel. + ''' + #teddy: not sure if we need this function + return "Evaluated: '" + text+ "'" + + # def process_response(self, responses): + + # reply = responses["reply"] + # if not isinstance(reply, str): # just in case i forget brackets in report.py + # reply = [reply] + # del responses["reply"] + + # for key, value in responses.items(): # go through data (not including reply) + # if key not in self.current_report: # don't allow overwriting + # self.current_report[key] = value + + # return reply + + +client = ModBot() +client.run(discord_token) \ No newline at end of file diff --git a/.history/DiscordBot/bot_20250509131355.py b/.history/DiscordBot/bot_20250509131355.py new file mode 100644 index 00000000..00e04973 --- /dev/null +++ b/.history/DiscordBot/bot_20250509131355.py @@ -0,0 +1,242 @@ +# bot.py +import discord +from discord.ext import commands +import os +import json +import logging +import re +import requests +from report import Report +from report_queue import SubmittedReport, PriorityReportQueue +import pdb + +# Set up logging to the console +logger = logging.getLogger('discord') +logger.setLevel(logging.DEBUG) +handler = logging.FileHandler(filename='discord.log', encoding='utf-8', mode='w') +handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s')) +logger.addHandler(handler) + +# There should be a file called 'tokens.json' inside the same folder as this file +token_path = 'tokens.json' +if not os.path.isfile(token_path): + raise Exception(f"{token_path} not found!") +with open(token_path) as f: + # If you get an error here, it means your token is formatted incorrectly. Did you put it in quotes? + tokens = json.load(f) + discord_token = tokens['discord'] + + +MOD_TODO_START = "---------------------------\nTODO" + + +class ModBot(discord.Client): + def __init__(self): + intents = discord.Intents.default() + intents.message_content = True + super().__init__(command_prefix='.', intents=intents) + self.group_num = None + self.mod_channels = {} # Map from guild to the mod channel id for that guild + self.reports = {} # Map from user IDs to the state of their report + self.report_queue = PriorityReportQueue(3) + + async def on_ready(self): + print(f'{self.user.name} has connected to Discord! It is these guilds:') + for guild in self.guilds: + print(f' - {guild.name}') + print('Press Ctrl-C to quit.') + + # Parse the group number out of the bot's name + match = re.search('[gG]roup (\d+) [bB]ot', self.user.name) + if match: + self.group_num = match.group(1) + else: + raise Exception("Group number not found in bot's name. Name format should be \"Group # Bot\".") + + # Find the mod channel in each guild that this bot should report to + for guild in self.guilds: + for channel in guild.text_channels: + if channel.name == f'group-{self.group_num}-mod': + self.mod_channels[guild.id] = channel + + + async def on_message(self, message): + ''' + This function is called whenever a message is sent in a channel that the bot can see (including DMs). + Currently the bot is configured to only handle messages that are sent over DMs or in your group's "group-#" channel. + ''' + # Ignore messages from the bot + if message.author.id == self.user.id: + return + + # Check if this message was sent in a server ("guild") or if it's a DM + if message.guild: + await self.handle_channel_message(message) + else: + await self.handle_dm(message) + + async def handle_dm(self, message): + # Handle a help message + if message.content == Report.HELP_KEYWORD: + reply = "Use the `report` command to begin the reporting process.\n" + reply += "Use the `cancel` command to cancel the report process.\n" + await message.channel.send(reply) + return + + author_id = message.author.id + responses = [] + + # Only respond to messages if they're part of a reporting flow + if author_id not in self.reports and not message.content.startswith(Report.START_KEYWORD): + return + + # If we don't currently have an active report for this user, add one + if author_id not in self.reports: + self.reports[author_id] = Report(self) + + # If we are starting a report + responses = await self.reports[author_id].handle_message(message) + + ## report.py updates state, and below, we route our response based on that state + + if self.reports[author_id].is_awaiting_message(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_reason(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_political_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_healthl_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_harmful_content_status(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_filter_action(): + for r in responses: + await message.channel.send(r) + + # if self.reports[author_id].harm_identified(): + # reply = responses[0] + # harm = responses[1] + # if harm: + # # TODO escalate (or simulate it) + # print("Escalating report") + # await message.channel.send(reply) + + # if self.reports[author_id].block_step(): + # reply = responses[0] + # block = responses[1] + # if block: + # # TODO block user (or simulate it) + # print("Blocking user") + # await message.channel.send(reply) + + # If the report is complete or cancelled, remove it from our map + if self.reports[author_id].is_report_complete(): + + reported_author = self.reports[author_id].get_reported_author() + reported_content = self.reports[author_id].get_reported_content() + report_type = self.reports[author_id].get_report_type() + disinfo_type = self.reports[author_id].get_disinfo_type() + disinfo_subtype = self.reports[author_id].get_disinfo_subtype() + imminent = self.reports[author_id].get_imminent() + priority = self.reports[author_id].get_priority() + + for r in responses: + await message.channel.send(r) + + # Put the report in the mod channel + mod_channel = self.mod_channels[self.reports[author_id].get_message_guild_id()] + # todo are we worried about code injection via author name or content? + report_info_msg = MOD_TODO_START + " User " + message.author.name + " reported user " + str(reported_author) + "'s message.\n" + report_info_msg += "Here is the message: \n```" + str(reported_content) + "\n```" + report_info_msg += "Category: " + str(report_type) + " > " + str(disinfo_type) + " > " + str(disinfo_subtype) + "\n" + if imminent: + report_info_msg += "FLAG: Imminent " + imminent + " harm reported." + submitted_report = SubmittedReport(reported_author, reported_content, report_type, disinfo_type, disinfo_subtype) + self.report_queue.enqueue(submitted_report, priority) + + await mod_channel.send(report_info_msg) + + # remove + self.reports.pop(author_id) + + # ------ starter code relevant to MILESTONE 3: -------------- + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------- + + + async def handle_channel_message(self, message): + + if not message.channel.name == f'group-{self.group_num}': + return + + # ----- teddy: commented out to reduce clutter for milestone 2 since we are not doing auto flagging ------------ + # # Forward the message to the mod channel + # mod_channel = self.mod_channels[message.guild.id] + # await mod_channel.send(f'Forwarded message:\n{message.author.name}: "{message.content}"') + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------------------------------------------------------ + return + + async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): + # see https://discordpy.readthedocs.io/en/latest/api.html?highlight=on_reaction_add#discord.RawReactionActionEvent + mod_channel = self.mod_channels[message.guild.id] + + message = await mod_channel.fetch_message(payload.message_id) + + # Ignore messages that are not the bot's moderator to-do messages + if message.author.id != self.user.id or (not message.content.startswith(MOD_TODO_START)): + return + + # TODO IMPLEMENT MODERATOR FLOW HERE + + return + + def eval_text(self, message): + '''' + TODO: Once you know how you want to evaluate messages in your channel, + insert your code here! This will primarily be used in Milestone 3. + ''' + return message + + + def code_format(self, text): + '''' + TODO: Once you know how you want to show that a message has been + evaluated, insert your code here for formatting the string to be + shown in the mod channel. + ''' + #teddy: not sure if we need this function + return "Evaluated: '" + text+ "'" + + # def process_response(self, responses): + + # reply = responses["reply"] + # if not isinstance(reply, str): # just in case i forget brackets in report.py + # reply = [reply] + # del responses["reply"] + + # for key, value in responses.items(): # go through data (not including reply) + # if key not in self.current_report: # don't allow overwriting + # self.current_report[key] = value + + # return reply + + +client = ModBot() +client.run(discord_token) \ No newline at end of file diff --git a/.history/DiscordBot/bot_20250509131440.py b/.history/DiscordBot/bot_20250509131440.py new file mode 100644 index 00000000..7ced23c7 --- /dev/null +++ b/.history/DiscordBot/bot_20250509131440.py @@ -0,0 +1,242 @@ +# bot.py +import discord +from discord.ext import commands +import os +import json +import logging +import re +import requests +from report import Report +from report_queue import SubmittedReport, PriorityReportQueue +import pdb + +# Set up logging to the console +logger = logging.getLogger('discord') +logger.setLevel(logging.DEBUG) +handler = logging.FileHandler(filename='discord.log', encoding='utf-8', mode='w') +handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s')) +logger.addHandler(handler) + +# There should be a file called 'tokens.json' inside the same folder as this file +token_path = 'tokens.json' +if not os.path.isfile(token_path): + raise Exception(f"{token_path} not found!") +with open(token_path) as f: + # If you get an error here, it means your token is formatted incorrectly. Did you put it in quotes? + tokens = json.load(f) + discord_token = tokens['discord'] + + +MOD_TODO_START = "---------------------------\nTODO" + + +class ModBot(discord.Client): + def __init__(self): + intents = discord.Intents.default() + intents.message_content = True + super().__init__(command_prefix='.', intents=intents) + self.group_num = None + self.mod_channels = {} # Map from guild to the mod channel id for that guild + self.reports = {} # Map from user IDs to the state of their report + self.report_queue = PriorityReportQueue(3) # should equal the number of distinct priorities defined in Report.get_priority + + async def on_ready(self): + print(f'{self.user.name} has connected to Discord! It is these guilds:') + for guild in self.guilds: + print(f' - {guild.name}') + print('Press Ctrl-C to quit.') + + # Parse the group number out of the bot's name + match = re.search('[gG]roup (\d+) [bB]ot', self.user.name) + if match: + self.group_num = match.group(1) + else: + raise Exception("Group number not found in bot's name. Name format should be \"Group # Bot\".") + + # Find the mod channel in each guild that this bot should report to + for guild in self.guilds: + for channel in guild.text_channels: + if channel.name == f'group-{self.group_num}-mod': + self.mod_channels[guild.id] = channel + + + async def on_message(self, message): + ''' + This function is called whenever a message is sent in a channel that the bot can see (including DMs). + Currently the bot is configured to only handle messages that are sent over DMs or in your group's "group-#" channel. + ''' + # Ignore messages from the bot + if message.author.id == self.user.id: + return + + # Check if this message was sent in a server ("guild") or if it's a DM + if message.guild: + await self.handle_channel_message(message) + else: + await self.handle_dm(message) + + async def handle_dm(self, message): + # Handle a help message + if message.content == Report.HELP_KEYWORD: + reply = "Use the `report` command to begin the reporting process.\n" + reply += "Use the `cancel` command to cancel the report process.\n" + await message.channel.send(reply) + return + + author_id = message.author.id + responses = [] + + # Only respond to messages if they're part of a reporting flow + if author_id not in self.reports and not message.content.startswith(Report.START_KEYWORD): + return + + # If we don't currently have an active report for this user, add one + if author_id not in self.reports: + self.reports[author_id] = Report(self) + + # If we are starting a report + responses = await self.reports[author_id].handle_message(message) + + ## report.py updates state, and below, we route our response based on that state + + if self.reports[author_id].is_awaiting_message(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_reason(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_political_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_healthl_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_harmful_content_status(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_filter_action(): + for r in responses: + await message.channel.send(r) + + # if self.reports[author_id].harm_identified(): + # reply = responses[0] + # harm = responses[1] + # if harm: + # # TODO escalate (or simulate it) + # print("Escalating report") + # await message.channel.send(reply) + + # if self.reports[author_id].block_step(): + # reply = responses[0] + # block = responses[1] + # if block: + # # TODO block user (or simulate it) + # print("Blocking user") + # await message.channel.send(reply) + + # If the report is complete or cancelled, remove it from our map + if self.reports[author_id].is_report_complete(): + + reported_author = self.reports[author_id].get_reported_author() + reported_content = self.reports[author_id].get_reported_content() + report_type = self.reports[author_id].get_report_type() + disinfo_type = self.reports[author_id].get_disinfo_type() + disinfo_subtype = self.reports[author_id].get_disinfo_subtype() + imminent = self.reports[author_id].get_imminent() + priority = self.reports[author_id].get_priority() + + for r in responses: + await message.channel.send(r) + + # Put the report in the mod channel + mod_channel = self.mod_channels[self.reports[author_id].get_message_guild_id()] + # todo are we worried about code injection via author name or content? + report_info_msg = MOD_TODO_START + " User " + message.author.name + " reported user " + str(reported_author) + "'s message.\n" + report_info_msg += "Here is the message: \n```" + str(reported_content) + "\n```" + report_info_msg += "Category: " + str(report_type) + " > " + str(disinfo_type) + " > " + str(disinfo_subtype) + "\n" + if imminent: + report_info_msg += "FLAG: Imminent " + imminent + " harm reported." + submitted_report = SubmittedReport(reported_author, reported_content, report_type, disinfo_type, disinfo_subtype) + self.report_queue.enqueue(submitted_report, priority) + + await mod_channel.send(report_info_msg) + + # remove + self.reports.pop(author_id) + + # ------ starter code relevant to MILESTONE 3: -------------- + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------- + + + async def handle_channel_message(self, message): + + if not message.channel.name == f'group-{self.group_num}': + return + + # ----- teddy: commented out to reduce clutter for milestone 2 since we are not doing auto flagging ------------ + # # Forward the message to the mod channel + # mod_channel = self.mod_channels[message.guild.id] + # await mod_channel.send(f'Forwarded message:\n{message.author.name}: "{message.content}"') + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------------------------------------------------------ + return + + async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): + # see https://discordpy.readthedocs.io/en/latest/api.html?highlight=on_reaction_add#discord.RawReactionActionEvent + mod_channel = self.mod_channels[message.guild.id] + + message = await mod_channel.fetch_message(payload.message_id) + + # Ignore messages that are not the bot's moderator to-do messages + if message.author.id != self.user.id or (not message.content.startswith(MOD_TODO_START)): + return + + # TODO IMPLEMENT MODERATOR FLOW HERE + + return + + def eval_text(self, message): + '''' + TODO: Once you know how you want to evaluate messages in your channel, + insert your code here! This will primarily be used in Milestone 3. + ''' + return message + + + def code_format(self, text): + '''' + TODO: Once you know how you want to show that a message has been + evaluated, insert your code here for formatting the string to be + shown in the mod channel. + ''' + #teddy: not sure if we need this function + return "Evaluated: '" + text+ "'" + + # def process_response(self, responses): + + # reply = responses["reply"] + # if not isinstance(reply, str): # just in case i forget brackets in report.py + # reply = [reply] + # del responses["reply"] + + # for key, value in responses.items(): # go through data (not including reply) + # if key not in self.current_report: # don't allow overwriting + # self.current_report[key] = value + + # return reply + + +client = ModBot() +client.run(discord_token) \ No newline at end of file diff --git a/.history/DiscordBot/bot_20250509131607.py b/.history/DiscordBot/bot_20250509131607.py new file mode 100644 index 00000000..8a74cb34 --- /dev/null +++ b/.history/DiscordBot/bot_20250509131607.py @@ -0,0 +1,243 @@ +# bot.py +import discord +from discord.ext import commands +import os +import json +import logging +import re +import requests +from report import Report +from report_queue import SubmittedReport, PriorityReportQueue +import pdb + +# Set up logging to the console +logger = logging.getLogger('discord') +logger.setLevel(logging.DEBUG) +handler = logging.FileHandler(filename='discord.log', encoding='utf-8', mode='w') +handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s')) +logger.addHandler(handler) + +# There should be a file called 'tokens.json' inside the same folder as this file +token_path = 'tokens.json' +if not os.path.isfile(token_path): + raise Exception(f"{token_path} not found!") +with open(token_path) as f: + # If you get an error here, it means your token is formatted incorrectly. Did you put it in quotes? + tokens = json.load(f) + discord_token = tokens['discord'] + + +MOD_TODO_START = "---------------------------\nTODO" + + +class ModBot(discord.Client): + def __init__(self): + intents = discord.Intents.default() + intents.message_content = True + super().__init__(command_prefix='.', intents=intents) + self.group_num = None + self.mod_channels = {} # Map from guild to the mod channel id for that guild + self.reports = {} # Map from user IDs to the state of their report + self.report_id_counter = 0 + self.report_queue = PriorityReportQueue(3) # should equal the number of distinct priorities defined in Report.get_priority + + async def on_ready(self): + print(f'{self.user.name} has connected to Discord! It is these guilds:') + for guild in self.guilds: + print(f' - {guild.name}') + print('Press Ctrl-C to quit.') + + # Parse the group number out of the bot's name + match = re.search('[gG]roup (\d+) [bB]ot', self.user.name) + if match: + self.group_num = match.group(1) + else: + raise Exception("Group number not found in bot's name. Name format should be \"Group # Bot\".") + + # Find the mod channel in each guild that this bot should report to + for guild in self.guilds: + for channel in guild.text_channels: + if channel.name == f'group-{self.group_num}-mod': + self.mod_channels[guild.id] = channel + + + async def on_message(self, message): + ''' + This function is called whenever a message is sent in a channel that the bot can see (including DMs). + Currently the bot is configured to only handle messages that are sent over DMs or in your group's "group-#" channel. + ''' + # Ignore messages from the bot + if message.author.id == self.user.id: + return + + # Check if this message was sent in a server ("guild") or if it's a DM + if message.guild: + await self.handle_channel_message(message) + else: + await self.handle_dm(message) + + async def handle_dm(self, message): + # Handle a help message + if message.content == Report.HELP_KEYWORD: + reply = "Use the `report` command to begin the reporting process.\n" + reply += "Use the `cancel` command to cancel the report process.\n" + await message.channel.send(reply) + return + + author_id = message.author.id + responses = [] + + # Only respond to messages if they're part of a reporting flow + if author_id not in self.reports and not message.content.startswith(Report.START_KEYWORD): + return + + # If we don't currently have an active report for this user, add one + if author_id not in self.reports: + self.reports[author_id] = Report(self) + + # If we are starting a report + responses = await self.reports[author_id].handle_message(message) + + ## report.py updates state, and below, we route our response based on that state + + if self.reports[author_id].is_awaiting_message(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_reason(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_political_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_healthl_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_harmful_content_status(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_filter_action(): + for r in responses: + await message.channel.send(r) + + # if self.reports[author_id].harm_identified(): + # reply = responses[0] + # harm = responses[1] + # if harm: + # # TODO escalate (or simulate it) + # print("Escalating report") + # await message.channel.send(reply) + + # if self.reports[author_id].block_step(): + # reply = responses[0] + # block = responses[1] + # if block: + # # TODO block user (or simulate it) + # print("Blocking user") + # await message.channel.send(reply) + + # If the report is complete or cancelled, remove it from our map + if self.reports[author_id].is_report_complete(): + + reported_author = self.reports[author_id].get_reported_author() + reported_content = self.reports[author_id].get_reported_content() + report_type = self.reports[author_id].get_report_type() + disinfo_type = self.reports[author_id].get_disinfo_type() + disinfo_subtype = self.reports[author_id].get_disinfo_subtype() + imminent = self.reports[author_id].get_imminent() + priority = self.reports[author_id].get_priority() + + for r in responses: + await message.channel.send(r) + + # Put the report in the mod channel + mod_channel = self.mod_channels[self.reports[author_id].get_message_guild_id()] + # todo are we worried about code injection via author name or content? + report_info_msg = MOD_TODO_START + " User " + message.author.name + " reported user " + str(reported_author) + "'s message.\n" + report_info_msg += "Here is the message: \n```" + str(reported_content) + "\n```" + report_info_msg += "Category: " + str(report_type) + " > " + str(disinfo_type) + " > " + str(disinfo_subtype) + "\n" + if imminent: + report_info_msg += "FLAG: Imminent " + imminent + " harm reported." + submitted_report = SubmittedReport(reported_author, reported_content, report_type, disinfo_type, disinfo_subtype) + self.report_queue.enqueue(submitted_report, priority) + + await mod_channel.send(report_info_msg) + + # remove + self.reports.pop(author_id) + + # ------ starter code relevant to MILESTONE 3: -------------- + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------- + + + async def handle_channel_message(self, message): + + if not message.channel.name == f'group-{self.group_num}': + return + + # ----- teddy: commented out to reduce clutter for milestone 2 since we are not doing auto flagging ------------ + # # Forward the message to the mod channel + # mod_channel = self.mod_channels[message.guild.id] + # await mod_channel.send(f'Forwarded message:\n{message.author.name}: "{message.content}"') + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------------------------------------------------------ + return + + async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): + # see https://discordpy.readthedocs.io/en/latest/api.html?highlight=on_reaction_add#discord.RawReactionActionEvent + mod_channel = self.mod_channels[message.guild.id] + + message = await mod_channel.fetch_message(payload.message_id) + + # Ignore messages that are not the bot's moderator to-do messages + if message.author.id != self.user.id or (not message.content.startswith(MOD_TODO_START)): + return + + # TODO IMPLEMENT MODERATOR FLOW HERE + + return + + def eval_text(self, message): + '''' + TODO: Once you know how you want to evaluate messages in your channel, + insert your code here! This will primarily be used in Milestone 3. + ''' + return message + + + def code_format(self, text): + '''' + TODO: Once you know how you want to show that a message has been + evaluated, insert your code here for formatting the string to be + shown in the mod channel. + ''' + #teddy: not sure if we need this function + return "Evaluated: '" + text+ "'" + + # def process_response(self, responses): + + # reply = responses["reply"] + # if not isinstance(reply, str): # just in case i forget brackets in report.py + # reply = [reply] + # del responses["reply"] + + # for key, value in responses.items(): # go through data (not including reply) + # if key not in self.current_report: # don't allow overwriting + # self.current_report[key] = value + + # return reply + + +client = ModBot() +client.run(discord_token) \ No newline at end of file diff --git a/.history/DiscordBot/bot_20250509131821.py b/.history/DiscordBot/bot_20250509131821.py new file mode 100644 index 00000000..13968086 --- /dev/null +++ b/.history/DiscordBot/bot_20250509131821.py @@ -0,0 +1,245 @@ +# bot.py +import discord +from discord.ext import commands +import os +import json +import logging +import re +import requests +from report import Report +from report_queue import SubmittedReport, PriorityReportQueue +import pdb + +# Set up logging to the console +logger = logging.getLogger('discord') +logger.setLevel(logging.DEBUG) +handler = logging.FileHandler(filename='discord.log', encoding='utf-8', mode='w') +handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s')) +logger.addHandler(handler) + +# There should be a file called 'tokens.json' inside the same folder as this file +token_path = 'tokens.json' +if not os.path.isfile(token_path): + raise Exception(f"{token_path} not found!") +with open(token_path) as f: + # If you get an error here, it means your token is formatted incorrectly. Did you put it in quotes? + tokens = json.load(f) + discord_token = tokens['discord'] + + +MOD_TODO_START = "---------------------------\nTODO" + + +class ModBot(discord.Client): + def __init__(self): + intents = discord.Intents.default() + intents.message_content = True + super().__init__(command_prefix='.', intents=intents) + self.group_num = None + self.mod_channels = {} # Map from guild to the mod channel id for that guild + self.reports = {} # Map from user IDs to the state of their report + self.report_id_counter = 0 + self.report_queue = PriorityReportQueue(3) # should equal the number of distinct priorities defined in Report.get_priority + + async def on_ready(self): + print(f'{self.user.name} has connected to Discord! It is these guilds:') + for guild in self.guilds: + print(f' - {guild.name}') + print('Press Ctrl-C to quit.') + + # Parse the group number out of the bot's name + match = re.search('[gG]roup (\d+) [bB]ot', self.user.name) + if match: + self.group_num = match.group(1) + else: + raise Exception("Group number not found in bot's name. Name format should be \"Group # Bot\".") + + # Find the mod channel in each guild that this bot should report to + for guild in self.guilds: + for channel in guild.text_channels: + if channel.name == f'group-{self.group_num}-mod': + self.mod_channels[guild.id] = channel + + + async def on_message(self, message): + ''' + This function is called whenever a message is sent in a channel that the bot can see (including DMs). + Currently the bot is configured to only handle messages that are sent over DMs or in your group's "group-#" channel. + ''' + # Ignore messages from the bot + if message.author.id == self.user.id: + return + + # Check if this message was sent in a server ("guild") or if it's a DM + if message.guild: + await self.handle_channel_message(message) + else: + await self.handle_dm(message) + + async def handle_dm(self, message): + # Handle a help message + if message.content == Report.HELP_KEYWORD: + reply = "Use the `report` command to begin the reporting process.\n" + reply += "Use the `cancel` command to cancel the report process.\n" + await message.channel.send(reply) + return + + author_id = message.author.id + responses = [] + + # Only respond to messages if they're part of a reporting flow + if author_id not in self.reports and not message.content.startswith(Report.START_KEYWORD): + return + + # If we don't currently have an active report for this user, add one + if author_id not in self.reports: + self.reports[author_id] = Report(self) + + # If we are starting a report + responses = await self.reports[author_id].handle_message(message) + + ## report.py updates state, and below, we route our response based on that state + + if self.reports[author_id].is_awaiting_message(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_reason(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_political_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_healthl_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_harmful_content_status(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_filter_action(): + for r in responses: + await message.channel.send(r) + + # if self.reports[author_id].harm_identified(): + # reply = responses[0] + # harm = responses[1] + # if harm: + # # TODO escalate (or simulate it) + # print("Escalating report") + # await message.channel.send(reply) + + # if self.reports[author_id].block_step(): + # reply = responses[0] + # block = responses[1] + # if block: + # # TODO block user (or simulate it) + # print("Blocking user") + # await message.channel.send(reply) + + # If the report is complete or cancelled, remove it from our map + if self.reports[author_id].is_report_complete(): + + reported_author = self.reports[author_id].get_reported_author() + reported_content = self.reports[author_id].get_reported_content() + report_type = self.reports[author_id].get_report_type() + disinfo_type = self.reports[author_id].get_disinfo_type() + disinfo_subtype = self.reports[author_id].get_disinfo_subtype() + imminent = self.reports[author_id].get_imminent() + priority = self.reports[author_id].get_priority() + id = self.report_id_counter + id += 1 + + for r in responses: + await message.channel.send(r) + + # Put the report in the mod channel + mod_channel = self.mod_channels[self.reports[author_id].get_message_guild_id()] + # todo are we worried about code injection via author name or content? + report_info_msg = MOD_TODO_START + " User " + message.author.name + " reported user " + str(reported_author) + "'s message.\n" + report_info_msg += "Here is the message: \n```" + str(reported_content) + "\n```" + report_info_msg += "Category: " + str(report_type) + " > " + str(disinfo_type) + " > " + str(disinfo_subtype) + "\n" + if imminent: + report_info_msg += "FLAG: Imminent " + imminent + " harm reported." + submitted_report = SubmittedReport(id, reported_author, reported_content, report_type, disinfo_type, disinfo_subtype) + self.report_queue.enqueue(submitted_report, priority) + + await mod_channel.send(report_info_msg) + + # remove + self.reports.pop(author_id) + + # ------ starter code relevant to MILESTONE 3: -------------- + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------- + + + async def handle_channel_message(self, message): + + if not message.channel.name == f'group-{self.group_num}': + return + + # ----- teddy: commented out to reduce clutter for milestone 2 since we are not doing auto flagging ------------ + # # Forward the message to the mod channel + # mod_channel = self.mod_channels[message.guild.id] + # await mod_channel.send(f'Forwarded message:\n{message.author.name}: "{message.content}"') + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------------------------------------------------------ + return + + async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): + # see https://discordpy.readthedocs.io/en/latest/api.html?highlight=on_reaction_add#discord.RawReactionActionEvent + mod_channel = self.mod_channels[message.guild.id] + + message = await mod_channel.fetch_message(payload.message_id) + + # Ignore messages that are not the bot's moderator to-do messages + if message.author.id != self.user.id or (not message.content.startswith(MOD_TODO_START)): + return + + # TODO IMPLEMENT MODERATOR FLOW HERE + + return + + def eval_text(self, message): + '''' + TODO: Once you know how you want to evaluate messages in your channel, + insert your code here! This will primarily be used in Milestone 3. + ''' + return message + + + def code_format(self, text): + '''' + TODO: Once you know how you want to show that a message has been + evaluated, insert your code here for formatting the string to be + shown in the mod channel. + ''' + #teddy: not sure if we need this function + return "Evaluated: '" + text+ "'" + + # def process_response(self, responses): + + # reply = responses["reply"] + # if not isinstance(reply, str): # just in case i forget brackets in report.py + # reply = [reply] + # del responses["reply"] + + # for key, value in responses.items(): # go through data (not including reply) + # if key not in self.current_report: # don't allow overwriting + # self.current_report[key] = value + + # return reply + + +client = ModBot() +client.run(discord_token) \ No newline at end of file diff --git a/.history/DiscordBot/bot_20250509132756.py b/.history/DiscordBot/bot_20250509132756.py new file mode 100644 index 00000000..56353661 --- /dev/null +++ b/.history/DiscordBot/bot_20250509132756.py @@ -0,0 +1,253 @@ +# bot.py +import discord +from discord.ext import commands +import os +import json +import logging +import re +import requests +from report import Report +from report_queue import SubmittedReport, PriorityReportQueue +import pdb + +# Set up logging to the console +logger = logging.getLogger('discord') +logger.setLevel(logging.DEBUG) +handler = logging.FileHandler(filename='discord.log', encoding='utf-8', mode='w') +handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s')) +logger.addHandler(handler) + +# There should be a file called 'tokens.json' inside the same folder as this file +token_path = 'tokens.json' +if not os.path.isfile(token_path): + raise Exception(f"{token_path} not found!") +with open(token_path) as f: + # If you get an error here, it means your token is formatted incorrectly. Did you put it in quotes? + tokens = json.load(f) + discord_token = tokens['discord'] + + +MOD_TODO_START = "---------------------------\nTODO" + + +class ModBot(discord.Client): + def __init__(self): + intents = discord.Intents.default() + intents.message_content = True + super().__init__(command_prefix='.', intents=intents) + self.group_num = None + self.mod_channels = {} # Map from guild to the mod channel id for that guild + self.reports = {} # Map from user IDs to the state of their report + self.report_id_counter = 0 + self.report_queue = PriorityReportQueue(3) # should equal the number of distinct priorities defined in Report.get_priority + + async def on_ready(self): + print(f'{self.user.name} has connected to Discord! It is these guilds:') + for guild in self.guilds: + print(f' - {guild.name}') + print('Press Ctrl-C to quit.') + + # Parse the group number out of the bot's name + match = re.search('[gG]roup (\d+) [bB]ot', self.user.name) + if match: + self.group_num = match.group(1) + else: + raise Exception("Group number not found in bot's name. Name format should be \"Group # Bot\".") + + # Find the mod channel in each guild that this bot should report to + for guild in self.guilds: + for channel in guild.text_channels: + if channel.name == f'group-{self.group_num}-mod': + self.mod_channels[guild.id] = channel + + + async def on_message(self, message): + ''' + This function is called whenever a message is sent in a channel that the bot can see (including DMs). + Currently the bot is configured to only handle messages that are sent over DMs or in your group's "group-#" channel. + ''' + # Ignore messages from the bot + if message.author.id == self.user.id: + return + + # Check if this message was sent in a server ("guild") or if it's a DM + if message.guild: + await self.handle_channel_message(message) + else: + await self.handle_dm(message) + + async def handle_dm(self, message): + # Handle a help message + if message.content == Report.HELP_KEYWORD: + reply = "Use the `report` command to begin the reporting process.\n" + reply += "Use the `cancel` command to cancel the report process.\n" + await message.channel.send(reply) + return + + author_id = message.author.id + responses = [] + + # Only respond to messages if they're part of a reporting flow + if author_id not in self.reports and not message.content.startswith(Report.START_KEYWORD): + return + + # If we don't currently have an active report for this user, add one + if author_id not in self.reports: + self.reports[author_id] = Report(self) + + # If we are starting a report + responses = await self.reports[author_id].handle_message(message) + + ## report.py updates state, and below, we route our response based on that state + + if self.reports[author_id].is_awaiting_message(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_reason(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_political_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_healthl_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_harmful_content_status(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_filter_action(): + for r in responses: + await message.channel.send(r) + + # if self.reports[author_id].harm_identified(): + # reply = responses[0] + # harm = responses[1] + # if harm: + # # TODO escalate (or simulate it) + # print("Escalating report") + # await message.channel.send(reply) + + # if self.reports[author_id].block_step(): + # reply = responses[0] + # block = responses[1] + # if block: + # # TODO block user (or simulate it) + # print("Blocking user") + # await message.channel.send(reply) + + # If the report is complete or cancelled, remove it from our map + if self.reports[author_id].is_report_complete(): + + reported_author = self.reports[author_id].get_reported_author() + reported_content = self.reports[author_id].get_reported_content() + report_type = self.reports[author_id].get_report_type() + disinfo_type = self.reports[author_id].get_disinfo_type() + disinfo_subtype = self.reports[author_id].get_disinfo_subtype() + imminent = self.reports[author_id].get_imminent() + priority = self.reports[author_id].get_priority() + id = self.report_id_counter + id += 1 + + for r in responses: + await message.channel.send(r) + + # Put the report in the mod channel + mod_channel = self.mod_channels[self.reports[author_id].get_message_guild_id()] + # todo are we worried about code injection via author name or content? + report_info_msg = MOD_TODO_START + " User " + message.author.name + " reported user " + str(reported_author) + "'s message.\n" + report_info_msg += "Here is the message: \n```" + str(reported_content) + "\n```" + report_info_msg += "Category: " + str(report_type) + " > " + str(disinfo_type) + " > " + str(disinfo_subtype) + "\n" + if imminent: + report_info_msg += "FLAG: Imminent " + imminent + " harm reported." + submitted_report = SubmittedReport(id, reported_author, reported_content, report_type, disinfo_type, disinfo_subtype) + self.report_queue.enqueue(submitted_report, priority) + + await mod_channel.send(report_info_msg) + + # remove + self.reports.pop(author_id) + + # ------ starter code relevant to MILESTONE 3: -------------- + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------- + + + async def handle_channel_message(self, message): + + if not message.channel.name == f'group-{self.group_num}': + return + + # moderator commands + if message.channel.name == f'group-{self.group_num}-mod': + if message.content == "report summary": + message.channel.send(self.report_queue.summary()) + elif message.content == "report display": + message.channel.send(self.report_queue.display()) + + + # ----- teddy: commented out to reduce clutter for milestone 2 since we are not doing auto flagging ------------ + # # Forward the message to the mod channel + # mod_channel = self.mod_channels[message.guild.id] + # await mod_channel.send(f'Forwarded message:\n{message.author.name}: "{message.content}"') + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------------------------------------------------------ + return + + async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): + # see https://discordpy.readthedocs.io/en/latest/api.html?highlight=on_reaction_add#discord.RawReactionActionEvent + mod_channel = self.mod_channels[message.guild.id] + + message = await mod_channel.fetch_message(payload.message_id) + + # Ignore messages that are not the bot's moderator to-do messages + if message.author.id != self.user.id or (not message.content.startswith(MOD_TODO_START)): + return + + # TODO IMPLEMENT MODERATOR FLOW HERE + + return + + def eval_text(self, message): + '''' + TODO: Once you know how you want to evaluate messages in your channel, + insert your code here! This will primarily be used in Milestone 3. + ''' + return message + + + def code_format(self, text): + '''' + TODO: Once you know how you want to show that a message has been + evaluated, insert your code here for formatting the string to be + shown in the mod channel. + ''' + #teddy: not sure if we need this function + return "Evaluated: '" + text+ "'" + + # def process_response(self, responses): + + # reply = responses["reply"] + # if not isinstance(reply, str): # just in case i forget brackets in report.py + # reply = [reply] + # del responses["reply"] + + # for key, value in responses.items(): # go through data (not including reply) + # if key not in self.current_report: # don't allow overwriting + # self.current_report[key] = value + + # return reply + + +client = ModBot() +client.run(discord_token) \ No newline at end of file diff --git a/.history/DiscordBot/bot_20250509133441.py b/.history/DiscordBot/bot_20250509133441.py new file mode 100644 index 00000000..56353661 --- /dev/null +++ b/.history/DiscordBot/bot_20250509133441.py @@ -0,0 +1,253 @@ +# bot.py +import discord +from discord.ext import commands +import os +import json +import logging +import re +import requests +from report import Report +from report_queue import SubmittedReport, PriorityReportQueue +import pdb + +# Set up logging to the console +logger = logging.getLogger('discord') +logger.setLevel(logging.DEBUG) +handler = logging.FileHandler(filename='discord.log', encoding='utf-8', mode='w') +handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s')) +logger.addHandler(handler) + +# There should be a file called 'tokens.json' inside the same folder as this file +token_path = 'tokens.json' +if not os.path.isfile(token_path): + raise Exception(f"{token_path} not found!") +with open(token_path) as f: + # If you get an error here, it means your token is formatted incorrectly. Did you put it in quotes? + tokens = json.load(f) + discord_token = tokens['discord'] + + +MOD_TODO_START = "---------------------------\nTODO" + + +class ModBot(discord.Client): + def __init__(self): + intents = discord.Intents.default() + intents.message_content = True + super().__init__(command_prefix='.', intents=intents) + self.group_num = None + self.mod_channels = {} # Map from guild to the mod channel id for that guild + self.reports = {} # Map from user IDs to the state of their report + self.report_id_counter = 0 + self.report_queue = PriorityReportQueue(3) # should equal the number of distinct priorities defined in Report.get_priority + + async def on_ready(self): + print(f'{self.user.name} has connected to Discord! It is these guilds:') + for guild in self.guilds: + print(f' - {guild.name}') + print('Press Ctrl-C to quit.') + + # Parse the group number out of the bot's name + match = re.search('[gG]roup (\d+) [bB]ot', self.user.name) + if match: + self.group_num = match.group(1) + else: + raise Exception("Group number not found in bot's name. Name format should be \"Group # Bot\".") + + # Find the mod channel in each guild that this bot should report to + for guild in self.guilds: + for channel in guild.text_channels: + if channel.name == f'group-{self.group_num}-mod': + self.mod_channels[guild.id] = channel + + + async def on_message(self, message): + ''' + This function is called whenever a message is sent in a channel that the bot can see (including DMs). + Currently the bot is configured to only handle messages that are sent over DMs or in your group's "group-#" channel. + ''' + # Ignore messages from the bot + if message.author.id == self.user.id: + return + + # Check if this message was sent in a server ("guild") or if it's a DM + if message.guild: + await self.handle_channel_message(message) + else: + await self.handle_dm(message) + + async def handle_dm(self, message): + # Handle a help message + if message.content == Report.HELP_KEYWORD: + reply = "Use the `report` command to begin the reporting process.\n" + reply += "Use the `cancel` command to cancel the report process.\n" + await message.channel.send(reply) + return + + author_id = message.author.id + responses = [] + + # Only respond to messages if they're part of a reporting flow + if author_id not in self.reports and not message.content.startswith(Report.START_KEYWORD): + return + + # If we don't currently have an active report for this user, add one + if author_id not in self.reports: + self.reports[author_id] = Report(self) + + # If we are starting a report + responses = await self.reports[author_id].handle_message(message) + + ## report.py updates state, and below, we route our response based on that state + + if self.reports[author_id].is_awaiting_message(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_reason(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_political_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_healthl_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_harmful_content_status(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_filter_action(): + for r in responses: + await message.channel.send(r) + + # if self.reports[author_id].harm_identified(): + # reply = responses[0] + # harm = responses[1] + # if harm: + # # TODO escalate (or simulate it) + # print("Escalating report") + # await message.channel.send(reply) + + # if self.reports[author_id].block_step(): + # reply = responses[0] + # block = responses[1] + # if block: + # # TODO block user (or simulate it) + # print("Blocking user") + # await message.channel.send(reply) + + # If the report is complete or cancelled, remove it from our map + if self.reports[author_id].is_report_complete(): + + reported_author = self.reports[author_id].get_reported_author() + reported_content = self.reports[author_id].get_reported_content() + report_type = self.reports[author_id].get_report_type() + disinfo_type = self.reports[author_id].get_disinfo_type() + disinfo_subtype = self.reports[author_id].get_disinfo_subtype() + imminent = self.reports[author_id].get_imminent() + priority = self.reports[author_id].get_priority() + id = self.report_id_counter + id += 1 + + for r in responses: + await message.channel.send(r) + + # Put the report in the mod channel + mod_channel = self.mod_channels[self.reports[author_id].get_message_guild_id()] + # todo are we worried about code injection via author name or content? + report_info_msg = MOD_TODO_START + " User " + message.author.name + " reported user " + str(reported_author) + "'s message.\n" + report_info_msg += "Here is the message: \n```" + str(reported_content) + "\n```" + report_info_msg += "Category: " + str(report_type) + " > " + str(disinfo_type) + " > " + str(disinfo_subtype) + "\n" + if imminent: + report_info_msg += "FLAG: Imminent " + imminent + " harm reported." + submitted_report = SubmittedReport(id, reported_author, reported_content, report_type, disinfo_type, disinfo_subtype) + self.report_queue.enqueue(submitted_report, priority) + + await mod_channel.send(report_info_msg) + + # remove + self.reports.pop(author_id) + + # ------ starter code relevant to MILESTONE 3: -------------- + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------- + + + async def handle_channel_message(self, message): + + if not message.channel.name == f'group-{self.group_num}': + return + + # moderator commands + if message.channel.name == f'group-{self.group_num}-mod': + if message.content == "report summary": + message.channel.send(self.report_queue.summary()) + elif message.content == "report display": + message.channel.send(self.report_queue.display()) + + + # ----- teddy: commented out to reduce clutter for milestone 2 since we are not doing auto flagging ------------ + # # Forward the message to the mod channel + # mod_channel = self.mod_channels[message.guild.id] + # await mod_channel.send(f'Forwarded message:\n{message.author.name}: "{message.content}"') + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------------------------------------------------------ + return + + async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): + # see https://discordpy.readthedocs.io/en/latest/api.html?highlight=on_reaction_add#discord.RawReactionActionEvent + mod_channel = self.mod_channels[message.guild.id] + + message = await mod_channel.fetch_message(payload.message_id) + + # Ignore messages that are not the bot's moderator to-do messages + if message.author.id != self.user.id or (not message.content.startswith(MOD_TODO_START)): + return + + # TODO IMPLEMENT MODERATOR FLOW HERE + + return + + def eval_text(self, message): + '''' + TODO: Once you know how you want to evaluate messages in your channel, + insert your code here! This will primarily be used in Milestone 3. + ''' + return message + + + def code_format(self, text): + '''' + TODO: Once you know how you want to show that a message has been + evaluated, insert your code here for formatting the string to be + shown in the mod channel. + ''' + #teddy: not sure if we need this function + return "Evaluated: '" + text+ "'" + + # def process_response(self, responses): + + # reply = responses["reply"] + # if not isinstance(reply, str): # just in case i forget brackets in report.py + # reply = [reply] + # del responses["reply"] + + # for key, value in responses.items(): # go through data (not including reply) + # if key not in self.current_report: # don't allow overwriting + # self.current_report[key] = value + + # return reply + + +client = ModBot() +client.run(discord_token) \ No newline at end of file diff --git a/.history/DiscordBot/bot_20250509133536.py b/.history/DiscordBot/bot_20250509133536.py new file mode 100644 index 00000000..842b93ab --- /dev/null +++ b/.history/DiscordBot/bot_20250509133536.py @@ -0,0 +1,254 @@ +# bot.py +import discord +from discord.ext import commands +import os +import json +import logging +import re +import requests +from report import Report +from report_queue import SubmittedReport, PriorityReportQueue +import pdb + +# Set up logging to the console +logger = logging.getLogger('discord') +logger.setLevel(logging.DEBUG) +handler = logging.FileHandler(filename='discord.log', encoding='utf-8', mode='w') +handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s')) +logger.addHandler(handler) + +# There should be a file called 'tokens.json' inside the same folder as this file +token_path = 'tokens.json' +if not os.path.isfile(token_path): + raise Exception(f"{token_path} not found!") +with open(token_path) as f: + # If you get an error here, it means your token is formatted incorrectly. Did you put it in quotes? + tokens = json.load(f) + discord_token = tokens['discord'] + + +MOD_TODO_START = "---------------------------\nTODO" + + +class ModBot(discord.Client): + def __init__(self): + intents = discord.Intents.default() + intents.message_content = True + super().__init__(command_prefix='.', intents=intents) + self.group_num = None + self.mod_channels = {} # Map from guild to the mod channel id for that guild + self.reports = {} # Map from user IDs to the state of their report + self.report_id_counter = 0 + # should equal the number of distinct priorities defined in Report.get_priority + self.report_queue = PriorityReportQueue(3, ["Imminent physical/mental harm", "Imminent financial/property harm", "Non-imminent"]) + + async def on_ready(self): + print(f'{self.user.name} has connected to Discord! It is these guilds:') + for guild in self.guilds: + print(f' - {guild.name}') + print('Press Ctrl-C to quit.') + + # Parse the group number out of the bot's name + match = re.search('[gG]roup (\d+) [bB]ot', self.user.name) + if match: + self.group_num = match.group(1) + else: + raise Exception("Group number not found in bot's name. Name format should be \"Group # Bot\".") + + # Find the mod channel in each guild that this bot should report to + for guild in self.guilds: + for channel in guild.text_channels: + if channel.name == f'group-{self.group_num}-mod': + self.mod_channels[guild.id] = channel + + + async def on_message(self, message): + ''' + This function is called whenever a message is sent in a channel that the bot can see (including DMs). + Currently the bot is configured to only handle messages that are sent over DMs or in your group's "group-#" channel. + ''' + # Ignore messages from the bot + if message.author.id == self.user.id: + return + + # Check if this message was sent in a server ("guild") or if it's a DM + if message.guild: + await self.handle_channel_message(message) + else: + await self.handle_dm(message) + + async def handle_dm(self, message): + # Handle a help message + if message.content == Report.HELP_KEYWORD: + reply = "Use the `report` command to begin the reporting process.\n" + reply += "Use the `cancel` command to cancel the report process.\n" + await message.channel.send(reply) + return + + author_id = message.author.id + responses = [] + + # Only respond to messages if they're part of a reporting flow + if author_id not in self.reports and not message.content.startswith(Report.START_KEYWORD): + return + + # If we don't currently have an active report for this user, add one + if author_id not in self.reports: + self.reports[author_id] = Report(self) + + # If we are starting a report + responses = await self.reports[author_id].handle_message(message) + + ## report.py updates state, and below, we route our response based on that state + + if self.reports[author_id].is_awaiting_message(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_reason(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_political_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_healthl_disinformation_type(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_harmful_content_status(): + for r in responses: + await message.channel.send(r) + + if self.reports[author_id].is_awaiting_filter_action(): + for r in responses: + await message.channel.send(r) + + # if self.reports[author_id].harm_identified(): + # reply = responses[0] + # harm = responses[1] + # if harm: + # # TODO escalate (or simulate it) + # print("Escalating report") + # await message.channel.send(reply) + + # if self.reports[author_id].block_step(): + # reply = responses[0] + # block = responses[1] + # if block: + # # TODO block user (or simulate it) + # print("Blocking user") + # await message.channel.send(reply) + + # If the report is complete or cancelled, remove it from our map + if self.reports[author_id].is_report_complete(): + + reported_author = self.reports[author_id].get_reported_author() + reported_content = self.reports[author_id].get_reported_content() + report_type = self.reports[author_id].get_report_type() + disinfo_type = self.reports[author_id].get_disinfo_type() + disinfo_subtype = self.reports[author_id].get_disinfo_subtype() + imminent = self.reports[author_id].get_imminent() + priority = self.reports[author_id].get_priority() + id = self.report_id_counter + id += 1 + + for r in responses: + await message.channel.send(r) + + # Put the report in the mod channel + mod_channel = self.mod_channels[self.reports[author_id].get_message_guild_id()] + # todo are we worried about code injection via author name or content? + report_info_msg = MOD_TODO_START + " User " + message.author.name + " reported user " + str(reported_author) + "'s message.\n" + report_info_msg += "Here is the message: \n```" + str(reported_content) + "\n```" + report_info_msg += "Category: " + str(report_type) + " > " + str(disinfo_type) + " > " + str(disinfo_subtype) + "\n" + if imminent: + report_info_msg += "FLAG: Imminent " + imminent + " harm reported." + submitted_report = SubmittedReport(id, reported_author, reported_content, report_type, disinfo_type, disinfo_subtype) + self.report_queue.enqueue(submitted_report, priority) + + await mod_channel.send(report_info_msg) + + # remove + self.reports.pop(author_id) + + # ------ starter code relevant to MILESTONE 3: -------------- + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------- + + + async def handle_channel_message(self, message): + + if not message.channel.name == f'group-{self.group_num}': + return + + # moderator commands + if message.channel.name == f'group-{self.group_num}-mod': + if message.content == "report summary": + message.channel.send(self.report_queue.summary()) + elif message.content == "report display": + message.channel.send(self.report_queue.display()) + + + # ----- teddy: commented out to reduce clutter for milestone 2 since we are not doing auto flagging ------------ + # # Forward the message to the mod channel + # mod_channel = self.mod_channels[message.guild.id] + # await mod_channel.send(f'Forwarded message:\n{message.author.name}: "{message.content}"') + # scores = self.eval_text(message.content) + # await mod_channel.send(self.code_format(scores)) + #------------------------------------------------------------------------------------------------ + return + + async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): + # see https://discordpy.readthedocs.io/en/latest/api.html?highlight=on_reaction_add#discord.RawReactionActionEvent + mod_channel = self.mod_channels[message.guild.id] + + message = await mod_channel.fetch_message(payload.message_id) + + # Ignore messages that are not the bot's moderator to-do messages + if message.author.id != self.user.id or (not message.content.startswith(MOD_TODO_START)): + return + + # TODO IMPLEMENT MODERATOR FLOW HERE + + return + + def eval_text(self, message): + '''' + TODO: Once you know how you want to evaluate messages in your channel, + insert your code here! This will primarily be used in Milestone 3. + ''' + return message + + + def code_format(self, text): + '''' + TODO: Once you know how you want to show that a message has been + evaluated, insert your code here for formatting the string to be + shown in the mod channel. + ''' + #teddy: not sure if we need this function + return "Evaluated: '" + text+ "'" + + # def process_response(self, responses): + + # reply = responses["reply"] + # if not isinstance(reply, str): # just in case i forget brackets in report.py + # reply = [reply] + # del responses["reply"] + + # for key, value in responses.items(): # go through data (not including reply) + # if key not in self.current_report: # don't allow overwriting + # self.current_report[key] = value + + # return reply + + +client = ModBot() +client.run(discord_token) \ No newline at end of file diff --git a/.history/DiscordBot/report_20250508231525.py b/.history/DiscordBot/report_20250508231525.py new file mode 100644 index 00000000..c391b916 --- /dev/null +++ b/.history/DiscordBot/report_20250508231525.py @@ -0,0 +1,426 @@ +from enum import Enum, auto +import discord +import re + +class State(Enum): + REPORT_START = auto() + AWAITING_MESSAGE = auto() + + AWAITING_REASON = auto() + AWAITING_DISINFORMATION_TYPE = auto() + AWAITING_POLITICAL_DISINFORMATION_TYPE =auto() + AWAITING_HEALTHL_DISINFORMATION_TYPE =auto() + AWAITING_FILTER_ACTION = auto() + AWAITING_HARMFUL_CONTENT_STATUS = auto() + + REPORT_COMPLETE = auto() + +class Report: + START_KEYWORD = "report" + CANCEL_KEYWORD = "cancel" + HELP_KEYWORD = "help" + + def __init__(self, client): + self.state = State.REPORT_START + self.client = client + self.message = None + + self.message_guild_id = None + self.reported_author = None + self.reported_content = None + self.report_type = None + self.disinfo_type = None + self.disinfo_subtype = None + self.filter = False + self.harmful = False + + async def handle_message(self, message): + ''' + This function makes up the meat of the user-side reporting flow. It defines how we transition between states and what + prompts to offer at each of those states. You're welcome to change anything you want; this skeleton is just here to + get you started and give you a model for working with Discord. + ''' + + if message.content == self.CANCEL_KEYWORD: + self.state = State.REPORT_COMPLETE + return ["Report cancelled."] + + if self.state == State.REPORT_START: + reply = "Thank you for starting the reporting process. " + reply += "Say `help` at any time for more information.\n\n" + reply += "Please copy paste the link to the message you want to report.\n" + reply += "You can obtain this link by right-clicking the message and clicking `Copy Message Link`." + self.state = State.AWAITING_MESSAGE + return [reply] + else: + if message.content == self.START_KEYWORD: + reply = "You currently have an active report open, the state is " + self.state.name + "." + return [reply] + + if self.state == State.AWAITING_MESSAGE: + # Parse out the three ID strings from the message link + m = re.search('/(\d+)/(\d+)/(\d+)', message.content) + if not m: + return ["I'm sorry, I couldn't read that link. Please try again or say `cancel` to cancel."] + + guild = self.client.get_guild(int(m.group(1))) + if not guild: + return ["I cannot accept reports of messages from guilds that I'm not in. Please have the guild owner add me to the guild and try again."] + + channel = guild.get_channel(int(m.group(2))) + if not channel: + return ["It seems this channel was deleted or never existed. Please try again or say `cancel` to cancel."] + + try: + message = await channel.fetch_message(int(m.group(3))) + except discord.errors.NotFound: + return ["It seems this message was deleted or never existed. Please try again or say `cancel` to cancel."] + + self.state = State.AWAITING_REASON + + # add guild ID so we know where to send the moderation todo + self.message_guild_id = message.guild.id + + self.reported_author = message.author.name + self.reported_content = message.content + + reply = "I found this message:```" + message.author.name + ": " + message.content + "```\n" + reply += "Please select the reason for reporting this message by typing the corresponding number:\n" + reply += "1. Disinformation\n" + reply += "2. Other\n" + return [reply] + + if self.state == State.AWAITING_REASON: + # Process user's report reason + + if message.content == "1": + # Handling disinformation + self.report_type = "Disinformation" + self.state = State.AWAITING_DISINFORMATION_TYPE + + reply = "You have selected " + self.report_type + ".\n" + reply += "Please select the type of disinformation by typing the corresponding number:\n" + reply += "1. Political Disinformation\n" + reply += "2. Health Disinformation\n" + reply += "3. Other Disinformation\n" + return [reply] + + elif message.content == "2" : + # Handling Other Abuse types + self.report_type = "Other" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content.", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + # elif message.content == "3" : + # # Handling Harassment + # self.report_type = "Harassment" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + # self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content.", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + + + # elif message.content == "4" : + # # Handling Spam + # self.report_type = "Spam" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + # self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + + else: + # Handling wrong report reason + reply = "Kindly enter a valid report reason by selecting the correponding number:\n" + reply += "1. Disinformation\n" + reply += "2. Other\n" + reply += "Please try again or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_DISINFORMATION_TYPE : + # Process Disinformation options + + if message.content == "1": + # Handle political disinformation + self.state = State.AWAITING_POLITICAL_DISINFORMATION_TYPE + self.disinfo_type = "Political Disinformation" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Please select the type of political Disinformation by typing the corresponding number:\n" + reply += "1. Election/Campaign Misinformation\n" + reply += "2. Government/Civic Services\n" + reply += "3. Manipulated Photos/Video\n" + reply += "4. Other\n" + return [reply] + + elif message.content == "2" : + # Handle Health Disinformation + self.state = State.AWAITING_HEALTHL_DISINFORMATION_TYPE + self.disinfo_type = "Health Disinformation" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Please select the type of health disinformation by typing the corresponding number:\n" + reply += "1. Vaccines\n" + reply += "2. Cures and Treatments\n" + reply += "3. Mental Health\n" + reply += "4. Other\n" + return [reply] + + + elif message.content == "3" : + # Handle other Disinformation + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + self.disinfo_type = "Other Disinformation" + self.disinfo_subtype = "[out of scope of project]" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong disinformation type + reply = "Kindly enter a valid disinformation type by selecting the correponding number:\n" + reply += "1. Political Disinformation\n" + reply += "2. Health Disinformation\n" + reply += "3. Other Disinformation\n" + reply += "Please try again or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_POLITICAL_DISINFORMATION_TYPE : + # Process political disinformation options + + if message.content == "1": + # Handling Election/Campaign Misinformation + self.disinfo_subtype = "Election/Campaign Misinformation" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "2": + # Handling Government/Civic Services + self.disinfo_subtype = "Government/Civic Services" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "3": + # Handling Manipulated Photos/Video + self.disinfo_subtype = "Manipulated Photos/Video" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "4": + # Handling Other + self.disinfo_subtype = "Other" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong political disinformation type + reply = "Please select the type of political Disinformation by typing the corresponding number:\n" + reply += "1. Election/Campaign Misinformation\n" + reply += "2. Government/Civic Services\n" + reply += "3. Manipulated Photos/Video\n" + reply += "4. Other\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + if self.state == State.AWAITING_HEALTHL_DISINFORMATION_TYPE: + # Process health disinformation options + + if message.content == "1": + # Handling Vaccines + self.disinfo_subtype = "Vaccines" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "2": + # Handling Cures and Treatments + self.disinfo_subtype = "Cures and Treatments" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "3": + # Handling Mental Health + self.disinfo_subtype = "Mental Health" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "4": + # Handling Other + self.disinfo_subtype = "Other" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong health disinformation type + reply = "Please select the type of health Disinformation by typing the corresponding number:\n" + reply += "1. Vaccines\n" + reply += "2. Cures and Treatments\n" + reply += "3. Mental Health\n" + reply += "4. Other\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + if self.state == State.AWAITING_HARMFUL_CONTENT_STATUS: + # Handle decision making on whether content is harmful + + if message.content == "1" : + # No harmful content + self.state = State.AWAITING_FILTER_ACTION + reply = "Please indicate if you would like to block content from this account on your feed. Select the correponding number:\n" + reply += "1. No \n" + reply += "2. Yes \n" + return [reply] + + elif message.content in ["2", "3", "4"] : + # Harmful content + self.harmful = True + self.state = State.AWAITING_FILTER_ACTION + reply = "Thank you. Our team has been notified.\n" + reply += "Please indicate if you would like to block content from this account on your feed. Select the correponding number:\n" + reply += "1. No \n" + reply += "2. Yes \n" + return [reply] + + else: + # Handle wrong response to harmful prompt + reply = "Kindly indicate if this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + + if self.state == State.AWAITING_FILTER_ACTION: + # Handling responses to filter account content + + if message.content == "1": + # Handle no content filtering action + self.state = State.REPORT_COMPLETE + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + elif message.content == "2": + # Handle content filtering action + self.filter = True + self.state = State.REPORT_COMPLETE + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + else: + # wrong option for account filtering prompt + reply = "Would you like to filter content from this account on your feed? Select the correponding number:\n" + reply += "1. Yes\n" + reply += "2. No\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + +# if self.state == State.BLOCK_STEP: +# # if user wants to block then block +# user_wants_to_block = True +# return [user_wants_to_block] + + return {} + + #getters for state + def get_message_guild_id(self): + return self.message_guild_id + def get_reported_author(self): + return self.reported_author + def get_reported_content(self): + return self.reported_content + def get_report_type(self): + return self.report_type + def get_disinfo_type(self): + return self.disinfo_type + def get_disinfo_subtype(self): + return self.disinfo_subtype + def get_filter(self): + return self.filter + + def is_report_start(self): + return self.state == State.REPORT_START + def is_awaiting_message(self): + return self.state == State.AWAITING_MESSAGE + def is_awaiting_reason(self): + return self.state == State.AWAITING_REASON + def is_awaiting_disinformation_type(self): + return self.state == State.AWAITING_DISINFORMATION_TYPE + def is_awaiting_political_disinformation_type(self): + return self.state == State.AWAITING_POLITICAL_DISINFORMATION_TYPE + def is_awaiting_healthl_disinformation_type(self): + return self.state == State.AWAITING_HEALTHL_DISINFORMATION_TYPE + def is_awaiting_harmful_content_status(self): + return self.state == State.AWAITING_HARMFUL_CONTENT_STATUS + def is_awaiting_filter_action(self): + return self.state == State.AWAITING_FILTER_ACTION + # def block_step(self): + # return self.state == State.BLOCK_STEP + def is_report_complete(self): + return self.state == State.REPORT_COMPLETE + diff --git a/.history/DiscordBot/report_20250509105254.py b/.history/DiscordBot/report_20250509105254.py new file mode 100644 index 00000000..aa024a9f --- /dev/null +++ b/.history/DiscordBot/report_20250509105254.py @@ -0,0 +1,427 @@ +from enum import Enum, auto +import discord +import re + +class State(Enum): + REPORT_START = auto() + AWAITING_MESSAGE = auto() + + AWAITING_REASON = auto() + AWAITING_DISINFORMATION_TYPE = auto() + AWAITING_POLITICAL_DISINFORMATION_TYPE =auto() + AWAITING_HEALTHL_DISINFORMATION_TYPE =auto() + AWAITING_FILTER_ACTION = auto() + AWAITING_HARMFUL_CONTENT_STATUS = auto() + + REPORT_COMPLETE = auto() + +class Report: + START_KEYWORD = "report" + CANCEL_KEYWORD = "cancel" + HELP_KEYWORD = "help" + + def __init__(self, client): + self.state = State.REPORT_START + self.client = client + self.message = None + + self.message_guild_id = None + self.reported_author = None + self.reported_content = None + self.report_type = None + self.disinfo_type = None + self.disinfo_subtype = None + self.filter = False + self.harmful = False + + async def handle_message(self, message): + ''' + This function makes up the meat of the user-side reporting flow. It defines how we transition between states and what + prompts to offer at each of those states. You're welcome to change anything you want; this skeleton is just here to + get you started and give you a model for working with Discord. + ''' + + if message.content == self.CANCEL_KEYWORD: + self.state = State.REPORT_COMPLETE + return ["Report cancelled."] + + if self.state == State.REPORT_START: + reply = "Thank you for starting the reporting process. " + reply += "Say `help` at any time for more information.\n\n" + reply += "Please copy paste the link to the message you want to report.\n" + reply += "You can obtain this link by right-clicking the message and clicking `Copy Message Link`." + self.state = State.AWAITING_MESSAGE + return [reply] + else: + if message.content == self.START_KEYWORD: + reply = "You currently have an active report open, the status is " + self.state.name + "." + reply += "Please continue this report or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_MESSAGE: + # Parse out the three ID strings from the message link + m = re.search('/(\d+)/(\d+)/(\d+)', message.content) + if not m: + return ["I'm sorry, I couldn't read that link. Please try again or say `cancel` to cancel."] + + guild = self.client.get_guild(int(m.group(1))) + if not guild: + return ["I cannot accept reports of messages from guilds that I'm not in. Please have the guild owner add me to the guild and try again."] + + channel = guild.get_channel(int(m.group(2))) + if not channel: + return ["It seems this channel was deleted or never existed. Please try again or say `cancel` to cancel."] + + try: + message = await channel.fetch_message(int(m.group(3))) + except discord.errors.NotFound: + return ["It seems this message was deleted or never existed. Please try again or say `cancel` to cancel."] + + self.state = State.AWAITING_REASON + + # add guild ID so we know where to send the moderation todo + self.message_guild_id = message.guild.id + + self.reported_author = message.author.name + self.reported_content = message.content + + reply = "I found this message:```" + message.author.name + ": " + message.content + "```\n" + reply += "Please select the reason for reporting this message by typing the corresponding number:\n" + reply += "1. Disinformation\n" + reply += "2. Other\n" + return [reply] + + if self.state == State.AWAITING_REASON: + # Process user's report reason + + if message.content == "1": + # Handling disinformation + self.report_type = "Disinformation" + self.state = State.AWAITING_DISINFORMATION_TYPE + + reply = "You have selected " + self.report_type + ".\n" + reply += "Please select the type of disinformation by typing the corresponding number:\n" + reply += "1. Political Disinformation\n" + reply += "2. Health Disinformation\n" + reply += "3. Other Disinformation\n" + return [reply] + + elif message.content == "2" : + # Handling Other Abuse types + self.report_type = "Other" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content.", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + # elif message.content == "3" : + # # Handling Harassment + # self.report_type = "Harassment" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + # self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content.", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + + + # elif message.content == "4" : + # # Handling Spam + # self.report_type = "Spam" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + # self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + + else: + # Handling wrong report reason + reply = "Kindly enter a valid report reason by selecting the correponding number:\n" + reply += "1. Disinformation\n" + reply += "2. Other\n" + reply += "Please try again or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_DISINFORMATION_TYPE : + # Process Disinformation options + + if message.content == "1": + # Handle political disinformation + self.state = State.AWAITING_POLITICAL_DISINFORMATION_TYPE + self.disinfo_type = "Political Disinformation" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Please select the type of political Disinformation by typing the corresponding number:\n" + reply += "1. Election/Campaign Misinformation\n" + reply += "2. Government/Civic Services\n" + reply += "3. Manipulated Photos/Video\n" + reply += "4. Other\n" + return [reply] + + elif message.content == "2" : + # Handle Health Disinformation + self.state = State.AWAITING_HEALTHL_DISINFORMATION_TYPE + self.disinfo_type = "Health Disinformation" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Please select the type of health disinformation by typing the corresponding number:\n" + reply += "1. Vaccines\n" + reply += "2. Cures and Treatments\n" + reply += "3. Mental Health\n" + reply += "4. Other\n" + return [reply] + + + elif message.content == "3" : + # Handle other Disinformation + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + self.disinfo_type = "Other Disinformation" + self.disinfo_subtype = "[out of scope of project]" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong disinformation type + reply = "Kindly enter a valid disinformation type by selecting the correponding number:\n" + reply += "1. Political Disinformation\n" + reply += "2. Health Disinformation\n" + reply += "3. Other Disinformation\n" + reply += "Please try again or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_POLITICAL_DISINFORMATION_TYPE : + # Process political disinformation options + + if message.content == "1": + # Handling Election/Campaign Misinformation + self.disinfo_subtype = "Election/Campaign Misinformation" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "2": + # Handling Government/Civic Services + self.disinfo_subtype = "Government/Civic Services" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "3": + # Handling Manipulated Photos/Video + self.disinfo_subtype = "Manipulated Photos/Video" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "4": + # Handling Other + self.disinfo_subtype = "Other" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong political disinformation type + reply = "Please select the type of political Disinformation by typing the corresponding number:\n" + reply += "1. Election/Campaign Misinformation\n" + reply += "2. Government/Civic Services\n" + reply += "3. Manipulated Photos/Video\n" + reply += "4. Other\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + if self.state == State.AWAITING_HEALTHL_DISINFORMATION_TYPE: + # Process health disinformation options + + if message.content == "1": + # Handling Vaccines + self.disinfo_subtype = "Vaccines" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "2": + # Handling Cures and Treatments + self.disinfo_subtype = "Cures and Treatments" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "3": + # Handling Mental Health + self.disinfo_subtype = "Mental Health" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "4": + # Handling Other + self.disinfo_subtype = "Other" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong health disinformation type + reply = "Please select the type of health Disinformation by typing the corresponding number:\n" + reply += "1. Vaccines\n" + reply += "2. Cures and Treatments\n" + reply += "3. Mental Health\n" + reply += "4. Other\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + if self.state == State.AWAITING_HARMFUL_CONTENT_STATUS: + # Handle decision making on whether content is harmful + + if message.content == "1" : + # No harmful content + self.state = State.AWAITING_FILTER_ACTION + reply = "Please indicate if you would like to block content from this account on your feed. Select the correponding number:\n" + reply += "1. No \n" + reply += "2. Yes \n" + return [reply] + + elif message.content in ["2", "3", "4"] : + # Harmful content + self.harmful = True + self.state = State.AWAITING_FILTER_ACTION + reply = "Thank you. Our team has been notified.\n" + reply += "Please indicate if you would like to block content from this account on your feed. Select the correponding number:\n" + reply += "1. No \n" + reply += "2. Yes \n" + return [reply] + + else: + # Handle wrong response to harmful prompt + reply = "Kindly indicate if this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + + if self.state == State.AWAITING_FILTER_ACTION: + # Handling responses to filter account content + + if message.content == "1": + # Handle no content filtering action + self.state = State.REPORT_COMPLETE + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + elif message.content == "2": + # Handle content filtering action + self.filter = True + self.state = State.REPORT_COMPLETE + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + else: + # wrong option for account filtering prompt + reply = "Would you like to filter content from this account on your feed? Select the correponding number:\n" + reply += "1. Yes\n" + reply += "2. No\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + +# if self.state == State.BLOCK_STEP: +# # if user wants to block then block +# user_wants_to_block = True +# return [user_wants_to_block] + + return {} + + #getters for state + def get_message_guild_id(self): + return self.message_guild_id + def get_reported_author(self): + return self.reported_author + def get_reported_content(self): + return self.reported_content + def get_report_type(self): + return self.report_type + def get_disinfo_type(self): + return self.disinfo_type + def get_disinfo_subtype(self): + return self.disinfo_subtype + def get_filter(self): + return self.filter + + def is_report_start(self): + return self.state == State.REPORT_START + def is_awaiting_message(self): + return self.state == State.AWAITING_MESSAGE + def is_awaiting_reason(self): + return self.state == State.AWAITING_REASON + def is_awaiting_disinformation_type(self): + return self.state == State.AWAITING_DISINFORMATION_TYPE + def is_awaiting_political_disinformation_type(self): + return self.state == State.AWAITING_POLITICAL_DISINFORMATION_TYPE + def is_awaiting_healthl_disinformation_type(self): + return self.state == State.AWAITING_HEALTHL_DISINFORMATION_TYPE + def is_awaiting_harmful_content_status(self): + return self.state == State.AWAITING_HARMFUL_CONTENT_STATUS + def is_awaiting_filter_action(self): + return self.state == State.AWAITING_FILTER_ACTION + # def block_step(self): + # return self.state == State.BLOCK_STEP + def is_report_complete(self): + return self.state == State.REPORT_COMPLETE + diff --git a/.history/DiscordBot/report_20250509105318.py b/.history/DiscordBot/report_20250509105318.py new file mode 100644 index 00000000..d4b65f7c --- /dev/null +++ b/.history/DiscordBot/report_20250509105318.py @@ -0,0 +1,427 @@ +from enum import Enum, auto +import discord +import re + +class State(Enum): + REPORT_START = auto() + AWAITING_MESSAGE = auto() + + AWAITING_REASON = auto() + AWAITING_DISINFORMATION_TYPE = auto() + AWAITING_POLITICAL_DISINFORMATION_TYPE =auto() + AWAITING_HEALTHL_DISINFORMATION_TYPE =auto() + AWAITING_FILTER_ACTION = auto() + AWAITING_HARMFUL_CONTENT_STATUS = auto() + + REPORT_COMPLETE = auto() + +class Report: + START_KEYWORD = "report" + CANCEL_KEYWORD = "cancel" + HELP_KEYWORD = "help" + + def __init__(self, client): + self.state = State.REPORT_START + self.client = client + self.message = None + + self.message_guild_id = None + self.reported_author = None + self.reported_content = None + self.report_type = None + self.disinfo_type = None + self.disinfo_subtype = None + self.filter = False + self.harmful = False + + async def handle_message(self, message): + ''' + This function makes up the meat of the user-side reporting flow. It defines how we transition between states and what + prompts to offer at each of those states. You're welcome to change anything you want; this skeleton is just here to + get you started and give you a model for working with Discord. + ''' + + if message.content == self.CANCEL_KEYWORD: + self.state = State.REPORT_COMPLETE + return ["Report cancelled."] + + if self.state == State.REPORT_START: + reply = "Thank you for starting the reporting process. " + reply += "Say `help` at any time for more information.\n\n" + reply += "Please copy paste the link to the message you want to report.\n" + reply += "You can obtain this link by right-clicking the message and clicking `Copy Message Link`." + self.state = State.AWAITING_MESSAGE + return [reply] + else: + if message.content == self.START_KEYWORD: + reply = "You currently have an active report open, the status is " + self.state.name + ". " + reply += "Please continue this report or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_MESSAGE: + # Parse out the three ID strings from the message link + m = re.search('/(\d+)/(\d+)/(\d+)', message.content) + if not m: + return ["I'm sorry, I couldn't read that link. Please try again or say `cancel` to cancel."] + + guild = self.client.get_guild(int(m.group(1))) + if not guild: + return ["I cannot accept reports of messages from guilds that I'm not in. Please have the guild owner add me to the guild and try again."] + + channel = guild.get_channel(int(m.group(2))) + if not channel: + return ["It seems this channel was deleted or never existed. Please try again or say `cancel` to cancel."] + + try: + message = await channel.fetch_message(int(m.group(3))) + except discord.errors.NotFound: + return ["It seems this message was deleted or never existed. Please try again or say `cancel` to cancel."] + + self.state = State.AWAITING_REASON + + # add guild ID so we know where to send the moderation todo + self.message_guild_id = message.guild.id + + self.reported_author = message.author.name + self.reported_content = message.content + + reply = "I found this message:```" + message.author.name + ": " + message.content + "```\n" + reply += "Please select the reason for reporting this message by typing the corresponding number:\n" + reply += "1. Disinformation\n" + reply += "2. Other\n" + return [reply] + + if self.state == State.AWAITING_REASON: + # Process user's report reason + + if message.content == "1": + # Handling disinformation + self.report_type = "Disinformation" + self.state = State.AWAITING_DISINFORMATION_TYPE + + reply = "You have selected " + self.report_type + ".\n" + reply += "Please select the type of disinformation by typing the corresponding number:\n" + reply += "1. Political Disinformation\n" + reply += "2. Health Disinformation\n" + reply += "3. Other Disinformation\n" + return [reply] + + elif message.content == "2" : + # Handling Other Abuse types + self.report_type = "Other" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content.", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + # elif message.content == "3" : + # # Handling Harassment + # self.report_type = "Harassment" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + # self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content.", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + + + # elif message.content == "4" : + # # Handling Spam + # self.report_type = "Spam" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + # self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + + else: + # Handling wrong report reason + reply = "Kindly enter a valid report reason by selecting the correponding number:\n" + reply += "1. Disinformation\n" + reply += "2. Other\n" + reply += "Please try again or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_DISINFORMATION_TYPE : + # Process Disinformation options + + if message.content == "1": + # Handle political disinformation + self.state = State.AWAITING_POLITICAL_DISINFORMATION_TYPE + self.disinfo_type = "Political Disinformation" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Please select the type of political Disinformation by typing the corresponding number:\n" + reply += "1. Election/Campaign Misinformation\n" + reply += "2. Government/Civic Services\n" + reply += "3. Manipulated Photos/Video\n" + reply += "4. Other\n" + return [reply] + + elif message.content == "2" : + # Handle Health Disinformation + self.state = State.AWAITING_HEALTHL_DISINFORMATION_TYPE + self.disinfo_type = "Health Disinformation" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Please select the type of health disinformation by typing the corresponding number:\n" + reply += "1. Vaccines\n" + reply += "2. Cures and Treatments\n" + reply += "3. Mental Health\n" + reply += "4. Other\n" + return [reply] + + + elif message.content == "3" : + # Handle other Disinformation + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + self.disinfo_type = "Other Disinformation" + self.disinfo_subtype = "[out of scope of project]" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong disinformation type + reply = "Kindly enter a valid disinformation type by selecting the correponding number:\n" + reply += "1. Political Disinformation\n" + reply += "2. Health Disinformation\n" + reply += "3. Other Disinformation\n" + reply += "Please try again or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_POLITICAL_DISINFORMATION_TYPE : + # Process political disinformation options + + if message.content == "1": + # Handling Election/Campaign Misinformation + self.disinfo_subtype = "Election/Campaign Misinformation" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "2": + # Handling Government/Civic Services + self.disinfo_subtype = "Government/Civic Services" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "3": + # Handling Manipulated Photos/Video + self.disinfo_subtype = "Manipulated Photos/Video" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "4": + # Handling Other + self.disinfo_subtype = "Other" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong political disinformation type + reply = "Please select the type of political Disinformation by typing the corresponding number:\n" + reply += "1. Election/Campaign Misinformation\n" + reply += "2. Government/Civic Services\n" + reply += "3. Manipulated Photos/Video\n" + reply += "4. Other\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + if self.state == State.AWAITING_HEALTHL_DISINFORMATION_TYPE: + # Process health disinformation options + + if message.content == "1": + # Handling Vaccines + self.disinfo_subtype = "Vaccines" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "2": + # Handling Cures and Treatments + self.disinfo_subtype = "Cures and Treatments" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "3": + # Handling Mental Health + self.disinfo_subtype = "Mental Health" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "4": + # Handling Other + self.disinfo_subtype = "Other" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong health disinformation type + reply = "Please select the type of health Disinformation by typing the corresponding number:\n" + reply += "1. Vaccines\n" + reply += "2. Cures and Treatments\n" + reply += "3. Mental Health\n" + reply += "4. Other\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + if self.state == State.AWAITING_HARMFUL_CONTENT_STATUS: + # Handle decision making on whether content is harmful + + if message.content == "1" : + # No harmful content + self.state = State.AWAITING_FILTER_ACTION + reply = "Please indicate if you would like to block content from this account on your feed. Select the correponding number:\n" + reply += "1. No \n" + reply += "2. Yes \n" + return [reply] + + elif message.content in ["2", "3", "4"] : + # Harmful content + self.harmful = True + self.state = State.AWAITING_FILTER_ACTION + reply = "Thank you. Our team has been notified.\n" + reply += "Please indicate if you would like to block content from this account on your feed. Select the correponding number:\n" + reply += "1. No \n" + reply += "2. Yes \n" + return [reply] + + else: + # Handle wrong response to harmful prompt + reply = "Kindly indicate if this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + + if self.state == State.AWAITING_FILTER_ACTION: + # Handling responses to filter account content + + if message.content == "1": + # Handle no content filtering action + self.state = State.REPORT_COMPLETE + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + elif message.content == "2": + # Handle content filtering action + self.filter = True + self.state = State.REPORT_COMPLETE + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + else: + # wrong option for account filtering prompt + reply = "Would you like to filter content from this account on your feed? Select the correponding number:\n" + reply += "1. Yes\n" + reply += "2. No\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + +# if self.state == State.BLOCK_STEP: +# # if user wants to block then block +# user_wants_to_block = True +# return [user_wants_to_block] + + return {} + + #getters for state + def get_message_guild_id(self): + return self.message_guild_id + def get_reported_author(self): + return self.reported_author + def get_reported_content(self): + return self.reported_content + def get_report_type(self): + return self.report_type + def get_disinfo_type(self): + return self.disinfo_type + def get_disinfo_subtype(self): + return self.disinfo_subtype + def get_filter(self): + return self.filter + + def is_report_start(self): + return self.state == State.REPORT_START + def is_awaiting_message(self): + return self.state == State.AWAITING_MESSAGE + def is_awaiting_reason(self): + return self.state == State.AWAITING_REASON + def is_awaiting_disinformation_type(self): + return self.state == State.AWAITING_DISINFORMATION_TYPE + def is_awaiting_political_disinformation_type(self): + return self.state == State.AWAITING_POLITICAL_DISINFORMATION_TYPE + def is_awaiting_healthl_disinformation_type(self): + return self.state == State.AWAITING_HEALTHL_DISINFORMATION_TYPE + def is_awaiting_harmful_content_status(self): + return self.state == State.AWAITING_HARMFUL_CONTENT_STATUS + def is_awaiting_filter_action(self): + return self.state == State.AWAITING_FILTER_ACTION + # def block_step(self): + # return self.state == State.BLOCK_STEP + def is_report_complete(self): + return self.state == State.REPORT_COMPLETE + diff --git a/.history/DiscordBot/report_20250509124520.py b/.history/DiscordBot/report_20250509124520.py new file mode 100644 index 00000000..c37314b4 --- /dev/null +++ b/.history/DiscordBot/report_20250509124520.py @@ -0,0 +1,429 @@ +from enum import Enum, auto +import discord +import re + +class State(Enum): + REPORT_START = auto() + AWAITING_MESSAGE = auto() + + AWAITING_REASON = auto() + AWAITING_DISINFORMATION_TYPE = auto() + AWAITING_POLITICAL_DISINFORMATION_TYPE =auto() + AWAITING_HEALTHL_DISINFORMATION_TYPE =auto() + AWAITING_FILTER_ACTION = auto() + AWAITING_HARMFUL_CONTENT_STATUS = auto() + + REPORT_COMPLETE = auto() + +class Report: + START_KEYWORD = "report" + CANCEL_KEYWORD = "cancel" + HELP_KEYWORD = "help" + + def __init__(self, client): + self.state = State.REPORT_START + self.client = client + self.message = None + + self.message_guild_id = None + self.reported_author = None + self.reported_content = None + self.report_type = None + self.disinfo_type = None + self.disinfo_subtype = None + self.filter = False + self.harmful = False + + async def handle_message(self, message): + ''' + This function makes up the meat of the user-side reporting flow. It defines how we transition between states and what + prompts to offer at each of those states. You're welcome to change anything you want; this skeleton is just here to + get you started and give you a model for working with Discord. + ''' + + if message.content == self.CANCEL_KEYWORD: + self.state = State.REPORT_COMPLETE + return ["Report cancelled."] + + if self.state == State.REPORT_START: + reply = "Thank you for starting the reporting process. " + reply += "Say `help` at any time for more information.\n\n" + reply += "Please copy paste the link to the message you want to report.\n" + reply += "You can obtain this link by right-clicking the message and clicking `Copy Message Link`." + self.state = State.AWAITING_MESSAGE + return [reply] + else: + if message.content == self.START_KEYWORD: + reply = "You currently have an active report open, the status is " + self.state.name + ". " + reply += "Please continue this report or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_MESSAGE: + # Parse out the three ID strings from the message link + m = re.search('/(\d+)/(\d+)/(\d+)', message.content) + if not m: + return ["I'm sorry, I couldn't read that link. Please try again or say `cancel` to cancel."] + + guild = self.client.get_guild(int(m.group(1))) + if not guild: + return ["I cannot accept reports of messages from guilds that I'm not in. Please have the guild owner add me to the guild and try again."] + + channel = guild.get_channel(int(m.group(2))) + if not channel: + return ["It seems this channel was deleted or never existed. Please try again or say `cancel` to cancel."] + + try: + message = await channel.fetch_message(int(m.group(3))) + except discord.errors.NotFound: + return ["It seems this message was deleted or never existed. Please try again or say `cancel` to cancel."] + + self.state = State.AWAITING_REASON + + # add guild ID so we know where to send the moderation todo + self.message_guild_id = message.guild.id + + self.reported_author = message.author.name + self.reported_content = message.content + + reply = "I found this message:```" + message.author.name + ": " + message.content + "```\n" + reply += "Please select the reason for reporting this message by typing the corresponding number:\n" + reply += "1. Disinformation\n" + reply += "2. Other\n" + return [reply] + + if self.state == State.AWAITING_REASON: + # Process user's report reason + + if message.content == "1": + # Handling disinformation + self.report_type = "Disinformation" + self.state = State.AWAITING_DISINFORMATION_TYPE + + reply = "You have selected " + self.report_type + ".\n" + reply += "Please select the type of disinformation by typing the corresponding number:\n" + reply += "1. Political Disinformation\n" + reply += "2. Health Disinformation\n" + reply += "3. Other Disinformation\n" + return [reply] + + elif message.content == "2" : + # Handling Other Abuse types + self.report_type = "Other" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content.", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + # elif message.content == "3" : + # # Handling Harassment + # self.report_type = "Harassment" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + # self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content.", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + + + # elif message.content == "4" : + # # Handling Spam + # self.report_type = "Spam" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + # self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + + else: + # Handling wrong report reason + reply = "Kindly enter a valid report reason by selecting the correponding number:\n" + reply += "1. Disinformation\n" + reply += "2. Other\n" + reply += "Please try again or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_DISINFORMATION_TYPE : + # Process Disinformation options + + if message.content == "1": + # Handle political disinformation + self.state = State.AWAITING_POLITICAL_DISINFORMATION_TYPE + self.disinfo_type = "Political Disinformation" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Please select the type of political Disinformation by typing the corresponding number:\n" + reply += "1. Election/Campaign Misinformation\n" + reply += "2. Government/Civic Services\n" + reply += "3. Manipulated Photos/Video\n" + reply += "4. Other\n" + return [reply] + + elif message.content == "2" : + # Handle Health Disinformation + self.state = State.AWAITING_HEALTHL_DISINFORMATION_TYPE + self.disinfo_type = "Health Disinformation" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Please select the type of health disinformation by typing the corresponding number:\n" + reply += "1. Vaccines\n" + reply += "2. Cures and Treatments\n" + reply += "3. Mental Health\n" + reply += "4. Other\n" + return [reply] + + + elif message.content == "3" : + # Handle other Disinformation + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + self.disinfo_type = "Other Disinformation" + self.disinfo_subtype = "[out of scope of project]" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong disinformation type + reply = "Kindly enter a valid disinformation type by selecting the correponding number:\n" + reply += "1. Political Disinformation\n" + reply += "2. Health Disinformation\n" + reply += "3. Other Disinformation\n" + reply += "Please try again or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_POLITICAL_DISINFORMATION_TYPE : + # Process political disinformation options + + if message.content == "1": + # Handling Election/Campaign Misinformation + self.disinfo_subtype = "Election/Campaign Misinformation" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "2": + # Handling Government/Civic Services + self.disinfo_subtype = "Government/Civic Services" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "3": + # Handling Manipulated Photos/Video + self.disinfo_subtype = "Manipulated Photos/Video" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "4": + # Handling Other + self.disinfo_subtype = "Other" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong political disinformation type + reply = "Please select the type of political Disinformation by typing the corresponding number:\n" + reply += "1. Election/Campaign Misinformation\n" + reply += "2. Government/Civic Services\n" + reply += "3. Manipulated Photos/Video\n" + reply += "4. Other\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + if self.state == State.AWAITING_HEALTHL_DISINFORMATION_TYPE: + # Process health disinformation options + + if message.content == "1": + # Handling Vaccines + self.disinfo_subtype = "Vaccines" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "2": + # Handling Cures and Treatments + self.disinfo_subtype = "Cures and Treatments" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "3": + # Handling Mental Health + self.disinfo_subtype = "Mental Health" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "4": + # Handling Other + self.disinfo_subtype = "Other" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong health disinformation type + reply = "Please select the type of health Disinformation by typing the corresponding number:\n" + reply += "1. Vaccines\n" + reply += "2. Cures and Treatments\n" + reply += "3. Mental Health\n" + reply += "4. Other\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + if self.state == State.AWAITING_HARMFUL_CONTENT_STATUS: + # Handle decision making on whether content is harmful + + if message.content == "1" : + # No harmful content + self.state = State.AWAITING_FILTER_ACTION + reply = "Please indicate if you would like to block content from this account on your feed. Select the correponding number:\n" + reply += "1. No \n" + reply += "2. Yes \n" + return [reply] + + elif message.content in ["2", "3", "4"] : + # Harmful content + self.harmful = True + self.state = State.AWAITING_FILTER_ACTION + reply = "Thank you. Our team has been notified.\n" + reply += "Please indicate if you would like to block content from this account on your feed. Select the correponding number:\n" + reply += "1. No \n" + reply += "2. Yes \n" + return [reply] + + else: + # Handle wrong response to harmful prompt + reply = "Kindly indicate if this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + + if self.state == State.AWAITING_FILTER_ACTION: + # Handling responses to filter account content + + if message.content == "1": + # Handle no content filtering action + self.state = State.REPORT_COMPLETE + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + elif message.content == "2": + # Handle content filtering action + self.filter = True + self.state = State.REPORT_COMPLETE + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + else: + # wrong option for account filtering prompt + reply = "Would you like to filter content from this account on your feed? Select the correponding number:\n" + reply += "1. Yes\n" + reply += "2. No\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + +# if self.state == State.BLOCK_STEP: +# # if user wants to block then block +# user_wants_to_block = True +# return [user_wants_to_block] + + return {} + + #getters for state + def get_message_guild_id(self): + return self.message_guild_id + def get_reported_author(self): + return self.reported_author + def get_reported_content(self): + return self.reported_content + def get_report_type(self): + return self.report_type + def get_disinfo_type(self): + return self.disinfo_type + def get_disinfo_subtype(self): + return self.disinfo_subtype + def get_harmful(self): + return self.harmful + def get_filter(self): + return self.filter + + def is_report_start(self): + return self.state == State.REPORT_START + def is_awaiting_message(self): + return self.state == State.AWAITING_MESSAGE + def is_awaiting_reason(self): + return self.state == State.AWAITING_REASON + def is_awaiting_disinformation_type(self): + return self.state == State.AWAITING_DISINFORMATION_TYPE + def is_awaiting_political_disinformation_type(self): + return self.state == State.AWAITING_POLITICAL_DISINFORMATION_TYPE + def is_awaiting_healthl_disinformation_type(self): + return self.state == State.AWAITING_HEALTHL_DISINFORMATION_TYPE + def is_awaiting_harmful_content_status(self): + return self.state == State.AWAITING_HARMFUL_CONTENT_STATUS + def is_awaiting_filter_action(self): + return self.state == State.AWAITING_FILTER_ACTION + # def block_step(self): + # return self.state == State.BLOCK_STEP + def is_report_complete(self): + return self.state == State.REPORT_COMPLETE + diff --git a/.history/DiscordBot/report_20250509124544.py b/.history/DiscordBot/report_20250509124544.py new file mode 100644 index 00000000..c37314b4 --- /dev/null +++ b/.history/DiscordBot/report_20250509124544.py @@ -0,0 +1,429 @@ +from enum import Enum, auto +import discord +import re + +class State(Enum): + REPORT_START = auto() + AWAITING_MESSAGE = auto() + + AWAITING_REASON = auto() + AWAITING_DISINFORMATION_TYPE = auto() + AWAITING_POLITICAL_DISINFORMATION_TYPE =auto() + AWAITING_HEALTHL_DISINFORMATION_TYPE =auto() + AWAITING_FILTER_ACTION = auto() + AWAITING_HARMFUL_CONTENT_STATUS = auto() + + REPORT_COMPLETE = auto() + +class Report: + START_KEYWORD = "report" + CANCEL_KEYWORD = "cancel" + HELP_KEYWORD = "help" + + def __init__(self, client): + self.state = State.REPORT_START + self.client = client + self.message = None + + self.message_guild_id = None + self.reported_author = None + self.reported_content = None + self.report_type = None + self.disinfo_type = None + self.disinfo_subtype = None + self.filter = False + self.harmful = False + + async def handle_message(self, message): + ''' + This function makes up the meat of the user-side reporting flow. It defines how we transition between states and what + prompts to offer at each of those states. You're welcome to change anything you want; this skeleton is just here to + get you started and give you a model for working with Discord. + ''' + + if message.content == self.CANCEL_KEYWORD: + self.state = State.REPORT_COMPLETE + return ["Report cancelled."] + + if self.state == State.REPORT_START: + reply = "Thank you for starting the reporting process. " + reply += "Say `help` at any time for more information.\n\n" + reply += "Please copy paste the link to the message you want to report.\n" + reply += "You can obtain this link by right-clicking the message and clicking `Copy Message Link`." + self.state = State.AWAITING_MESSAGE + return [reply] + else: + if message.content == self.START_KEYWORD: + reply = "You currently have an active report open, the status is " + self.state.name + ". " + reply += "Please continue this report or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_MESSAGE: + # Parse out the three ID strings from the message link + m = re.search('/(\d+)/(\d+)/(\d+)', message.content) + if not m: + return ["I'm sorry, I couldn't read that link. Please try again or say `cancel` to cancel."] + + guild = self.client.get_guild(int(m.group(1))) + if not guild: + return ["I cannot accept reports of messages from guilds that I'm not in. Please have the guild owner add me to the guild and try again."] + + channel = guild.get_channel(int(m.group(2))) + if not channel: + return ["It seems this channel was deleted or never existed. Please try again or say `cancel` to cancel."] + + try: + message = await channel.fetch_message(int(m.group(3))) + except discord.errors.NotFound: + return ["It seems this message was deleted or never existed. Please try again or say `cancel` to cancel."] + + self.state = State.AWAITING_REASON + + # add guild ID so we know where to send the moderation todo + self.message_guild_id = message.guild.id + + self.reported_author = message.author.name + self.reported_content = message.content + + reply = "I found this message:```" + message.author.name + ": " + message.content + "```\n" + reply += "Please select the reason for reporting this message by typing the corresponding number:\n" + reply += "1. Disinformation\n" + reply += "2. Other\n" + return [reply] + + if self.state == State.AWAITING_REASON: + # Process user's report reason + + if message.content == "1": + # Handling disinformation + self.report_type = "Disinformation" + self.state = State.AWAITING_DISINFORMATION_TYPE + + reply = "You have selected " + self.report_type + ".\n" + reply += "Please select the type of disinformation by typing the corresponding number:\n" + reply += "1. Political Disinformation\n" + reply += "2. Health Disinformation\n" + reply += "3. Other Disinformation\n" + return [reply] + + elif message.content == "2" : + # Handling Other Abuse types + self.report_type = "Other" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content.", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + # elif message.content == "3" : + # # Handling Harassment + # self.report_type = "Harassment" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + # self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content.", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + + + # elif message.content == "4" : + # # Handling Spam + # self.report_type = "Spam" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + # self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + + else: + # Handling wrong report reason + reply = "Kindly enter a valid report reason by selecting the correponding number:\n" + reply += "1. Disinformation\n" + reply += "2. Other\n" + reply += "Please try again or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_DISINFORMATION_TYPE : + # Process Disinformation options + + if message.content == "1": + # Handle political disinformation + self.state = State.AWAITING_POLITICAL_DISINFORMATION_TYPE + self.disinfo_type = "Political Disinformation" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Please select the type of political Disinformation by typing the corresponding number:\n" + reply += "1. Election/Campaign Misinformation\n" + reply += "2. Government/Civic Services\n" + reply += "3. Manipulated Photos/Video\n" + reply += "4. Other\n" + return [reply] + + elif message.content == "2" : + # Handle Health Disinformation + self.state = State.AWAITING_HEALTHL_DISINFORMATION_TYPE + self.disinfo_type = "Health Disinformation" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Please select the type of health disinformation by typing the corresponding number:\n" + reply += "1. Vaccines\n" + reply += "2. Cures and Treatments\n" + reply += "3. Mental Health\n" + reply += "4. Other\n" + return [reply] + + + elif message.content == "3" : + # Handle other Disinformation + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + self.disinfo_type = "Other Disinformation" + self.disinfo_subtype = "[out of scope of project]" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong disinformation type + reply = "Kindly enter a valid disinformation type by selecting the correponding number:\n" + reply += "1. Political Disinformation\n" + reply += "2. Health Disinformation\n" + reply += "3. Other Disinformation\n" + reply += "Please try again or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_POLITICAL_DISINFORMATION_TYPE : + # Process political disinformation options + + if message.content == "1": + # Handling Election/Campaign Misinformation + self.disinfo_subtype = "Election/Campaign Misinformation" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "2": + # Handling Government/Civic Services + self.disinfo_subtype = "Government/Civic Services" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "3": + # Handling Manipulated Photos/Video + self.disinfo_subtype = "Manipulated Photos/Video" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "4": + # Handling Other + self.disinfo_subtype = "Other" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong political disinformation type + reply = "Please select the type of political Disinformation by typing the corresponding number:\n" + reply += "1. Election/Campaign Misinformation\n" + reply += "2. Government/Civic Services\n" + reply += "3. Manipulated Photos/Video\n" + reply += "4. Other\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + if self.state == State.AWAITING_HEALTHL_DISINFORMATION_TYPE: + # Process health disinformation options + + if message.content == "1": + # Handling Vaccines + self.disinfo_subtype = "Vaccines" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "2": + # Handling Cures and Treatments + self.disinfo_subtype = "Cures and Treatments" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "3": + # Handling Mental Health + self.disinfo_subtype = "Mental Health" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "4": + # Handling Other + self.disinfo_subtype = "Other" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong health disinformation type + reply = "Please select the type of health Disinformation by typing the corresponding number:\n" + reply += "1. Vaccines\n" + reply += "2. Cures and Treatments\n" + reply += "3. Mental Health\n" + reply += "4. Other\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + if self.state == State.AWAITING_HARMFUL_CONTENT_STATUS: + # Handle decision making on whether content is harmful + + if message.content == "1" : + # No harmful content + self.state = State.AWAITING_FILTER_ACTION + reply = "Please indicate if you would like to block content from this account on your feed. Select the correponding number:\n" + reply += "1. No \n" + reply += "2. Yes \n" + return [reply] + + elif message.content in ["2", "3", "4"] : + # Harmful content + self.harmful = True + self.state = State.AWAITING_FILTER_ACTION + reply = "Thank you. Our team has been notified.\n" + reply += "Please indicate if you would like to block content from this account on your feed. Select the correponding number:\n" + reply += "1. No \n" + reply += "2. Yes \n" + return [reply] + + else: + # Handle wrong response to harmful prompt + reply = "Kindly indicate if this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + + if self.state == State.AWAITING_FILTER_ACTION: + # Handling responses to filter account content + + if message.content == "1": + # Handle no content filtering action + self.state = State.REPORT_COMPLETE + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + elif message.content == "2": + # Handle content filtering action + self.filter = True + self.state = State.REPORT_COMPLETE + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + else: + # wrong option for account filtering prompt + reply = "Would you like to filter content from this account on your feed? Select the correponding number:\n" + reply += "1. Yes\n" + reply += "2. No\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + +# if self.state == State.BLOCK_STEP: +# # if user wants to block then block +# user_wants_to_block = True +# return [user_wants_to_block] + + return {} + + #getters for state + def get_message_guild_id(self): + return self.message_guild_id + def get_reported_author(self): + return self.reported_author + def get_reported_content(self): + return self.reported_content + def get_report_type(self): + return self.report_type + def get_disinfo_type(self): + return self.disinfo_type + def get_disinfo_subtype(self): + return self.disinfo_subtype + def get_harmful(self): + return self.harmful + def get_filter(self): + return self.filter + + def is_report_start(self): + return self.state == State.REPORT_START + def is_awaiting_message(self): + return self.state == State.AWAITING_MESSAGE + def is_awaiting_reason(self): + return self.state == State.AWAITING_REASON + def is_awaiting_disinformation_type(self): + return self.state == State.AWAITING_DISINFORMATION_TYPE + def is_awaiting_political_disinformation_type(self): + return self.state == State.AWAITING_POLITICAL_DISINFORMATION_TYPE + def is_awaiting_healthl_disinformation_type(self): + return self.state == State.AWAITING_HEALTHL_DISINFORMATION_TYPE + def is_awaiting_harmful_content_status(self): + return self.state == State.AWAITING_HARMFUL_CONTENT_STATUS + def is_awaiting_filter_action(self): + return self.state == State.AWAITING_FILTER_ACTION + # def block_step(self): + # return self.state == State.BLOCK_STEP + def is_report_complete(self): + return self.state == State.REPORT_COMPLETE + diff --git a/.history/DiscordBot/report_20250509124556.py b/.history/DiscordBot/report_20250509124556.py new file mode 100644 index 00000000..6ea0d6f3 --- /dev/null +++ b/.history/DiscordBot/report_20250509124556.py @@ -0,0 +1,429 @@ +from enum import Enum, auto +import discord +import re + +class State(Enum): + REPORT_START = auto() + AWAITING_MESSAGE = auto() + + AWAITING_REASON = auto() + AWAITING_DISINFORMATION_TYPE = auto() + AWAITING_POLITICAL_DISINFORMATION_TYPE =auto() + AWAITING_HEALTHL_DISINFORMATION_TYPE =auto() + AWAITING_FILTER_ACTION = auto() + AWAITING_HARMFUL_CONTENT_STATUS = auto() + + REPORT_COMPLETE = auto() + +class Report: + START_KEYWORD = "report" + CANCEL_KEYWORD = "cancel" + HELP_KEYWORD = "help" + + def __init__(self, client): + self.state = State.REPORT_START + self.client = client + self.message = None + + self.message_guild_id = None + self.reported_author = None + self.reported_content = None + self.report_type = None + self.disinfo_type = None + self.disinfo_subtype = None + self.filter = False + self.harmful = None + + async def handle_message(self, message): + ''' + This function makes up the meat of the user-side reporting flow. It defines how we transition between states and what + prompts to offer at each of those states. You're welcome to change anything you want; this skeleton is just here to + get you started and give you a model for working with Discord. + ''' + + if message.content == self.CANCEL_KEYWORD: + self.state = State.REPORT_COMPLETE + return ["Report cancelled."] + + if self.state == State.REPORT_START: + reply = "Thank you for starting the reporting process. " + reply += "Say `help` at any time for more information.\n\n" + reply += "Please copy paste the link to the message you want to report.\n" + reply += "You can obtain this link by right-clicking the message and clicking `Copy Message Link`." + self.state = State.AWAITING_MESSAGE + return [reply] + else: + if message.content == self.START_KEYWORD: + reply = "You currently have an active report open, the status is " + self.state.name + ". " + reply += "Please continue this report or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_MESSAGE: + # Parse out the three ID strings from the message link + m = re.search('/(\d+)/(\d+)/(\d+)', message.content) + if not m: + return ["I'm sorry, I couldn't read that link. Please try again or say `cancel` to cancel."] + + guild = self.client.get_guild(int(m.group(1))) + if not guild: + return ["I cannot accept reports of messages from guilds that I'm not in. Please have the guild owner add me to the guild and try again."] + + channel = guild.get_channel(int(m.group(2))) + if not channel: + return ["It seems this channel was deleted or never existed. Please try again or say `cancel` to cancel."] + + try: + message = await channel.fetch_message(int(m.group(3))) + except discord.errors.NotFound: + return ["It seems this message was deleted or never existed. Please try again or say `cancel` to cancel."] + + self.state = State.AWAITING_REASON + + # add guild ID so we know where to send the moderation todo + self.message_guild_id = message.guild.id + + self.reported_author = message.author.name + self.reported_content = message.content + + reply = "I found this message:```" + message.author.name + ": " + message.content + "```\n" + reply += "Please select the reason for reporting this message by typing the corresponding number:\n" + reply += "1. Disinformation\n" + reply += "2. Other\n" + return [reply] + + if self.state == State.AWAITING_REASON: + # Process user's report reason + + if message.content == "1": + # Handling disinformation + self.report_type = "Disinformation" + self.state = State.AWAITING_DISINFORMATION_TYPE + + reply = "You have selected " + self.report_type + ".\n" + reply += "Please select the type of disinformation by typing the corresponding number:\n" + reply += "1. Political Disinformation\n" + reply += "2. Health Disinformation\n" + reply += "3. Other Disinformation\n" + return [reply] + + elif message.content == "2" : + # Handling Other Abuse types + self.report_type = "Other" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content.", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + # elif message.content == "3" : + # # Handling Harassment + # self.report_type = "Harassment" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + # self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content.", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + + + # elif message.content == "4" : + # # Handling Spam + # self.report_type = "Spam" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + # self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + + else: + # Handling wrong report reason + reply = "Kindly enter a valid report reason by selecting the correponding number:\n" + reply += "1. Disinformation\n" + reply += "2. Other\n" + reply += "Please try again or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_DISINFORMATION_TYPE : + # Process Disinformation options + + if message.content == "1": + # Handle political disinformation + self.state = State.AWAITING_POLITICAL_DISINFORMATION_TYPE + self.disinfo_type = "Political Disinformation" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Please select the type of political Disinformation by typing the corresponding number:\n" + reply += "1. Election/Campaign Misinformation\n" + reply += "2. Government/Civic Services\n" + reply += "3. Manipulated Photos/Video\n" + reply += "4. Other\n" + return [reply] + + elif message.content == "2" : + # Handle Health Disinformation + self.state = State.AWAITING_HEALTHL_DISINFORMATION_TYPE + self.disinfo_type = "Health Disinformation" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Please select the type of health disinformation by typing the corresponding number:\n" + reply += "1. Vaccines\n" + reply += "2. Cures and Treatments\n" + reply += "3. Mental Health\n" + reply += "4. Other\n" + return [reply] + + + elif message.content == "3" : + # Handle other Disinformation + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + self.disinfo_type = "Other Disinformation" + self.disinfo_subtype = "[out of scope of project]" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong disinformation type + reply = "Kindly enter a valid disinformation type by selecting the correponding number:\n" + reply += "1. Political Disinformation\n" + reply += "2. Health Disinformation\n" + reply += "3. Other Disinformation\n" + reply += "Please try again or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_POLITICAL_DISINFORMATION_TYPE : + # Process political disinformation options + + if message.content == "1": + # Handling Election/Campaign Misinformation + self.disinfo_subtype = "Election/Campaign Misinformation" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "2": + # Handling Government/Civic Services + self.disinfo_subtype = "Government/Civic Services" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "3": + # Handling Manipulated Photos/Video + self.disinfo_subtype = "Manipulated Photos/Video" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "4": + # Handling Other + self.disinfo_subtype = "Other" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong political disinformation type + reply = "Please select the type of political Disinformation by typing the corresponding number:\n" + reply += "1. Election/Campaign Misinformation\n" + reply += "2. Government/Civic Services\n" + reply += "3. Manipulated Photos/Video\n" + reply += "4. Other\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + if self.state == State.AWAITING_HEALTHL_DISINFORMATION_TYPE: + # Process health disinformation options + + if message.content == "1": + # Handling Vaccines + self.disinfo_subtype = "Vaccines" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "2": + # Handling Cures and Treatments + self.disinfo_subtype = "Cures and Treatments" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "3": + # Handling Mental Health + self.disinfo_subtype = "Mental Health" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "4": + # Handling Other + self.disinfo_subtype = "Other" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong health disinformation type + reply = "Please select the type of health Disinformation by typing the corresponding number:\n" + reply += "1. Vaccines\n" + reply += "2. Cures and Treatments\n" + reply += "3. Mental Health\n" + reply += "4. Other\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + if self.state == State.AWAITING_HARMFUL_CONTENT_STATUS: + # Handle decision making on whether content is harmful + + if message.content == "1" : + # No harmful content + self.state = State.AWAITING_FILTER_ACTION + reply = "Please indicate if you would like to block content from this account on your feed. Select the correponding number:\n" + reply += "1. No \n" + reply += "2. Yes \n" + return [reply] + + elif message.content in ["2", "3", "4"] : + # Harmful content + self.harmful = True + self.state = State.AWAITING_FILTER_ACTION + reply = "Thank you. Our team has been notified.\n" + reply += "Please indicate if you would like to block content from this account on your feed. Select the correponding number:\n" + reply += "1. No \n" + reply += "2. Yes \n" + return [reply] + + else: + # Handle wrong response to harmful prompt + reply = "Kindly indicate if this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + + if self.state == State.AWAITING_FILTER_ACTION: + # Handling responses to filter account content + + if message.content == "1": + # Handle no content filtering action + self.state = State.REPORT_COMPLETE + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + elif message.content == "2": + # Handle content filtering action + self.filter = True + self.state = State.REPORT_COMPLETE + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + else: + # wrong option for account filtering prompt + reply = "Would you like to filter content from this account on your feed? Select the correponding number:\n" + reply += "1. Yes\n" + reply += "2. No\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + +# if self.state == State.BLOCK_STEP: +# # if user wants to block then block +# user_wants_to_block = True +# return [user_wants_to_block] + + return {} + + #getters for state + def get_message_guild_id(self): + return self.message_guild_id + def get_reported_author(self): + return self.reported_author + def get_reported_content(self): + return self.reported_content + def get_report_type(self): + return self.report_type + def get_disinfo_type(self): + return self.disinfo_type + def get_disinfo_subtype(self): + return self.disinfo_subtype + def get_harmful(self): + return self.harmful + def get_filter(self): + return self.filter + + def is_report_start(self): + return self.state == State.REPORT_START + def is_awaiting_message(self): + return self.state == State.AWAITING_MESSAGE + def is_awaiting_reason(self): + return self.state == State.AWAITING_REASON + def is_awaiting_disinformation_type(self): + return self.state == State.AWAITING_DISINFORMATION_TYPE + def is_awaiting_political_disinformation_type(self): + return self.state == State.AWAITING_POLITICAL_DISINFORMATION_TYPE + def is_awaiting_healthl_disinformation_type(self): + return self.state == State.AWAITING_HEALTHL_DISINFORMATION_TYPE + def is_awaiting_harmful_content_status(self): + return self.state == State.AWAITING_HARMFUL_CONTENT_STATUS + def is_awaiting_filter_action(self): + return self.state == State.AWAITING_FILTER_ACTION + # def block_step(self): + # return self.state == State.BLOCK_STEP + def is_report_complete(self): + return self.state == State.REPORT_COMPLETE + diff --git a/.history/DiscordBot/report_20250509124712.py b/.history/DiscordBot/report_20250509124712.py new file mode 100644 index 00000000..1f55cc16 --- /dev/null +++ b/.history/DiscordBot/report_20250509124712.py @@ -0,0 +1,434 @@ +from enum import Enum, auto +import discord +import re + +class State(Enum): + REPORT_START = auto() + AWAITING_MESSAGE = auto() + + AWAITING_REASON = auto() + AWAITING_DISINFORMATION_TYPE = auto() + AWAITING_POLITICAL_DISINFORMATION_TYPE =auto() + AWAITING_HEALTHL_DISINFORMATION_TYPE =auto() + AWAITING_FILTER_ACTION = auto() + AWAITING_HARMFUL_CONTENT_STATUS = auto() + + REPORT_COMPLETE = auto() + +class Report: + START_KEYWORD = "report" + CANCEL_KEYWORD = "cancel" + HELP_KEYWORD = "help" + + def __init__(self, client): + self.state = State.REPORT_START + self.client = client + self.message = None + + self.message_guild_id = None + self.reported_author = None + self.reported_content = None + self.report_type = None + self.disinfo_type = None + self.disinfo_subtype = None + self.filter = False + self.harmful = None + + async def handle_message(self, message): + ''' + This function makes up the meat of the user-side reporting flow. It defines how we transition between states and what + prompts to offer at each of those states. You're welcome to change anything you want; this skeleton is just here to + get you started and give you a model for working with Discord. + ''' + + if message.content == self.CANCEL_KEYWORD: + self.state = State.REPORT_COMPLETE + return ["Report cancelled."] + + if self.state == State.REPORT_START: + reply = "Thank you for starting the reporting process. " + reply += "Say `help` at any time for more information.\n\n" + reply += "Please copy paste the link to the message you want to report.\n" + reply += "You can obtain this link by right-clicking the message and clicking `Copy Message Link`." + self.state = State.AWAITING_MESSAGE + return [reply] + else: + if message.content == self.START_KEYWORD: + reply = "You currently have an active report open, the status is " + self.state.name + ". " + reply += "Please continue this report or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_MESSAGE: + # Parse out the three ID strings from the message link + m = re.search('/(\d+)/(\d+)/(\d+)', message.content) + if not m: + return ["I'm sorry, I couldn't read that link. Please try again or say `cancel` to cancel."] + + guild = self.client.get_guild(int(m.group(1))) + if not guild: + return ["I cannot accept reports of messages from guilds that I'm not in. Please have the guild owner add me to the guild and try again."] + + channel = guild.get_channel(int(m.group(2))) + if not channel: + return ["It seems this channel was deleted or never existed. Please try again or say `cancel` to cancel."] + + try: + message = await channel.fetch_message(int(m.group(3))) + except discord.errors.NotFound: + return ["It seems this message was deleted or never existed. Please try again or say `cancel` to cancel."] + + self.state = State.AWAITING_REASON + + # add guild ID so we know where to send the moderation todo + self.message_guild_id = message.guild.id + + self.reported_author = message.author.name + self.reported_content = message.content + + reply = "I found this message:```" + message.author.name + ": " + message.content + "```\n" + reply += "Please select the reason for reporting this message by typing the corresponding number:\n" + reply += "1. Disinformation\n" + reply += "2. Other\n" + return [reply] + + if self.state == State.AWAITING_REASON: + # Process user's report reason + + if message.content == "1": + # Handling disinformation + self.report_type = "Disinformation" + self.state = State.AWAITING_DISINFORMATION_TYPE + + reply = "You have selected " + self.report_type + ".\n" + reply += "Please select the type of disinformation by typing the corresponding number:\n" + reply += "1. Political Disinformation\n" + reply += "2. Health Disinformation\n" + reply += "3. Other Disinformation\n" + return [reply] + + elif message.content == "2" : + # Handling Other Abuse types + self.report_type = "Other" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content.", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + # elif message.content == "3" : + # # Handling Harassment + # self.report_type = "Harassment" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + # self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content.", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + + + # elif message.content == "4" : + # # Handling Spam + # self.report_type = "Spam" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + # self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + + else: + # Handling wrong report reason + reply = "Kindly enter a valid report reason by selecting the correponding number:\n" + reply += "1. Disinformation\n" + reply += "2. Other\n" + reply += "Please try again or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_DISINFORMATION_TYPE : + # Process Disinformation options + + if message.content == "1": + # Handle political disinformation + self.state = State.AWAITING_POLITICAL_DISINFORMATION_TYPE + self.disinfo_type = "Political Disinformation" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Please select the type of political Disinformation by typing the corresponding number:\n" + reply += "1. Election/Campaign Misinformation\n" + reply += "2. Government/Civic Services\n" + reply += "3. Manipulated Photos/Video\n" + reply += "4. Other\n" + return [reply] + + elif message.content == "2" : + # Handle Health Disinformation + self.state = State.AWAITING_HEALTHL_DISINFORMATION_TYPE + self.disinfo_type = "Health Disinformation" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Please select the type of health disinformation by typing the corresponding number:\n" + reply += "1. Vaccines\n" + reply += "2. Cures and Treatments\n" + reply += "3. Mental Health\n" + reply += "4. Other\n" + return [reply] + + + elif message.content == "3" : + # Handle other Disinformation + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + self.disinfo_type = "Other Disinformation" + self.disinfo_subtype = "[out of scope of project]" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong disinformation type + reply = "Kindly enter a valid disinformation type by selecting the correponding number:\n" + reply += "1. Political Disinformation\n" + reply += "2. Health Disinformation\n" + reply += "3. Other Disinformation\n" + reply += "Please try again or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_POLITICAL_DISINFORMATION_TYPE : + # Process political disinformation options + + if message.content == "1": + # Handling Election/Campaign Misinformation + self.disinfo_subtype = "Election/Campaign Misinformation" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "2": + # Handling Government/Civic Services + self.disinfo_subtype = "Government/Civic Services" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "3": + # Handling Manipulated Photos/Video + self.disinfo_subtype = "Manipulated Photos/Video" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "4": + # Handling Other + self.disinfo_subtype = "Other" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong political disinformation type + reply = "Please select the type of political Disinformation by typing the corresponding number:\n" + reply += "1. Election/Campaign Misinformation\n" + reply += "2. Government/Civic Services\n" + reply += "3. Manipulated Photos/Video\n" + reply += "4. Other\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + if self.state == State.AWAITING_HEALTHL_DISINFORMATION_TYPE: + # Process health disinformation options + + if message.content == "1": + # Handling Vaccines + self.disinfo_subtype = "Vaccines" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "2": + # Handling Cures and Treatments + self.disinfo_subtype = "Cures and Treatments" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "3": + # Handling Mental Health + self.disinfo_subtype = "Mental Health" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "4": + # Handling Other + self.disinfo_subtype = "Other" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong health disinformation type + reply = "Please select the type of health Disinformation by typing the corresponding number:\n" + reply += "1. Vaccines\n" + reply += "2. Cures and Treatments\n" + reply += "3. Mental Health\n" + reply += "4. Other\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + if self.state == State.AWAITING_HARMFUL_CONTENT_STATUS: + # Handle decision making on whether content is harmful + + if message.content == "1" : + # No harmful content + self.state = State.AWAITING_FILTER_ACTION + reply = "Please indicate if you would like to block content from this account on your feed. Select the correponding number:\n" + reply += "1. No \n" + reply += "2. Yes \n" + return [reply] + + elif message.content in ["2", "3", "4"] : + # Harmful content + harm_dict = { + "2": "physical", + "3": "mental", + "4": "financial" + } + self.harmful = harm_dict[message.content] + self.state = State.AWAITING_FILTER_ACTION + reply = "Thank you. Our team has been notified.\n" + reply += "Please indicate if you would like to block content from this account on your feed. Select the correponding number:\n" + reply += "1. No \n" + reply += "2. Yes \n" + return [reply] + + else: + # Handle wrong response to harmful prompt + reply = "Kindly indicate if this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + + if self.state == State.AWAITING_FILTER_ACTION: + # Handling responses to filter account content + + if message.content == "1": + # Handle no content filtering action + self.state = State.REPORT_COMPLETE + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + elif message.content == "2": + # Handle content filtering action + self.filter = True + self.state = State.REPORT_COMPLETE + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + else: + # wrong option for account filtering prompt + reply = "Would you like to filter content from this account on your feed? Select the correponding number:\n" + reply += "1. Yes\n" + reply += "2. No\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + +# if self.state == State.BLOCK_STEP: +# # if user wants to block then block +# user_wants_to_block = True +# return [user_wants_to_block] + + return {} + + #getters for state + def get_message_guild_id(self): + return self.message_guild_id + def get_reported_author(self): + return self.reported_author + def get_reported_content(self): + return self.reported_content + def get_report_type(self): + return self.report_type + def get_disinfo_type(self): + return self.disinfo_type + def get_disinfo_subtype(self): + return self.disinfo_subtype + def get_harmful(self): + return self.harmful + def get_filter(self): + return self.filter + + def is_report_start(self): + return self.state == State.REPORT_START + def is_awaiting_message(self): + return self.state == State.AWAITING_MESSAGE + def is_awaiting_reason(self): + return self.state == State.AWAITING_REASON + def is_awaiting_disinformation_type(self): + return self.state == State.AWAITING_DISINFORMATION_TYPE + def is_awaiting_political_disinformation_type(self): + return self.state == State.AWAITING_POLITICAL_DISINFORMATION_TYPE + def is_awaiting_healthl_disinformation_type(self): + return self.state == State.AWAITING_HEALTHL_DISINFORMATION_TYPE + def is_awaiting_harmful_content_status(self): + return self.state == State.AWAITING_HARMFUL_CONTENT_STATUS + def is_awaiting_filter_action(self): + return self.state == State.AWAITING_FILTER_ACTION + # def block_step(self): + # return self.state == State.BLOCK_STEP + def is_report_complete(self): + return self.state == State.REPORT_COMPLETE + diff --git a/.history/DiscordBot/report_20250509124922.py b/.history/DiscordBot/report_20250509124922.py new file mode 100644 index 00000000..f5ca5686 --- /dev/null +++ b/.history/DiscordBot/report_20250509124922.py @@ -0,0 +1,434 @@ +from enum import Enum, auto +import discord +import re + +class State(Enum): + REPORT_START = auto() + AWAITING_MESSAGE = auto() + + AWAITING_REASON = auto() + AWAITING_DISINFORMATION_TYPE = auto() + AWAITING_POLITICAL_DISINFORMATION_TYPE =auto() + AWAITING_HEALTHL_DISINFORMATION_TYPE =auto() + AWAITING_FILTER_ACTION = auto() + AWAITING_HARMFUL_CONTENT_STATUS = auto() + + REPORT_COMPLETE = auto() + +class Report: + START_KEYWORD = "report" + CANCEL_KEYWORD = "cancel" + HELP_KEYWORD = "help" + + def __init__(self, client): + self.state = State.REPORT_START + self.client = client + self.message = None + + self.message_guild_id = None + self.reported_author = None + self.reported_content = None + self.report_type = None + self.disinfo_type = None + self.disinfo_subtype = None + self.filter = False + self.imminent = None + + async def handle_message(self, message): + ''' + This function makes up the meat of the user-side reporting flow. It defines how we transition between states and what + prompts to offer at each of those states. You're welcome to change anything you want; this skeleton is just here to + get you started and give you a model for working with Discord. + ''' + + if message.content == self.CANCEL_KEYWORD: + self.state = State.REPORT_COMPLETE + return ["Report cancelled."] + + if self.state == State.REPORT_START: + reply = "Thank you for starting the reporting process. " + reply += "Say `help` at any time for more information.\n\n" + reply += "Please copy paste the link to the message you want to report.\n" + reply += "You can obtain this link by right-clicking the message and clicking `Copy Message Link`." + self.state = State.AWAITING_MESSAGE + return [reply] + else: + if message.content == self.START_KEYWORD: + reply = "You currently have an active report open, the status is " + self.state.name + ". " + reply += "Please continue this report or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_MESSAGE: + # Parse out the three ID strings from the message link + m = re.search('/(\d+)/(\d+)/(\d+)', message.content) + if not m: + return ["I'm sorry, I couldn't read that link. Please try again or say `cancel` to cancel."] + + guild = self.client.get_guild(int(m.group(1))) + if not guild: + return ["I cannot accept reports of messages from guilds that I'm not in. Please have the guild owner add me to the guild and try again."] + + channel = guild.get_channel(int(m.group(2))) + if not channel: + return ["It seems this channel was deleted or never existed. Please try again or say `cancel` to cancel."] + + try: + message = await channel.fetch_message(int(m.group(3))) + except discord.errors.NotFound: + return ["It seems this message was deleted or never existed. Please try again or say `cancel` to cancel."] + + self.state = State.AWAITING_REASON + + # add guild ID so we know where to send the moderation todo + self.message_guild_id = message.guild.id + + self.reported_author = message.author.name + self.reported_content = message.content + + reply = "I found this message:```" + message.author.name + ": " + message.content + "```\n" + reply += "Please select the reason for reporting this message by typing the corresponding number:\n" + reply += "1. Disinformation\n" + reply += "2. Other\n" + return [reply] + + if self.state == State.AWAITING_REASON: + # Process user's report reason + + if message.content == "1": + # Handling disinformation + self.report_type = "Disinformation" + self.state = State.AWAITING_DISINFORMATION_TYPE + + reply = "You have selected " + self.report_type + ".\n" + reply += "Please select the type of disinformation by typing the corresponding number:\n" + reply += "1. Political Disinformation\n" + reply += "2. Health Disinformation\n" + reply += "3. Other Disinformation\n" + return [reply] + + elif message.content == "2" : + # Handling Other Abuse types + self.report_type = "Other" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content.", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + # elif message.content == "3" : + # # Handling Harassment + # self.report_type = "Harassment" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + # self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content.", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + + + # elif message.content == "4" : + # # Handling Spam + # self.report_type = "Spam" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + # self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + + else: + # Handling wrong report reason + reply = "Kindly enter a valid report reason by selecting the correponding number:\n" + reply += "1. Disinformation\n" + reply += "2. Other\n" + reply += "Please try again or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_DISINFORMATION_TYPE : + # Process Disinformation options + + if message.content == "1": + # Handle political disinformation + self.state = State.AWAITING_POLITICAL_DISINFORMATION_TYPE + self.disinfo_type = "Political Disinformation" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Please select the type of political Disinformation by typing the corresponding number:\n" + reply += "1. Election/Campaign Misinformation\n" + reply += "2. Government/Civic Services\n" + reply += "3. Manipulated Photos/Video\n" + reply += "4. Other\n" + return [reply] + + elif message.content == "2" : + # Handle Health Disinformation + self.state = State.AWAITING_HEALTHL_DISINFORMATION_TYPE + self.disinfo_type = "Health Disinformation" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Please select the type of health disinformation by typing the corresponding number:\n" + reply += "1. Vaccines\n" + reply += "2. Cures and Treatments\n" + reply += "3. Mental Health\n" + reply += "4. Other\n" + return [reply] + + + elif message.content == "3" : + # Handle other Disinformation + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + self.disinfo_type = "Other Disinformation" + self.disinfo_subtype = "[out of scope of project]" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong disinformation type + reply = "Kindly enter a valid disinformation type by selecting the correponding number:\n" + reply += "1. Political Disinformation\n" + reply += "2. Health Disinformation\n" + reply += "3. Other Disinformation\n" + reply += "Please try again or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_POLITICAL_DISINFORMATION_TYPE : + # Process political disinformation options + + if message.content == "1": + # Handling Election/Campaign Misinformation + self.disinfo_subtype = "Election/Campaign Misinformation" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "2": + # Handling Government/Civic Services + self.disinfo_subtype = "Government/Civic Services" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "3": + # Handling Manipulated Photos/Video + self.disinfo_subtype = "Manipulated Photos/Video" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "4": + # Handling Other + self.disinfo_subtype = "Other" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong political disinformation type + reply = "Please select the type of political Disinformation by typing the corresponding number:\n" + reply += "1. Election/Campaign Misinformation\n" + reply += "2. Government/Civic Services\n" + reply += "3. Manipulated Photos/Video\n" + reply += "4. Other\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + if self.state == State.AWAITING_HEALTHL_DISINFORMATION_TYPE: + # Process health disinformation options + + if message.content == "1": + # Handling Vaccines + self.disinfo_subtype = "Vaccines" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "2": + # Handling Cures and Treatments + self.disinfo_subtype = "Cures and Treatments" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "3": + # Handling Mental Health + self.disinfo_subtype = "Mental Health" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "4": + # Handling Other + self.disinfo_subtype = "Other" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong health disinformation type + reply = "Please select the type of health Disinformation by typing the corresponding number:\n" + reply += "1. Vaccines\n" + reply += "2. Cures and Treatments\n" + reply += "3. Mental Health\n" + reply += "4. Other\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + if self.state == State.AWAITING_HARMFUL_CONTENT_STATUS: + # Handle decision making on whether content is harmful + + if message.content == "1" : + # No harmful content + self.state = State.AWAITING_FILTER_ACTION + reply = "Please indicate if you would like to block content from this account on your feed. Select the correponding number:\n" + reply += "1. No \n" + reply += "2. Yes \n" + return [reply] + + elif message.content in ["2", "3", "4"] : + # Harmful content + harm_dict = { + "2": "physical", + "3": "mental", + "4": "financial" + } + self.imminent = harm_dict[message.content] + self.state = State.AWAITING_FILTER_ACTION + reply = "Thank you. Our team has been notified.\n" + reply += "Please indicate if you would like to block content from this account on your feed. Select the correponding number:\n" + reply += "1. No \n" + reply += "2. Yes \n" + return [reply] + + else: + # Handle wrong response to harmful prompt + reply = "Kindly indicate if this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + + if self.state == State.AWAITING_FILTER_ACTION: + # Handling responses to filter account content + + if message.content == "1": + # Handle no content filtering action + self.state = State.REPORT_COMPLETE + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + elif message.content == "2": + # Handle content filtering action + self.filter = True + self.state = State.REPORT_COMPLETE + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + else: + # wrong option for account filtering prompt + reply = "Would you like to filter content from this account on your feed? Select the correponding number:\n" + reply += "1. Yes\n" + reply += "2. No\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + +# if self.state == State.BLOCK_STEP: +# # if user wants to block then block +# user_wants_to_block = True +# return [user_wants_to_block] + + return {} + + #getters for state + def get_message_guild_id(self): + return self.message_guild_id + def get_reported_author(self): + return self.reported_author + def get_reported_content(self): + return self.reported_content + def get_report_type(self): + return self.report_type + def get_disinfo_type(self): + return self.disinfo_type + def get_disinfo_subtype(self): + return self.disinfo_subtype + def get_harmful(self): + return self.imminent + def get_filter(self): + return self.filter + + def is_report_start(self): + return self.state == State.REPORT_START + def is_awaiting_message(self): + return self.state == State.AWAITING_MESSAGE + def is_awaiting_reason(self): + return self.state == State.AWAITING_REASON + def is_awaiting_disinformation_type(self): + return self.state == State.AWAITING_DISINFORMATION_TYPE + def is_awaiting_political_disinformation_type(self): + return self.state == State.AWAITING_POLITICAL_DISINFORMATION_TYPE + def is_awaiting_healthl_disinformation_type(self): + return self.state == State.AWAITING_HEALTHL_DISINFORMATION_TYPE + def is_awaiting_harmful_content_status(self): + return self.state == State.AWAITING_HARMFUL_CONTENT_STATUS + def is_awaiting_filter_action(self): + return self.state == State.AWAITING_FILTER_ACTION + # def block_step(self): + # return self.state == State.BLOCK_STEP + def is_report_complete(self): + return self.state == State.REPORT_COMPLETE + diff --git a/.history/DiscordBot/report_20250509124933.py b/.history/DiscordBot/report_20250509124933.py new file mode 100644 index 00000000..cc6f7e3d --- /dev/null +++ b/.history/DiscordBot/report_20250509124933.py @@ -0,0 +1,434 @@ +from enum import Enum, auto +import discord +import re + +class State(Enum): + REPORT_START = auto() + AWAITING_MESSAGE = auto() + + AWAITING_REASON = auto() + AWAITING_DISINFORMATION_TYPE = auto() + AWAITING_POLITICAL_DISINFORMATION_TYPE =auto() + AWAITING_HEALTHL_DISINFORMATION_TYPE =auto() + AWAITING_FILTER_ACTION = auto() + AWAITING_HARMFUL_CONTENT_STATUS = auto() + + REPORT_COMPLETE = auto() + +class Report: + START_KEYWORD = "report" + CANCEL_KEYWORD = "cancel" + HELP_KEYWORD = "help" + + def __init__(self, client): + self.state = State.REPORT_START + self.client = client + self.message = None + + self.message_guild_id = None + self.reported_author = None + self.reported_content = None + self.report_type = None + self.disinfo_type = None + self.disinfo_subtype = None + self.filter = False + self.imminent = None + + async def handle_message(self, message): + ''' + This function makes up the meat of the user-side reporting flow. It defines how we transition between states and what + prompts to offer at each of those states. You're welcome to change anything you want; this skeleton is just here to + get you started and give you a model for working with Discord. + ''' + + if message.content == self.CANCEL_KEYWORD: + self.state = State.REPORT_COMPLETE + return ["Report cancelled."] + + if self.state == State.REPORT_START: + reply = "Thank you for starting the reporting process. " + reply += "Say `help` at any time for more information.\n\n" + reply += "Please copy paste the link to the message you want to report.\n" + reply += "You can obtain this link by right-clicking the message and clicking `Copy Message Link`." + self.state = State.AWAITING_MESSAGE + return [reply] + else: + if message.content == self.START_KEYWORD: + reply = "You currently have an active report open, the status is " + self.state.name + ". " + reply += "Please continue this report or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_MESSAGE: + # Parse out the three ID strings from the message link + m = re.search('/(\d+)/(\d+)/(\d+)', message.content) + if not m: + return ["I'm sorry, I couldn't read that link. Please try again or say `cancel` to cancel."] + + guild = self.client.get_guild(int(m.group(1))) + if not guild: + return ["I cannot accept reports of messages from guilds that I'm not in. Please have the guild owner add me to the guild and try again."] + + channel = guild.get_channel(int(m.group(2))) + if not channel: + return ["It seems this channel was deleted or never existed. Please try again or say `cancel` to cancel."] + + try: + message = await channel.fetch_message(int(m.group(3))) + except discord.errors.NotFound: + return ["It seems this message was deleted or never existed. Please try again or say `cancel` to cancel."] + + self.state = State.AWAITING_REASON + + # add guild ID so we know where to send the moderation todo + self.message_guild_id = message.guild.id + + self.reported_author = message.author.name + self.reported_content = message.content + + reply = "I found this message:```" + message.author.name + ": " + message.content + "```\n" + reply += "Please select the reason for reporting this message by typing the corresponding number:\n" + reply += "1. Disinformation\n" + reply += "2. Other\n" + return [reply] + + if self.state == State.AWAITING_REASON: + # Process user's report reason + + if message.content == "1": + # Handling disinformation + self.report_type = "Disinformation" + self.state = State.AWAITING_DISINFORMATION_TYPE + + reply = "You have selected " + self.report_type + ".\n" + reply += "Please select the type of disinformation by typing the corresponding number:\n" + reply += "1. Political Disinformation\n" + reply += "2. Health Disinformation\n" + reply += "3. Other Disinformation\n" + return [reply] + + elif message.content == "2" : + # Handling Other Abuse types + self.report_type = "Other" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content.", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + # elif message.content == "3" : + # # Handling Harassment + # self.report_type = "Harassment" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + # self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content.", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + + + # elif message.content == "4" : + # # Handling Spam + # self.report_type = "Spam" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + # self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + + else: + # Handling wrong report reason + reply = "Kindly enter a valid report reason by selecting the correponding number:\n" + reply += "1. Disinformation\n" + reply += "2. Other\n" + reply += "Please try again or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_DISINFORMATION_TYPE : + # Process Disinformation options + + if message.content == "1": + # Handle political disinformation + self.state = State.AWAITING_POLITICAL_DISINFORMATION_TYPE + self.disinfo_type = "Political Disinformation" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Please select the type of political Disinformation by typing the corresponding number:\n" + reply += "1. Election/Campaign Misinformation\n" + reply += "2. Government/Civic Services\n" + reply += "3. Manipulated Photos/Video\n" + reply += "4. Other\n" + return [reply] + + elif message.content == "2" : + # Handle Health Disinformation + self.state = State.AWAITING_HEALTHL_DISINFORMATION_TYPE + self.disinfo_type = "Health Disinformation" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Please select the type of health disinformation by typing the corresponding number:\n" + reply += "1. Vaccines\n" + reply += "2. Cures and Treatments\n" + reply += "3. Mental Health\n" + reply += "4. Other\n" + return [reply] + + + elif message.content == "3" : + # Handle other Disinformation + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + self.disinfo_type = "Other Disinformation" + self.disinfo_subtype = "[out of scope of project]" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong disinformation type + reply = "Kindly enter a valid disinformation type by selecting the correponding number:\n" + reply += "1. Political Disinformation\n" + reply += "2. Health Disinformation\n" + reply += "3. Other Disinformation\n" + reply += "Please try again or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_POLITICAL_DISINFORMATION_TYPE : + # Process political disinformation options + + if message.content == "1": + # Handling Election/Campaign Misinformation + self.disinfo_subtype = "Election/Campaign Misinformation" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "2": + # Handling Government/Civic Services + self.disinfo_subtype = "Government/Civic Services" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "3": + # Handling Manipulated Photos/Video + self.disinfo_subtype = "Manipulated Photos/Video" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "4": + # Handling Other + self.disinfo_subtype = "Other" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong political disinformation type + reply = "Please select the type of political Disinformation by typing the corresponding number:\n" + reply += "1. Election/Campaign Misinformation\n" + reply += "2. Government/Civic Services\n" + reply += "3. Manipulated Photos/Video\n" + reply += "4. Other\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + if self.state == State.AWAITING_HEALTHL_DISINFORMATION_TYPE: + # Process health disinformation options + + if message.content == "1": + # Handling Vaccines + self.disinfo_subtype = "Vaccines" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "2": + # Handling Cures and Treatments + self.disinfo_subtype = "Cures and Treatments" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "3": + # Handling Mental Health + self.disinfo_subtype = "Mental Health" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "4": + # Handling Other + self.disinfo_subtype = "Other" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong health disinformation type + reply = "Please select the type of health Disinformation by typing the corresponding number:\n" + reply += "1. Vaccines\n" + reply += "2. Cures and Treatments\n" + reply += "3. Mental Health\n" + reply += "4. Other\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + if self.state == State.AWAITING_HARMFUL_CONTENT_STATUS: + # Handle decision making on whether content is harmful + + if message.content == "1" : + # No harmful content + self.state = State.AWAITING_FILTER_ACTION + reply = "Please indicate if you would like to block content from this account on your feed. Select the correponding number:\n" + reply += "1. No \n" + reply += "2. Yes \n" + return [reply] + + elif message.content in ["2", "3", "4"] : + # Harmful content + harm_dict = { + "2": "physical", + "3": "mental", + "4": "financial" + } + self.imminent = harm_dict[message.content] + self.state = State.AWAITING_FILTER_ACTION + reply = "Thank you. Our team has been notified.\n" + reply += "Please indicate if you would like to block content from this account on your feed. Select the correponding number:\n" + reply += "1. No \n" + reply += "2. Yes \n" + return [reply] + + else: + # Handle wrong response to harmful prompt + reply = "Kindly indicate if this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + + if self.state == State.AWAITING_FILTER_ACTION: + # Handling responses to filter account content + + if message.content == "1": + # Handle no content filtering action + self.state = State.REPORT_COMPLETE + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + elif message.content == "2": + # Handle content filtering action + self.filter = True + self.state = State.REPORT_COMPLETE + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + else: + # wrong option for account filtering prompt + reply = "Would you like to filter content from this account on your feed? Select the correponding number:\n" + reply += "1. Yes\n" + reply += "2. No\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + +# if self.state == State.BLOCK_STEP: +# # if user wants to block then block +# user_wants_to_block = True +# return [user_wants_to_block] + + return {} + + #getters for state + def get_message_guild_id(self): + return self.message_guild_id + def get_reported_author(self): + return self.reported_author + def get_reported_content(self): + return self.reported_content + def get_report_type(self): + return self.report_type + def get_disinfo_type(self): + return self.disinfo_type + def get_disinfo_subtype(self): + return self.disinfo_subtype + def get_imminent(self): + return self.imminent + def get_filter(self): + return self.filter + + def is_report_start(self): + return self.state == State.REPORT_START + def is_awaiting_message(self): + return self.state == State.AWAITING_MESSAGE + def is_awaiting_reason(self): + return self.state == State.AWAITING_REASON + def is_awaiting_disinformation_type(self): + return self.state == State.AWAITING_DISINFORMATION_TYPE + def is_awaiting_political_disinformation_type(self): + return self.state == State.AWAITING_POLITICAL_DISINFORMATION_TYPE + def is_awaiting_healthl_disinformation_type(self): + return self.state == State.AWAITING_HEALTHL_DISINFORMATION_TYPE + def is_awaiting_harmful_content_status(self): + return self.state == State.AWAITING_HARMFUL_CONTENT_STATUS + def is_awaiting_filter_action(self): + return self.state == State.AWAITING_FILTER_ACTION + # def block_step(self): + # return self.state == State.BLOCK_STEP + def is_report_complete(self): + return self.state == State.REPORT_COMPLETE + diff --git a/.history/DiscordBot/report_20250509131005.py b/.history/DiscordBot/report_20250509131005.py new file mode 100644 index 00000000..01d75064 --- /dev/null +++ b/.history/DiscordBot/report_20250509131005.py @@ -0,0 +1,441 @@ +from enum import Enum, auto +import discord +import re + +class State(Enum): + REPORT_START = auto() + AWAITING_MESSAGE = auto() + + AWAITING_REASON = auto() + AWAITING_DISINFORMATION_TYPE = auto() + AWAITING_POLITICAL_DISINFORMATION_TYPE =auto() + AWAITING_HEALTHL_DISINFORMATION_TYPE =auto() + AWAITING_FILTER_ACTION = auto() + AWAITING_HARMFUL_CONTENT_STATUS = auto() + + REPORT_COMPLETE = auto() + +class Report: + START_KEYWORD = "report" + CANCEL_KEYWORD = "cancel" + HELP_KEYWORD = "help" + + def __init__(self, client): + self.state = State.REPORT_START + self.client = client + self.message = None + + self.message_guild_id = None + self.reported_author = None + self.reported_content = None + self.report_type = None + self.disinfo_type = None + self.disinfo_subtype = None + self.filter = False + self.imminent = None + + async def handle_message(self, message): + ''' + This function makes up the meat of the user-side reporting flow. It defines how we transition between states and what + prompts to offer at each of those states. You're welcome to change anything you want; this skeleton is just here to + get you started and give you a model for working with Discord. + ''' + + if message.content == self.CANCEL_KEYWORD: + self.state = State.REPORT_COMPLETE + return ["Report cancelled."] + + if self.state == State.REPORT_START: + reply = "Thank you for starting the reporting process. " + reply += "Say `help` at any time for more information.\n\n" + reply += "Please copy paste the link to the message you want to report.\n" + reply += "You can obtain this link by right-clicking the message and clicking `Copy Message Link`." + self.state = State.AWAITING_MESSAGE + return [reply] + else: + if message.content == self.START_KEYWORD: + reply = "You currently have an active report open, the status is " + self.state.name + ". " + reply += "Please continue this report or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_MESSAGE: + # Parse out the three ID strings from the message link + m = re.search('/(\d+)/(\d+)/(\d+)', message.content) + if not m: + return ["I'm sorry, I couldn't read that link. Please try again or say `cancel` to cancel."] + + guild = self.client.get_guild(int(m.group(1))) + if not guild: + return ["I cannot accept reports of messages from guilds that I'm not in. Please have the guild owner add me to the guild and try again."] + + channel = guild.get_channel(int(m.group(2))) + if not channel: + return ["It seems this channel was deleted or never existed. Please try again or say `cancel` to cancel."] + + try: + message = await channel.fetch_message(int(m.group(3))) + except discord.errors.NotFound: + return ["It seems this message was deleted or never existed. Please try again or say `cancel` to cancel."] + + self.state = State.AWAITING_REASON + + # add guild ID so we know where to send the moderation todo + self.message_guild_id = message.guild.id + + self.reported_author = message.author.name + self.reported_content = message.content + + reply = "I found this message:```" + message.author.name + ": " + message.content + "```\n" + reply += "Please select the reason for reporting this message by typing the corresponding number:\n" + reply += "1. Disinformation\n" + reply += "2. Other\n" + return [reply] + + if self.state == State.AWAITING_REASON: + # Process user's report reason + + if message.content == "1": + # Handling disinformation + self.report_type = "Disinformation" + self.state = State.AWAITING_DISINFORMATION_TYPE + + reply = "You have selected " + self.report_type + ".\n" + reply += "Please select the type of disinformation by typing the corresponding number:\n" + reply += "1. Political Disinformation\n" + reply += "2. Health Disinformation\n" + reply += "3. Other Disinformation\n" + return [reply] + + elif message.content == "2" : + # Handling Other Abuse types + self.report_type = "Other" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content.", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + # elif message.content == "3" : + # # Handling Harassment + # self.report_type = "Harassment" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + # self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content.", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + + + # elif message.content == "4" : + # # Handling Spam + # self.report_type = "Spam" + # self.disinfo_type = "[out of scope of project]" + # self.disinfo_subtype = "[out of scope of project]" + # self.state = State.REPORT_COMPLETE + # return [ + # "Thank you for reporting " + self.report_type + " content", + # "Our content moderation team will review the message and take action which may result in content or account removal." + # ] + + else: + # Handling wrong report reason + reply = "Kindly enter a valid report reason by selecting the correponding number:\n" + reply += "1. Disinformation\n" + reply += "2. Other\n" + reply += "Please try again or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_DISINFORMATION_TYPE : + # Process Disinformation options + + if message.content == "1": + # Handle political disinformation + self.state = State.AWAITING_POLITICAL_DISINFORMATION_TYPE + self.disinfo_type = "Political Disinformation" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Please select the type of political Disinformation by typing the corresponding number:\n" + reply += "1. Election/Campaign Misinformation\n" + reply += "2. Government/Civic Services\n" + reply += "3. Manipulated Photos/Video\n" + reply += "4. Other\n" + return [reply] + + elif message.content == "2" : + # Handle Health Disinformation + self.state = State.AWAITING_HEALTHL_DISINFORMATION_TYPE + self.disinfo_type = "Health Disinformation" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Please select the type of health disinformation by typing the corresponding number:\n" + reply += "1. Vaccines\n" + reply += "2. Cures and Treatments\n" + reply += "3. Mental Health\n" + reply += "4. Other\n" + return [reply] + + + elif message.content == "3" : + # Handle other Disinformation + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + self.disinfo_type = "Other Disinformation" + self.disinfo_subtype = "[out of scope of project]" + reply = "You have selected " + self.disinfo_type + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong disinformation type + reply = "Kindly enter a valid disinformation type by selecting the correponding number:\n" + reply += "1. Political Disinformation\n" + reply += "2. Health Disinformation\n" + reply += "3. Other Disinformation\n" + reply += "Please try again or say `cancel` to cancel.\n" + return [reply] + + if self.state == State.AWAITING_POLITICAL_DISINFORMATION_TYPE : + # Process political disinformation options + + if message.content == "1": + # Handling Election/Campaign Misinformation + self.disinfo_subtype = "Election/Campaign Misinformation" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "2": + # Handling Government/Civic Services + self.disinfo_subtype = "Government/Civic Services" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "3": + # Handling Manipulated Photos/Video + self.disinfo_subtype = "Manipulated Photos/Video" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "4": + # Handling Other + self.disinfo_subtype = "Other" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong political disinformation type + reply = "Please select the type of political Disinformation by typing the corresponding number:\n" + reply += "1. Election/Campaign Misinformation\n" + reply += "2. Government/Civic Services\n" + reply += "3. Manipulated Photos/Video\n" + reply += "4. Other\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + if self.state == State.AWAITING_HEALTHL_DISINFORMATION_TYPE: + # Process health disinformation options + + if message.content == "1": + # Handling Vaccines + self.disinfo_subtype = "Vaccines" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "2": + # Handling Cures and Treatments + self.disinfo_subtype = "Cures and Treatments" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "3": + # Handling Mental Health + self.disinfo_subtype = "Mental Health" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + elif message.content == "4": + # Handling Other + self.disinfo_subtype = "Other" + self.state = State.AWAITING_HARMFUL_CONTENT_STATUS + reply = "You have selected " + self.disinfo_subtype + ".\n" + reply += "Could this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + return [reply] + + else : + # Handling wrong health disinformation type + reply = "Please select the type of health Disinformation by typing the corresponding number:\n" + reply += "1. Vaccines\n" + reply += "2. Cures and Treatments\n" + reply += "3. Mental Health\n" + reply += "4. Other\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + if self.state == State.AWAITING_HARMFUL_CONTENT_STATUS: + # Handle decision making on whether content is harmful + + if message.content == "1" : + # No harmful content + self.state = State.AWAITING_FILTER_ACTION + reply = "Please indicate if you would like to block content from this account on your feed. Select the correponding number:\n" + reply += "1. No \n" + reply += "2. Yes \n" + return [reply] + + elif message.content in ["2", "3", "4"] : + # Harmful content + harm_dict = { + "2": "physical", + "3": "mental", + "4": "financial" + } + self.imminent = harm_dict[message.content] + self.state = State.AWAITING_FILTER_ACTION + reply = "Thank you. Our team has been notified.\n" + reply += "Please indicate if you would like to block content from this account on your feed. Select the correponding number:\n" + reply += "1. No \n" + reply += "2. Yes \n" + return [reply] + + else: + # Handle wrong response to harmful prompt + reply = "Kindly indicate if this content likely cause imminent harm to people or public safety? Select the correponding number:\n" + reply += "1. No.\n" + reply += "2. Yes, physical harm.\n" + reply += "3. Yes, mental harm.\n" + reply += "4. Yes, financial or property harm.\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + + + if self.state == State.AWAITING_FILTER_ACTION: + # Handling responses to filter account content + + if message.content == "1": + # Handle no content filtering action + self.state = State.REPORT_COMPLETE + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + elif message.content == "2": + # Handle content filtering action + self.filter = True + self.state = State.REPORT_COMPLETE + reply = "Thank you for reporting " + self.report_type + " content.\n" + reply += "Our content moderation team will review the message and take action which may result in content or account removal.\n" + return [reply] + + else: + # wrong option for account filtering prompt + reply = "Would you like to filter content from this account on your feed? Select the correponding number:\n" + reply += "1. Yes\n" + reply += "2. No\n" + reply += "Please try again or say `cancel` to cancel." + return [reply] + +# if self.state == State.BLOCK_STEP: +# # if user wants to block then block +# user_wants_to_block = True +# return [user_wants_to_block] + + return {} + + #getters for state + def get_message_guild_id(self): + return self.message_guild_id + def get_reported_author(self): + return self.reported_author + def get_reported_content(self): + return self.reported_content + def get_report_type(self): + return self.report_type + def get_disinfo_type(self): + return self.disinfo_type + def get_disinfo_subtype(self): + return self.disinfo_subtype + def get_imminent(self): + return self.imminent + def get_priority(self): # defining priorities, can be changed + if self.imminent in ["physical", "mental"]: + return 0 + elif self.imminent == "financial": + return 1 + else: + return 2 + def get_filter(self): + return self.filter + + def is_report_start(self): + return self.state == State.REPORT_START + def is_awaiting_message(self): + return self.state == State.AWAITING_MESSAGE + def is_awaiting_reason(self): + return self.state == State.AWAITING_REASON + def is_awaiting_disinformation_type(self): + return self.state == State.AWAITING_DISINFORMATION_TYPE + def is_awaiting_political_disinformation_type(self): + return self.state == State.AWAITING_POLITICAL_DISINFORMATION_TYPE + def is_awaiting_healthl_disinformation_type(self): + return self.state == State.AWAITING_HEALTHL_DISINFORMATION_TYPE + def is_awaiting_harmful_content_status(self): + return self.state == State.AWAITING_HARMFUL_CONTENT_STATUS + def is_awaiting_filter_action(self): + return self.state == State.AWAITING_FILTER_ACTION + # def block_step(self): + # return self.state == State.BLOCK_STEP + def is_report_complete(self): + return self.state == State.REPORT_COMPLETE + diff --git a/.history/DiscordBot/report_queue_20250509131250.py b/.history/DiscordBot/report_queue_20250509131250.py new file mode 100644 index 00000000..7be0e391 --- /dev/null +++ b/.history/DiscordBot/report_queue_20250509131250.py @@ -0,0 +1,30 @@ +from collections import deque() + +class SubmittedReport: + def __init__(self, author, content, type, subtype): + self.author = author + self.content = content + self.type = type + self.subtype = subtype + +class PriorityReportQueue: + def __init__(self, num_levels): + self.num_queues = num_levels + self.queues = [deque() for _ in range(num_levels)] + + def enqueue(self, report, priority): + if not (0 <= priority < len(self.queues)): + raise ValueError("Invalid priority level") + self.queues[priority].append(item) + + def dequeue(self): + for queue in self.queues: + if queue: + return queue.popleft() + raise IndexError("All queues are empty") + + def is_empty(self): + return all(len(q) == 0 for q in self.queues) + + def __getitem__(self, priority): + return list(self.queues[priority]) diff --git a/.history/DiscordBot/report_queue_20250509131330.py b/.history/DiscordBot/report_queue_20250509131330.py new file mode 100644 index 00000000..1998010f --- /dev/null +++ b/.history/DiscordBot/report_queue_20250509131330.py @@ -0,0 +1,30 @@ +from collections import deque() + +class SubmittedReport: + def __init__(self, author, content, type, subtype): + self.author = author + self.content = content + self.type = type + self.subtype = subtype + +class PriorityReportQueue: + def __init__(self, num_levels): + self.num_queues = num_levels + self.queues = [deque() for _ in range(num_levels)] + + def enqueue(self, report, priority): + if not (0 <= priority < len(self.queues)): + raise ValueError("Invalid priority level") + self.queues[priority].append(report) + + def dequeue(self): + for queue in self.queues: + if queue: + return queue.popleft() + raise IndexError("All queues are empty") + + def is_empty(self): + return all(len(q) == 0 for q in self.queues) + + def __getitem__(self, priority): + return list(self.queues[priority]) diff --git a/.history/DiscordBot/report_queue_20250509131820.py b/.history/DiscordBot/report_queue_20250509131820.py new file mode 100644 index 00000000..c8bc496e --- /dev/null +++ b/.history/DiscordBot/report_queue_20250509131820.py @@ -0,0 +1,34 @@ +from collections import deque + +class SubmittedReport: + def __init__(self, id, author, content, type, subtype): + self.author = author + self.id = id + self.content = content + self.type = type + self.subtype = subtype + +class PriorityReportQueue: + def __init__(self, num_levels): + self.num_queues = num_levels + self.queues = [deque() for _ in range(num_levels)] + + def enqueue(self, report, priority): + if not (0 <= priority < len(self.queues)): + raise ValueError("Invalid priority level") + self.queues[priority].append(report) + + def dequeue(self): + for queue in self.queues: + if queue: + return queue.popleft() + raise IndexError("All queues are empty") + + def is_empty(self): + return all(len(q) == 0 for q in self.queues) + + def __getitem__(self, priority): + return list(self.queues[priority]) + + def display(self): + diff --git a/.history/DiscordBot/report_queue_20250509132041.py b/.history/DiscordBot/report_queue_20250509132041.py new file mode 100644 index 00000000..9f1628e1 --- /dev/null +++ b/.history/DiscordBot/report_queue_20250509132041.py @@ -0,0 +1,34 @@ +from collections import deque + +class SubmittedReport: + def __init__(self, id, author, content, type, subtype): + self.author = author + self.id = id + self.content = content + self.type = type + self.subtype = subtype + +class PriorityReportQueue: + def __init__(self, num_levels, queue_names): + self.num_queues = num_levels + self.queues = [deque() for _ in range(num_levels)] + + def enqueue(self, report, priority): + if not (0 <= priority < len(self.queues)): + raise ValueError("Invalid priority level") + self.queues[priority].append(report) + + def dequeue(self): + for queue in self.queues: + if queue: + return queue.popleft() + raise IndexError("All queues are empty") + + def is_empty(self): + return all(len(q) == 0 for q in self.queues) + + def __getitem__(self, priority): + return list(self.queues[priority]) + + def summary(self): + diff --git a/.history/DiscordBot/report_queue_20250509132223.py b/.history/DiscordBot/report_queue_20250509132223.py new file mode 100644 index 00000000..7b3456d6 --- /dev/null +++ b/.history/DiscordBot/report_queue_20250509132223.py @@ -0,0 +1,37 @@ +from collections import deque + +class SubmittedReport: + def __init__(self, id, author, content, type, subtype): + self.author = author + self.id = id + self.content = content + self.type = type + self.subtype = subtype + +class PriorityReportQueue: + def __init__(self, num_levels, queue_names): + self.num_queues = num_levels + self.queue_names = queue_names + self.queues = [deque() for _ in range(num_levels)] + + def enqueue(self, report, priority): + if not (0 <= priority < len(self.queues)): + raise ValueError("Invalid priority level") + self.queues[priority].append(report) + + def dequeue(self): + for queue in self.queues: + if queue: + return queue.popleft() + raise IndexError("All queues are empty") + + def is_empty(self): + return all(len(q) == 0 for q in self.queues) + + def __getitem__(self, priority): + return list(self.queues[priority]) + + def summary(self): + for i in range(self.num_queues): + print(f"{self.queue_names[i]} queue has {len(self.queues[i])} reports") + diff --git a/.history/DiscordBot/report_queue_20250509132453.py b/.history/DiscordBot/report_queue_20250509132453.py new file mode 100644 index 00000000..e3810921 --- /dev/null +++ b/.history/DiscordBot/report_queue_20250509132453.py @@ -0,0 +1,45 @@ +from collections import deque + +class SubmittedReport: + def __init__(self, id, author, content, type, subtype): + self.author = author + self.id = id + self.content = content + self.type = type + self.subtype = subtype + +class PriorityReportQueue: + def __init__(self, num_levels, queue_names): + self.num_queues = num_levels + self.queue_names = queue_names + self.queues = [deque() for _ in range(num_levels)] + + def enqueue(self, report, priority): + if not (0 <= priority < len(self.queues)): + raise ValueError("Invalid priority level") + self.queues[priority].append(report) + + def dequeue(self): + for queue in self.queues: + if queue: + return queue.popleft() + raise IndexError("All queues are empty") + + def is_empty(self): + return all(len(q) == 0 for q in self.queues) + + def __getitem__(self, priority): + return list(self.queues[priority]) + + def summary(self): + out = "" + total = 0 + for i in range(self.num_queues): + out += f"Priority {i}: {self.queue_names[i]} queue has {len(self.queues[i])} reports.\n" + total += len(self.queues[i]) + out += f"In total, there are {total} pending reports" + return out + + def display(self): + + diff --git a/.history/DiscordBot/report_queue_20250509133058.py b/.history/DiscordBot/report_queue_20250509133058.py new file mode 100644 index 00000000..a20b2e3c --- /dev/null +++ b/.history/DiscordBot/report_queue_20250509133058.py @@ -0,0 +1,61 @@ +from collections import deque + +class SubmittedReport: + def __init__(self, id, author, content, type, subtype): + self.author = author + self.id = id + self.content = content + self.type = type + self.subtype = subtype + +class PriorityReportQueue: + def __init__(self, num_levels, queue_names): + self.num_queues = num_levels + self.queue_names = queue_names + self.queues = [deque() for _ in range(num_levels)] + + def enqueue(self, report, priority): + if not (0 <= priority < len(self.queues)): + raise ValueError("Invalid priority level") + self.queues[priority].append(report) + + def dequeue(self): + for queue in self.queues: + if queue: + return queue.popleft() + raise IndexError("All queues are empty") + + def is_empty(self): + return all(len(q) == 0 for q in self.queues) + + def __getitem__(self, priority): + return list(self.queues[priority]) + + def summary(self): + out = "" + total = 0 + for i in range(self.num_queues): + out += f"Priority {i}: {self.queue_names[i]} queue has {len(self.queues[i])} reports.\n" + total += len(self.queues[i]) + out += f"In total, there are {total} pending reports" + return out + + def display(self): + out = "" + for i in range(self.num_queues): + queue = self.queues[i] + output += f"--- Priority {i}: {self.queue_names[i]} ---\n" + if not queue: + output += " (No reports)\n" + else: + for idx, report in enumerate(queue, 1): + output += ( + f" [{idx}] Report ID: {report.id}\n" + f" Author: {report.author}\n" + f" Type: {report.type}\n" + f" Subtype: {report.subtype}\n" + ) + + output += "\n" + return output.strip() + diff --git a/.history/DiscordBot/report_queue_20250509133229.py b/.history/DiscordBot/report_queue_20250509133229.py new file mode 100644 index 00000000..5900391f --- /dev/null +++ b/.history/DiscordBot/report_queue_20250509133229.py @@ -0,0 +1,60 @@ +from collections import deque + +class SubmittedReport: + def __init__(self, id, author, content, type, subtype): + self.author = author + self.id = id + self.content = content + self.type = type + self.subtype = subtype + +class PriorityReportQueue: + def __init__(self, num_levels, queue_names): + self.num_queues = num_levels + self.queue_names = queue_names + self.queues = [deque() for _ in range(num_levels)] + + def enqueue(self, report, priority): + if not (0 <= priority < len(self.queues)): + raise ValueError("Invalid priority level") + self.queues[priority].append(report) + + def dequeue(self): + for queue in self.queues: + if queue: + return queue.popleft() + raise IndexError("All queues are empty") + + def is_empty(self): + return all(len(q) == 0 for q in self.queues) + + def __getitem__(self, priority): + return list(self.queues[priority]) + + def summary(self): + out = "" + total = 0 + for i in range(self.num_queues): + queue = self.queues[i] + output += f"{i:^8} | {self.queue_names[i]:<16} | {len(queue):^9}" + out += f"In total, there are {total} pending reports" + return out + + def display(self): + out = "" + for i in range(self.num_queues): + queue = self.queues[i] + output += f"--- Priority {i}: {self.queue_names[i]} ---\n" + if not queue: + output += " (No reports)\n" + else: + for idx, report in enumerate(queue, 1): + output += ( + f" [{idx}] Report ID: {report.id}\n" + f" Author: {report.author}\n" + f" Type: {report.type}\n" + f" Subtype: {report.subtype}\n" + ) + output += "\n" + return output.strip() + diff --git a/.history/DiscordBot/report_queue_20250509133302.py b/.history/DiscordBot/report_queue_20250509133302.py new file mode 100644 index 00000000..5d68b8d0 --- /dev/null +++ b/.history/DiscordBot/report_queue_20250509133302.py @@ -0,0 +1,62 @@ +from collections import deque + +class SubmittedReport: + def __init__(self, id, author, content, type, subtype): + self.author = author + self.id = id + self.content = content + self.type = type + self.subtype = subtype + +class PriorityReportQueue: + def __init__(self, num_levels, queue_names): + self.num_queues = num_levels + self.queue_names = queue_names + self.queues = [deque() for _ in range(num_levels)] + + def enqueue(self, report, priority): + if not (0 <= priority < len(self.queues)): + raise ValueError("Invalid priority level") + self.queues[priority].append(report) + + def dequeue(self): + for queue in self.queues: + if queue: + return queue.popleft() + raise IndexError("All queues are empty") + + def is_empty(self): + return all(len(q) == 0 for q in self.queues) + + def __getitem__(self, priority): + return list(self.queues[priority]) + + def summary(self): + out = "" + out += "Priority | Queue Name | # Reports | Report IDs\n" + output += "-" * 60 + "\n" + for i in range(self.num_queues): + queue = self.queues[i] + output += f"{i:^8} | {self.queue_names[i]:<16} | {len(queue):^9}" + total += len(queue) + out += f"In total, there are {total} pending reports" + return out + + def display(self): + out = "" + for i in range(self.num_queues): + queue = self.queues[i] + output += f"--- Priority {i}: {self.queue_names[i]} ---\n" + if not queue: + output += " (No reports)\n" + else: + for idx, report in enumerate(queue, 1): + output += ( + f" [{idx}] Report ID: {report.id}\n" + f" Author: {report.author}\n" + f" Type: {report.type}\n" + f" Subtype: {report.subtype}\n" + ) + output += "\n" + return output.strip() + diff --git a/.history/DiscordBot/report_queue_20250509133440.py b/.history/DiscordBot/report_queue_20250509133440.py new file mode 100644 index 00000000..5d68b8d0 --- /dev/null +++ b/.history/DiscordBot/report_queue_20250509133440.py @@ -0,0 +1,62 @@ +from collections import deque + +class SubmittedReport: + def __init__(self, id, author, content, type, subtype): + self.author = author + self.id = id + self.content = content + self.type = type + self.subtype = subtype + +class PriorityReportQueue: + def __init__(self, num_levels, queue_names): + self.num_queues = num_levels + self.queue_names = queue_names + self.queues = [deque() for _ in range(num_levels)] + + def enqueue(self, report, priority): + if not (0 <= priority < len(self.queues)): + raise ValueError("Invalid priority level") + self.queues[priority].append(report) + + def dequeue(self): + for queue in self.queues: + if queue: + return queue.popleft() + raise IndexError("All queues are empty") + + def is_empty(self): + return all(len(q) == 0 for q in self.queues) + + def __getitem__(self, priority): + return list(self.queues[priority]) + + def summary(self): + out = "" + out += "Priority | Queue Name | # Reports | Report IDs\n" + output += "-" * 60 + "\n" + for i in range(self.num_queues): + queue = self.queues[i] + output += f"{i:^8} | {self.queue_names[i]:<16} | {len(queue):^9}" + total += len(queue) + out += f"In total, there are {total} pending reports" + return out + + def display(self): + out = "" + for i in range(self.num_queues): + queue = self.queues[i] + output += f"--- Priority {i}: {self.queue_names[i]} ---\n" + if not queue: + output += " (No reports)\n" + else: + for idx, report in enumerate(queue, 1): + output += ( + f" [{idx}] Report ID: {report.id}\n" + f" Author: {report.author}\n" + f" Type: {report.type}\n" + f" Subtype: {report.subtype}\n" + ) + output += "\n" + return output.strip() + diff --git a/.history/DiscordBot/submitted_report_20250509124230.py b/.history/DiscordBot/submitted_report_20250509124230.py new file mode 100644 index 00000000..e69de29b diff --git a/.history/DiscordBot/submitted_report_20250509125057.py b/.history/DiscordBot/submitted_report_20250509125057.py new file mode 100644 index 00000000..e66ea57c --- /dev/null +++ b/.history/DiscordBot/submitted_report_20250509125057.py @@ -0,0 +1,7 @@ +class SubmittedReport: + def __init__(self, author, content, type, subtype, imminent): + self.author = author + self.content = content + self.type = type + self.subtype = subtype + self.imminent = imminent \ No newline at end of file diff --git a/.history/DiscordBot/submitted_report_20250509131251.py b/.history/DiscordBot/submitted_report_20250509131251.py new file mode 100644 index 00000000..7be0e391 --- /dev/null +++ b/.history/DiscordBot/submitted_report_20250509131251.py @@ -0,0 +1,30 @@ +from collections import deque() + +class SubmittedReport: + def __init__(self, author, content, type, subtype): + self.author = author + self.content = content + self.type = type + self.subtype = subtype + +class PriorityReportQueue: + def __init__(self, num_levels): + self.num_queues = num_levels + self.queues = [deque() for _ in range(num_levels)] + + def enqueue(self, report, priority): + if not (0 <= priority < len(self.queues)): + raise ValueError("Invalid priority level") + self.queues[priority].append(item) + + def dequeue(self): + for queue in self.queues: + if queue: + return queue.popleft() + raise IndexError("All queues are empty") + + def is_empty(self): + return all(len(q) == 0 for q in self.queues) + + def __getitem__(self, priority): + return list(self.queues[priority]) diff --git a/DiscordBot/report_queue.py b/DiscordBot/report_queue.py new file mode 100644 index 00000000..5d68b8d0 --- /dev/null +++ b/DiscordBot/report_queue.py @@ -0,0 +1,62 @@ +from collections import deque + +class SubmittedReport: + def __init__(self, id, author, content, type, subtype): + self.author = author + self.id = id + self.content = content + self.type = type + self.subtype = subtype + +class PriorityReportQueue: + def __init__(self, num_levels, queue_names): + self.num_queues = num_levels + self.queue_names = queue_names + self.queues = [deque() for _ in range(num_levels)] + + def enqueue(self, report, priority): + if not (0 <= priority < len(self.queues)): + raise ValueError("Invalid priority level") + self.queues[priority].append(report) + + def dequeue(self): + for queue in self.queues: + if queue: + return queue.popleft() + raise IndexError("All queues are empty") + + def is_empty(self): + return all(len(q) == 0 for q in self.queues) + + def __getitem__(self, priority): + return list(self.queues[priority]) + + def summary(self): + out = "" + out += "Priority | Queue Name | # Reports | Report IDs\n" + output += "-" * 60 + "\n" + for i in range(self.num_queues): + queue = self.queues[i] + output += f"{i:^8} | {self.queue_names[i]:<16} | {len(queue):^9}" + total += len(queue) + out += f"In total, there are {total} pending reports" + return out + + def display(self): + out = "" + for i in range(self.num_queues): + queue = self.queues[i] + output += f"--- Priority {i}: {self.queue_names[i]} ---\n" + if not queue: + output += " (No reports)\n" + else: + for idx, report in enumerate(queue, 1): + output += ( + f" [{idx}] Report ID: {report.id}\n" + f" Author: {report.author}\n" + f" Type: {report.type}\n" + f" Subtype: {report.subtype}\n" + ) + output += "\n" + return output.strip() + diff --git a/venv/bin/Activate.ps1 b/venv/bin/Activate.ps1 new file mode 100644 index 00000000..b49d77ba --- /dev/null +++ b/venv/bin/Activate.ps1 @@ -0,0 +1,247 @@ +<# +.Synopsis +Activate a Python virtual environment for the current PowerShell session. + +.Description +Pushes the python executable for a virtual environment to the front of the +$Env:PATH environment variable and sets the prompt to signify that you are +in a Python virtual environment. Makes use of the command line switches as +well as the `pyvenv.cfg` file values present in the virtual environment. + +.Parameter VenvDir +Path to the directory that contains the virtual environment to activate. The +default value for this is the parent of the directory that the Activate.ps1 +script is located within. + +.Parameter Prompt +The prompt prefix to display when this virtual environment is activated. By +default, this prompt is the name of the virtual environment folder (VenvDir) +surrounded by parentheses and followed by a single space (ie. '(.venv) '). + +.Example +Activate.ps1 +Activates the Python virtual environment that contains the Activate.ps1 script. + +.Example +Activate.ps1 -Verbose +Activates the Python virtual environment that contains the Activate.ps1 script, +and shows extra information about the activation as it executes. + +.Example +Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv +Activates the Python virtual environment located in the specified location. + +.Example +Activate.ps1 -Prompt "MyPython" +Activates the Python virtual environment that contains the Activate.ps1 script, +and prefixes the current prompt with the specified string (surrounded in +parentheses) while the virtual environment is active. + +.Notes +On Windows, it may be required to enable this Activate.ps1 script by setting the +execution policy for the user. You can do this by issuing the following PowerShell +command: + +PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser + +For more information on Execution Policies: +https://go.microsoft.com/fwlink/?LinkID=135170 + +#> +Param( + [Parameter(Mandatory = $false)] + [String] + $VenvDir, + [Parameter(Mandatory = $false)] + [String] + $Prompt +) + +<# Function declarations --------------------------------------------------- #> + +<# +.Synopsis +Remove all shell session elements added by the Activate script, including the +addition of the virtual environment's Python executable from the beginning of +the PATH variable. + +.Parameter NonDestructive +If present, do not remove this function from the global namespace for the +session. + +#> +function global:deactivate ([switch]$NonDestructive) { + # Revert to original values + + # The prior prompt: + if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) { + Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt + Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT + } + + # The prior PYTHONHOME: + if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) { + Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME + Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME + } + + # The prior PATH: + if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) { + Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH + Remove-Item -Path Env:_OLD_VIRTUAL_PATH + } + + # Just remove the VIRTUAL_ENV altogether: + if (Test-Path -Path Env:VIRTUAL_ENV) { + Remove-Item -Path env:VIRTUAL_ENV + } + + # Just remove VIRTUAL_ENV_PROMPT altogether. + if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) { + Remove-Item -Path env:VIRTUAL_ENV_PROMPT + } + + # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether: + if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) { + Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force + } + + # Leave deactivate function in the global namespace if requested: + if (-not $NonDestructive) { + Remove-Item -Path function:deactivate + } +} + +<# +.Description +Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the +given folder, and returns them in a map. + +For each line in the pyvenv.cfg file, if that line can be parsed into exactly +two strings separated by `=` (with any amount of whitespace surrounding the =) +then it is considered a `key = value` line. The left hand string is the key, +the right hand is the value. + +If the value starts with a `'` or a `"` then the first and last character is +stripped from the value before being captured. + +.Parameter ConfigDir +Path to the directory that contains the `pyvenv.cfg` file. +#> +function Get-PyVenvConfig( + [String] + $ConfigDir +) { + Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg" + + # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue). + $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue + + # An empty map will be returned if no config file is found. + $pyvenvConfig = @{ } + + if ($pyvenvConfigPath) { + + Write-Verbose "File exists, parse `key = value` lines" + $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath + + $pyvenvConfigContent | ForEach-Object { + $keyval = $PSItem -split "\s*=\s*", 2 + if ($keyval[0] -and $keyval[1]) { + $val = $keyval[1] + + # Remove extraneous quotations around a string value. + if ("'""".Contains($val.Substring(0, 1))) { + $val = $val.Substring(1, $val.Length - 2) + } + + $pyvenvConfig[$keyval[0]] = $val + Write-Verbose "Adding Key: '$($keyval[0])'='$val'" + } + } + } + return $pyvenvConfig +} + + +<# Begin Activate script --------------------------------------------------- #> + +# Determine the containing directory of this script +$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition +$VenvExecDir = Get-Item -Path $VenvExecPath + +Write-Verbose "Activation script is located in path: '$VenvExecPath'" +Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)" +Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)" + +# Set values required in priority: CmdLine, ConfigFile, Default +# First, get the location of the virtual environment, it might not be +# VenvExecDir if specified on the command line. +if ($VenvDir) { + Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values" +} +else { + Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir." + $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/") + Write-Verbose "VenvDir=$VenvDir" +} + +# Next, read the `pyvenv.cfg` file to determine any required value such +# as `prompt`. +$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir + +# Next, set the prompt from the command line, or the config file, or +# just use the name of the virtual environment folder. +if ($Prompt) { + Write-Verbose "Prompt specified as argument, using '$Prompt'" +} +else { + Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value" + if ($pyvenvCfg -and $pyvenvCfg['prompt']) { + Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'" + $Prompt = $pyvenvCfg['prompt']; + } + else { + Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)" + Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'" + $Prompt = Split-Path -Path $venvDir -Leaf + } +} + +Write-Verbose "Prompt = '$Prompt'" +Write-Verbose "VenvDir='$VenvDir'" + +# Deactivate any currently active virtual environment, but leave the +# deactivate function in place. +deactivate -nondestructive + +# Now set the environment variable VIRTUAL_ENV, used by many tools to determine +# that there is an activated venv. +$env:VIRTUAL_ENV = $VenvDir + +if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { + + Write-Verbose "Setting prompt to '$Prompt'" + + # Set the prompt to include the env name + # Make sure _OLD_VIRTUAL_PROMPT is global + function global:_OLD_VIRTUAL_PROMPT { "" } + Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT + New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt + + function global:prompt { + Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) " + _OLD_VIRTUAL_PROMPT + } + $env:VIRTUAL_ENV_PROMPT = $Prompt +} + +# Clear PYTHONHOME +if (Test-Path -Path Env:PYTHONHOME) { + Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME + Remove-Item -Path Env:PYTHONHOME +} + +# Add the venv to the PATH +Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH +$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH" diff --git a/venv/bin/activate b/venv/bin/activate new file mode 100644 index 00000000..a06d713c --- /dev/null +++ b/venv/bin/activate @@ -0,0 +1,70 @@ +# This file must be used with "source bin/activate" *from bash* +# You cannot run it directly + +deactivate () { + # reset old environment variables + if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then + PATH="${_OLD_VIRTUAL_PATH:-}" + export PATH + unset _OLD_VIRTUAL_PATH + fi + if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then + PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}" + export PYTHONHOME + unset _OLD_VIRTUAL_PYTHONHOME + fi + + # Call hash to forget past commands. Without forgetting + # past commands the $PATH changes we made may not be respected + hash -r 2> /dev/null + + if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then + PS1="${_OLD_VIRTUAL_PS1:-}" + export PS1 + unset _OLD_VIRTUAL_PS1 + fi + + unset VIRTUAL_ENV + unset VIRTUAL_ENV_PROMPT + if [ ! "${1:-}" = "nondestructive" ] ; then + # Self destruct! + unset -f deactivate + fi +} + +# unset irrelevant variables +deactivate nondestructive + +# on Windows, a path can contain colons and backslashes and has to be converted: +if [ "${OSTYPE:-}" = "cygwin" ] || [ "${OSTYPE:-}" = "msys" ] ; then + # transform D:\path\to\venv to /d/path/to/venv on MSYS + # and to /cygdrive/d/path/to/venv on Cygwin + export VIRTUAL_ENV=$(cygpath "/Users/andrewzchen/S-Junior/Spring Quarter/CS 152/cs152bots-group8/venv") +else + # use the path as-is + export VIRTUAL_ENV="/Users/andrewzchen/S-Junior/Spring Quarter/CS 152/cs152bots-group8/venv" +fi + +_OLD_VIRTUAL_PATH="$PATH" +PATH="$VIRTUAL_ENV/bin:$PATH" +export PATH + +# unset PYTHONHOME if set +# this will fail if PYTHONHOME is set to the empty string (which is bad anyway) +# could use `if (set -u; : $PYTHONHOME) ;` in bash +if [ -n "${PYTHONHOME:-}" ] ; then + _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}" + unset PYTHONHOME +fi + +if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then + _OLD_VIRTUAL_PS1="${PS1:-}" + PS1="(venv) ${PS1:-}" + export PS1 + VIRTUAL_ENV_PROMPT="(venv) " + export VIRTUAL_ENV_PROMPT +fi + +# Call hash to forget past commands. Without forgetting +# past commands the $PATH changes we made may not be respected +hash -r 2> /dev/null diff --git a/venv/bin/activate.csh b/venv/bin/activate.csh new file mode 100644 index 00000000..6d35843e --- /dev/null +++ b/venv/bin/activate.csh @@ -0,0 +1,27 @@ +# This file must be used with "source bin/activate.csh" *from csh*. +# You cannot run it directly. + +# Created by Davide Di Blasi . +# Ported to Python 3.3 venv by Andrew Svetlov + +alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate' + +# Unset irrelevant variables. +deactivate nondestructive + +setenv VIRTUAL_ENV "/Users/andrewzchen/S-Junior/Spring Quarter/CS 152/cs152bots-group8/venv" + +set _OLD_VIRTUAL_PATH="$PATH" +setenv PATH "$VIRTUAL_ENV/bin:$PATH" + + +set _OLD_VIRTUAL_PROMPT="$prompt" + +if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then + set prompt = "(venv) $prompt" + setenv VIRTUAL_ENV_PROMPT "(venv) " +endif + +alias pydoc python -m pydoc + +rehash diff --git a/venv/bin/activate.fish b/venv/bin/activate.fish new file mode 100644 index 00000000..b0613041 --- /dev/null +++ b/venv/bin/activate.fish @@ -0,0 +1,69 @@ +# This file must be used with "source /bin/activate.fish" *from fish* +# (https://fishshell.com/). You cannot run it directly. + +function deactivate -d "Exit virtual environment and return to normal shell environment" + # reset old environment variables + if test -n "$_OLD_VIRTUAL_PATH" + set -gx PATH $_OLD_VIRTUAL_PATH + set -e _OLD_VIRTUAL_PATH + end + if test -n "$_OLD_VIRTUAL_PYTHONHOME" + set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME + set -e _OLD_VIRTUAL_PYTHONHOME + end + + if test -n "$_OLD_FISH_PROMPT_OVERRIDE" + set -e _OLD_FISH_PROMPT_OVERRIDE + # prevents error when using nested fish instances (Issue #93858) + if functions -q _old_fish_prompt + functions -e fish_prompt + functions -c _old_fish_prompt fish_prompt + functions -e _old_fish_prompt + end + end + + set -e VIRTUAL_ENV + set -e VIRTUAL_ENV_PROMPT + if test "$argv[1]" != "nondestructive" + # Self-destruct! + functions -e deactivate + end +end + +# Unset irrelevant variables. +deactivate nondestructive + +set -gx VIRTUAL_ENV "/Users/andrewzchen/S-Junior/Spring Quarter/CS 152/cs152bots-group8/venv" + +set -gx _OLD_VIRTUAL_PATH $PATH +set -gx PATH "$VIRTUAL_ENV/bin" $PATH + +# Unset PYTHONHOME if set. +if set -q PYTHONHOME + set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME + set -e PYTHONHOME +end + +if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" + # fish uses a function instead of an env var to generate the prompt. + + # Save the current fish_prompt function as the function _old_fish_prompt. + functions -c fish_prompt _old_fish_prompt + + # With the original prompt function renamed, we can override with our own. + function fish_prompt + # Save the return status of the last command. + set -l old_status $status + + # Output the venv prompt; color taken from the blue of the Python logo. + printf "%s%s%s" (set_color 4B8BBE) "(venv) " (set_color normal) + + # Restore the return status of the previous command. + echo "exit $old_status" | . + # Output the original/"old" prompt. + _old_fish_prompt + end + + set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" + set -gx VIRTUAL_ENV_PROMPT "(venv) " +end diff --git a/venv/bin/normalizer b/venv/bin/normalizer new file mode 100755 index 00000000..20d03799 --- /dev/null +++ b/venv/bin/normalizer @@ -0,0 +1,10 @@ +#!/bin/sh +'''exec' "/Users/andrewzchen/S-Junior/Spring Quarter/CS 152/cs152bots-group8/venv/bin/python3" "$0" "$@" +' ''' +# -*- coding: utf-8 -*- +import re +import sys +from charset_normalizer import cli +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(cli.cli_detect()) diff --git a/venv/bin/pip b/venv/bin/pip new file mode 100755 index 00000000..7b0363cd --- /dev/null +++ b/venv/bin/pip @@ -0,0 +1,10 @@ +#!/bin/sh +'''exec' "/Users/andrewzchen/S-Junior/Spring Quarter/CS 152/cs152bots-group8/venv/bin/python3" "$0" "$@" +' ''' +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/pip3 b/venv/bin/pip3 new file mode 100755 index 00000000..7b0363cd --- /dev/null +++ b/venv/bin/pip3 @@ -0,0 +1,10 @@ +#!/bin/sh +'''exec' "/Users/andrewzchen/S-Junior/Spring Quarter/CS 152/cs152bots-group8/venv/bin/python3" "$0" "$@" +' ''' +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/pip3.12 b/venv/bin/pip3.12 new file mode 100755 index 00000000..7b0363cd --- /dev/null +++ b/venv/bin/pip3.12 @@ -0,0 +1,10 @@ +#!/bin/sh +'''exec' "/Users/andrewzchen/S-Junior/Spring Quarter/CS 152/cs152bots-group8/venv/bin/python3" "$0" "$@" +' ''' +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/python b/venv/bin/python new file mode 120000 index 00000000..b8a0adbb --- /dev/null +++ b/venv/bin/python @@ -0,0 +1 @@ +python3 \ No newline at end of file diff --git a/venv/bin/python3 b/venv/bin/python3 new file mode 120000 index 00000000..ce212157 --- /dev/null +++ b/venv/bin/python3 @@ -0,0 +1 @@ +/Users/andrewzchen/miniconda3/bin/python3 \ No newline at end of file diff --git a/venv/bin/python3.12 b/venv/bin/python3.12 new file mode 120000 index 00000000..b8a0adbb --- /dev/null +++ b/venv/bin/python3.12 @@ -0,0 +1 @@ +python3 \ No newline at end of file diff --git a/venv/lib/python3.12/site-packages/aiohappyeyeballs-2.6.1.dist-info/INSTALLER b/venv/lib/python3.12/site-packages/aiohappyeyeballs-2.6.1.dist-info/INSTALLER new file mode 100644 index 00000000..a1b589e3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohappyeyeballs-2.6.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.12/site-packages/aiohappyeyeballs-2.6.1.dist-info/LICENSE b/venv/lib/python3.12/site-packages/aiohappyeyeballs-2.6.1.dist-info/LICENSE new file mode 100644 index 00000000..f26bcf4d --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohappyeyeballs-2.6.1.dist-info/LICENSE @@ -0,0 +1,279 @@ +A. HISTORY OF THE SOFTWARE +========================== + +Python was created in the early 1990s by Guido van Rossum at Stichting +Mathematisch Centrum (CWI, see https://www.cwi.nl) in the Netherlands +as a successor of a language called ABC. Guido remains Python's +principal author, although it includes many contributions from others. + +In 1995, Guido continued his work on Python at the Corporation for +National Research Initiatives (CNRI, see https://www.cnri.reston.va.us) +in Reston, Virginia where he released several versions of the +software. + +In May 2000, Guido and the Python core development team moved to +BeOpen.com to form the BeOpen PythonLabs team. In October of the same +year, the PythonLabs team moved to Digital Creations, which became +Zope Corporation. In 2001, the Python Software Foundation (PSF, see +https://www.python.org/psf/) was formed, a non-profit organization +created specifically to own Python-related Intellectual Property. +Zope Corporation was a sponsoring member of the PSF. + +All Python releases are Open Source (see https://opensource.org for +the Open Source Definition). Historically, most, but not all, Python +releases have also been GPL-compatible; the table below summarizes +the various releases. + + Release Derived Year Owner GPL- + from compatible? (1) + + 0.9.0 thru 1.2 1991-1995 CWI yes + 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes + 1.6 1.5.2 2000 CNRI no + 2.0 1.6 2000 BeOpen.com no + 1.6.1 1.6 2001 CNRI yes (2) + 2.1 2.0+1.6.1 2001 PSF no + 2.0.1 2.0+1.6.1 2001 PSF yes + 2.1.1 2.1+2.0.1 2001 PSF yes + 2.1.2 2.1.1 2002 PSF yes + 2.1.3 2.1.2 2002 PSF yes + 2.2 and above 2.1.1 2001-now PSF yes + +Footnotes: + +(1) GPL-compatible doesn't mean that we're distributing Python under + the GPL. All Python licenses, unlike the GPL, let you distribute + a modified version without making your changes open source. The + GPL-compatible licenses make it possible to combine Python with + other software that is released under the GPL; the others don't. + +(2) According to Richard Stallman, 1.6.1 is not GPL-compatible, + because its license has a choice of law clause. According to + CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1 + is "not incompatible" with the GPL. + +Thanks to the many outside volunteers who have worked under Guido's +direction to make these releases possible. + + +B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON +=============================================================== + +Python software and documentation are licensed under the +Python Software Foundation License Version 2. + +Starting with Python 3.8.6, examples, recipes, and other code in +the documentation are dual licensed under the PSF License Version 2 +and the Zero-Clause BSD license. + +Some software incorporated into Python is under different licenses. +The licenses are listed with code falling under that license. + + +PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 +-------------------------------------------- + +1. This LICENSE AGREEMENT is between the Python Software Foundation +("PSF"), and the Individual or Organization ("Licensee") accessing and +otherwise using this software ("Python") in source or binary form and +its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF hereby +grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, +analyze, test, perform and/or display publicly, prepare derivative works, +distribute, and otherwise use Python alone or in any derivative version, +provided, however, that PSF's License Agreement and PSF's notice of copyright, +i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Python Software Foundation; +All Rights Reserved" are retained in Python alone or in any derivative version +prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python. + +4. PSF is making Python available to Licensee on an "AS IS" +basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between PSF and +Licensee. This License Agreement does not grant permission to use PSF +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using Python, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + + +BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 +------------------------------------------- + +BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 + +1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an +office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the +Individual or Organization ("Licensee") accessing and otherwise using +this software in source or binary form and its associated +documentation ("the Software"). + +2. Subject to the terms and conditions of this BeOpen Python License +Agreement, BeOpen hereby grants Licensee a non-exclusive, +royalty-free, world-wide license to reproduce, analyze, test, perform +and/or display publicly, prepare derivative works, distribute, and +otherwise use the Software alone or in any derivative version, +provided, however, that the BeOpen Python License is retained in the +Software, alone or in any derivative version prepared by Licensee. + +3. BeOpen is making the Software available to Licensee on an "AS IS" +basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE +SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS +AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY +DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +5. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +6. This License Agreement shall be governed by and interpreted in all +respects by the law of the State of California, excluding conflict of +law provisions. Nothing in this License Agreement shall be deemed to +create any relationship of agency, partnership, or joint venture +between BeOpen and Licensee. This License Agreement does not grant +permission to use BeOpen trademarks or trade names in a trademark +sense to endorse or promote products or services of Licensee, or any +third party. As an exception, the "BeOpen Python" logos available at +http://www.pythonlabs.com/logos.html may be used according to the +permissions granted on that web page. + +7. By copying, installing or otherwise using the software, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + + +CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 +--------------------------------------- + +1. This LICENSE AGREEMENT is between the Corporation for National +Research Initiatives, having an office at 1895 Preston White Drive, +Reston, VA 20191 ("CNRI"), and the Individual or Organization +("Licensee") accessing and otherwise using Python 1.6.1 software in +source or binary form and its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, CNRI +hereby grants Licensee a nonexclusive, royalty-free, world-wide +license to reproduce, analyze, test, perform and/or display publicly, +prepare derivative works, distribute, and otherwise use Python 1.6.1 +alone or in any derivative version, provided, however, that CNRI's +License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) +1995-2001 Corporation for National Research Initiatives; All Rights +Reserved" are retained in Python 1.6.1 alone or in any derivative +version prepared by Licensee. Alternately, in lieu of CNRI's License +Agreement, Licensee may substitute the following text (omitting the +quotes): "Python 1.6.1 is made available subject to the terms and +conditions in CNRI's License Agreement. This Agreement together with +Python 1.6.1 may be located on the internet using the following +unique, persistent identifier (known as a handle): 1895.22/1013. This +Agreement may also be obtained from a proxy server on the internet +using the following URL: http://hdl.handle.net/1895.22/1013". + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python 1.6.1 or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python 1.6.1. + +4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" +basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. This License Agreement shall be governed by the federal +intellectual property law of the United States, including without +limitation the federal copyright law, and, to the extent such +U.S. federal law does not apply, by the law of the Commonwealth of +Virginia, excluding Virginia's conflict of law provisions. +Notwithstanding the foregoing, with regard to derivative works based +on Python 1.6.1 that incorporate non-separable material that was +previously distributed under the GNU General Public License (GPL), the +law of the Commonwealth of Virginia shall govern this License +Agreement only as to issues arising under or with respect to +Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this +License Agreement shall be deemed to create any relationship of +agency, partnership, or joint venture between CNRI and Licensee. This +License Agreement does not grant permission to use CNRI trademarks or +trade name in a trademark sense to endorse or promote products or +services of Licensee, or any third party. + +8. By clicking on the "ACCEPT" button where indicated, or by copying, +installing or otherwise using Python 1.6.1, Licensee agrees to be +bound by the terms and conditions of this License Agreement. + + ACCEPT + + +CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 +-------------------------------------------------- + +Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, +The Netherlands. All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +ZERO-CLAUSE BSD LICENSE FOR CODE IN THE PYTHON DOCUMENTATION +---------------------------------------------------------------------- + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/venv/lib/python3.12/site-packages/aiohappyeyeballs-2.6.1.dist-info/METADATA b/venv/lib/python3.12/site-packages/aiohappyeyeballs-2.6.1.dist-info/METADATA new file mode 100644 index 00000000..c632040d --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohappyeyeballs-2.6.1.dist-info/METADATA @@ -0,0 +1,123 @@ +Metadata-Version: 2.3 +Name: aiohappyeyeballs +Version: 2.6.1 +Summary: Happy Eyeballs for asyncio +License: PSF-2.0 +Author: J. Nick Koston +Author-email: nick@koston.org +Requires-Python: >=3.9 +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Natural Language :: English +Classifier: Operating System :: OS Independent +Classifier: Topic :: Software Development :: Libraries +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: License :: OSI Approved :: Python Software Foundation License +Project-URL: Bug Tracker, https://github.com/aio-libs/aiohappyeyeballs/issues +Project-URL: Changelog, https://github.com/aio-libs/aiohappyeyeballs/blob/main/CHANGELOG.md +Project-URL: Documentation, https://aiohappyeyeballs.readthedocs.io +Project-URL: Repository, https://github.com/aio-libs/aiohappyeyeballs +Description-Content-Type: text/markdown + +# aiohappyeyeballs + +

+ + CI Status + + + Documentation Status + + + Test coverage percentage + +

+

+ + Poetry + + + Ruff + + + pre-commit + +

+

+ + PyPI Version + + Supported Python versions + License +

+ +--- + +**Documentation**: https://aiohappyeyeballs.readthedocs.io + +**Source Code**: https://github.com/aio-libs/aiohappyeyeballs + +--- + +[Happy Eyeballs](https://en.wikipedia.org/wiki/Happy_Eyeballs) +([RFC 8305](https://www.rfc-editor.org/rfc/rfc8305.html)) + +## Use case + +This library exists to allow connecting with +[Happy Eyeballs](https://en.wikipedia.org/wiki/Happy_Eyeballs) +([RFC 8305](https://www.rfc-editor.org/rfc/rfc8305.html)) +when you +already have a list of addrinfo and not a DNS name. + +The stdlib version of `loop.create_connection()` +will only work when you pass in an unresolved name which +is not a good fit when using DNS caching or resolving +names via another method such as `zeroconf`. + +## Installation + +Install this via pip (or your favourite package manager): + +`pip install aiohappyeyeballs` + +## License + +[aiohappyeyeballs is licensed under the same terms as cpython itself.](https://github.com/python/cpython/blob/main/LICENSE) + +## Example usage + +```python + +addr_infos = await loop.getaddrinfo("example.org", 80) + +socket = await start_connection(addr_infos) +socket = await start_connection(addr_infos, local_addr_infos=local_addr_infos, happy_eyeballs_delay=0.2) + +transport, protocol = await loop.create_connection( + MyProtocol, sock=socket, ...) + +# Remove the first address for each family from addr_info +pop_addr_infos_interleave(addr_info, 1) + +# Remove all matching address from addr_info +remove_addr_infos(addr_info, "dead::beef::") + +# Convert a local_addr to local_addr_infos +local_addr_infos = addr_to_addr_infos(("127.0.0.1",0)) +``` + +## Credits + +This package contains code from cpython and is licensed under the same terms as cpython itself. + +This package was created with +[Copier](https://copier.readthedocs.io/) and the +[browniebroke/pypackage-template](https://github.com/browniebroke/pypackage-template) +project template. + diff --git a/venv/lib/python3.12/site-packages/aiohappyeyeballs-2.6.1.dist-info/RECORD b/venv/lib/python3.12/site-packages/aiohappyeyeballs-2.6.1.dist-info/RECORD new file mode 100644 index 00000000..9e0e2023 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohappyeyeballs-2.6.1.dist-info/RECORD @@ -0,0 +1,16 @@ +aiohappyeyeballs-2.6.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +aiohappyeyeballs-2.6.1.dist-info/LICENSE,sha256=Oy-B_iHRgcSZxZolbI4ZaEVdZonSaaqFNzv7avQdo78,13936 +aiohappyeyeballs-2.6.1.dist-info/METADATA,sha256=NSXlhJwAfi380eEjAo7BQ4P_TVal9xi0qkyZWibMsVM,5915 +aiohappyeyeballs-2.6.1.dist-info/RECORD,, +aiohappyeyeballs-2.6.1.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88 +aiohappyeyeballs/__init__.py,sha256=x7kktHEtaD9quBcWDJPuLeKyjuVAI-Jj14S9B_5hcTs,361 +aiohappyeyeballs/__pycache__/__init__.cpython-312.pyc,, +aiohappyeyeballs/__pycache__/_staggered.cpython-312.pyc,, +aiohappyeyeballs/__pycache__/impl.cpython-312.pyc,, +aiohappyeyeballs/__pycache__/types.cpython-312.pyc,, +aiohappyeyeballs/__pycache__/utils.cpython-312.pyc,, +aiohappyeyeballs/_staggered.py,sha256=edfVowFx-P-ywJjIEF3MdPtEMVODujV6CeMYr65otac,6900 +aiohappyeyeballs/impl.py,sha256=Dlcm2mTJ28ucrGnxkb_fo9CZzLAkOOBizOt7dreBbXE,9681 +aiohappyeyeballs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +aiohappyeyeballs/types.py,sha256=YZJIAnyoV4Dz0WFtlaf_OyE4EW7Xus1z7aIfNI6tDDQ,425 +aiohappyeyeballs/utils.py,sha256=on9GxIR0LhEfZu8P6Twi9hepX9zDanuZM20MWsb3xlQ,3028 diff --git a/venv/lib/python3.12/site-packages/aiohappyeyeballs-2.6.1.dist-info/WHEEL b/venv/lib/python3.12/site-packages/aiohappyeyeballs-2.6.1.dist-info/WHEEL new file mode 100644 index 00000000..0582547b --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohappyeyeballs-2.6.1.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: poetry-core 2.1.1 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/venv/lib/python3.12/site-packages/aiohappyeyeballs/__init__.py b/venv/lib/python3.12/site-packages/aiohappyeyeballs/__init__.py new file mode 100644 index 00000000..71c689cc --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohappyeyeballs/__init__.py @@ -0,0 +1,14 @@ +__version__ = "2.6.1" + +from .impl import start_connection +from .types import AddrInfoType, SocketFactoryType +from .utils import addr_to_addr_infos, pop_addr_infos_interleave, remove_addr_infos + +__all__ = ( + "AddrInfoType", + "SocketFactoryType", + "addr_to_addr_infos", + "pop_addr_infos_interleave", + "remove_addr_infos", + "start_connection", +) diff --git a/venv/lib/python3.12/site-packages/aiohappyeyeballs/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohappyeyeballs/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b02212d9dbfc4c243fe4927d006e06cb558d2bda GIT binary patch literal 542 zcmZ8eJ!=#}7@qyQz2uBBf`vsO*llq)+=*fl0znY85M;I4W|-R@?}p45GqW2uRq_L@ z{SEmE{st>MnI?r;*agz1^4&u*_!iH+pU?a7&exrtZ3On^)Bc)A2>lp>zZU;-ZVtiu zj2cv-CTe04$+(K6!B0dY(<+r&m2KiwjAUNra$Jq&R<#AWtlI8JMShkoX3uByU$6od zQF!1ywVu>kDOP)~RS}1K$4z5jtB?A9Z&=tXb$!D8D_VPP`yo{%;UR?<;x*a49C}@N zY_z!(6Rte7g3%5*ER(upcdEt6rl7!P1B?d92N(~K0K6?GVM0j9tOHSmgp^AoHl>hx z5aIsKhphEnxc_KEP6!o(kV|v}gy{AHe{evDscI}cJ*(GD;d1(>Ra{$K8q3w{;9U#X zU>3hD59ZGnxORX`?cH=`b!%SWj;Rg{zQm^YYptHn<_qk&XH!G#6S`u+&h?ra)3cr} zVZFly4#7PkGt=LW52bEe!H(=6C>p-N?E_pVQ51c@|LA=36Fs>?iz`%qL*;dvPvVQ* H?n1|JqWzom literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohappyeyeballs/__pycache__/_staggered.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohappyeyeballs/__pycache__/_staggered.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..596c7dc9459e6cf529763ff0747815922bfe531d GIT binary patch literal 8041 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 P9xHku{3uM@Eu#MuZnp(c literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohappyeyeballs/__pycache__/impl.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohappyeyeballs/__pycache__/impl.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..484e8c7763d92113cec318ca61b5cf43e3c959f5 GIT binary patch literal 10155 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 P+14CewZ=jXMK}KgjnJPv literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohappyeyeballs/__pycache__/types.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohappyeyeballs/__pycache__/types.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1bd1bcc8679e18dad0159fc68a4d0b0dca04e0d5 GIT binary patch literal 638 zcmZ8f&1(}u6rb6h-6q?_q*4zefi3Y8AsJc`L`9H7K?On5dRVAov-^^4yV+T0Hj(W? zJoe(*{0Zjd*}uU{_GF!t(37`F4?<7Qwuu2B!~4C@-@N(wRxVpe$=8py!4xBOo;yo1 z7skaz8K01k9OPqP3$cS0>Y+B&9eqd~GBg|mBOqXa3Ha#7l3;~B?Y43j`RXdZv=(_2 zia>fsUh7z(gVo21Pg_>4@VeevPqhX)xwD_fAnYFFwi~d48^?+^wh9HgoQJlj;6tJjKl53rg&%91Ynu2-9kVrF0;~?sDUA1zOD?=%%2T>x+&wQVQ z5PR-02vcdbuUcLPkuPz(>ygV7;B>cbZ$H?fo>02W64C5)Hi{q8F+^h;23;Db$$&-o zTiZKS1PL@_*E@FmpxFPr4ysNDq7|o?g(pMik3x9LZ>n+B%OepeHPKVEFFJxyGduG`g**YU@SF1QL5@Y?hZdSDqrFj+I bs!hVl+s|*l98M2swMW_J;|y)^{1f~IU|Ozn literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohappyeyeballs/__pycache__/utils.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohappyeyeballs/__pycache__/utils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aa2a80d8d694dde59f8946603a488530934bf4c4 GIT binary patch literal 3750 zcmbVOO>7&-6`o!0E|<%tWQn32*|N2EY%6pu(La&nKP6El|K&$=B-v<)6a>XxinPdG zc6Ldd!m1UD6rfrcpwR**P!v#mC{&~cl$+C&k4AeTD;r|A25KPfK{vX}$(Q!ckQ5oW z2;2<8*_nB7-h2Dzec$X~d_D<5`{L*O5|6wHeMKhCMkO%W))|EEAr*y@%BXCL2{ZJ` zhFN&JQm!-?=F)taPYYoo?GC%sVpwF5%Bg(Hla|5~j0H{5M9r;vHJSY4Tpt*2&f~7u zEY6Z~eT9rvH|*p!iHxa)Q^ilYu+M|k4%O3?s1j(&b$ykM3##{1KHLFb8$Rn+oBo>q z>#N{_XfZeUgNqj$XwrD7TzNqV)AqM%M9!%)#Mjjp+e=1441A%n`6=Ww9P3D$T~jzy<$pnO1;}mYFSvf=b0H4^enzPZs<7;TS`<{NCGv}R4kHf#WIwrl7eGUj5rlVl91}U&>Wt`n^|T7Ow2q17n(rd zKMjE4Y_0)3-sWvK$6#J{0bKYCu#Y?mgluL3Y~wE5b#n)Zu-s@i*MuZPcid)gQ&6ky zq7R{%E5;IAcg}Fgc7azv^@?tiLVcmNTe=hAP@V~Li;pByMAwW=Tm8qekyfmP_TSJj zl{ug}T7gP7L-5l|kYXj%nmH^{gR`)^O_Yh^Xj+3*DoInxnwm z(}Ds%2${jJLg#R%1`zf@>DGmgXXo@Wxn)d3PIZ{!0kWYF+_#lE5Js~=@KKN-CVN(( zgNpA){rjQH-CbpOUp3HMkgA7{EMKh#2L6Qveow(u?IH!;4|VD7D)m&n`>K2U3lqiO zl@ACqgp~`Wqkr`ts>*>)xxXU!mp*>XK~SnpczUb|B9j+D8P zdQRHkmK-z9$p!Fw4*`f-3gUi%6Wo>c8~{*X14qmq*=GMIR9($1G3d^I03?h1Z1(>I zC2J9Kq0MHR_Tc6vlmgWS(eP~=jmVmMjramD5#Qi3hNR2B#X?&*9c8H2B1uN;?xhheTU~YE2C*x z2a)za-NVI*;Rl4X%>8KS;)YV>OkFGk)P+`Nw2$;A8fAi1K0c-T2*N2v; zC`+*XFhJVdQ=DEIElq5Am8!gVQ$ARc53ZhlEDzOqP48^~% zBJV4uAIryTE?9gjcKoC3=-L|_UB{Q-YquMC)OT|I?EUG_M>qP$HoRls)%p{ur+9mn zE9J_EN6Ue?Hl(-9+}jjlL1r@OcifSPYQ!QDd<@3;Ui3n9+Pxo zQeF-Z3Yv*MWb866?6`nv={E(XS@JQpLn?G~x^d3*05M7G?-7lG63BD$LfTNXDeW!% z7KjM5nD0Xm31XNp(a=|D*WZxu?`Y&P8u=$0s0ptySD32QT@`%=tvFutmtw1@$~{La z9fNCuHFJIZzJG105*)pseK7Oz)d%1E;z#9<$%;7j%*A?znv3kNiAd-usKpDF4yD2$ z*!IxHGiZ#t$UJien8W0=<&(;;gEcxie&)Xaa~~Z)%hc(y3zN zZs%%X)m$52_piswgJ&xT&Xsqat4QZ-F3@|*OI6NO2yRLP6=`7AUzQG4xWlX2wU0N4 z-mMJ1`(XT`|6!~=^igGSy39>OpaQ$i!^T?oUgjO96%3g@eF>*LQLG6_kiK@4Ax-vw E0PbY5ng9R* literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohappyeyeballs/_staggered.py b/venv/lib/python3.12/site-packages/aiohappyeyeballs/_staggered.py new file mode 100644 index 00000000..9a4ba720 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohappyeyeballs/_staggered.py @@ -0,0 +1,207 @@ +import asyncio +import contextlib + +# PY3.9: Import Callable from typing until we drop Python 3.9 support +# https://github.com/python/cpython/issues/87131 +from typing import ( + TYPE_CHECKING, + Any, + Awaitable, + Callable, + Iterable, + List, + Optional, + Set, + Tuple, + TypeVar, + Union, +) + +_T = TypeVar("_T") + +RE_RAISE_EXCEPTIONS = (SystemExit, KeyboardInterrupt) + + +def _set_result(wait_next: "asyncio.Future[None]") -> None: + """Set the result of a future if it is not already done.""" + if not wait_next.done(): + wait_next.set_result(None) + + +async def _wait_one( + futures: "Iterable[asyncio.Future[Any]]", + loop: asyncio.AbstractEventLoop, +) -> _T: + """Wait for the first future to complete.""" + wait_next = loop.create_future() + + def _on_completion(fut: "asyncio.Future[Any]") -> None: + if not wait_next.done(): + wait_next.set_result(fut) + + for f in futures: + f.add_done_callback(_on_completion) + + try: + return await wait_next + finally: + for f in futures: + f.remove_done_callback(_on_completion) + + +async def staggered_race( + coro_fns: Iterable[Callable[[], Awaitable[_T]]], + delay: Optional[float], + *, + loop: Optional[asyncio.AbstractEventLoop] = None, +) -> Tuple[Optional[_T], Optional[int], List[Optional[BaseException]]]: + """ + Run coroutines with staggered start times and take the first to finish. + + This method takes an iterable of coroutine functions. The first one is + started immediately. From then on, whenever the immediately preceding one + fails (raises an exception), or when *delay* seconds has passed, the next + coroutine is started. This continues until one of the coroutines complete + successfully, in which case all others are cancelled, or until all + coroutines fail. + + The coroutines provided should be well-behaved in the following way: + + * They should only ``return`` if completed successfully. + + * They should always raise an exception if they did not complete + successfully. In particular, if they handle cancellation, they should + probably reraise, like this:: + + try: + # do work + except asyncio.CancelledError: + # undo partially completed work + raise + + Args: + ---- + coro_fns: an iterable of coroutine functions, i.e. callables that + return a coroutine object when called. Use ``functools.partial`` or + lambdas to pass arguments. + + delay: amount of time, in seconds, between starting coroutines. If + ``None``, the coroutines will run sequentially. + + loop: the event loop to use. If ``None``, the running loop is used. + + Returns: + ------- + tuple *(winner_result, winner_index, exceptions)* where + + - *winner_result*: the result of the winning coroutine, or ``None`` + if no coroutines won. + + - *winner_index*: the index of the winning coroutine in + ``coro_fns``, or ``None`` if no coroutines won. If the winning + coroutine may return None on success, *winner_index* can be used + to definitively determine whether any coroutine won. + + - *exceptions*: list of exceptions returned by the coroutines. + ``len(exceptions)`` is equal to the number of coroutines actually + started, and the order is the same as in ``coro_fns``. The winning + coroutine's entry is ``None``. + + """ + loop = loop or asyncio.get_running_loop() + exceptions: List[Optional[BaseException]] = [] + tasks: Set[asyncio.Task[Optional[Tuple[_T, int]]]] = set() + + async def run_one_coro( + coro_fn: Callable[[], Awaitable[_T]], + this_index: int, + start_next: "asyncio.Future[None]", + ) -> Optional[Tuple[_T, int]]: + """ + Run a single coroutine. + + If the coroutine fails, set the exception in the exceptions list and + start the next coroutine by setting the result of the start_next. + + If the coroutine succeeds, return the result and the index of the + coroutine in the coro_fns list. + + If SystemExit or KeyboardInterrupt is raised, re-raise it. + """ + try: + result = await coro_fn() + except RE_RAISE_EXCEPTIONS: + raise + except BaseException as e: + exceptions[this_index] = e + _set_result(start_next) # Kickstart the next coroutine + return None + + return result, this_index + + start_next_timer: Optional[asyncio.TimerHandle] = None + start_next: Optional[asyncio.Future[None]] + task: asyncio.Task[Optional[Tuple[_T, int]]] + done: Union[asyncio.Future[None], asyncio.Task[Optional[Tuple[_T, int]]]] + coro_iter = iter(coro_fns) + this_index = -1 + try: + while True: + if coro_fn := next(coro_iter, None): + this_index += 1 + exceptions.append(None) + start_next = loop.create_future() + task = loop.create_task(run_one_coro(coro_fn, this_index, start_next)) + tasks.add(task) + start_next_timer = ( + loop.call_later(delay, _set_result, start_next) if delay else None + ) + elif not tasks: + # We exhausted the coro_fns list and no tasks are running + # so we have no winner and all coroutines failed. + break + + while tasks or start_next: + done = await _wait_one( + (*tasks, start_next) if start_next else tasks, loop + ) + if done is start_next: + # The current task has failed or the timer has expired + # so we need to start the next task. + start_next = None + if start_next_timer: + start_next_timer.cancel() + start_next_timer = None + + # Break out of the task waiting loop to start the next + # task. + break + + if TYPE_CHECKING: + assert isinstance(done, asyncio.Task) + + tasks.remove(done) + if winner := done.result(): + return *winner, exceptions + finally: + # We either have: + # - a winner + # - all tasks failed + # - a KeyboardInterrupt or SystemExit. + + # + # If the timer is still running, cancel it. + # + if start_next_timer: + start_next_timer.cancel() + + # + # If there are any tasks left, cancel them and than + # wait them so they fill the exceptions list. + # + for task in tasks: + task.cancel() + with contextlib.suppress(asyncio.CancelledError): + await task + + return None, None, exceptions diff --git a/venv/lib/python3.12/site-packages/aiohappyeyeballs/impl.py b/venv/lib/python3.12/site-packages/aiohappyeyeballs/impl.py new file mode 100644 index 00000000..8f3919a0 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohappyeyeballs/impl.py @@ -0,0 +1,259 @@ +"""Base implementation.""" + +import asyncio +import collections +import contextlib +import functools +import itertools +import socket +from typing import List, Optional, Sequence, Set, Union + +from . import _staggered +from .types import AddrInfoType, SocketFactoryType + + +async def start_connection( + addr_infos: Sequence[AddrInfoType], + *, + local_addr_infos: Optional[Sequence[AddrInfoType]] = None, + happy_eyeballs_delay: Optional[float] = None, + interleave: Optional[int] = None, + loop: Optional[asyncio.AbstractEventLoop] = None, + socket_factory: Optional[SocketFactoryType] = None, +) -> socket.socket: + """ + Connect to a TCP server. + + Create a socket connection to a specified destination. The + destination is specified as a list of AddrInfoType tuples as + returned from getaddrinfo(). + + The arguments are, in order: + + * ``family``: the address family, e.g. ``socket.AF_INET`` or + ``socket.AF_INET6``. + * ``type``: the socket type, e.g. ``socket.SOCK_STREAM`` or + ``socket.SOCK_DGRAM``. + * ``proto``: the protocol, e.g. ``socket.IPPROTO_TCP`` or + ``socket.IPPROTO_UDP``. + * ``canonname``: the canonical name of the address, e.g. + ``"www.python.org"``. + * ``sockaddr``: the socket address + + This method is a coroutine which will try to establish the connection + in the background. When successful, the coroutine returns a + socket. + + The expected use case is to use this method in conjunction with + loop.create_connection() to establish a connection to a server:: + + socket = await start_connection(addr_infos) + transport, protocol = await loop.create_connection( + MyProtocol, sock=socket, ...) + """ + if not (current_loop := loop): + current_loop = asyncio.get_running_loop() + + single_addr_info = len(addr_infos) == 1 + + if happy_eyeballs_delay is not None and interleave is None: + # If using happy eyeballs, default to interleave addresses by family + interleave = 1 + + if interleave and not single_addr_info: + addr_infos = _interleave_addrinfos(addr_infos, interleave) + + sock: Optional[socket.socket] = None + # uvloop can raise RuntimeError instead of OSError + exceptions: List[List[Union[OSError, RuntimeError]]] = [] + if happy_eyeballs_delay is None or single_addr_info: + # not using happy eyeballs + for addrinfo in addr_infos: + try: + sock = await _connect_sock( + current_loop, + exceptions, + addrinfo, + local_addr_infos, + None, + socket_factory, + ) + break + except (RuntimeError, OSError): + continue + else: # using happy eyeballs + open_sockets: Set[socket.socket] = set() + try: + sock, _, _ = await _staggered.staggered_race( + ( + functools.partial( + _connect_sock, + current_loop, + exceptions, + addrinfo, + local_addr_infos, + open_sockets, + socket_factory, + ) + for addrinfo in addr_infos + ), + happy_eyeballs_delay, + ) + finally: + # If we have a winner, staggered_race will + # cancel the other tasks, however there is a + # small race window where any of the other tasks + # can be done before they are cancelled which + # will leave the socket open. To avoid this problem + # we pass a set to _connect_sock to keep track of + # the open sockets and close them here if there + # are any "runner up" sockets. + for s in open_sockets: + if s is not sock: + with contextlib.suppress(OSError): + s.close() + open_sockets = None # type: ignore[assignment] + + if sock is None: + all_exceptions = [exc for sub in exceptions for exc in sub] + try: + first_exception = all_exceptions[0] + if len(all_exceptions) == 1: + raise first_exception + else: + # If they all have the same str(), raise one. + model = str(first_exception) + if all(str(exc) == model for exc in all_exceptions): + raise first_exception + # Raise a combined exception so the user can see all + # the various error messages. + msg = "Multiple exceptions: {}".format( + ", ".join(str(exc) for exc in all_exceptions) + ) + # If the errno is the same for all exceptions, raise + # an OSError with that errno. + if isinstance(first_exception, OSError): + first_errno = first_exception.errno + if all( + isinstance(exc, OSError) and exc.errno == first_errno + for exc in all_exceptions + ): + raise OSError(first_errno, msg) + elif isinstance(first_exception, RuntimeError) and all( + isinstance(exc, RuntimeError) for exc in all_exceptions + ): + raise RuntimeError(msg) + # We have a mix of OSError and RuntimeError + # so we have to pick which one to raise. + # and we raise OSError for compatibility + raise OSError(msg) + finally: + all_exceptions = None # type: ignore[assignment] + exceptions = None # type: ignore[assignment] + + return sock + + +async def _connect_sock( + loop: asyncio.AbstractEventLoop, + exceptions: List[List[Union[OSError, RuntimeError]]], + addr_info: AddrInfoType, + local_addr_infos: Optional[Sequence[AddrInfoType]] = None, + open_sockets: Optional[Set[socket.socket]] = None, + socket_factory: Optional[SocketFactoryType] = None, +) -> socket.socket: + """ + Create, bind and connect one socket. + + If open_sockets is passed, add the socket to the set of open sockets. + Any failure caught here will remove the socket from the set and close it. + + Callers can use this set to close any sockets that are not the winner + of all staggered tasks in the result there are runner up sockets aka + multiple winners. + """ + my_exceptions: List[Union[OSError, RuntimeError]] = [] + exceptions.append(my_exceptions) + family, type_, proto, _, address = addr_info + sock = None + try: + if socket_factory is not None: + sock = socket_factory(addr_info) + else: + sock = socket.socket(family=family, type=type_, proto=proto) + if open_sockets is not None: + open_sockets.add(sock) + sock.setblocking(False) + if local_addr_infos is not None: + for lfamily, _, _, _, laddr in local_addr_infos: + # skip local addresses of different family + if lfamily != family: + continue + try: + sock.bind(laddr) + break + except OSError as exc: + msg = ( + f"error while attempting to bind on " + f"address {laddr!r}: " + f"{(exc.strerror or '').lower()}" + ) + exc = OSError(exc.errno, msg) + my_exceptions.append(exc) + else: # all bind attempts failed + if my_exceptions: + raise my_exceptions.pop() + else: + raise OSError(f"no matching local address with {family=} found") + await loop.sock_connect(sock, address) + return sock + except (RuntimeError, OSError) as exc: + my_exceptions.append(exc) + if sock is not None: + if open_sockets is not None: + open_sockets.remove(sock) + try: + sock.close() + except OSError as e: + my_exceptions.append(e) + raise + raise + except: + if sock is not None: + if open_sockets is not None: + open_sockets.remove(sock) + try: + sock.close() + except OSError as e: + my_exceptions.append(e) + raise + raise + finally: + exceptions = my_exceptions = None # type: ignore[assignment] + + +def _interleave_addrinfos( + addrinfos: Sequence[AddrInfoType], first_address_family_count: int = 1 +) -> List[AddrInfoType]: + """Interleave list of addrinfo tuples by family.""" + # Group addresses by family + addrinfos_by_family: collections.OrderedDict[int, List[AddrInfoType]] = ( + collections.OrderedDict() + ) + for addr in addrinfos: + family = addr[0] + if family not in addrinfos_by_family: + addrinfos_by_family[family] = [] + addrinfos_by_family[family].append(addr) + addrinfos_lists = list(addrinfos_by_family.values()) + + reordered: List[AddrInfoType] = [] + if first_address_family_count > 1: + reordered.extend(addrinfos_lists[0][: first_address_family_count - 1]) + del addrinfos_lists[0][: first_address_family_count - 1] + reordered.extend( + a + for a in itertools.chain.from_iterable(itertools.zip_longest(*addrinfos_lists)) + if a is not None + ) + return reordered diff --git a/venv/lib/python3.12/site-packages/aiohappyeyeballs/py.typed b/venv/lib/python3.12/site-packages/aiohappyeyeballs/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/venv/lib/python3.12/site-packages/aiohappyeyeballs/types.py b/venv/lib/python3.12/site-packages/aiohappyeyeballs/types.py new file mode 100644 index 00000000..e8c75074 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohappyeyeballs/types.py @@ -0,0 +1,17 @@ +"""Types for aiohappyeyeballs.""" + +import socket + +# PY3.9: Import Callable from typing until we drop Python 3.9 support +# https://github.com/python/cpython/issues/87131 +from typing import Callable, Tuple, Union + +AddrInfoType = Tuple[ + Union[int, socket.AddressFamily], + Union[int, socket.SocketKind], + int, + str, + Tuple, # type: ignore[type-arg] +] + +SocketFactoryType = Callable[[AddrInfoType], socket.socket] diff --git a/venv/lib/python3.12/site-packages/aiohappyeyeballs/utils.py b/venv/lib/python3.12/site-packages/aiohappyeyeballs/utils.py new file mode 100644 index 00000000..ea29adb9 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohappyeyeballs/utils.py @@ -0,0 +1,97 @@ +"""Utility functions for aiohappyeyeballs.""" + +import ipaddress +import socket +from typing import Dict, List, Optional, Tuple, Union + +from .types import AddrInfoType + + +def addr_to_addr_infos( + addr: Optional[ + Union[Tuple[str, int, int, int], Tuple[str, int, int], Tuple[str, int]] + ], +) -> Optional[List[AddrInfoType]]: + """Convert an address tuple to a list of addr_info tuples.""" + if addr is None: + return None + host = addr[0] + port = addr[1] + is_ipv6 = ":" in host + if is_ipv6: + flowinfo = 0 + scopeid = 0 + addr_len = len(addr) + if addr_len >= 4: + scopeid = addr[3] # type: ignore[misc] + if addr_len >= 3: + flowinfo = addr[2] # type: ignore[misc] + addr = (host, port, flowinfo, scopeid) + family = socket.AF_INET6 + else: + addr = (host, port) + family = socket.AF_INET + return [(family, socket.SOCK_STREAM, socket.IPPROTO_TCP, "", addr)] + + +def pop_addr_infos_interleave( + addr_infos: List[AddrInfoType], interleave: Optional[int] = None +) -> None: + """ + Pop addr_info from the list of addr_infos by family up to interleave times. + + The interleave parameter is used to know how many addr_infos for + each family should be popped of the top of the list. + """ + seen: Dict[int, int] = {} + if interleave is None: + interleave = 1 + to_remove: List[AddrInfoType] = [] + for addr_info in addr_infos: + family = addr_info[0] + if family not in seen: + seen[family] = 0 + if seen[family] < interleave: + to_remove.append(addr_info) + seen[family] += 1 + for addr_info in to_remove: + addr_infos.remove(addr_info) + + +def _addr_tuple_to_ip_address( + addr: Union[Tuple[str, int], Tuple[str, int, int, int]], +) -> Union[ + Tuple[ipaddress.IPv4Address, int], Tuple[ipaddress.IPv6Address, int, int, int] +]: + """Convert an address tuple to an IPv4Address.""" + return (ipaddress.ip_address(addr[0]), *addr[1:]) + + +def remove_addr_infos( + addr_infos: List[AddrInfoType], + addr: Union[Tuple[str, int], Tuple[str, int, int, int]], +) -> None: + """ + Remove an address from the list of addr_infos. + + The addr value is typically the return value of + sock.getpeername(). + """ + bad_addrs_infos: List[AddrInfoType] = [] + for addr_info in addr_infos: + if addr_info[-1] == addr: + bad_addrs_infos.append(addr_info) + if bad_addrs_infos: + for bad_addr_info in bad_addrs_infos: + addr_infos.remove(bad_addr_info) + return + # Slow path in case addr is formatted differently + match_addr = _addr_tuple_to_ip_address(addr) + for addr_info in addr_infos: + if match_addr == _addr_tuple_to_ip_address(addr_info[-1]): + bad_addrs_infos.append(addr_info) + if bad_addrs_infos: + for bad_addr_info in bad_addrs_infos: + addr_infos.remove(bad_addr_info) + return + raise ValueError(f"Address {addr} not found in addr_infos") diff --git a/venv/lib/python3.12/site-packages/aiohttp-3.11.18.dist-info/INSTALLER b/venv/lib/python3.12/site-packages/aiohttp-3.11.18.dist-info/INSTALLER new file mode 100644 index 00000000..a1b589e3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp-3.11.18.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.12/site-packages/aiohttp-3.11.18.dist-info/METADATA b/venv/lib/python3.12/site-packages/aiohttp-3.11.18.dist-info/METADATA new file mode 100644 index 00000000..08abb52b --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp-3.11.18.dist-info/METADATA @@ -0,0 +1,251 @@ +Metadata-Version: 2.4 +Name: aiohttp +Version: 3.11.18 +Summary: Async http client/server framework (asyncio) +Home-page: https://github.com/aio-libs/aiohttp +Maintainer: aiohttp team +Maintainer-email: team@aiohttp.org +License: Apache-2.0 +Project-URL: Chat: Matrix, https://matrix.to/#/#aio-libs:matrix.org +Project-URL: Chat: Matrix Space, https://matrix.to/#/#aio-libs-space:matrix.org +Project-URL: CI: GitHub Actions, https://github.com/aio-libs/aiohttp/actions?query=workflow%3ACI +Project-URL: Coverage: codecov, https://codecov.io/github/aio-libs/aiohttp +Project-URL: Docs: Changelog, https://docs.aiohttp.org/en/stable/changes.html +Project-URL: Docs: RTD, https://docs.aiohttp.org +Project-URL: GitHub: issues, https://github.com/aio-libs/aiohttp/issues +Project-URL: GitHub: repo, https://github.com/aio-libs/aiohttp +Classifier: Development Status :: 5 - Production/Stable +Classifier: Framework :: AsyncIO +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Apache Software License +Classifier: Operating System :: POSIX +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Operating System :: Microsoft :: Windows +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Topic :: Internet :: WWW/HTTP +Requires-Python: >=3.9 +Description-Content-Type: text/x-rst +License-File: LICENSE.txt +Requires-Dist: aiohappyeyeballs>=2.3.0 +Requires-Dist: aiosignal>=1.1.2 +Requires-Dist: async-timeout<6.0,>=4.0; python_version < "3.11" +Requires-Dist: attrs>=17.3.0 +Requires-Dist: frozenlist>=1.1.1 +Requires-Dist: multidict<7.0,>=4.5 +Requires-Dist: propcache>=0.2.0 +Requires-Dist: yarl<2.0,>=1.17.0 +Provides-Extra: speedups +Requires-Dist: aiodns>=3.2.0; (sys_platform == "linux" or sys_platform == "darwin") and extra == "speedups" +Requires-Dist: Brotli; platform_python_implementation == "CPython" and extra == "speedups" +Requires-Dist: brotlicffi; platform_python_implementation != "CPython" and extra == "speedups" +Dynamic: license-file + +================================== +Async http client/server framework +================================== + +.. image:: https://raw.githubusercontent.com/aio-libs/aiohttp/master/docs/aiohttp-plain.svg + :height: 64px + :width: 64px + :alt: aiohttp logo + +| + +.. image:: https://github.com/aio-libs/aiohttp/workflows/CI/badge.svg + :target: https://github.com/aio-libs/aiohttp/actions?query=workflow%3ACI + :alt: GitHub Actions status for master branch + +.. image:: https://codecov.io/gh/aio-libs/aiohttp/branch/master/graph/badge.svg + :target: https://codecov.io/gh/aio-libs/aiohttp + :alt: codecov.io status for master branch + +.. image:: https://img.shields.io/endpoint?url=https://codspeed.io/badge.json + :target: https://codspeed.io/aio-libs/aiohttp + :alt: Codspeed.io status for aiohttp + +.. image:: https://badge.fury.io/py/aiohttp.svg + :target: https://pypi.org/project/aiohttp + :alt: Latest PyPI package version + +.. image:: https://readthedocs.org/projects/aiohttp/badge/?version=latest + :target: https://docs.aiohttp.org/ + :alt: Latest Read The Docs + +.. image:: https://img.shields.io/matrix/aio-libs:matrix.org?label=Discuss%20on%20Matrix%20at%20%23aio-libs%3Amatrix.org&logo=matrix&server_fqdn=matrix.org&style=flat + :target: https://matrix.to/#/%23aio-libs:matrix.org + :alt: Matrix Room — #aio-libs:matrix.org + +.. image:: https://img.shields.io/matrix/aio-libs-space:matrix.org?label=Discuss%20on%20Matrix%20at%20%23aio-libs-space%3Amatrix.org&logo=matrix&server_fqdn=matrix.org&style=flat + :target: https://matrix.to/#/%23aio-libs-space:matrix.org + :alt: Matrix Space — #aio-libs-space:matrix.org + + +Key Features +============ + +- Supports both client and server side of HTTP protocol. +- Supports both client and server Web-Sockets out-of-the-box and avoids + Callback Hell. +- Provides Web-server with middleware and pluggable routing. + + +Getting started +=============== + +Client +------ + +To get something from the web: + +.. code-block:: python + + import aiohttp + import asyncio + + async def main(): + + async with aiohttp.ClientSession() as session: + async with session.get('http://python.org') as response: + + print("Status:", response.status) + print("Content-type:", response.headers['content-type']) + + html = await response.text() + print("Body:", html[:15], "...") + + asyncio.run(main()) + +This prints: + +.. code-block:: + + Status: 200 + Content-type: text/html; charset=utf-8 + Body: ... + +Coming from `requests `_ ? Read `why we need so many lines `_. + +Server +------ + +An example using a simple server: + +.. code-block:: python + + # examples/server_simple.py + from aiohttp import web + + async def handle(request): + name = request.match_info.get('name', "Anonymous") + text = "Hello, " + name + return web.Response(text=text) + + async def wshandle(request): + ws = web.WebSocketResponse() + await ws.prepare(request) + + async for msg in ws: + if msg.type == web.WSMsgType.text: + await ws.send_str("Hello, {}".format(msg.data)) + elif msg.type == web.WSMsgType.binary: + await ws.send_bytes(msg.data) + elif msg.type == web.WSMsgType.close: + break + + return ws + + + app = web.Application() + app.add_routes([web.get('/', handle), + web.get('/echo', wshandle), + web.get('/{name}', handle)]) + + if __name__ == '__main__': + web.run_app(app) + + +Documentation +============= + +https://aiohttp.readthedocs.io/ + + +Demos +===== + +https://github.com/aio-libs/aiohttp-demos + + +External links +============== + +* `Third party libraries + `_ +* `Built with aiohttp + `_ +* `Powered by aiohttp + `_ + +Feel free to make a Pull Request for adding your link to these pages! + + +Communication channels +====================== + +*aio-libs Discussions*: https://github.com/aio-libs/aiohttp/discussions + +*Matrix*: `#aio-libs:matrix.org `_ + +We support `Stack Overflow +`_. +Please add *aiohttp* tag to your question there. + +Requirements +============ + +- attrs_ +- multidict_ +- yarl_ +- frozenlist_ + +Optionally you may install the aiodns_ library (highly recommended for sake of speed). + +.. _aiodns: https://pypi.python.org/pypi/aiodns +.. _attrs: https://github.com/python-attrs/attrs +.. _multidict: https://pypi.python.org/pypi/multidict +.. _frozenlist: https://pypi.org/project/frozenlist/ +.. _yarl: https://pypi.python.org/pypi/yarl +.. _async-timeout: https://pypi.python.org/pypi/async_timeout + +License +======= + +``aiohttp`` is offered under the Apache 2 license. + + +Keepsafe +======== + +The aiohttp community would like to thank Keepsafe +(https://www.getkeepsafe.com) for its support in the early days of +the project. + + +Source code +=========== + +The latest developer version is available in a GitHub repository: +https://github.com/aio-libs/aiohttp + +Benchmarks +========== + +If you are interested in efficiency, the AsyncIO community maintains a +list of benchmarks on the official wiki: +https://github.com/python/asyncio/wiki/Benchmarks diff --git a/venv/lib/python3.12/site-packages/aiohttp-3.11.18.dist-info/RECORD b/venv/lib/python3.12/site-packages/aiohttp-3.11.18.dist-info/RECORD new file mode 100644 index 00000000..981a3fab --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp-3.11.18.dist-info/RECORD @@ -0,0 +1,131 @@ +aiohttp-3.11.18.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +aiohttp-3.11.18.dist-info/METADATA,sha256=UQ-0odI_X0zoX3I7iqbE9eoQmKQoLKI7mLXcW3TXvJQ,7734 +aiohttp-3.11.18.dist-info/RECORD,, +aiohttp-3.11.18.dist-info/WHEEL,sha256=s3SCZeN-G9VuOPYdbIQ149WhzOgcaPLKGJFMWgov7lM,109 +aiohttp-3.11.18.dist-info/licenses/LICENSE.txt,sha256=n4DQ2311WpQdtFchcsJw7L2PCCuiFd3QlZhZQu2Uqes,588 +aiohttp-3.11.18.dist-info/top_level.txt,sha256=iv-JIaacmTl-hSho3QmphcKnbRRYx1st47yjz_178Ro,8 +aiohttp/.hash/_cparser.pxd.hash,sha256=ND581Lvrk-K59r0E07G3CdJKQo3ScvVS9zoo7lvkLYs,64 +aiohttp/.hash/_find_header.pxd.hash,sha256=BtbSPeZ2eOtt807jecTkoEeBQ4C5AiBxjzbvJj9eV6E,64 +aiohttp/.hash/_http_parser.pyx.hash,sha256=TWqCWxc7H7X4J7E7SCLa9_b4ZlsjUxhTh4-uNlrPwqY,64 +aiohttp/.hash/_http_writer.pyx.hash,sha256=gFrTY7VEARZbbvOr0txsB4Kbot2EX1xkOCPZR3lu3rA,64 +aiohttp/.hash/hdrs.py.hash,sha256=LtOwhipa1RSijAkQISL_oWWzED2PRlxP8CZwWOx62Tc,64 +aiohttp/__init__.py,sha256=0cJB-M8GgSmOQVpa6xqnk1pBf7pLBc4RcLde78nmzug,7840 +aiohttp/__pycache__/__init__.cpython-312.pyc,, +aiohttp/__pycache__/abc.cpython-312.pyc,, +aiohttp/__pycache__/base_protocol.cpython-312.pyc,, +aiohttp/__pycache__/client.cpython-312.pyc,, +aiohttp/__pycache__/client_exceptions.cpython-312.pyc,, +aiohttp/__pycache__/client_proto.cpython-312.pyc,, +aiohttp/__pycache__/client_reqrep.cpython-312.pyc,, +aiohttp/__pycache__/client_ws.cpython-312.pyc,, +aiohttp/__pycache__/compression_utils.cpython-312.pyc,, +aiohttp/__pycache__/connector.cpython-312.pyc,, +aiohttp/__pycache__/cookiejar.cpython-312.pyc,, +aiohttp/__pycache__/formdata.cpython-312.pyc,, +aiohttp/__pycache__/hdrs.cpython-312.pyc,, +aiohttp/__pycache__/helpers.cpython-312.pyc,, +aiohttp/__pycache__/http.cpython-312.pyc,, +aiohttp/__pycache__/http_exceptions.cpython-312.pyc,, +aiohttp/__pycache__/http_parser.cpython-312.pyc,, +aiohttp/__pycache__/http_websocket.cpython-312.pyc,, +aiohttp/__pycache__/http_writer.cpython-312.pyc,, +aiohttp/__pycache__/log.cpython-312.pyc,, +aiohttp/__pycache__/multipart.cpython-312.pyc,, +aiohttp/__pycache__/payload.cpython-312.pyc,, +aiohttp/__pycache__/payload_streamer.cpython-312.pyc,, +aiohttp/__pycache__/pytest_plugin.cpython-312.pyc,, +aiohttp/__pycache__/resolver.cpython-312.pyc,, +aiohttp/__pycache__/streams.cpython-312.pyc,, +aiohttp/__pycache__/tcp_helpers.cpython-312.pyc,, +aiohttp/__pycache__/test_utils.cpython-312.pyc,, +aiohttp/__pycache__/tracing.cpython-312.pyc,, +aiohttp/__pycache__/typedefs.cpython-312.pyc,, +aiohttp/__pycache__/web.cpython-312.pyc,, +aiohttp/__pycache__/web_app.cpython-312.pyc,, +aiohttp/__pycache__/web_exceptions.cpython-312.pyc,, +aiohttp/__pycache__/web_fileresponse.cpython-312.pyc,, +aiohttp/__pycache__/web_log.cpython-312.pyc,, +aiohttp/__pycache__/web_middlewares.cpython-312.pyc,, +aiohttp/__pycache__/web_protocol.cpython-312.pyc,, +aiohttp/__pycache__/web_request.cpython-312.pyc,, +aiohttp/__pycache__/web_response.cpython-312.pyc,, +aiohttp/__pycache__/web_routedef.cpython-312.pyc,, +aiohttp/__pycache__/web_runner.cpython-312.pyc,, +aiohttp/__pycache__/web_server.cpython-312.pyc,, +aiohttp/__pycache__/web_urldispatcher.cpython-312.pyc,, +aiohttp/__pycache__/web_ws.cpython-312.pyc,, +aiohttp/__pycache__/worker.cpython-312.pyc,, +aiohttp/_cparser.pxd,sha256=8jGIg-VJ9p3llwCakUYDsPGxA4HiZe9dmK9Jmtlz-5g,4318 +aiohttp/_find_header.pxd,sha256=0GfwFCPN2zxEKTO1_MA5sYq2UfzsG8kcV3aTqvwlz3g,68 +aiohttp/_headers.pxi,sha256=n701k28dVPjwRnx5j6LpJhLTfj7dqu2vJt7f0O60Oyg,2007 +aiohttp/_http_parser.cpython-312-darwin.so,sha256=evfEY-ZNgH8Tgx3FnTtrRUAgu9ip-55RDSQhh3ivsbU,388096 +aiohttp/_http_parser.pyx,sha256=wQdADj5LizwC_7nFGr8nIlk6GpoaQeQ0359H0HMKGuM,28241 +aiohttp/_http_writer.cpython-312-darwin.so,sha256=VJefNGhxvqDOM53twm1314Xd3mP3YS-ETBXwcM2KKMk,99216 +aiohttp/_http_writer.pyx,sha256=96seJigne4J3LVnB3DAzwTSV12nfZ7HR1JsaR0p13VI,4561 +aiohttp/_websocket/.hash/mask.pxd.hash,sha256=1l0t0G2gky43IXuRTduT2EnQlMuoUdITrBrQksCLlzA,64 +aiohttp/_websocket/.hash/mask.pyx.hash,sha256=iM53azQIY5pydRZUsfEP3HbS6JrhrXR-haTK4TGoWrQ,64 +aiohttp/_websocket/.hash/reader_c.pxd.hash,sha256=kGVrGDxNmLUb06ygH-Adi2O8Jjx1ujeIU0c58tfZaxA,64 +aiohttp/_websocket/__init__.py,sha256=Mar3R9_vBN_Ea4lsW7iTAVXD7OKswKPGqF5xgSyt77k,44 +aiohttp/_websocket/__pycache__/__init__.cpython-312.pyc,, +aiohttp/_websocket/__pycache__/helpers.cpython-312.pyc,, +aiohttp/_websocket/__pycache__/models.cpython-312.pyc,, +aiohttp/_websocket/__pycache__/reader.cpython-312.pyc,, +aiohttp/_websocket/__pycache__/reader_c.cpython-312.pyc,, +aiohttp/_websocket/__pycache__/reader_py.cpython-312.pyc,, +aiohttp/_websocket/__pycache__/writer.cpython-312.pyc,, +aiohttp/_websocket/helpers.py,sha256=P-XLv8IUaihKzDenVUqfKU5DJbWE5HvG8uhvUZK8Ic4,5038 +aiohttp/_websocket/mask.cpython-312-darwin.so,sha256=8sCv3EynG9yVSTEOnphjQiEk9YPuTDYCc2zsmcAiQfc,79832 +aiohttp/_websocket/mask.pxd,sha256=sBmZ1Amym9kW4Ge8lj1fLZ7mPPya4LzLdpkQExQXv5M,112 +aiohttp/_websocket/mask.pyx,sha256=BHjOtV0O0w7xp9p0LNADRJvGmgfPn9sGeJvSs0fL__4,1397 +aiohttp/_websocket/models.py,sha256=XAzjs_8JYszWXIgZ6R3ZRrF-tX9Q_6LiD49WRYojopM,2121 +aiohttp/_websocket/reader.py,sha256=eC4qS0c5sOeQ2ebAHLaBpIaTVFaSKX79pY2xvh3Pqyw,1030 +aiohttp/_websocket/reader_c.cpython-312-darwin.so,sha256=Zs91jayucwP_BY6berI6wyMwRlP2R_rhkiEWH0GACJ8,225616 +aiohttp/_websocket/reader_c.pxd,sha256=nl_njtDrzlQU0rjgGGjZDB-swguE0tX_bCPobkShVa4,2625 +aiohttp/_websocket/reader_c.py,sha256=PGPGNljGjdyi-Vu0EJmSqeeUKYYpMUfOXXTm4XYGgkY,18358 +aiohttp/_websocket/reader_py.py,sha256=PGPGNljGjdyi-Vu0EJmSqeeUKYYpMUfOXXTm4XYGgkY,18358 +aiohttp/_websocket/writer.py,sha256=T3P36iMrzVPPC2XeScserHMD5vd9an6yizWzqDUkRZ0,7077 +aiohttp/abc.py,sha256=JLMOxrKLGTDaPRLfraY1pl-xka53YiHhAH9yaF9QRXQ,6512 +aiohttp/base_protocol.py,sha256=Tp8cxUPQvv9kUPk3w6lAzk6d2MAzV3scwI_3Go3C47c,3025 +aiohttp/client.py,sha256=isdfGlM4O5ILr4F4gBABlybxo4MQ1tNaMm7zjMcrfrM,54309 +aiohttp/client_exceptions.py,sha256=uyKbxI2peZhKl7lELBMx3UeusNkfpemPWpGFq0r6JeM,11367 +aiohttp/client_proto.py,sha256=ThkL2fsULn00l1yjez4bHrGlnShVZaijMq-RvX-XsVc,10073 +aiohttp/client_reqrep.py,sha256=VAgh0NxP2HvYWx6nX1Pr8FINc1m-W8-5q2zKeZV68n8,43925 +aiohttp/client_ws.py,sha256=1CIjIXwyzOMIYw6AjUES4-qUwbyVHW1seJKQfg_Rta8,15109 +aiohttp/compression_utils.py,sha256=0J3EAOR-0HehlYIudJXRu_Kr6hrYCY0IfuJ1px9MhQs,5681 +aiohttp/connector.py,sha256=P3F6Bb1QI62mKPJxfK0Ru_7Q5YmvxKg7uHQOcS8UXUI,60545 +aiohttp/cookiejar.py,sha256=PYR1K1mkLa24Hm6c9UEJnAitccNzz97CbsJyQ2ULAlU,17615 +aiohttp/formdata.py,sha256=CUJnCWDNHFcXSYZ_TupaT6rHkY-Q7ghssvWzaYBPIo0,6552 +aiohttp/hdrs.py,sha256=2rj5MyA-6yRdYPhW5UKkW4iNWhEAlGIOSBH5D4FmKNE,5111 +aiohttp/helpers.py,sha256=bblNEhp4hFimEmxMdPNxEluBY17L5YUArHYvoxzoEe4,29614 +aiohttp/http.py,sha256=8o8j8xH70OWjnfTWA9V44NR785QPxEPrUtzMXiAVpwc,1842 +aiohttp/http_exceptions.py,sha256=RYmBycJvvPerKkgXXm8v145I1N-fbsgSpcsbNIC-gdE,2961 +aiohttp/http_parser.py,sha256=UqerYPJzA1MqLmeG1jURhTNO1YhwUASK3QVcNEz0me8,36851 +aiohttp/http_websocket.py,sha256=8VXFKw6KQUEmPg48GtRMB37v0gTK7A0inoxXuDxMZEc,842 +aiohttp/http_writer.py,sha256=pRIyfOmL3cZmdWDWBBJ2cZEwEJzLWzlPPAJInaPLThI,7595 +aiohttp/log.py,sha256=BbNKx9e3VMIm0xYjZI0IcBBoS7wjdeIeSaiJE7-qK2g,325 +aiohttp/multipart.py,sha256=SABIvo3vhXzG4bLDZ0C4V3yG_86vAb-3Zb9Li7BVmI8,36944 +aiohttp/payload.py,sha256=rCA9JJI_RMCik_7qNIaC1Bh21aXhABGYK2tsYeaHRQ4,15793 +aiohttp/payload_streamer.py,sha256=ZzEYyfzcjGWkVkK3XR2pBthSCSIykYvY3Wr5cGQ2eTc,2211 +aiohttp/py.typed,sha256=sow9soTwP9T_gEAQSVh7Gb8855h04Nwmhs2We-JRgZM,7 +aiohttp/pytest_plugin.py,sha256=9_W52SURT-ap75wXSJmrAOvCl2DWr_aMHgM5qfQlH2s,12768 +aiohttp/resolver.py,sha256=aFKe2klqUyrczmvB31_dju50J8_ROl8LwlbTXgqig7s,6469 +aiohttp/streams.py,sha256=U-qTkuAqIfpJChuKEy-vYn8nQ_Z1MVcW0WO2DHiJz_o,22329 +aiohttp/tcp_helpers.py,sha256=BSadqVWaBpMFDRWnhaaR941N9MiDZ7bdTrxgCb0CW-M,961 +aiohttp/test_utils.py,sha256=ZJSzZWjC76KSbtwddTKcP6vHpUl_ozfAf3F93ewmHRU,23016 +aiohttp/tracing.py,sha256=66XQwtdR5DHv8p953eeNL0l8o6iHDaNwH9bBaybHXD4,15137 +aiohttp/typedefs.py,sha256=wUlqwe9Mw9W8jT3HsYJcYk00qP3EMPz3nTkYXmeNN48,1657 +aiohttp/web.py,sha256=As5nqGQy4QXWMXSaOsh0JudSVVJVIt_nr3n0b8CaMb0,18422 +aiohttp/web_app.py,sha256=Zre0QHM9JAp4d7jrj5NRxlPnfTrKLNuA42Rdsh8Q2TI,19554 +aiohttp/web_exceptions.py,sha256=7nIuiwhZ39vJJ9KrWqArA5QcWbUdqkz2CLwEpJapeN8,10360 +aiohttp/web_fileresponse.py,sha256=FRsS0p9r1KU5y8ceG0QXBYnrL6xggjbxcXSmI6qIR4k,16504 +aiohttp/web_log.py,sha256=rX5D7xLOX2B6BMdiZ-chme_KfJfW5IXEoFwLfkfkajs,7865 +aiohttp/web_middlewares.py,sha256=sFI0AgeNjdyAjuz92QtMIpngmJSOxrqe2Jfbs4BNUu0,4165 +aiohttp/web_protocol.py,sha256=c8a0PKGqfhIAiq2RboMsy1NRza4dnj6gnXIWvJUeCF0,27015 +aiohttp/web_request.py,sha256=S1m2Z_NLJ17XwuGC1em9bHWrtYcp_a1mNvqCrwY-FkQ,29637 +aiohttp/web_response.py,sha256=hP4vgcpX8Vqp1ArwjxZh31M57Pzw_M4a4_DtfIdQE30,28571 +aiohttp/web_routedef.py,sha256=VT1GAx6BrawoDh5RwBwBu5wSABSqgWwAe74AUCyZAEo,6110 +aiohttp/web_runner.py,sha256=v1G1nKiOOQgFnTSR4IMc6I9ReEFDMaHtMLvO_roDM-A,11786 +aiohttp/web_server.py,sha256=-9WDKUAiR9ll-rSdwXSqG6YjaoW79d1R4y0BGSqgUMA,2888 +aiohttp/web_urldispatcher.py,sha256=sFkcsa8qLFkDp47_oW7Z7fiq7DcVXiff1Etn0QN8DJA,44000 +aiohttp/web_ws.py,sha256=pyC31WpoQP9WIeCId9uJ4PKeFguESMb7DE3fcybT_RQ,22652 +aiohttp/worker.py,sha256=zT0iWN5Xze194bO6_VjHou0x7lR_k0MviN6Kadnk22g,8152 diff --git a/venv/lib/python3.12/site-packages/aiohttp-3.11.18.dist-info/WHEEL b/venv/lib/python3.12/site-packages/aiohttp-3.11.18.dist-info/WHEEL new file mode 100644 index 00000000..e9c4e0e4 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp-3.11.18.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: setuptools (79.0.0) +Root-Is-Purelib: false +Tag: cp312-cp312-macosx_11_0_arm64 + diff --git a/venv/lib/python3.12/site-packages/aiohttp-3.11.18.dist-info/licenses/LICENSE.txt b/venv/lib/python3.12/site-packages/aiohttp-3.11.18.dist-info/licenses/LICENSE.txt new file mode 100644 index 00000000..e497a322 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp-3.11.18.dist-info/licenses/LICENSE.txt @@ -0,0 +1,13 @@ + Copyright aio-libs contributors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/venv/lib/python3.12/site-packages/aiohttp-3.11.18.dist-info/top_level.txt b/venv/lib/python3.12/site-packages/aiohttp-3.11.18.dist-info/top_level.txt new file mode 100644 index 00000000..ee4ba4f3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp-3.11.18.dist-info/top_level.txt @@ -0,0 +1 @@ +aiohttp diff --git a/venv/lib/python3.12/site-packages/aiohttp/.hash/_cparser.pxd.hash b/venv/lib/python3.12/site-packages/aiohttp/.hash/_cparser.pxd.hash new file mode 100644 index 00000000..39d701a8 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/.hash/_cparser.pxd.hash @@ -0,0 +1 @@ +f2318883e549f69de597009a914603b0f1b10381e265ef5d98af499ad973fb98 \ No newline at end of file diff --git a/venv/lib/python3.12/site-packages/aiohttp/.hash/_find_header.pxd.hash b/venv/lib/python3.12/site-packages/aiohttp/.hash/_find_header.pxd.hash new file mode 100644 index 00000000..9762f43c --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/.hash/_find_header.pxd.hash @@ -0,0 +1 @@ +d067f01423cddb3c442933b5fcc039b18ab651fcec1bc91c577693aafc25cf78 \ No newline at end of file diff --git a/venv/lib/python3.12/site-packages/aiohttp/.hash/_http_parser.pyx.hash b/venv/lib/python3.12/site-packages/aiohttp/.hash/_http_parser.pyx.hash new file mode 100644 index 00000000..7c40990e --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/.hash/_http_parser.pyx.hash @@ -0,0 +1 @@ +c107400e3e4b8b3c02ffb9c51abf2722593a1a9a1a41e434df9f47d0730a1ae3 \ No newline at end of file diff --git a/venv/lib/python3.12/site-packages/aiohttp/.hash/_http_writer.pyx.hash b/venv/lib/python3.12/site-packages/aiohttp/.hash/_http_writer.pyx.hash new file mode 100644 index 00000000..8e75ab56 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/.hash/_http_writer.pyx.hash @@ -0,0 +1 @@ +f7ab1e2628277b82772d59c1dc3033c13495d769df67b1d1d49b1a474a75dd52 \ No newline at end of file diff --git a/venv/lib/python3.12/site-packages/aiohttp/.hash/hdrs.py.hash b/venv/lib/python3.12/site-packages/aiohttp/.hash/hdrs.py.hash new file mode 100644 index 00000000..60ea10f1 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/.hash/hdrs.py.hash @@ -0,0 +1 @@ +dab8f933203eeb245d60f856e542a45b888d5a110094620e4811f90f816628d1 \ No newline at end of file diff --git a/venv/lib/python3.12/site-packages/aiohttp/__init__.py b/venv/lib/python3.12/site-packages/aiohttp/__init__.py new file mode 100644 index 00000000..e3e0f3cc --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/__init__.py @@ -0,0 +1,264 @@ +__version__ = "3.11.18" + +from typing import TYPE_CHECKING, Tuple + +from . import hdrs as hdrs +from .client import ( + BaseConnector, + ClientConnectionError, + ClientConnectionResetError, + ClientConnectorCertificateError, + ClientConnectorDNSError, + ClientConnectorError, + ClientConnectorSSLError, + ClientError, + ClientHttpProxyError, + ClientOSError, + ClientPayloadError, + ClientProxyConnectionError, + ClientRequest, + ClientResponse, + ClientResponseError, + ClientSession, + ClientSSLError, + ClientTimeout, + ClientWebSocketResponse, + ClientWSTimeout, + ConnectionTimeoutError, + ContentTypeError, + Fingerprint, + InvalidURL, + InvalidUrlClientError, + InvalidUrlRedirectClientError, + NamedPipeConnector, + NonHttpUrlClientError, + NonHttpUrlRedirectClientError, + RedirectClientError, + RequestInfo, + ServerConnectionError, + ServerDisconnectedError, + ServerFingerprintMismatch, + ServerTimeoutError, + SocketTimeoutError, + TCPConnector, + TooManyRedirects, + UnixConnector, + WSMessageTypeError, + WSServerHandshakeError, + request, +) +from .cookiejar import CookieJar as CookieJar, DummyCookieJar as DummyCookieJar +from .formdata import FormData as FormData +from .helpers import BasicAuth, ChainMapProxy, ETag +from .http import ( + HttpVersion as HttpVersion, + HttpVersion10 as HttpVersion10, + HttpVersion11 as HttpVersion11, + WebSocketError as WebSocketError, + WSCloseCode as WSCloseCode, + WSMessage as WSMessage, + WSMsgType as WSMsgType, +) +from .multipart import ( + BadContentDispositionHeader as BadContentDispositionHeader, + BadContentDispositionParam as BadContentDispositionParam, + BodyPartReader as BodyPartReader, + MultipartReader as MultipartReader, + MultipartWriter as MultipartWriter, + content_disposition_filename as content_disposition_filename, + parse_content_disposition as parse_content_disposition, +) +from .payload import ( + PAYLOAD_REGISTRY as PAYLOAD_REGISTRY, + AsyncIterablePayload as AsyncIterablePayload, + BufferedReaderPayload as BufferedReaderPayload, + BytesIOPayload as BytesIOPayload, + BytesPayload as BytesPayload, + IOBasePayload as IOBasePayload, + JsonPayload as JsonPayload, + Payload as Payload, + StringIOPayload as StringIOPayload, + StringPayload as StringPayload, + TextIOPayload as TextIOPayload, + get_payload as get_payload, + payload_type as payload_type, +) +from .payload_streamer import streamer as streamer +from .resolver import ( + AsyncResolver as AsyncResolver, + DefaultResolver as DefaultResolver, + ThreadedResolver as ThreadedResolver, +) +from .streams import ( + EMPTY_PAYLOAD as EMPTY_PAYLOAD, + DataQueue as DataQueue, + EofStream as EofStream, + FlowControlDataQueue as FlowControlDataQueue, + StreamReader as StreamReader, +) +from .tracing import ( + TraceConfig as TraceConfig, + TraceConnectionCreateEndParams as TraceConnectionCreateEndParams, + TraceConnectionCreateStartParams as TraceConnectionCreateStartParams, + TraceConnectionQueuedEndParams as TraceConnectionQueuedEndParams, + TraceConnectionQueuedStartParams as TraceConnectionQueuedStartParams, + TraceConnectionReuseconnParams as TraceConnectionReuseconnParams, + TraceDnsCacheHitParams as TraceDnsCacheHitParams, + TraceDnsCacheMissParams as TraceDnsCacheMissParams, + TraceDnsResolveHostEndParams as TraceDnsResolveHostEndParams, + TraceDnsResolveHostStartParams as TraceDnsResolveHostStartParams, + TraceRequestChunkSentParams as TraceRequestChunkSentParams, + TraceRequestEndParams as TraceRequestEndParams, + TraceRequestExceptionParams as TraceRequestExceptionParams, + TraceRequestHeadersSentParams as TraceRequestHeadersSentParams, + TraceRequestRedirectParams as TraceRequestRedirectParams, + TraceRequestStartParams as TraceRequestStartParams, + TraceResponseChunkReceivedParams as TraceResponseChunkReceivedParams, +) + +if TYPE_CHECKING: + # At runtime these are lazy-loaded at the bottom of the file. + from .worker import ( + GunicornUVLoopWebWorker as GunicornUVLoopWebWorker, + GunicornWebWorker as GunicornWebWorker, + ) + +__all__: Tuple[str, ...] = ( + "hdrs", + # client + "BaseConnector", + "ClientConnectionError", + "ClientConnectionResetError", + "ClientConnectorCertificateError", + "ClientConnectorDNSError", + "ClientConnectorError", + "ClientConnectorSSLError", + "ClientError", + "ClientHttpProxyError", + "ClientOSError", + "ClientPayloadError", + "ClientProxyConnectionError", + "ClientResponse", + "ClientRequest", + "ClientResponseError", + "ClientSSLError", + "ClientSession", + "ClientTimeout", + "ClientWebSocketResponse", + "ClientWSTimeout", + "ConnectionTimeoutError", + "ContentTypeError", + "Fingerprint", + "FlowControlDataQueue", + "InvalidURL", + "InvalidUrlClientError", + "InvalidUrlRedirectClientError", + "NonHttpUrlClientError", + "NonHttpUrlRedirectClientError", + "RedirectClientError", + "RequestInfo", + "ServerConnectionError", + "ServerDisconnectedError", + "ServerFingerprintMismatch", + "ServerTimeoutError", + "SocketTimeoutError", + "TCPConnector", + "TooManyRedirects", + "UnixConnector", + "NamedPipeConnector", + "WSServerHandshakeError", + "request", + # cookiejar + "CookieJar", + "DummyCookieJar", + # formdata + "FormData", + # helpers + "BasicAuth", + "ChainMapProxy", + "ETag", + # http + "HttpVersion", + "HttpVersion10", + "HttpVersion11", + "WSMsgType", + "WSCloseCode", + "WSMessage", + "WebSocketError", + # multipart + "BadContentDispositionHeader", + "BadContentDispositionParam", + "BodyPartReader", + "MultipartReader", + "MultipartWriter", + "content_disposition_filename", + "parse_content_disposition", + # payload + "AsyncIterablePayload", + "BufferedReaderPayload", + "BytesIOPayload", + "BytesPayload", + "IOBasePayload", + "JsonPayload", + "PAYLOAD_REGISTRY", + "Payload", + "StringIOPayload", + "StringPayload", + "TextIOPayload", + "get_payload", + "payload_type", + # payload_streamer + "streamer", + # resolver + "AsyncResolver", + "DefaultResolver", + "ThreadedResolver", + # streams + "DataQueue", + "EMPTY_PAYLOAD", + "EofStream", + "StreamReader", + # tracing + "TraceConfig", + "TraceConnectionCreateEndParams", + "TraceConnectionCreateStartParams", + "TraceConnectionQueuedEndParams", + "TraceConnectionQueuedStartParams", + "TraceConnectionReuseconnParams", + "TraceDnsCacheHitParams", + "TraceDnsCacheMissParams", + "TraceDnsResolveHostEndParams", + "TraceDnsResolveHostStartParams", + "TraceRequestChunkSentParams", + "TraceRequestEndParams", + "TraceRequestExceptionParams", + "TraceRequestHeadersSentParams", + "TraceRequestRedirectParams", + "TraceRequestStartParams", + "TraceResponseChunkReceivedParams", + # workers (imported lazily with __getattr__) + "GunicornUVLoopWebWorker", + "GunicornWebWorker", + "WSMessageTypeError", +) + + +def __dir__() -> Tuple[str, ...]: + return __all__ + ("__doc__",) + + +def __getattr__(name: str) -> object: + global GunicornUVLoopWebWorker, GunicornWebWorker + + # Importing gunicorn takes a long time (>100ms), so only import if actually needed. + if name in ("GunicornUVLoopWebWorker", "GunicornWebWorker"): + try: + from .worker import GunicornUVLoopWebWorker as guv, GunicornWebWorker as gw + except ImportError: + return None + + GunicornUVLoopWebWorker = guv # type: ignore[misc] + GunicornWebWorker = gw # type: ignore[misc] + return guv if name == "GunicornUVLoopWebWorker" else gw + + raise AttributeError(f"module {__name__} has no attribute {name}") diff --git a/venv/lib/python3.12/site-packages/aiohttp/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ae3e61c0a11c85c48113116ffa0f4d0f6e063680 GIT binary patch literal 5018 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/__pycache__/base_protocol.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/__pycache__/base_protocol.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..173fdf199a8c65ea0a8a5ea40f1104cc2b0a2e60 GIT binary patch literal 4555 zcmd5ATWk~A_0D)~kK@=c+OX1!ubwk6$00%e z?2U5nx%b@1ne)E>OE}y^p#A>C!P!QTkbmO9X`o)@$P4qOau7`c2$dF;SvKI#`q#|%$T69RJwfOL(1)P!fj$g<5c-H5g8O!K--RO-F5DM} zHG&*bVoJQfGaH53UN}L3zHgor<3{LMPE)=^%X&FqE{ZZOO|njsxzBRVC3#KX}0p=Ymw$?h0K%N?9?gIOTjP+4Iv04h$0XGfQ4|H zQk7k6j-O5L zeR*FduK}Dc>)PlATCP@J$-J$oZ)b{y=}cu_pDnB37~8uqqk+UmE4loSau*ahy-=Rj z^-5+M`sl&^^~TnW-{oK|l*Ho-x&xJV&cavM`g> zXO(0}>B)kYELRkDY)WKIk=|x#0?yL#!X(`S&&0%lCD&T=>9bX8*dy(sSuffS>RWW)nNK-|t7WLb# zX>x|o3QD#gTecU$B_+ibVYjBci6d~6_67j(EY$Q*YYl$8?OcyziDoR-h^3Z%tzfJk z9Bd8mTsrX}w4>GAzdU|p{Np1nVM|jOZV1CG>4(Cuwukf$x4k5^<5}sWTukZz4voFAFyCHop&)eYt4AlghGNoPp%~|l6O4k$wh`H zVV&sf#8AUFQakJ$kx5;rh3TrUnEBM`ohs|Emnuc21Q}P6t;x`ts;U=C){^yRPer(5 zLu0q^*avj&2LMb(HKVC}(bO&Ow~^bC`pB_1>j@`XLf>-aMx-h1X$X5B2xAac(j!YJ z9)^3UBwLXi)|C+kA0H~&)q%- zU{?tGpHxWyUsY(j)LIofUSi9a?uO5&Uq`S9!MdX4;-)A8-g3Xm0`l1qGwc z;LyF`(8`HlPyKSLo}TDd&}c&#eIR5|L87Ceok#1zq37v`jv`x_!MlnG4kk>;`XM08 zM0bOc?z+nyu36V=%pIG4iPhbpRD&|knP*6i?Jg`VH}FzC&hY27c{N`s8-a69twYhB ztQx~(MkfBRJO5ZgY^Qi74|Z&coD$n8pHE9*BDY?!~HSiD%II2Vj8jYHoI4K_l9H|2++)W1UgkZv9c zL-pj|`@+7K(EFvI3tI~Bic=_?_u+rF4d9y~qs`LIVoGo`M~Qn zt>7TJ=KYNaQq@6NFY=c9k=HdgfUFqdJj5$qk!Gs!AW`UEobze31*Irc^s=r>!g=}3 zD#eOI*QF=>Rb{_|bak=yR+f(Z8I%k!>bM z8;Q~TiOkZe*6=Q~)OZw0TvxBEH@|;Bl5X zq|LJ4-8c7tL7-dpI1_ED|u3J1B~J7AL#^RWPU-aE3|=K~=4ykcAMcn5B6ZHf~O zaiUFN@F%zex^_?88(Def)*Fq~p*8{hQ+*Y?CnEvxPK$lyTnyRPq|aC2ond~rl`CR- z^QVW-?+Y45(=_~+?Pyj^GJkP!X3&)k-g%T;lEJvrk=9fGu%+4wiuEh{hBg8Ksu_m) mJBj>*4F8+F`WboQGm?Jddy8Rqesr+en`-o?z9cv@Px>$G?a+7t literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/__pycache__/client.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/__pycache__/client.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3c8458e78d0649f6eb8871f35121cf1aaefb2292 GIT binary patch literal 53109 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 HCL{d6Wp9E4 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/__pycache__/client_proto.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/__pycache__/client_proto.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7e6923abe2cc99c6133f6f3335cd2fc8218f5dd6 GIT binary patch literal 11686 zcmcgSYiwKBdFS$ZNnVN+MM;z_iIhZHrXG|nKk7J9633F`B(|JHN>g(wSep0BqRNMQ z?^SFmRB9K-CIwF83>_k)9ijpQYA*$r0vqQ2>xKjJ2K9gGvkW6GF*(yxMOZwZ%;R5 zJTXtk8}nuwV~rVK%t!0lbW_G3^Jki4&9v-Dw`5vltu*gU2QqE3woH4hJ+mjahao2N zG~r!W3C{_v&@R}7W?|2asSWmvzxONSf>}})57l==m{OUrxKFzyqJ@7$y_>OQQRleDIqJLothBEoT&KJ;`52c zbS}ZGb*)o^_^Kd|r=(;qn-!9>pf&iWa>;KC@^mUAkC+tS zDOsL>QIO_yS=e+!lmyt}i;0VR)fqT&;(`FjYQmmytR&Q=vKQ37m=(9W`18lloj!Yf zTycyiM5L?AJSCovPx#LT=&u*^~P z(z~lEZ{{sCfFxHfF`HoL%>p}P;%!$g?`hp)4x`pyQ|si1c^1aFAay{>X(OGGck?cx zLGa+EtFy0=8HVSsaxpLTc0-RwewfxZK%Gy^dm!H=_@Spu@bF&v;m&NdU*lDGteN)- zEqoLFXg%+Td0GLzo8hko(pEmex4~cgj~x6SSU*75?+{qN6MkLr3qoxhtqlq7e7DfX z_dwbUKb+Cehp*aVdtirsFmnf_dm-(Fv>(zg3I%OEKxkhLEP_IC?nw>4YSOPD1VoB$6^NLLrEyZN^-*&9<$l-6)x%Cu@{& zoX#470Yb^ZaawX2J+X~5N){-&_0l4VSb-Obh#M!ju=e-3mq>$%3n^?op30`=cw9sZ z12!Se<`&X?Jekf(0<_MnJO>-Totig_9z6#sWdOFgj7&qZ#^ppRtvKQf^A|**VqUT9 zUEFb?ZJzc6#-#YS72~rM50qBDJ)RU&>9{-#>~l7k=7H~6Bq2RR&mrL*g+gECM_vNv zBaOgNQMkC2oE5SoQ^U_LWK%hDWNKano)dauAtB0wIC5etbl~vlNK%6Md`^~zFNnE? z`J*GR3fWgj(y8+!^NaFqE_*O~V01)E$-?k_BKd7#V=#LvHw%1hBuRO4d>+|!bbe9n zf=w(1>hL(K!?PV)r3HvClY6Yc#C8_h&Ncp~|1KN7$2OMO_9EN9c4*zd!S3Dc>{+pF zuKsCI2O2Ox2l+qxiWC?9?V5^gg(N{5zDJdJ7h=257= z%Z9}cSUG8+I}|WaNdY(Z4j{}Nr1fEn++q+}`k>(!BMv|!;lPkM2(iNIm%8)Vddmn7 zK~%gq9YBmtM-DnW3S`0!#3_+yWQc_&V&Cq*NoK@*8_F$_$etuzQMi9j?4v0cj zdx=~vg)eo~<8N*2K^*#hh%S?lJxyiKTjIKkT-SYKbGMhh{&(DOyVs`+-pEJZQ}2iW zarkG$rO}hc(UW&ZPZgr4?wg^Ph6DGlkgwQ?*Z7*v9Zx|g#hEm`0Fi>^pzFv%+7l`0NdOk_cS6J^Cp8NG^C z?l>>z=5+=fF;V&#kHH9y;ZiOjJ_;2}&GnF?^E`!pk3$47YDYfhDfx<~RR*~jMe*MOvi}uB0bt<6&cgt2VU|sK)3P~l0-%s( zPzrYAtXD>>YL0BEB{~N>3}R#VaSz8hu-4$OMm-|SR+wiOK6+)316SCkj3KFp#`SZZX=CQ9uxVGU`J#=Z84`d}wZR2w$+(d^`bQP7QJ+-~>$z1& zp1gU6ki1#nD+9FOOAdepxCmDCIk-=TT>Hf(^Eq;n=_S=04-;{G*#-mAAd85hCu1C(E|iZP)&wrWcuu zMBN`Ku1mc-p9yK2XecFxvN<`F%w@oU2CMg2Xvq`}O`nYT#m4{+R0N7RyW*J8tyYDd z5d@x!Oe93g?nH#Uh=?bSVsD`KR92D`*`%P@HOpH>zN%Of;sr@`VNX=6sT@%}RDA{3 z0P5|61bVI&jD1jmJsMX4Gd~WzLykCAHu@ya)Rq%d7gAvV>%0SdfuIH(pA!W!k%Ea( znk#KJvrx{88o7|jrWY00Le@CD(y)*POF6xW`@nH6x{|7@?N}GjNEeirntoYaGdDx~ zJK``e7+mo<6>T9sTvl2AGqCBUpne6KsTQr-8=i0yI!SK=FZvu99LuSyE$Xe|{sP-w zZr#7aZHC8w?k|KVpuFkwlw850D_C$1-fL|8QRGfz_!Gjo_k%)F@`j7vaLGGd^bT)$ zM?Nz{HE0d3dsbX!m*=g=Rv#<4dMhTcyQSRK^KSY^y3}>B*mdwu*Wv4~N)PG@udTjz zZTX(3t)bCr`|bsgy#Lyr;EC(pCr;uY{?tqw zyEdDn6+3bFg6`oTC^Q`|a)--J!9vquksCB*(^|eTd}4ze-$d~b`g$2Q20C~-&;f~C zSJ%tIFt&Dl%(_?YMK-w3-DQVA`!fd5g6I6>g9hU7yiXe76iuz~jJ-WpXd2pVAG@6` zj6GinyihTd=D|;Fq~q{r@Nl8)k=wp<@Mxjyv5J}Ld>k6vMjo)Fxd&E#*L}l%FECIT zJboweR5`Hsf!)&F@;{$fnqlfMq+Ym|f7mnLYX0Z`_VHfwL92B*HN5)3^GIm%ay7+tMkRLZMYtvJLoQ2;~kRe|3rBWqj#9C4@tA}||t6uQfH z?9>8~u<^Hrss@Td8B#T@g4XvYuuokGP|;oH>G5quIZU>X-d!w z(5@;$8fCl$6-%A5nAPUk#M$iwaG(k=RqnTew z3%b@Pe!c#rsBSHF)t_|xRNvou)UFLSM2{LOvZ1?dkE+%BJG0+t{d1$muk}+w+$RYM}oEF`Xj&-REXF#2Z~*j zZ`1cE8^{1XqDKgFYJfA=m;?Z$hvGW48_I+}1Dtj5?)5yAMAh*tjg0Mz2Kbsx zlk`{-t14rAU@4V3gdwN6d2sat)~PH(hx{wp>6_SY!FEXlz2OU@0h-K#&}J;}~%3cb9G~-8@*}I#$N7hkr0oW%Ke~E?lt^ zu7w`uss9EW66|rS>g?jS`NV*{z`eDQmBDWXyiM^W7UW!<7f@OQxkxDD zYy4ko2`qIfwInDlI3u{l>fBz6JCnE+Pp7g%oOWx#;!H{a4;_}p^ROxEC>MFm2^h^_ zbOEDTj9~XfoP)^V^r+OJnny9~W612lEKt^~#%A6QC6o*_$c8%w{H0`$)$6Ni-j-)% z)T?O7n>bKM^OiiDcYt?QtA`m4Y=l{m^VbE6nY+~UCcsQ5jIY_poS|Y?C&@c?WfN6k zz)bUG#7^O*G-{-V8j$*`q4?l}=zB)|VoIKkpU?4&H4rsGsN%Lm?1pv3evBd*;qu`5 zL_f5uQ0~RrFh)qO5tqtg{*=oSzXby&)H!vP3{uq#*MvxK>=!5_k&&u;vaY1<(&=w; z%GV$Q5@{!015}CG?2M>s{}`s>k6R-^3Gn~cv#ZaRxj@<1darALxp$-x94YUKlsg8? z?fsB>(Ci90QT>6bp!1(ZQU)f%Uf^X-!^CevhUy%U)`u%SfF<>nP=2^vphlB1s_F(Y ziO8oFTN0K1biHj)`PEKlzs))FZ!lg$=NzcKsL+Osu5iJ%pYo8tBG*^qhKk(K1{W>w z8(JB^%k?2YIY7~8+uhn z*10ZRYZ=9&>X$OS61sY2Q%MD3E`A52EJTVknMkMO=>$0E6>l7Dl3MPlIiD1}#um3Z zpw7YYod}O4QK!t@fsPW2bhss7OUV~5`ob&rhhNxlT|T(8zjNMlmiCPm_l=dkt!w^L zTeR2~-7=dZ4eD*OBr;5MJFnEh=P)cxuhaktRA`~9yXZh-L_AhKF2d`p4DT1ZcD55M zw>AF;X3(_g9jezhw8I@yv_tju%g|2qhQT`k<#bV;90#gwh>Dq=N`37m{s)dg7Ea#+ zN}lebryDFl6=Vn|Js2QU-M3V+(c5(2rML(+x=#{C+%}ZJiidCJcQ^#44{Qcm-mdOj z3$#5ae_?Jqh`3a6)ToDfFTy>~vXCPkn#DVMieX z!=)iq=stO;;pr8#p~|iuL^B5TsIk?tf-8KFYg-GyJA7mKX47467%Wt-k6tkqVcUF| z$a5%oTj20tO&WPdViv!||9Iu8|2yxiUd<~2-eu|&6}zc$FfL@fe=Tno8)1G_lURQ zVjDok*pFThrkX<@&`a>~fw@Wo*Ixdz5qbQOqqb+-Lh|gDLwUA3*8(GUkC(sco5 zMP^nPbOL8c)(buGA+s)2nRebPHUp0Mpx;;G2&x_6X*ImO;Avf@o>l|G)n%@rMBk-; z&hTbe`&M@&x9YWdn;g*dIvmB}8eg|rRquFPnA3(6$-X#$cNu0#!NsQ3Wr7LZBxN1Tb zx4%=!Z?l>!&_()p5X73d75yt4Y|n4;fz}7!Qh24+{j1<3ECq&&fuU01NHK8aefdt{ zvDIf*PF(l@(&Hh zc8nSs@X)sU-ZnqrNbA6zmci@h>ax=MKHsufR!p0zQC|Pow3E)UL4bc?&#a$cy3uD5}Uy2?5msm1>^A95Qn8 z3P#UhG=&lRL`8HLs?Q{ph(OR2F@X_26Digi_<~VZ%&Dv_=CGFf;;80(5sNd}$p*G7 zSOp>~D~k2}qAW<%j)sqr)Yl3y+S2hjyy(9GJ*ZClr21Zg%umD!IimC{Ad=6ol3!Y$ zs#uz=$JSmhbsi~p9;py0+&;90No9c88Y(8n+O-zGPaxSc>lHvs*yOM}*LXl%t5a*j zTnl6E*|OQK-4!2Won+SdEf_n=RBT7A(ee$ zHMq9$cCO;Vl9#l$R~j+rBi(x|O_=kOz@ADo=2}QwM}@8tfSqo&LEY9V#%vwlaylUj zFxFlTbO5Ba+4Y4RIfQJF0ofjG_LZ!GqBVe^AGjHKzwcHM9!IPLx2Li10QPO8ZCf@A zK!O`*02F-{g6Yli&uFSDnRwfgPVo&$z@${aS%uHJ)E7XTyf}}q_Y?~$%AyLYxX*(? zP(S2??`_o&;TpA;sZ6s+gn6E)gV-S!9J#v^W!2qHvyT6gx-002x6FD zk%nKB;BQEOk@Wu;>Ho}RWlUQHqR+T$jxdk>n(Y4#d9+9#ePH{hh3UJVUVrAMP&jn* V7hK`cbTRr;G5qyU3AWI6{}ID3_{JH_v3H_OGGjT(tewXso^ST1FOHGrl{UZ}#5Bmggq% z%>Cy6{&im6&5`WM?)|=dpzGAB*Qu)Wud4s6{`D8x*;yQ}cU~$#`_(r&?(gV9xw2)? z-5N8;UFCR=Hw<%r>2B~F*t5}ZWOtL_#O`LlncXdZ3%gtWR(8+uXRy1?Z^PX7Rj}G$9jx)! z1Z(}Z!L|OiEIwnnE?Dochu_9$4*P-){)XT>|GHqKzcJY4Zwfa1n^|1ea7%E#e?9Zt zhg*Xi{2PJ~_#X&v^luDq@^1=m_HPbu@o!=Aj^VArZT@Y{pFO-ixWm7L`E!QX1>5{> z!JYn{!Cn4c!QKAd!3X^h2HXAZ!9D&x!47{%u+!fe?DBU7_xks;JkH_9;6DGpV7I?J zxZl4&c)))kc+h{4#kqzL1rPfVGk@-IPw) z$Ab_1A2x78zG!FPv&rlj`|vd}7oRttk_ z=nxC7L1?W~j{lr+;!>e-V(6w^VA4$(7S5rDLEfO${*2i_GLj_>r-d5*Bm7#y%hyqk zGp1sc!Pg7r!Z7psgmS))`5F*5%6uiMsn2Bb>(C$PQSKM`M&)gOk=3^e^=(dSTZnHF z1b#h!CBpC-E8mKoVU}_OQa+%zYz(Ds;5VwJJ;l;&LYmFOZnaM?j2o&s;n5mSwBdUj z{3isz|B*+zS;J-L1@39nqud39Z_BT!S9*M=gek~xN|-}u`&$!MxEnTYMxec8boAVy z&?SnaV#0cOR168j2}kc>@cghKMfr>g*Wv#2=LbigJSvVpJ>EBdUPxs3iTwk@>HdLp z^yqUS;L)R9fsXF3j)VJq_9aa1BjX8MNB{6}|LI{NVeT9p2q$d&!-6P19~umW6B%-` ziL9RfpuqQy;hhQFk@Mlf(UJb)ghdK4vlm*9k08`%Muqnu9vco1vJzcM53F*DOf51; z^|C0RAz?ax?9i_W;C+^a`7AGn5*cTO;qwAK=Ck4O`9x-riay^jqH^c^$A?Gzd1Ujn zpALo5-f(YN6#9cF#6h&fXHDdH3=aw;;f~Rf5n+HTE%joy6nvytdUQ*V$Ar-N(UFkc z(=KERBQLd0N|v>MlqzApYWWfH2p{uI3tb*10zCM97yD_n-n69Je4qyP+E&9 z44xTJWQT-sKzMpUU|%hfMUSEoLN}t1oxNSh9_~68=smKx??n5tu7tfCz5FmDp`XXJXzRqnkYT_cvEF{P3_vchIP%4 z2cDRGc74;f{-%lcCjY64%EvJXhw*s`(pu_wZ$J6ih30ilr`GL$Y@KiSPzXJ06@~Da zI5I#ZUbzU|X(ql~0Ou+fR>C>a$QydG?)P#&Q_n>1lM{pI8@;@6X1G5rGE^>ce)flm_ ziJ04Ow!jgOAg~V;p95e%8t4y)#lh2|gca~UA&ev}pIa=*UpQc4lx`7{OByin9d*~rp zDF11G`gBhnb&4i&HlHPIn4X6N$bk+L{iuX^lAOoLDJAD|a!!$x*8V3bjGR&YLWOX? z%*8VuU+RuKoL@Q^&#qZC*Ti#jpFb=$ol>SW-Hrgd?l!{Fnl6~m7E(+uvf-_)&qg*z42qy3L!ATy_Lll~JO>&cl zN#mqx(i}D`QDdB#F=;qsR*;QeZql6m(9_2~o$eYDi!_h{p+cQhl4{f}WZ~J}KZ_`B$c9 zrtoQJt7o5@zi{K}A8w1bblxyUa(nNZjIOK|&X}1MKX5GNnSJ>lUq(7$Q57ZVVt_?e zNQW-=g~@pezYszC^V~`fS6uaxJ=>CXC)>4R!F|Qb<$6{!$YazqiFzsD_bx$EG6)K0nxU?nK=v7h3tclU>I z0KPK)!2wVeYiqxYbK>(0I)Z^@#v5^7Hq)F8S{$d7hk9Cfv;s>$9 zhUpbHC4GqU(_ms_i58f_k-=~vFyTqUWiX(m&?`tBqB-^=x9lmLw=a5XrZeO2!kD`$ z>TZg;TchsQo4!SN+qCT$&cfxqvPk*P#k^e+$F6vG{&n|EV8QlQXVkl%#hh5odnDp` zBwk!OZN8inFRPn2e_$(SfIgrC2;QY4GbMPq$^lGpPrrJ(Hw-;KgGhtz4TE?Aw-9BN z+Qr&GQJCDMq+Ys)ba!*$T;%RJ-7%*(>hwlzURIMtCWwF$EZ$-`1)>Q;7(`d$EvS@X zD7ngrq)UUwkYW5@X;j$52r%kR=e+4Ha}vCBx+B7*q!?16RjLEI$}pcYPnywv>Zs6C zoZA9WYP?4)EK1pr8>cK&)~SrJvhvZ#&?yaXu}oUuB+$b39NO-)_JB+X4G$0n1j2;; zfzi`LAfftz3foT)j`WM;fis|M61MY#AQCbIgeM0u4@v{y01!wRHl8VZKoG;?7z$5V zC7@;>UaUum&&IyK_(c|r_uw@NGiAUC8V!T!8wDP3rZ1W>1VU7Of`7WCF<=2^J8*6y zHyK)3(ASYP^b(wlT-;d{bJj(jbvGPK&P{PgUOcxXmg|e=`ffBX=5Cp`#+~^wXJyn` zd4rEQD;J#)Oq=65c~?eeM&|n#bE;xFzG#kbF=yShDQ?f1t%>DTNAs$0+pFW{Yh&e` zqUD=z4lS0qPxnlB&eqK5F6XVg(HU#p8ExEoEA(FH`!$PsMYTs3^ioSWb_Jg^)Nwe%pC*6hv@%T$&p)`a|O*1B0WW3>A16e~&Vz;Y{5WM$R;T zAzJ*N=k7S1afb_?@KJ`j+!`?#uQ+U$`h~6)4!0ZpUAnD!IBU*|(O{{ZKmIX?+g+0q zuwu1YjvD4K#46TDE7nt{qlTM(pRl{M?9uyx(uRh`PV!}eOa>VmKtRGyfFwf|Ysr8N zbx6o@)O0pVe_tA<+(pnoQy7VtS|$ylCT$(kTX}e+hCZ<|NG0Ji0P161p3Zo0JjGwN>p-AWH#fTXjV_(1ZYC#YZ8XY3+F`v^sc}+ddFyO3=Qwx+dm8+VWGhJ ze?_0+4G`17Ne9ji3r`8d6FpiPAfYsfX!Isc^U|6e8rCq<5L=ytV_{HF!{c6XG=|4Q zgHH*2CpIJ%a<5v+P^Z*uq9gfT_iBlTCeK#fyOtjE)WS-qV6tV?}^E9~~WT z^zPM4@B#<#865%Pj(N@dOrOxS>$k03GFT;xmSb;>;p8uWw|B@$zRjpjtw zU`WC86S;V6p#9LHBPY5#1H|I%#jK$6tgJLi_lJFE@ny>W6>`2x4x^%I^l4LRZUD@v zCj}a*0Y(Re#8;8v5Ah5A7S2Tu7_QBJ@fpmGm&^PRNEhZ-j3=^7RLo+TO zkS1+o!a}@`P{MQ}l*)flCb7Fj!)SQD#D7q!YAfSJ$h5VP0WwqKL;%OfQ})x4kP57=`n3R`X+^u z^AGri_QUxy2b#*B^QHZ9jg{eWed$m$Wt_98hbuAO2KW41Nd&bwHE&f$$m}gshcq{t(>hq;@xmNW5cqufJo;^`3B%I zw>CzcyCb&Ual1ECvn^uZ7BO#QJvD%A>a||>-SuJ#PK94Rgi$aJsic`&1~_U%>SB`; znxj1_zOzKxnuhX}XYGzqqEpi@gc69QU1v>xhhQ5bXiK{Uhq83(#+ru8(lX%jtV-Pa zop_&jbqcVFOhZ+x!yyRDds7Y`H2U4V(eDxRg#u}O^Jae`ent2d<5z-TsZhpS*k~@` z*=PpaN&OSbhiE{jT`WFBO9h`z4a>Zq&u0l0yj}3}4xy6I7RrPwDxc4RuUe=eKYMlx z`Me8ZHS8%DzFOwX!&?ufy^`{~g*u@^s0Tkn61#bjqn_o+M`!__d_#S!^RX0#h+W4Q zk)J&mX;}7zU$*E9wJ#scZZ}x9xrPV>4sMa1aElH`ju@u`8x;`m%2Meu0D1?m)B>CH< zx(Pewx@|~`+r{E`BgX?tp${?$kXpVG^=aqx(3iSjR>0d>A4;h=A@!alxRF9PBeY`` z3`ucY5Z9RmOH$}ogm&=+WzzFDJn!WX@!N6V#~uX{`JXe4}n~xs*I@NV^|t zcgiWu{4S(8!0W+}1{+kCjo*#D2l;ivA^t(WT`qqQ!VdF2dw z182uZ&Ix=XQ(7fj*RM~Qhe`IAqpg9%{h^TfI^HDSpx0T#By&t;gd{4kVoQC*=DnIS0x4Gje_gXMk2}y7KWOJ_=j8zi(zM zclJfk{b?>`m`!DCw3i+?M&o%tZI~(&y&BEM8zv23GxEmCq9Hp~BlS|sM+(!|ljzN` zq8|jRQ(2_K>JkagXT|}FkqZOm<-Amsl*f6`JWef7nE1Wy63vr&7mWwN)tSr#Z#0Qs z6m!A9qMl2;k|;@VxR6I}8`A5roLMV zR0?%63r{M_Fqw@f!b91`gUS!6h{I&g#f)%+5;s*mVw}vGDxNGx8WoM0%)Mls%pJ)L zwOi zW-P_Qv}im|W~9{PuuckVN{S;oDQuGk3g?2oha|^o*Q9gOHR(|_Zdj_`v?O>0hZ9^S zx{$(pu?RimWsfNiLUquYrwpPCF(*=zvIpfWv$sCFI(||`M3Ex@qU}k7(;m{nX&=6A8cdHH&k&$y`~;^25-~z|v40=s42T*S^1}mwApIIRvGk_G1Ake^^68 zzc_G~aT*d9rUf8Ut0m!?ol3I>CPVIKjb8<>k;^mN@#6UPj;OODVyjtjFWGA1 zc2~q+w(KsPx4gXLwd$z5HsWYp7+Z2Q{-c$16vy2q5%=1tV{N>s0`ju#U)XcwdHJ!t zs%T!-!e+*SikBf~$yOY1ZjCkXy4}2M_JNqYChD$P=v#6(yw`zjws=9=)#16}mq+km zj~A}N%>kANl^FLF;g%UMC}DB-;)uO+xoUmXQE{hgeZ)}_-?)#8FO65!L@L(L3Evz1 z?m3pSbj|$kxsID=mb;>v5|!PtJFo1T*|lUZU9N48)wV@z+kV*l?x}Z9z2CaH^YCIV z1RG0^syjAE%vKt;mCo;@9-yb9sI6!o{ZY=IQscZ)n>SLqVafJ@PGn6K9oe^JYtV}E z%#SbGeC)Y6YAc?vT`0M6YRR^Py|yZ9t6JE&WUG(coe_KKeE5}Tu03L0Q-k2Ds0=mEmN+)@^2O?+)^h_M?MCL(YUp6oR8q2>~8N zXkY-+61K>dr2}m;&?R#Fc|J9R0?q%3B9oz6yo-Pd{m#BX5V0Ha=xod>J7;!A>@^sh zR}Rk{jyam6j^-QTSj(Ph%bq1iN4$t8wCuPoCuXC`V!;!u+!(Fg_wB*M;c|*_0Br`;; z@`9H#579EiW`Wn>NzwAt)$CKpvmt53>MT{779U0t%`|BjLTNEhyJ!*A8{f%FuhO@) zi8M4Nb|VcfkqxJPV?0a@;qlGo{7sL*KSr zHSadQ)41r{H=RKw0n<-ib`;Lnyi$LyexdXAgRdUES$L}^w*6pq`@u-@Ax%wHf^I_D zl#Aw4*7vvJ0c;rbkO^o?QW|z?Tu5;840^~w$boRHl3u%uTQ!cQ?)Nb0eGheBHRyd6 zC03dDfWWA8`?zu3=rc`hJNH;8_^Z z>pf6irO_(Zp&`;V3GEW>4xtJ2JowocMnztvQ7O{sN|;%!O^x|J0+sJiP?7xo#lJ?t zL~-h8muY9J;UCghKZ-O=s_JrInS5aq1mk?~%PkQ{B?PSw=ase>+U6gKm9D#8x^B6s zB39&!7Wr;ef4lyT`foMgJbkO0Am#S8EY{NTKhM)mE z&g4t!WRb@QRu^FE@k|n^Ob013OroU3D0QLCXdL!Uv2~#tU3Er?JAZWe(d}la!UrV7GH$ zSDEI#R#Luy4XpWoIk`uguHwhDW{O3!`4_9VA{<$jj8%lXT-DiUDYO zyZic%s(I>Kn_KI=J9l~OTN}NtzAS}3kuWqf)*5yW0*0zP`iU(UCKV-UJdtvUTEfU! z@U$Rq_Yx$39f{eN2JBtI_Mk9s*wS)dtf26%qFgYYGQPz9%L-moix*48IUGT+a z#HFwDG7!rRzeR9-4auNS4{e-+*(a}umY}lO(E9DBH=1slZaswM{jXdPF4W9=u9nP| ze6=j%dT_cO&Wh2JUAA1ZCRWlAEope`fg4}Anfpfg&28TsxK(+p{hgZc4lb5FIGX`Q z9%631-+W@_JZnCNrcc>&fj3^T?N;5b;)tgM(_vxWox;);i!rxs z#f0cj*+TWr!uFl!cboSZxgQ&g_mrAah%uVa*gQFzHb4{*24EpZy0C(n6~A`Zn-ghZ z$T-41^w_mkOmEI?L-Ei^G>jXPz~7*Ot|os8tN7;`lQJN{OE&09UX(V`fa&B;b#UBc z05c3vbFyx{9=`e%h6>XaRwoUu{gWoD?d5v(j!x`Qv6fQt(N+|tt_JRMmzf(k_>2>U z@{F#GFPR2}etqfZrx8(Ba1pKbj8N*pxVh|2rPFZ+5w%sstJY4NuQ+BLU+KI0 z=-i_S`K7Y}y0afbeeB8C%&(1nZ!l8v;F7&PUQm8DI2U|*bb8;NlFE-cOJ>u|f$5If z{5#IPukaKVbymk~e6wakm*;zLyDEWFlRxJ2MqSWiS`a>PHGX7A#?=djIt~`tIDkg% z!iV<&Y)kXJu>u{nmKJu>d}N$j##BphWa(We;G8+ z#_VWN%D^yOs5uun7Fu)7kBesR~tMqNZESvJw!HarR@P-s`Pn(J?A7|@XWuiS4g zavyWX4LNad^{jiA|BC%16P|v{mYe5tTn3+=jc$mBFq{QmVj0qCgqHp&HhNkmDNw?x z?CtIDYR9hLUN)Ge5ubG&n~VeP`>^v_+(NCA$MoA&iUX({uP8@|v_B(Z!r)FH+JA$z z6P2IY);rX&TSyDusl6;>uU}r<`Vlp6xvnYFynC_k!B41pcR6ES4)L_BG5E{8ue4oj zi3wMK81d6B`5+S9Z_rUTBPh&~Dr@-FfBE%%SU^ zS1PVm+;;eYBsyB|Gxl!+0*F>%>kir}UCPLqGHNKJ-a4oc(O5b9FsgM%y?%PV@qhpK zYRIWJBj}fX|8jP6`fIJSQb7;Fpr_5Q_Kyi#0EQ{-K*Jm|CeI<}DN9nR7HzdwOFcPh z(Q7k8RW6e9B{(kZR{Y9am2#%6lhz?xCDShbauBM=f3ghe@Sl?8-d5;YFy-OPU%-wY z#ecyJeUc$sdebf*nkm?;B(Dhf*U8XZEAIcj*lcLFRglI=e3<* z+dXsWPH7dUuhP1Yxr|Kj%t35Ns$F(MlJ;7`lC%C!srQv_*S0MjfBn%{AN`*7ySByB zZL{Fk6)}wD_$!ZId-R6o+x9o?H;>0Q?Tv2QyX4vzFR7X}%+~yV#+{N1$+O}_(JOge z?b_G7U+uoR=T^r;H<*O6n!VAQy^A&7D!O!X?&NJ-UWhQe5$9(rlrd zLZbncaTUUL-sINlm#p97`?rop7}HDAcrU0qMqGKXppn7gvXB)Muc9Z=+%vI_Fmecg zuoGM+V6k@v1I9ae#tSN%k~ek9rW)j7O1o;1B9S3mpXdWw`$N26;={4A$dG#%sg_`! z4|MgwxChM4NK`Ewr>7|WpTbc%Gqg@8qc!3$5in7!yU5GUP}LnA0Fcm^k)Fnt8*J?9 z&dY~^n3L40ZKf?|FOAwuuXo1ETBBvHOZE*UpP71Libzt=5k`w*2YGHD)?8OP)^>1q zPrYzz*L{JqeD6|}@qLKxeoxKU16-d+7fEX?8_&6Y$J%>(_X2%a z26VzQJbD3&TQra*J+T~R%wya8zP@hBc*hqg`g?E`fr}A)SqXHNrSreQKe1MKtScR* z4)!%P*nfr$kZNS-UU_Whu~>F_G`svdA6v6Ax@P0e(~H^LV%fW+*}E6B+oz3p?4Eh! z%x)U<#Jnx=Vt-eDrvW-Wg?ZT5B@O#BY-Yo-f9!?FmT4P#Rn%Fvz`s8H>TuM#flU*{ z!Kd^zP1v}NJGB|0C0g8a+p+#bCEtyjZ#TZt7 z>wU5E_0jV6w_VUJ;#`tqgsQ!aW^n}VY)$-@ye3{GnwetKE+*aLCynB1#LF{5auPkv z|I#7N;(|Ium_CEytJ3AlDA>d$Gh@l_!smUzGGk#@Vt>jrsXkmJ9-2BbCk+|~t~)a2 z7DFs{v0k-k`IwQA?;%0*ig;2LOJFF*wl}r7eK0?lG)Ct z2`8U|QknHEptnhlBquk85*dP_nINoMsT`8L2wWU+Pb=`f5g zC2VAOf|luo9Y(Rvjh$y!$i!Ak{B?3v`G@!l<+ZYTMUaLt8@<`>$DuWNY`?#~Z~u`V zg{{oq`)8CRQ!*QdE%#~M<-bMjJwznb%8fK0zlk(V%VW9?HYKiZo7*`HGsCXDJ)rHj|qp5}KmvsNP(@+`7pru_i!Gibd)F>ovNYJe<2z1?H3MRO2S$c%6 z@?}8i=gWjX3}JvIHa*3Ktdr(T7WmCTPYjoHC#{&u*bdvvg~We@1WNmsI;az*Qf@NV zsVACM-aBP@l)L;ZRW@aUrIUo6*KCUQ`JB=KUWYCdE8!$uN82Agbfmo#O4$4M_x2ro zR9b^OupF>eR9bFnP>Z`LjHgWI(BOn1Ew_J6F~mMss9IWj#RFX4LU& ziuOa~gJ3H~vq+XJrK%-&(j1V77Z9gS8mo}}K+MEn?_RRk{=!}O^5*Hz6|*U`hN!>)Qg>~@3y_u7WM9f4&*DD z*D@on%2_iMtFXl0GJkjfs+ILlMK!Q>nVFArpr#tnE4bP?*EpRKFD#7}Hb)DarycQ< zHAHd8N*bdjjf*AC5L9JWN}PJI?q;8yd3K>OQnej+JBFjXkAXOjmwKo7&33$S=%Wmz z{LLqooU2g67GM}7vnKAY{L0q(&X;#Bx~pI4gz9i+&8Hz+(5_c@8n~YtsypjUKV55p zOPo^Lf1EP=(4x;4elL2GW*>145yN^*zcvr)E%I#i9lC!S{cx-9#_mp%SXdDqnicHKhd1BC=)e}YCR!v(x4jS0P9s5P5_LUt zw5y{}+(}UXE`ni@lG#WLoPo^fPoFV#2FWjS zq}*K(V3)bMrPoStJ8C}!ulL~0!TF8ET#h>GQusGfmoMgOiMm=AU9C4CzwPR{gHf>e zmnf&alK3#O@{Q5*jf>?d^rar+3+G9E6f@qZTbqd^q%x^&lg1U%mXI^5(gMm<`KC#` z&%mignMpNC-q9q6zIQ@qxvkm9tZf}!%sUiu9Ez9JAg}X|y$EWwZ~5bn;_Lfgdp1(K8B&bq zEX=p%^*6E?%QjCRj+Zx(L9P-8CnTB~84(Yl1}S6)jlVD9clSS;G)a`+Tyu$xOCe4A zrHsrkLF?oh#Q!_vRnxz*Sb!4i&mcPKjC!*dvE?O!Ja8%Eva(Bm#t5scvYz6S0;pn* zer`SCq9!s`>uXZlHS*YJ)<;!5)rc1jxWzpEdYqx*st#xUG{9f5v65jvIwDbRi{9#5 zUoHpJ|Gr8FY98$in)Cz|$`?0431AC%`Txf6L;QXZzfJg+17A`_6~K)Kr+`}#uBAt6 zkr^haj+KIt)V{Ih{sfrvJssRs#$*N*k}Fl{(0>Q9ma3FA+Wl(=Xb#Df$&@u*tHfZE zL2Wf5%A zK&VzI>Pu`FgsL}1Xr32VgS- zS^L=QD-@5S_6Z9wV%H)wToxW3fQ=YNvNE)kK4Bu`sARl5VUadrT%o{Bs$;(>_Kznr zS#UrYJp%*QVdy}y-G69TB119TZ2=oh?QvM8Wbjx)|;r<9JF*m7)D!I zbiy()3?tKt%r3fqeq)zP`pg)@r< zO)*zf)YbGM<9!ca8+@zwd&LpojwN>+mZ{f^UoBp6%yxcd{~ZZ40n(e>Jlhp7@e&%n zFt%8N4R%dYPZRB$YhKyPxr?P;Zi{&}F-J|rf!!aTn4>D{sQSQBv(jtevMYZRcX)pT z?ptm%x%qH6bJ?}O{bUnR>yJ4{<{m@5)CW0xWlOAbQ?zo^t-eTQJ7nxtIsdUF?pj0K zfQ?ZvOiCFK7+_P%xYv*qajf|WYCKiT6^(IERm@W#_0-1;Hr?dkKKq@sH&2oNnZ@MI zn{_}HF1uvDe&NtfbX$AW(f&`cmlJc=MxC`p3gq2EUmut`a2ZMfxy#NX5~Sro%^ifm zva2>;aNzxo@B1R2KD--TL0E&W__f`do%0a~=bu(gNc_*CuK<3Y^X{uP{I7=2V)HlL z@coIQv()^y2fiOU+Krvn+>dh%o#o~qJKIa}@Drb*v%>n51}pj3Q~IBp44swcpPCEE zUuqz?+<@4hRxr1cg;Zzmt1|txvAtri%k(q51&MyqogjDS{Zno4qsB-6ee+qIQu|WzXf*YbaJna%ofmqa~1>#XZwem$7a$3JS*CiK9Temt~fthRceB z`w`Q;I_6SY(imF5I$l2)*mm1KGavDc(=OyICyDcrPTc*=BNhVkZA>c=k3g7Y)Cna2 z=GF1~Z$nK6FgmubPOoPNL#&&$hN%kdV)IHTNw+_v9XhpPtdO-RZC6TZ9UHy&_ z$$q<6heNVt9y+i(TznSk53ddft5joC+rm9ciXqw}k#_N!=N<#vR2}YBBJ`|jOxo}! zoq3SYddsfNNmH34rTVG#tZ+=)l(9aQIhi^1sPcC0u8e8XguRHFBMp<8Aiq?!d!!0| za!O0B_>^3j2`obaB~-g>@l-16`-B#!_@=TZv!s;(LIYT^(Ssy}o>tOpcdDb_7epwp zrBZwdC2myOg;1S&9ick?kI=Je+41<6<4sx906j+7G`o;iry;%E7CPDJAR|b!dp58iqq)3&e>>nGekZCW?{`B#y$YNw^8yBXEe1NDQTktaE~Jz6r6{KLzD7rS=qk_RCZN;}rb?`3Qm%c4>4gj-C{>n37mOUtp$OCjySGT;R}|<2 z{DKN_$oo~;c07rgGn1_Vd^L%C8>R;{?PX^>&qY77lKC)h6uyDsXkn`V!x6yb7iImj{EkH3FrKgbtP(bcx! zZ~Mf=!5+G+GU}>asEJkWj8^Tu6@K@bcb<8_^Dn#qynD%Y9PDXGYIIZYj#lk{&-3%r zACa{qqWE{LBf<{a){^EWDPh;V-uNmhVw08#cJ0TU4Y!>QakuAs_HB1< zeB+MU&Z~#!4!!1iz2eo1+n&~VZr)ddw{xrG>)RCB(<^~%0Z`89M+lX`^`FmPcxWNK zaOTF|o2_qe`OcP`zFV!g9(wo0J11`Kj}+{kw#Rckv7D-CPSwJWo94G2-*GJF?2OrV zMr=E&H@3a7ZQlG!&b6FK(T1C6W1A1(-h7yy)fyP=pSZJ%v%uEQUcoUh zY#%xHC$H=`aGAUQDMXTh=MEMftvCEdiQ#Ci`7cVl?087gturGHqg|npabMc?QbFdu z8PgILr80U+zyyY-6%0*`S?SVaRfB!k4hE)5@9I&x5PcCIv`!Ne>uKRB*aNe);0C6g zt-M#eD``Z-bI?5*SAWT@zc-9M%1TI+6BfPyh8vqn#mCV@Y?>7>O0(aXC}I^3usJmg z>Yv0G!?gT{Y`NwIq)HKpu{BsdA5SvA#Fl^pOlqM?yok+g5CO}^K30sj>=I%zVarp@ zRSh%EbnZdz9ar^lRntr#gI!Ycp{FqBsfl`OZe-l{v@BQFOU$0d$}N%NE%P2Y1XRvz z&ZQ#X9Z&H`7OuGABNJD$6;A&86$^^^=MbUu&tAnn+g6DXhJ(A5iIQsIa6># z00>TAWI5<)UH8rUJrT@5jc1ECq-iv1Rn+S`eP%1TKa6 zSWRMGt{~kIOb;3A{wxeRhRzkzG7tMrY-l7Qy2>V})2Nulil)lL`YN-mO2S(&UDC!y z>g9B?vp!1bqYfrART_5r#aADjdyF&@It|lZ@w~!VUQ0Bu<)#(;dyg;Xb;KMUQAfu| zP)q1E#2p=DmhohF!I zqyt+Mc9y%d>rhu8j{n5QTZK+YSlc@~x{mfGoYGy@0cPhnignc1?@>J+yHao;4zN)>;R zeBUDHGCBLmVf4jclW&&uApf&x_gf5CD=U?y()mYfUk2VK8bOX1XnH<$-9z0i^GtQMvi`#nfAaFa( z4@c&XfQWef)yHr4y?yFCry}l-i-+QQ<dY(21; zcM!R)TxRwa`;2||I4i#_YAcJb*}k}@ZN*|Lv|c=d;&VM0JEyC^bOdw##ZKUt7rSvJ z*Trs3@E7;r+1eH{7tGrtu<2E_Y0=!aQp6RP#~YgCo3;THBu`B}{$n+pqcxl3>sqka zI$i?1gAVsGvFCxIW(0N+Ihv(j#JhO&>pS*kIWTyF)7$@}QbIxhomWo5khg zBtGVKaCs&3jnUk?m2CE$!QG^>DOw!-|uIxj1LuN-p!}sma~!*~2*tXUC&C zl`Hw|xq!F3tyHte8ZN(l{?VwX zZl#tzuSImEs6OiSt<flh?{YTdlOPu=P~qR_5Knl~gTMUn{@M`un5DaT-+lf)zTomhzi5 zcj<<%mrjY=y0GI$I9iQ;u=pVAQBm}1r1qtv@<#OvhZ}uR+&S z6WurLV)r|l*>^2?zI)p6I6=aLrYuXz-6D&nawW%T=``F#P3eBCSGvESFWn=(C$ME3 z5i2&c1xsx~@rsFgyw$R&`9aBpH+*8DD5eO-rp-@tJ2dqK3E3UMOsZZU*?0F@V3x_J zpWwK5oO>%sCw1Ut&Nd`OScYH|th`Bn%0!AR(jh|_+kA@@cEN!srd5omY^2DMQ&{C( zPQj(-%3xtOf3A?nXUgfaQ$9`yl1>4#^4W4&0ZK2FbLGfkMM&qA!(4J$ zG18Uj32)?dxpKNP#`UXcC%+9+SUr(v7D!vRcaJB%k`x#L6o~ zN$ZkIY7ts=OKKDfP47wWJBaSy`3S54WTlyV!zeMM}%Yi zQ8fqE)5br96KHz*Q~WWM*vI!G_PFpc^*4j@K0LE0{y2OmSQx>!jei*FAHn9`$3>z9 zdYBm~nA~8DXgV{#pU#fQc_3_aZo(2EB`ug@R}}h5DhGm;@-|cOU?@CFHrWHrz$A|0 zgROX`4w|ql9DTz4ZFpeY-6uSXmEOHfRr(~I>UD}Ka*6*Lg-WM!5L>-(Z_3<>5H171 zyF`>>qV zl>0|WC*k%#CEr1Eh(RL$m>iA-a zG^Wu|>4E~GP4R1YcD9CHdscj_&epIhG0?ouV0zP3OLk$qO9pA4XcqdQ@R)oOhy^EH zSa1#o5mM|@1}{>n?;a#x5|MfAnuLrxpmHloo||;KN9Ls>CS6svaUhZP${CYx$U|fr zyC!Wz)rw!cEA^~v}EX0+86|Wk(hncH81+YAR*?y;(ZaMLm4Y8Kpw_A44cEmijQ4hp8OP+P_ z^&&1aZqJR_%j2b$&}=^xw--e0Rq^tAJoLoNePms}WR(f}we?hXypWmSin9$s?5IU| z#J=WESvB$=j@PV<)wD%x+DK8pl6Z-qVW0j3M-^?9kSu$%Nhd|$jiwVCZFlqF+|#hT z_yhVh|0j~9Fv0&X1Wc4GEKhm1N;TR(g~G-Ej&#yS4HTnZIvh&T6At!|dq)IG;kSPP=Re`F^l-D9Mf?eMP8w5KG6t@m z&Y<*-)QF1&U^!?t_Ce%mvL306=!+;9br0*JJMi4Ai~hefx=#C$A%Rh6O{HSmxkTb> zDq}=zG}V0vZx*^AbyEH&u@`X z{1i?K028ZAJ3=G%BhAo9dK3wmy;Bm`elDZ!_T1@R5Eo+flO3DOJDCZNmk!?{VQx*- zfx{hQwOgaLTR(8f2Tmpr33W6c#e47dy)Qa7`I)j7VD3f^>C%_3Xx5Yeg!+S4)m1S2 z4gyzohl~ncrS7Oe0=BnV>J0C4S^d{=1_q`jG9#iHRA$D5?l;e*?#famFb0w8284}G z@>H9YuXVrbeVwXD3OT4Av%aZwI0W@H8%_70a3nspLHrNYPwB(DA7y9?4Kl=F;d>PY zi~oYi)$^Q+6dgl!GE$@`IOCJdNb|vE97hT^EN$Ey>FxW# zc3c*w>)O}h-^Xdaqiz6>Q{NR5ilJ00aQYXJ?*`*veOb5Van}n!nd5)B8BG zZB$)Js9t()%(0$+k@`FxpeS%c6(q|5#q2FpV=C3gKtq8wh$$P$z5LlN{Ctr9M|wTY zQ^nF3FqyFWErA-!prww;gJ2{q!335`}!tsPC7lS-ksrCr+gI&9XW4c+Vl)n?W< zWhroK%S5g7eDc4zeL4Pn5;9*(!Pmo-sr9DKQDxrRo!kSy>H4{~7 zAfS`xU4jG}F_?K^JSR94lukpSUHe<3-mQx{+i);~J!g6cg#OEQ>tl5XqICz}e_*lh z2o8M0Y&qYsoLjlju$bF4ZC!Sk#oXJX?rpc$F1p*NZOeeFstq^y-s)a-c13JmY|w!S z10Fj9{5O=c(5j&J6aesEpe6!X^c6QQE$D~ePoaaYP4__&S-cJzf4@EM;z`;BGYCr@ zWK%?MYYSP__?q$SMr{-I86(JX<7f_@qhVPa{^Z z#%?9QcGtFM1BqpSIINJ&!qQoK6M4r+B-T3i5lRyn&L&(H26bTP0JAMY936H>dmluqBrrZ#52+}T1H)zuEmPOf$kzx=_*P2agYK-r~w1V-d^c^r< zj3-NfXkc(K;UfAy1mgUxD4ZY0Sz|qOc~3qw<$Y%A)GnBrG1F4v zb0my|qX}CtP8k?^a{m#@L`*;4C4L*9QG{U<06H&_Wz>Y_JQ9V)1&XDkFC^14Hk_8p zOs2|%BVnSQw{BKB$t)XFJO`?rC`b>KxYcO`$42au^CCu$syZg)IZDJYXz09*YFy-& zb6i)>&76BNh?9oaKqvY2`d90}7L3563-~}gUf2<@^}T-b)swN>Ez#O7aaUoacpWxm zuFd)T9M8;|*%L30LRm1o8luUyjS)xHvMoFAXoxvlqmI_Ns~XA>$Q#+vjV#$Y5NGD) z|6`^lGwTxvmzguoUm2bmUT}Y4tA#n3E0Z&mFMbAY{rS*8n!eIeVrJ}1-Zri629|pT z(~lhW57aM7$QSAUMr;+UM=W0PdB{HSnKrazLpK!Gp#A9`JwyM>Y#eIz!U!nrl)+Zn z01nF-9T*^uQN9_B{O{_uAw!lmteOzz@c*vW9$l@f`>w7%VLxoX`4og47<7gqYERmQ z(V5IPl4JGOY#yheDC0C4eGIuZ+XET`sEk1+Wp5ISsl>s+wq2=??mCUFpvoINu?^-F zkWS1vS{@xF6C2#rVNrR$_ycL+L}9 z+3PiPNT)MrVq={;3uA+oZdp8SpDNPIR(yJJ6)sg`QLYSk>RpC7;99x|rfb`DC$p41 z8jNXM)3kPBiia9h9E1vO}Ol3BzHri~<>r(~lTQd+!u{IRAtAScy!katJ%G zup5YZ#RjDqX$O@;njnQln*1~3u>cXlBH1K+i3(nW&=65<62T(7l03tVkD;B#D9@Gb zW!S{Rg&ss!P$t-CuzzkpO!*F98;-4Mjjn0Ex%O7o;+ma{o?X+KzjPKYyDMMwePi9C zyE)=${;;j<2M4DuAG-5t^UVCA8#p?6BXn{yH&1sgdkU_0&vi%2n{I>_Jr6*|*6Ep^ zx&yOdYpSXAuZ_$cf!Y6(cz#7Jzc!j*yD+er-*BV##)e3K^Yq>iTeiOW3^w8vSHO@! zcI~WXxv1n7+coIK?SFsM(y_kSv4^9_9$qXuF>8sti)MG;@s!b7#BHy(ePb661(`L? zJ~VHc|H2($Za7$P-aU^qLTX@vJG*uzkAqfq{apS0riJRoytUIEw85o&rW;yPov(CX z>we|%wZm^!-xzqaezEKU+Hd2?rAsH^PhFjeq6Xw9 zQv-I9aziu()2>V9Vd5XNOFxBnCIYnd$;y?wG+e%zNdz7KwCTdgebGGRl?zO|q3o)p zN7<`PK?d%NCcQoMc$+$r>$eXnRPqlg(AM+|DHNqC4k-u)O1qFko!*h6F)bR8NTE*b zOg^nn)o7Pai9-*pE+f2A3DZ+-;%!PFVuy`YYzS{tQY$cnJ=j((g=ou^4RDt+v_nau z-L(lE3sM0VB$9nsD)EyzQkLy`-G+Tbs(f6}cqjG^b*FHW^a%}pGQy$?FI5rKW5HoG0>>^6HZ;J(Lhh*Uvt!k6WJsk_76(x&vwtH(szAEvTRK#&OU?<@vl0_nhlrN#6gc&po&(zZs z?rt38c2up0WKXD;-e#vV$ecTE3WY|ES}jRWW-}FJ#eQ98vPk7`uuZBzp!|%wVgwlD z7DlN!#umOwzJDR7oXW`R?drqUV|L&LQOM$YiXsl4NZ%rnA@jo|AyTF!MEVV-p$1CT zs-%P_vP^`%&!plLpd*BsxQd;z!$e5x`YQ1RaVi}?#;Vnog%)8(4*ea9XFDVA6p~he zBVJrBZx1v>MWD2ng#ATip!?*^$&WZsW&^eZu9&lOE1=E&%Cpy=o$Zb{ZTj}9H%`47 zh}E@W=hy7M`4cN1&QnU81Q)8Y@A5_=ZQ;CSy6xL>>%zN}?@YcQx(zd&o?_bCx@&G% z#ND*)S%cHxQQVF2l4m1GL0Bj1S*gQvh~1|7CBLr3i&vVt%);pm(v6=D#|nMXLLZKr z2LXc3l3$$rBC9+O>>8dMW{L>#j?9ga7fFh}wCM~F+3~XKSXoQ7tc4mz8pb4WW9Nlo z&n`0}+7vBmdW-+|=o_QA#Kn?55&NF$9dMQls$L$M-WM;d`j|6k_ZenQD@IdppCOKx zVoxc^OHb{Jg<_yDTV5jz7N_lG9;trkr^{rnv?W^D0;D0gV!5OV8{wogCTT~U<+nQfN)`)T|KK*qzx`Ta;fBNKM16NcH6=&3B z*;5(w_@W+Pq~Y-Up_r#P>gh!eiu&geNgAGO?5;Nap>bb>={psB9mXHI40|)JKg!J@ ze^Gl8!hhVlX9v>!SyS%5Eyh3FWrzP~nFhrF%;DZwXZcx0yJ=sQ<>yrvJp8=Qgd9I_ zuNGHi!j` zGpiyaC`P_?5e+B;T*?NoMn@1q{Nyy$htpF6P!<^WUc2%(?XJa-bJ)Jw2cABgq1cSX zrYYOl`6or_?eQXwx`Z3^31fXGsqZQBV@jVQKh8xwUev>wd)xEUOD0Km2}{vE+TC zY8}}=(IPa-p4@K=z zFG?ns9vTZ@`bD%B7$3%o?;jIjr+Fmged38eaZGsP3F1XQ@r0xWO-~{3Fe#knm?8{FYIRRMv0?ps?~#Kj_w*PJ zq?V(Y!A#Q3Ql`r+uY5_>pyHS%NH1Qm>BbGtqIba~WjJ0M@F$F;=O%K~V1M-7Q`F}~ zXi3U(?%BSpI5I2h^hRvn)pM3Aj`;*R?g^a3=wa&hv`f|Jz$?=)HqYG`L^T#7O4pOO z>&`_;t5UVvJN4^_P#w`Fjz^Gb7Mx53_~;RBXd4cmsv;OCL>k)cgD@^6N$MDYi>a8p zCecVA4ha{t-Wh-%B-sjry%*R+m95^(Yf5^8FVY9=M_Z&pa^Zywgp}@>+YxcYz(@l# zkb>p&w!4}nZ8)p#D>)zL)xs}XCy@hTeBv7JNd4?8-nItC9IK5M+Y(1sPX%4$d49}}( zxg?1(KH&hqntD-TGyvGas9!apQMycjr9z6fg+ZiA4x(hk8Akg^xX(q2LHG_{pq+`T z;XdieQ_`WR@~(rc^mz#ke{+$$RTJBOEV}*J;`Y9alI{=WU<^59+L$zzN}87HP=7*t zJ=JWL9)%9>Hb*ZzD7`FY(ZcLY`i0IK1~+svaLiR7b=5Dq8sgP;v*r(6Ug8Ea^9js= z{QABRT*p`Jx+@w%&6lWyi%{YFSx2~(&)9BAntrLa5L81c7_6!kRZFdWB>K{@laT*8 z%&5Rl|K~EJQm3hb>P?+)3vbdSP7nke1Ss|q6hZUA(A&=EWE%?+b z-EB|YsBkQUhk0%cuKLA0^0;uWUZ^%8UokaKIg%5cae1%fh*gbzmpu5`>5^b$S0O4 zs;Y9`X!k1-w0pyqd zJ8(T@-1;s>2RWcoflo_Dgpva@NvS6C4mLQ$a}DC}IUe7`snX7Fn>~oCRtE); zOT(%5eqe1R+Xqw4gGhN*&YVF{-vkJhv#O5B{4J@*{fWl?*%^iekOVm3;;W1BcxtL! zQyjH*4@Kcb3j}7tk@u5d_~gCnE_3T}vUkmv*N3@bX0r*MWmiR#*jL?yX1}G63}m|Bh5JFt&loarM=bSBi*awz+1aT z+1E7Yb^h3^p?(8j;VZ}-MAv_q@Ghp9Z0?!<+velVn{kTS?eZS$VwKw-4Y=RzU$HyO zk9(%iF^=ZF)QfS91*~$)zXh8M}4^sL6CSa&aeRF~`S*ATz_skV)+qwaj1@N8*r9UQr-l;W82 z#jlckhDoFXEXex#schCym&{oYA7L4do_4Q;FotstWA!y-cKWjM8ixPkUMx^Tr4oUd zR~F{N&%xh@?wxi@ZaUyihk431k+>UdjPd>3{9@5FpN-eJN^T<3o3U%tUKvX;kIW|v z*DlW)XHiLTO2s(LVwA-KPb}ejI!g@=jY_2 zC&QF;?w|S$&q}*;zm<07k{B2Gd3xYaWasVO5LB}M;2pBMf5%Nguax$Zl#lb>ulrN2 zdlIdCZXZti_NIIX621dT-=QVlMvuJJnXK8h$@c0?&7e95!y-nmRp@;Tz z$sNy@TU%4zLy7L8*Pgr6&1{AKCPKAJTlBr^(2DOkm?~{I^d)t{!7)|Yk*GxUm&r)qENdC7asIeQ9}AWmBN#Nu4QLpbjK~aGRPGP`BUPdA zgVNL2X6+$*B9b>`2fq;PeOaO0T2v^9 z;dmdG{>ME?j%kddDZVrzp@nchj0(fz_m`EU>?Cp8BXShD%y7})AV^vHZ~VHR!UGiu zQchvE-Prb(?I};Q>1lqzRjnqGA2K_cSt5j)bixnA7`t45dy82aPF6lr6Tk} zgyxUy;gNbIcp0hFzSa-Q_zvoDv*KkUL-zD+L_kf8ARjTnj_?VNqOiph-xv+Ae}?~= zf5yZ9j^DA<_$=NbzoLS_V()PC^nZDWrOm7>2&u9yLvZP_U6>-ndC`PBDx%J!))r6s zn?%Zs26{>yrYX?{P|`!wONX2W-p6~P;fCmn(Rh4kslw3*8y-wvHY`n zah?-GVody0j0t_QMU0935Qv0NOg?ei)?A^ns`wZd`$hmvIDZ*&;+L{xMV|L3=NHal z2|}i$M6iC2CDYSITFA4yt{6$PxbvbCgqyF;5&56}Y7xTKikiiMgC-pB4-58SEZnCBm5~MPK7@A^?;oVAq?CeWZH>My( zYI~BEy{4nnu_l@*7NTh#1Hp@`JC7l_fc;Z-Unf9CM(TFS&ms#P#)Zj|vHnlx0Gy zmy$xX2Q$>7>e)vSV9BKfhr0NoH@=zd5tF%1V}kv2ip6OZ1zJcMJL4*hvQvxog(kt=k$U#hPCS(S6yZ42D*6dh9JrS-bik*{ zTb=T@0tGVZZBMz{@3`8f{Jy?@K>e25r+vF*K$Y$a65G|7!R26V<4k6;_tcdO3+Knq z&n&>3?CP~o6zrZM_Ub1vf_8+@JT>vmGtc0`-sjLefyUwr#t~9~g*q&p5Ddz|wX#?p$zmOKbG!kqol;* z#}9aa!X@oVQg?YEg(B^lT!2D5d1Zcn+PEg|v+wc@F-I2fPhj5AGB5486gDw{2G_Zy`CfklkF85ZQH(uu8~yVERw#=1FDUt}Q|UV?RkuYHttY3}|7DLPFU z|H|F}WFb17E`5f^FR6|Ny=NrkY>?CxkBYBPEIW3xPAsx>nlIfR#1cHeO=(#WymOqp z2l;FCmlO=qILSJ?#TxyjXgD&SBz2n96JnQzc<(IsV(>*?0n7Yz1&&=?x}!&z&c^;I zQPGyvwt-(pk1UNQwYrsH7}T-YgS{OVIr#%e{c7f>l(!SXE3x|?g>k675GrggB zB;jpOYTYY4d!xse=1h2jdApNZFPtNy6ERTj54wAzCu8*jJvFKItaNS1iRWU^C%hd= zZ9BpWqsN!7n)N-2%HE_lxH5Fm)M{f_m&;P&!36#V_9nH1Kx-9^KAZ4%;Tq7efeU*S zGydptfK*3MzB@8$YW~Nljah`!=6H|@rMb(1f`ef0GO8YqKTrJC@NJDi zrQz%aK%rAg+!hd88)B0-FsiJ`9&+dn@fz4)BxWiOfdZ$KtwM3S1?nMQP_zo!twO|1 zb=ZeMiB|6s4c0zg0J(~Wt?`fZO0D*xR{Pf4h@q9}p;orbKAEQ)J5er);aL~sv(NAwO}MZR|& zcvrP%OMjwafRB{BeNfp)Y6UQ<>;Y0o)PCKcxuClB_U!vn^tWZoR{5 zbm?{R8e+iKL8XviKx=Fac@AV(h)<$5Oh<|SQ8nYkWiyR@)#Vy`*W=a$R%5l^ z7$46l*jQU@^}X?#jDpR>9+y6}yzkcND+h=+JM=m_0vq!qz(mCsH`m^^(!6_R%f9#A zE&49>YE4tT@5WB6lzW(yHd$q)%9TJ1L2fN^mPaYC$W)*{b69oge#?dDcmN#X{^g29 zQx7oYEuBw>@W{sa&P3H#tCYJgVg?Jm;409kT5hV8=QU^LPiP^C-^a^8EI{L0ijD}^Ay{&5VaC2 zTu4OP#zcrzTDvw4^fw{CsHF>!ZG+Yr32q)H)runRoPKu3Xd_iMBO~6ST*<)mh|$i| zI#_hF*utWV1*U$vY&yc? zFbkm~e1+5)inROq{N+nVHWx4DIOFCSdp|`7&hyY<1)yZQEF0x|$q-skx^w}_5%?NU z@+t_ypTCT7X5$}u;oB^P^74B;s74GS+W&ynLWej;>YFTR*)sl`g-~o>0fnqv#-+u% zi^PunFCO_D7Ge%GPO6t*rjWaj%3`2Z&R?3na$)YEaUQ4OQQ)=#03l~SN+?6`D7)7j6{=%R$rS*CRvnp;qI%v@PA8Sq_Z9!Y zCdBW@(PX>>eO2bOIf2r-o z?iaev+Q*XRL(x*JL{$%~%iu=bf(JNUQUB-bK35m}$a2T6*|*icHHT9TS_%qqMn^xq z-PPc#M^md~L#qlltKLerJho$1!Dg+aS$$G{sIasiR~4-^dT6B~_;ToGi0Ixw9DCjW zqZ4NR(S%m}prQHZ!t&T(E}He-P%^BNezkH1LE6s)cYWBb>`9dMT29m<9xv{{;k9(o zl4A+v_fqb<$iO;pv{+@_gEVz7?FZ`lpPKIOguXrFM(x9ks^V(^%tErVJL*~Wl&M={ zCsq|~ta@D?T4@SdPHy)OiR}ZuETdz8&1bmOQ9OymdPDymBM>RfeK1&i5o ztXy5)@AY5?APCZSa{I?sZ5R3ab@%I@p6=JL-+SGdA7y7}aR`6+nDUkfu}NI+%RDrG)|ZXO%vup^Mqy4!t!gc-}<*VE#nGU;#^K zjTcT74Hiwf23-@ygT)gigC!HCgQXK?gJrDTI$l0eF<3ECIatZkwsH4F)nFCFv&X9^ zY6fd2Y6oj4JcFKzy1_c0lXPQ!>Z>MW(f-6Aahz;OylKOvz_5nF1|275jU7!=s+i~y z9XFic(kW>jw}%sR&T?X|n)9s$;b0?LXcTo~-i>^M8rqtay1J>r+$LxJhZ;Zc9{d(>#3mycx+$V0=@v7zB72BuF+ULmIMo}7-E z51kB-`X`6RV*+KzgyEq;@I6c;hbp;R%e#kyLr12hDaoskS$DCg^vJSbj^*}C@{^K0 zFghXmr-F&R$NCRSfxysliJD}2Xw0ruJ1PZE`X>XDR~IWB9vUB>8XpQuzMxXycj|;R z8OsVtL7yxIrpAL_V=U*fe&4PGhx&VV`wsT>_jm87t^z~hH|`eP2Qwa4Vqpd_RJ zmLC5|e^8c&CNOsSyL%q#e)PbAZ(skRKHu)1U59q}98JsZ=~Hs8M6+8OMn~irOY}^# zgje^T9s~WJ6<`44VH}bDGkAYPVB8-J3?o+yLIPVl0publaadX0pbmVZA2VxI8X_4a zV=+=9e?zBni|G?lo2PlqwL_V-$NCc!+=p%oL1Gk>D2)u!3|V4kpKo$#Lh|`ySw7!{ zUz{2z+~)IrerjkuQ6dZlgK|tadQ2u^5i^X8`-g(DtWyC@^sqGgq!cp)AEp_*&Mnc4 zJeY2IG$6@=mZ3>emQKwKgEdZ)LQ$sSQr)5{ad*ef!T80CF z$1r&7kIVk4lN~KjN|R5vjE^2`IXN9X;h$`6-ngkHfC*iH66*jAiq=Q{CxXF~Ey~jI zoeDIcoR+Kcd1q4)A`K4sH1Q$_|mC!r!MWC zfAsR9n*)oEt14v5?Yuxx5+o+vE+27)0uwIobLy(qk_7Y&kL zG)jVK(x%lcnM8|Z7PBOaXvMz`0;f=ECKZa=s9|G_V3)E*2PmB)KjMPeF%H_rhsE5p z!k`0j9%3ire8f433lQguyTn4oc}N!_&KF%$0jn>F#Yh(-zXWj+;!?yesaSMMmJyv; zc2>|tSqaNENZHg2l$EEHl_tswTrL2sVWh1vTCAVCAhC3y~I;lGG4)vg^S(ej)oLUQq)`-e0c|QKH8Pg`DQ6q`_1&&sM-l&wcu1GOx9#paiJ)UQmTX@Rh(c`=I{&YA|-Nljyesk5ly zqDS2LvQFHDd1UW^kv590n8#*3)1u9@Q)(Fz#5O!{132g*JS(-#h_cP7voS+iHOksi zwn=J5X$PLQMQU4Cn?`mkC>|0Y5w~GHH)DibFhiZd+mW{&afi4Aec7UnJL9}Abr!^( zz_zkHq`tw`1m$vOnk__K(NRsKR!hm?^Q_#4JNoC?lB@GZT6eA|)n_ z`~4^7O?a-{N}vsZnhj3LlfxDyD3IKyu2H;nmT5h+!Yt=QQVFxd7?r05P-wZcI;5yR z3$r{@s+8wu^+>5&6{I*)MwODKOj?RVnYIJW8jw=^$jus&VpU zB~mNdT8esRS5vc=XR~H4qJ9Q-k?&CRSskaEnl+;=M@_Ll=4vUbm$xjHucl_RP*$L& ztVn5sj6I=9E91sCs(3P11r5(lb6%nEk%YYEI2GCHEsj}8n^5LHYuGqN z7IUN|nd0N{p_9jxxv?B2L+w3PGWdu;@!V5GqruefP#T?(P7g~=rNdim3ndp_Ce6^7 zvQn~q)IVQvDDXtgNdp9>OY5rF783%}_=x-vhFacCpq)Smfh`2K5`ZDV$(;n2ua^LE zmOCZLEyy56VRUjd==06ES6T4QDh1I8ZUa2S#Vfdy>N(*>d$gcDQqT}CXh0(CUQszB zTQm_BS22pBGM4G0vg~MM^PI3~c12y4ELl>6$PrDDCQ_X{iKZl4=cTwTYRwN>-O-w+ zYk@0WbGsL9?&!|lR8kQwC`R?HXa%*B9o^QYwB6dC+Guqv>O7BuOS zq<*$KbNp=6;p>u~Kw(790deK%Jt*D;c{pCY(181vWV{-o(4`!2# zI6bf-PR~SoOdG&tVcO(r1vJF+XOM(~c?gmGSpuH}NEtvGmMS;1;iHC(NuLy9Gfb_l z2f)bDXjO%+RUzwoHd-_a5t}z`^Df%fMLpiR-S66}X)u~s4hHcez0%S#%;{=_@eDsr zYhcY+N4d5~qP;{o!_V^1==O2XVV}&z$!B!4x@QY#b(t)sF>QZTTjRJ%crDK8XZbO0 zM@*Kf({M%zYC9qA{9{QH4V%?}EAcjG3~Xmk?$g|uwmWL%+%wg9rnVO*^Qmqo^02c!7s)edapVqK`(tj!@&~_Ifp`+{( zY?aH8AwAQuDwC#dQ71qh_$B~jPGyl+M{T*w*0>|@rI~Xxb3)XS7jjgFA(_>jd+pmo z?R(~SD{H#-j;;0fk+`0-RK|@QXhzSCzVO7H{;tC_KYXq2wXW-3q0XZVj(#*%i4B15 z6q@|-#BE%4-PN)yW!J=;yCZFT!)<#Ps(NWjRK&A6TiqH<;y#2rxy&$$co!vLx-*D+ zV)M0xFR^*%1@Ht~lbcXmV-xjBq|#+tGRV!aFj5#!Yk)0UO_9{HIV>PO7M*@fQzVmR zW18BS%wvmA2x@8~dlyYjOw!E?DT|65)6~Nxg}Ov}Zk0Et<>X4zt60k0X$v2eWomgc z9;-~^DkkcJZWSM^RQpQli+bi(EDn0rys<_VOU6*`;Y7V*(8j_v znS-|_S)CSUjo(Ua^k+=7rZLj1(tOv(UE z1*okf{+KD@Q-!OPlxFKN%mwmYQbG{@lM+*3VmU*i=%XZ*mho|NxI$iPx;88Env?QU zrmaIJX(o>nc!Kp|*f0BI7Ohr*whmRFR-`4p_)Pt((sH?gJ_F*w1~3AIWjR!3(s)%# z7`5lB;x1~npU;ovc)~fJJ66xVDi6uDs53v}tPMMB=fz0f)^Od{CB3fN&a@-Q%Iv&* zYD24v)ZZ96XC2AW$hxlZx~@?7V+)Q?Lz1RyW6HA>`ME#bwtu1O0Cls1TAw{P8*$Wy z9d+}88@;dfUGH0PY?~AATI~^QY1mqN>C_!--EYiXvHKO`pu&w@@5NYTPH*~&h+kTI9 zL3h~Zo-cmawoZ}Uke^zhEuH?CP6I%h;nz~zv8MR7RGQQL8J(Pi6_Y_-pVcK-3^SlmEbPs?xzja9XuhqiDlfxl5Vp8#-*SXXeI^RqNv5=k{GijZNyUF3Ak6` zuVtLZ^gpeTakE#?I2HN;ak(Ca0qO==QQ^XAB-Y?Uje!~4zXIX_S&GkaG_A^1T-(iN zw5c=X>74HeVCrR4*w%Edf6=xvT2e75eA%&b2Q{G`HV*?pRx_W1+L+M@W>Ox%#)-PG z>(!A~W9ClK_stab`Q3*P_3d#dywsw5XaxRd_l(&cfJc8)3}AqsMh9do0VZ?Ob#FgP zFk8$3*NzpACL9vYD`nGPfIdLdA8VCXNJH4%aMxB5s_J+>KeFXuc+0_1N8jxep~}Y= zY@hyTz0Q)w21kAtRfbbJRU4tbSoo`{-7-H-BcqKI8c76oU*Nf*pyp-P6;d2mXe;Ts zLc19>gE38UR$Jw`XRDE+Q~6YWWCdJVIa>BIKag(+0WS{=CZK4j65l*y8TPr=ku?Yf1{kt>I3Hv zC}#DmTW&o5n(w;r_2FA>3pIOhSG{XH0HwUTWp4XQ0YGoW1OQ1CsL;fEz?1;CSd*o3 za;l#Z`*CJULNj3yVW)Qo{WwL1M_6pm%2GGnUCedi9-5qXYhDF6Gmrwv6d?){&9I8@ zk@2D9&06IFoSCsXm#KFvEc3I-oT*uLE|OgGA3+!(br&A7EY77kx=21$gv}N2n%(~r z12nSw01-?7ej`L1RE8m9ES+hHaFVEw0;c1=-tYXC-xaMGylFYb?WW#F0 zvOnQ!;gtzZll1UnF$S2aSgngn`P=mPVhk8cZGwWFd7PF%=l*xDb3H!DiO|Ia4awxCv2v$AtKLOQJaxrEaDQLjf6#)n|aL#_Ab85U}Z=ftR5l2UMAKsWZZ?kSG_%Nc%_&IONjy(|%kq znW>dd2jw9*SyygcewbJ$h~=S49NNJ86WIPI??h`c3+R>XnEg0*P}Tr5&%6d@xBCjn z*gGpW)mM=Wkao?4xuUdQL~^EXwdJt9*`HJWhXFL5HR5OpJ8%YpZEUVHnpZN{7tMEF z?7Pr6XJMxYWlEmI6>-#u9WX7f9ba&44w*Oq!3@K6fpms>ie9E_wU^O!lwZ+%DC>wU zzo*YV9Wqz29x)IzO(<7(mT8d0DbM47DG0Ei<5%aFRQ>`jg;{=Wy;1duJP+^J7f}DJ zx{LZR8Vq>KG}q3(X!y4N6t8%;1(_y5K1qN~bouiD*Av>!W#FmWO-vy5Yo=_q5uwum zjyg-UF8&AiTWHxZfXB~`N9>-k-7|mu#`J4XU4Lr9z9VAZamT#l0h2z@HFxkg`OU(2 zj2-;{4?_em2Fw=uYbyr_YUvt-gVOgbt8fZN+zMx~3PtF(c z?P;!Y%s!ts`@A~)uyWn~@Xol0ARQpe+;qgx6t+{+u>iaB2HRGb-cZ- zUg1^aIvyS&=;X`ft`QBgQTsIzWz>SSWw3zNLJBPl>dFWd1!<&N5c!}cQD=G8PMtxU zD$b5Sv?B(!9!`_UG))WeN@zaLWD%^LM1O*$1hA0F8k^PKNS(h`S1%6aXDVnI+(Yv5 zsR_E8I58Cnx{pcjKu~r!cx3O4VJbMXz5{1|G*h@tmNg1%30^-O7QzRIJ7X5@5}{lJ zlH_E^jFNJXjzj`{ay_3OxUP6B?pM86o3Av#-T@oN zQMbhD99bW5u-ESscn~0a_POr5?hX7K4SaXA@P^k2JTuGO1?^falN7ZpxUV-FIKlWu{!4Vq znFW%^l zGa0DlOMk}G zLZ(xw??zt7md_}A^+dH%(6XllQx;nw!2)^hSj z_>e2qCyu#QEE)fyJ$jA{)~T)Gc{|VOKf&|pvSq$n`}g6s$1!(j^iS!h^-6q-KgFHa zKhB+kCW}$Z!zeA`|DS5OjU1a>tp2aExo?Nu4)CXRJoh;49-e#gpOt$5I;N|SDcOb4 zES0Ol1Kx@hkN9ECVk|pxE;}-XE4z|R`=R^-fn5atgaC2B;=(&i*uwR-m_#L`dBtQ8&+@AC|4x+5;cjPm_Qdx6O^js-d3<98Y&!P!DIySF>xGr_Y29Kd=G9U)e>C9F)qJNAzQV22$1JuR~-|F0C8QG#RbZXO&6LXxwYZk+WCQN?F+fB5nF4>)*3HFuW)jE z$689y=sVY^oVPC8s-t;D_w2cGoi)4cZfQfLbVImw!_EBfmVc)_vT;v%jOPX7){*8IrCmReeU$jTVCn9+!b~-Mr-P> zc3kN=FDyFUIMlvqzhGAmwilgs(W26L4Rnt9dM>->L#Q9wZ6Drs6h<7Lu)}ko(_3=y zRyIZ|w}mUWsUx+#=eC@?4%dB7u(;9)E2@-}=H+jCH?Qb-aSNy)#9ip|htZPO-^Qu$ zzh#|IzUA+JomUdUjOBUJi|oR?HO-Nlu5e9P=C^Pb+|4UPFED<~39CKlg|9f$-}-J* zDfJ?|?0*N|1#><3uwj1{|E7t5q*i#-Tt#?eKZJYPD=x;aDlW(^ekaN3DPk1|z8n?IdXz6w*!*>{aou+pLzSm@X$6zAdW&+JS zdEM6i75X1mY~Ek2|4}|Q^rK<}a(+}n4K4H5XsY19g`u2K1^Lr_ppYp_7=rYWNgX_+ zV=9lP!X@j-)})c1G^STG%w=OxyJQ8IYR1D-xdQoX9GGgVgyuX;Z4*B^p;NJhGRTpt zrjw5Zwaq`1%9p%$kfQ7)6csi~+E$r-?@Y(7E0i5WLfOG4nNiu%o-s)`kAL5%s45jU z^|cj5k+ywpWI#;^KWRZO3ewFa7BW*Ll{Qj@pVp7RKpo)*wE`zk%t zq0KfLO{PNrF9zRW@EZ*NyJgBGTU+VMBvjAmQ`FEGYPkRRJb#K)Rb8m8YpVDurPXP} zfaHh{YI_mPgj%&M)8)uiPKL_gsM4bDfn{|w8hgu>{Ey;l0V+B(@n}@hc8mI~U~-ji zQuC5AlWgR4L>SgR&h>M_HYJ50f#S%JNzisRCmAQ#@W&s4q@+(gNizcRq|eY{+$zSO zCR@RK8O9-Vy&J+Z{-^QLOqf;1r!)C}DmDvKSM>){uVF9=PYL~r_!J-9p;F=<#^@a| z=WaC*{asW3ef+V@{O0N`uoeC<^oHts!7A3h_~#5(Gn2;9H!!nqmw$42N|wo0PPa$t zI!fZ|S%cR-8gSzhs~h?LQLtl z=X{T_Ed-cRMAs$Q^?SuyBA#HTko=#4#cTs9zwS@BhFnCUJG4LL_K{KfxxP%wjeM2> zd6rmT?w6n=q2+RYhb`!ls%#j!) z&HnmtL`H^Gnhg~*B`9YqSF@uM1RZ2abz>znODbAYb*E(e{J_=EUioaqvpwwDKIed? zLMN$bzI5hpVRfkH@Iv8{kn;##Y@Gel?A@YRmcXWP$<>VA{O)ozT`bcAa4h0k+zDf+xHH<&^qTFu zEz+BuBa8=k@wdkx_W>giGUYz~Y*=xdUj=yr?;^r%jmm9y<6v?j(<=4e?x%{HJ zeeoPFx8S1dg6rkSBjwFu{N*&W3&x4&V0kgJY>n)d&t3jpIA`5W;k)*~vC~M7UKpL% zUo~GbFBEzsPH)KR{khW>&B<3KAw}2WDL%M(M+7^|lXTY5`+I$H09W zzXy2T$_|2_#8E`MAqBdeWGYb$O=Ll5F^uAu%yoSEh{{x0wkmeO~**39p^y7$W7`K{NETnoH*`ugc>bRA2G(K3Oo&LFk?ydYqzPm%X)LjMiUpWYag0PH({8YbDnx zXT&S{=5MG{8sEG|c|QhN&MVm}8z=|Lo{!Kte2nZI@yjUM`UrlBl&%Zo&$@1PjyW1~ z_NQ}9&!yH^IxcrCIBG-YT7_fepWS@&ciN!sqe7^nHM}riH{Eg%wjmKPuI{U!^B@| z&_uva&I{DyteXUC(o==b+!K^+Lh^|ll%*SwAD@vM>@?u9N^>3xgP zh`P>Ul#QJmdtp3cF1ceaNv!Dn3d~BGaM4(S8zk~}kmHAP@-v8Ma@Ei0(Jwte(}y2( zepVq+_>*TVF;Pk0h#KBb*@H-~BT!F(R3(}Ez`l6KbPJhO9`;$Vm~hPRA6JeWbGnZ~ znHU-l_TXz}!2|U5p+?Zf^rMqO`Ejb@Bk)HA9wR{7ggi~a4-m_Kcqkwxk0YO^g0lo( zpi=q((n(1UPRn1Wyq5^H6QKJE?6$c~lPq5(@Du^Io4rif6#{f%sa(DNHevsP0J+NL zG6MgJKpug&2z-$MxtEj${1d`L1d0ii5?CNWr%iH{K#Ty1PMP>i{w0C+1n6dla$%Fk zmklyy1)c!iSq`Urb&XM1akRSreyP{szURcpClJGU%W=m|gqgX#(o3xu*2gWB%Hr~> z;#R_JTy9l7n=sg#uDF9RCzn?g&mkOOWK5Va#=TW+l%P+gsbD=90kA z!EouOB~+?>-^d%f<~?vj7`krOQdU=nEKJD({xJW(UNCg?(W0`rg4DGnkZrqe?fSdz zO5&a+d&xj_@7oN9Eb0ZKn+>nGerG*HZ?`Q`&ii(~;RrwfXq=-JVu6PC+0KJ;3}^@`gVxE4bh zbp+8Zyegv5(N8T={Qfb14{s=%|MWHKiZ9L)e#^4N;`mV=*R_kk&lwFh*Y@6g^!lMV zp|=7{6rpq7d=D%2Tsv`d>bjpwJ+}*})C1+$Sb;v~AdVDGizvCVD`4s1%jO7?J(8dv9i#KKjj@$K$ zKrzs&Web}$7`cInb9~8*+jJ#Dl9`y)KIDd7NBMYFKye<@mc^89T5l_u35 zm^+nEW$uvgqZMpeT;S^f@J#Xi&$*gkarS@YvVOr;{*r52;F^BLS^tUK_)G3+m^=Cl z&ihNQ{R5qe*L}bdaB|?GUvL#4=nT9L%YxTIv^DDuHIoFw= z$^VnWXYtX>OKpq1`vaYh-v)z{--czctBO1ObjxLCG7#1(&Fe9FL=-scE1 GX86CNS5rLz literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/__pycache__/compression_utils.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/__pycache__/compression_utils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0e6975064cdc58ddab1d460d25e063da4b4ea3c7 GIT binary patch literal 8991 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

P^^v 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 Du*v29 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/__pycache__/cookiejar.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/__pycache__/cookiejar.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b13b2e751f78ac6ef29dc3ee0efdb9375c9077d2 GIT binary patch literal 20509 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 MdHatju*nkme>UuO<^TWy literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/__pycache__/formdata.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/__pycache__/formdata.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..760ddb1bc404900815b5d33f81276d0c2721169c GIT binary patch literal 7762 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 Ld4Nc*f9C%I$Uo<) literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/__pycache__/hdrs.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/__pycache__/hdrs.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ffe0f673a40b04a5e4acf5e274c70ae62a6bd44d GIT binary patch literal 8519 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/__pycache__/http.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/__pycache__/http.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f9d1698f34e5937de1ef886ad50463da4f357369 GIT binary patch literal 1720 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 WLjF>jU|9|cf-j%`FN}6>tN#N8PB-5G literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/__pycache__/http_parser.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/__pycache__/http_parser.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6428b677fe93be5be83b67758cb36224dc9e289d GIT binary patch literal 35666 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 OO=ObtfkJNb-2VaU77D=t literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/__pycache__/http_writer.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/__pycache__/http_writer.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..93d9a7877398d64a01422aff63046f8abc913df4 GIT binary patch literal 10840 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/__pycache__/log.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/__pycache__/log.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..39d7accc3c34efe82c99c81edbbbabeefb085493 GIT binary patch literal 757 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 EznLuVIRF3v literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/__pycache__/pytest_plugin.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/__pycache__/pytest_plugin.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..10991ec87c7cc05f4feb515b262b680d71db1c3c GIT binary patch literal 18293 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/__pycache__/resolver.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/__pycache__/resolver.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6d39de637b456c40b50ee9704a4cb05891d58bfb GIT binary patch literal 7645 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/__pycache__/streams.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/__pycache__/streams.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..08c26b4dee5b56c41c374767700e75a043291884 GIT binary patch literal 30991 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 Fe*z`Zc#!}A literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/__pycache__/test_utils.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/__pycache__/test_utils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..185b5e4fcea0adb083935d3a7c17743f612da834 GIT binary patch literal 34840 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 VE=@Cg6NVMu?-?!kjj-7){$C#H7K8u* literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/__pycache__/tracing.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/__pycache__/tracing.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d892f27cce4304fd43d035447de0628eac4f5c7f GIT binary patch literal 22588 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/__pycache__/typedefs.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/__pycache__/typedefs.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..66c5886540c60b65cd967ad5753e4c1a6c049cba GIT binary patch literal 2309 zcmZWp%Wu?17$2|geR$tE&kclyJemzj7DACKf(kU*lF*QZgdA#wR?d2oEZFO1>?LeY zTZuz@sI;8OF~?N>3#wjv@5Me;S`7zM^-ysOf(nUKzp*zDQA_^K_s#d7`M&uh9+wb& zzy5S?vmQj~Z^j&bo&=cpnE*nskcKo)M~c643I}{Z4;Z|{8-gMjq9PhWC1`|{kP%kG zMns7ik|G&VCCV`yUXK}ZC2k~?gppK|MoLK;X(jE+1pSO5E3(m{baDuHDjgU-9y?0o zWL3Ih|MCfcL@B+PCqp=nGrh2-^x;ICI*XHS>KsnBseZ^s)Xy7PC2L$zEms+a|m!EOdONGNGMx2 z$pt9Cx;#(C`!!7Jz)9bz7M?cECuK~7_e^48{VfL-fGD(#pVqKt)5MBRuxc!0t7=v( zJh7cTF?tA2A8ki{%ZE_oBhm%tq#K|F|M3@UQ}2g?c!e-xL!$&VP77!}<~0Eens?#r zK`r<~P{evD7pBs^vZm>HOC^|wh@X!afQB~J3P=bI5^UE<#gEv&nB%C7e=m3u>nO)9 z{ETuu6`;s5DuJ8H-mj?y zt}8#ilD%?mGGDR)*G$_Q-ymkK`c?iJt~|@@<+XgZZf}~Es}oly^H$l$<5jivMBTvP zy=-pUb~SI;t60P9)Pq5bxxi6{k*fJ|LU|KW?b;7|BcF2U? zgr5q$uZXaoAYld(2JDR`Q2-h-SdVMa<0Qs5;|vlEk_=J+RH&;&Cuzo?VSKRY^)wZ= zno+fA$4ued+pF^rig#BQ7m9_2>BX7CG8J`G)jk)_6nr5My$t7fYN%-XH0RHeR6HIm znmnO>VT@hvM9G^ci^wdw4wf9hh1X67gNkc)8(TEO7L^dSP9*~yCaFIw<1HHc2DZ!A zCXKS(3zd?oL7#if4ECAWylGl^7ONn!sI;tZ9noPJ)UdV56 z#gRwcc+M3@4)aD}&${yPKJUnv-1t~SYDH5`xmjxV{CKkw zKIn!j_X_(1PX5;KnsS93 z@AyD(z(JjdL6m}|dRjs+WOoQd+5L_eycA+6DmUkvQ+p9-^tzj!a^xvjy3q)I2=d%$ bv*!bX89*-jX3EMH=6q)?2Yt)aa?|0 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/__pycache__/web.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/__pycache__/web.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..acfc3aade0d59bed7bba94cf93fd78e62cbfc3ef GIT binary patch literal 16595 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_exceptions.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_exceptions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2e7219533a2c2a89d10402573b4aa95eb272f685 GIT binary patch literal 15041 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_log.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_log.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..64bc7f7ead1db7a2cd87df1195b559c50b00e3b0 GIT binary patch literal 10713 zcmbU{ZA@HOcJIyi3^NSo+s42%Fu)KG1jlv~Y?5HW@dpM1IGc=P&pzh8fx+`Z-g_7` z9iBV44YOEZQ58>RpB~q*><(Et4g(6Rm!SAI0xbpT6HfQU8e#S~07gCm%y+jp8Vd zj!=H3rTsK{Huw#sHTsRDHTg}XHTx~l8Y0%H&2OU-#~86k9ezi tD1`khgi-xV$O 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_middlewares.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_middlewares.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2052b4ca6c212b8cbd74ae72e4d2b50b8e5ace88 GIT binary patch literal 5662 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_protocol.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_protocol.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b2e6d79b3d0bc0aae4d4994662ca267666acb15a GIT binary patch literal 31295 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_request.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_request.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b1f5bbd939aa77eac0aa05ee9a9c8eea6eb0605f GIT binary patch literal 38650 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 TQ=f_NYE6{3{Wk*-RG9x4HNr@m literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_runner.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_runner.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..191f5b3b423f00bca6304604b72c8137333fe583 GIT binary patch literal 19064 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_ws.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/__pycache__/web_ws.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bf0e903481d6a92cfcc920c037897cd58704bc95 GIT binary patch literal 31380 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

    }L^x|^VLZ=XAdxaKD^r*E?l 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≪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

    ChhEd*Tos3XqXi1p7UQ?W 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/_http_parser.pyx b/venv/lib/python3.12/site-packages/aiohttp/_http_parser.pyx new file mode 100644 index 00000000..19dc3e63 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/_http_parser.pyx @@ -0,0 +1,837 @@ +#cython: language_level=3 +# +# Based on https://github.com/MagicStack/httptools +# + +from cpython cimport ( + Py_buffer, + PyBUF_SIMPLE, + PyBuffer_Release, + PyBytes_AsString, + PyBytes_AsStringAndSize, + PyObject_GetBuffer, +) +from cpython.mem cimport PyMem_Free, PyMem_Malloc +from libc.limits cimport ULLONG_MAX +from libc.string cimport memcpy + +from multidict import CIMultiDict as _CIMultiDict, CIMultiDictProxy as _CIMultiDictProxy +from yarl import URL as _URL + +from aiohttp import hdrs +from aiohttp.helpers import DEBUG, set_exception + +from .http_exceptions import ( + BadHttpMessage, + BadHttpMethod, + BadStatusLine, + ContentLengthError, + InvalidHeader, + InvalidURLError, + LineTooLong, + PayloadEncodingError, + TransferEncodingError, +) +from .http_parser import DeflateBuffer as _DeflateBuffer +from .http_writer import ( + HttpVersion as _HttpVersion, + HttpVersion10 as _HttpVersion10, + HttpVersion11 as _HttpVersion11, +) +from .streams import EMPTY_PAYLOAD as _EMPTY_PAYLOAD, StreamReader as _StreamReader + +cimport cython + +from aiohttp cimport _cparser as cparser + +include "_headers.pxi" + +from aiohttp cimport _find_header + +ALLOWED_UPGRADES = frozenset({"websocket"}) +DEF DEFAULT_FREELIST_SIZE = 250 + +cdef extern from "Python.h": + int PyByteArray_Resize(object, Py_ssize_t) except -1 + Py_ssize_t PyByteArray_Size(object) except -1 + char* PyByteArray_AsString(object) + +__all__ = ('HttpRequestParser', 'HttpResponseParser', + 'RawRequestMessage', 'RawResponseMessage') + +cdef object URL = _URL +cdef object URL_build = URL.build +cdef object CIMultiDict = _CIMultiDict +cdef object CIMultiDictProxy = _CIMultiDictProxy +cdef object HttpVersion = _HttpVersion +cdef object HttpVersion10 = _HttpVersion10 +cdef object HttpVersion11 = _HttpVersion11 +cdef object SEC_WEBSOCKET_KEY1 = hdrs.SEC_WEBSOCKET_KEY1 +cdef object CONTENT_ENCODING = hdrs.CONTENT_ENCODING +cdef object EMPTY_PAYLOAD = _EMPTY_PAYLOAD +cdef object StreamReader = _StreamReader +cdef object DeflateBuffer = _DeflateBuffer +cdef bytes EMPTY_BYTES = b"" + +cdef inline object extend(object buf, const char* at, size_t length): + cdef Py_ssize_t s + cdef char* ptr + s = PyByteArray_Size(buf) + PyByteArray_Resize(buf, s + length) + ptr = PyByteArray_AsString(buf) + memcpy(ptr + s, at, length) + + +DEF METHODS_COUNT = 46; + +cdef list _http_method = [] + +for i in range(METHODS_COUNT): + _http_method.append( + cparser.llhttp_method_name( i).decode('ascii')) + + +cdef inline str http_method_str(int i): + if i < METHODS_COUNT: + return _http_method[i] + else: + return "" + +cdef inline object find_header(bytes raw_header): + cdef Py_ssize_t size + cdef char *buf + cdef int idx + PyBytes_AsStringAndSize(raw_header, &buf, &size) + idx = _find_header.find_header(buf, size) + if idx == -1: + return raw_header.decode('utf-8', 'surrogateescape') + return headers[idx] + + +@cython.freelist(DEFAULT_FREELIST_SIZE) +cdef class RawRequestMessage: + cdef readonly str method + cdef readonly str path + cdef readonly object version # HttpVersion + cdef readonly object headers # CIMultiDict + cdef readonly object raw_headers # tuple + cdef readonly object should_close + cdef readonly object compression + cdef readonly object upgrade + cdef readonly object chunked + cdef readonly object url # yarl.URL + + def __init__(self, method, path, version, headers, raw_headers, + should_close, compression, upgrade, chunked, url): + self.method = method + self.path = path + self.version = version + self.headers = headers + self.raw_headers = raw_headers + self.should_close = should_close + self.compression = compression + self.upgrade = upgrade + self.chunked = chunked + self.url = url + + def __repr__(self): + info = [] + info.append(("method", self.method)) + info.append(("path", self.path)) + info.append(("version", self.version)) + info.append(("headers", self.headers)) + info.append(("raw_headers", self.raw_headers)) + info.append(("should_close", self.should_close)) + info.append(("compression", self.compression)) + info.append(("upgrade", self.upgrade)) + info.append(("chunked", self.chunked)) + info.append(("url", self.url)) + sinfo = ', '.join(name + '=' + repr(val) for name, val in info) + return '' + + def _replace(self, **dct): + cdef RawRequestMessage ret + ret = _new_request_message(self.method, + self.path, + self.version, + self.headers, + self.raw_headers, + self.should_close, + self.compression, + self.upgrade, + self.chunked, + self.url) + if "method" in dct: + ret.method = dct["method"] + if "path" in dct: + ret.path = dct["path"] + if "version" in dct: + ret.version = dct["version"] + if "headers" in dct: + ret.headers = dct["headers"] + if "raw_headers" in dct: + ret.raw_headers = dct["raw_headers"] + if "should_close" in dct: + ret.should_close = dct["should_close"] + if "compression" in dct: + ret.compression = dct["compression"] + if "upgrade" in dct: + ret.upgrade = dct["upgrade"] + if "chunked" in dct: + ret.chunked = dct["chunked"] + if "url" in dct: + ret.url = dct["url"] + return ret + +cdef _new_request_message(str method, + str path, + object version, + object headers, + object raw_headers, + bint should_close, + object compression, + bint upgrade, + bint chunked, + object url): + cdef RawRequestMessage ret + ret = RawRequestMessage.__new__(RawRequestMessage) + ret.method = method + ret.path = path + ret.version = version + ret.headers = headers + ret.raw_headers = raw_headers + ret.should_close = should_close + ret.compression = compression + ret.upgrade = upgrade + ret.chunked = chunked + ret.url = url + return ret + + +@cython.freelist(DEFAULT_FREELIST_SIZE) +cdef class RawResponseMessage: + cdef readonly object version # HttpVersion + cdef readonly int code + cdef readonly str reason + cdef readonly object headers # CIMultiDict + cdef readonly object raw_headers # tuple + cdef readonly object should_close + cdef readonly object compression + cdef readonly object upgrade + cdef readonly object chunked + + def __init__(self, version, code, reason, headers, raw_headers, + should_close, compression, upgrade, chunked): + self.version = version + self.code = code + self.reason = reason + self.headers = headers + self.raw_headers = raw_headers + self.should_close = should_close + self.compression = compression + self.upgrade = upgrade + self.chunked = chunked + + def __repr__(self): + info = [] + info.append(("version", self.version)) + info.append(("code", self.code)) + info.append(("reason", self.reason)) + info.append(("headers", self.headers)) + info.append(("raw_headers", self.raw_headers)) + info.append(("should_close", self.should_close)) + info.append(("compression", self.compression)) + info.append(("upgrade", self.upgrade)) + info.append(("chunked", self.chunked)) + sinfo = ', '.join(name + '=' + repr(val) for name, val in info) + return '' + + +cdef _new_response_message(object version, + int code, + str reason, + object headers, + object raw_headers, + bint should_close, + object compression, + bint upgrade, + bint chunked): + cdef RawResponseMessage ret + ret = RawResponseMessage.__new__(RawResponseMessage) + ret.version = version + ret.code = code + ret.reason = reason + ret.headers = headers + ret.raw_headers = raw_headers + ret.should_close = should_close + ret.compression = compression + ret.upgrade = upgrade + ret.chunked = chunked + return ret + + +@cython.internal +cdef class HttpParser: + + cdef: + cparser.llhttp_t* _cparser + cparser.llhttp_settings_t* _csettings + + bytes _raw_name + object _name + bytes _raw_value + bint _has_value + + object _protocol + object _loop + object _timer + + size_t _max_line_size + size_t _max_field_size + size_t _max_headers + bint _response_with_body + bint _read_until_eof + + bint _started + object _url + bytearray _buf + str _path + str _reason + list _headers + list _raw_headers + bint _upgraded + list _messages + object _payload + bint _payload_error + object _payload_exception + object _last_error + bint _auto_decompress + int _limit + + str _content_encoding + + Py_buffer py_buf + + def __cinit__(self): + self._cparser = \ + PyMem_Malloc(sizeof(cparser.llhttp_t)) + if self._cparser is NULL: + raise MemoryError() + + self._csettings = \ + PyMem_Malloc(sizeof(cparser.llhttp_settings_t)) + if self._csettings is NULL: + raise MemoryError() + + def __dealloc__(self): + PyMem_Free(self._cparser) + PyMem_Free(self._csettings) + + cdef _init( + self, cparser.llhttp_type mode, + object protocol, object loop, int limit, + object timer=None, + size_t max_line_size=8190, size_t max_headers=32768, + size_t max_field_size=8190, payload_exception=None, + bint response_with_body=True, bint read_until_eof=False, + bint auto_decompress=True, + ): + cparser.llhttp_settings_init(self._csettings) + cparser.llhttp_init(self._cparser, mode, self._csettings) + self._cparser.data = self + self._cparser.content_length = 0 + + self._protocol = protocol + self._loop = loop + self._timer = timer + + self._buf = bytearray() + self._payload = None + self._payload_error = 0 + self._payload_exception = payload_exception + self._messages = [] + + self._raw_name = EMPTY_BYTES + self._raw_value = EMPTY_BYTES + self._has_value = False + + self._max_line_size = max_line_size + self._max_headers = max_headers + self._max_field_size = max_field_size + self._response_with_body = response_with_body + self._read_until_eof = read_until_eof + self._upgraded = False + self._auto_decompress = auto_decompress + self._content_encoding = None + + self._csettings.on_url = cb_on_url + self._csettings.on_status = cb_on_status + self._csettings.on_header_field = cb_on_header_field + self._csettings.on_header_value = cb_on_header_value + self._csettings.on_headers_complete = cb_on_headers_complete + self._csettings.on_body = cb_on_body + self._csettings.on_message_begin = cb_on_message_begin + self._csettings.on_message_complete = cb_on_message_complete + self._csettings.on_chunk_header = cb_on_chunk_header + self._csettings.on_chunk_complete = cb_on_chunk_complete + + self._last_error = None + self._limit = limit + + cdef _process_header(self): + cdef str value + if self._raw_name is not EMPTY_BYTES: + name = find_header(self._raw_name) + value = self._raw_value.decode('utf-8', 'surrogateescape') + + self._headers.append((name, value)) + + if name is CONTENT_ENCODING: + self._content_encoding = value + + self._has_value = False + self._raw_headers.append((self._raw_name, self._raw_value)) + self._raw_name = EMPTY_BYTES + self._raw_value = EMPTY_BYTES + + cdef _on_header_field(self, char* at, size_t length): + if self._has_value: + self._process_header() + + if self._raw_name is EMPTY_BYTES: + self._raw_name = at[:length] + else: + self._raw_name += at[:length] + + cdef _on_header_value(self, char* at, size_t length): + if self._raw_value is EMPTY_BYTES: + self._raw_value = at[:length] + else: + self._raw_value += at[:length] + self._has_value = True + + cdef _on_headers_complete(self): + self._process_header() + + should_close = not cparser.llhttp_should_keep_alive(self._cparser) + upgrade = self._cparser.upgrade + chunked = self._cparser.flags & cparser.F_CHUNKED + + raw_headers = tuple(self._raw_headers) + headers = CIMultiDictProxy(CIMultiDict(self._headers)) + + if self._cparser.type == cparser.HTTP_REQUEST: + allowed = upgrade and headers.get("upgrade", "").lower() in ALLOWED_UPGRADES + if allowed or self._cparser.method == cparser.HTTP_CONNECT: + self._upgraded = True + else: + if upgrade and self._cparser.status_code == 101: + self._upgraded = True + + # do not support old websocket spec + if SEC_WEBSOCKET_KEY1 in headers: + raise InvalidHeader(SEC_WEBSOCKET_KEY1) + + encoding = None + enc = self._content_encoding + if enc is not None: + self._content_encoding = None + enc = enc.lower() + if enc in ('gzip', 'deflate', 'br'): + encoding = enc + + if self._cparser.type == cparser.HTTP_REQUEST: + method = http_method_str(self._cparser.method) + msg = _new_request_message( + method, self._path, + self.http_version(), headers, raw_headers, + should_close, encoding, upgrade, chunked, self._url) + else: + msg = _new_response_message( + self.http_version(), self._cparser.status_code, self._reason, + headers, raw_headers, should_close, encoding, + upgrade, chunked) + + if ( + ULLONG_MAX > self._cparser.content_length > 0 or chunked or + self._cparser.method == cparser.HTTP_CONNECT or + (self._cparser.status_code >= 199 and + self._cparser.content_length == 0 and + self._read_until_eof) + ): + payload = StreamReader( + self._protocol, timer=self._timer, loop=self._loop, + limit=self._limit) + else: + payload = EMPTY_PAYLOAD + + self._payload = payload + if encoding is not None and self._auto_decompress: + self._payload = DeflateBuffer(payload, encoding) + + if not self._response_with_body: + payload = EMPTY_PAYLOAD + + self._messages.append((msg, payload)) + + cdef _on_message_complete(self): + self._payload.feed_eof() + self._payload = None + + cdef _on_chunk_header(self): + self._payload.begin_http_chunk_receiving() + + cdef _on_chunk_complete(self): + self._payload.end_http_chunk_receiving() + + cdef object _on_status_complete(self): + pass + + cdef inline http_version(self): + cdef cparser.llhttp_t* parser = self._cparser + + if parser.http_major == 1: + if parser.http_minor == 0: + return HttpVersion10 + elif parser.http_minor == 1: + return HttpVersion11 + + return HttpVersion(parser.http_major, parser.http_minor) + + ### Public API ### + + def feed_eof(self): + cdef bytes desc + + if self._payload is not None: + if self._cparser.flags & cparser.F_CHUNKED: + raise TransferEncodingError( + "Not enough data for satisfy transfer length header.") + elif self._cparser.flags & cparser.F_CONTENT_LENGTH: + raise ContentLengthError( + "Not enough data for satisfy content length header.") + elif cparser.llhttp_get_errno(self._cparser) != cparser.HPE_OK: + desc = cparser.llhttp_get_error_reason(self._cparser) + raise PayloadEncodingError(desc.decode('latin-1')) + else: + self._payload.feed_eof() + elif self._started: + self._on_headers_complete() + if self._messages: + return self._messages[-1][0] + + def feed_data(self, data): + cdef: + size_t data_len + size_t nb + cdef cparser.llhttp_errno_t errno + + PyObject_GetBuffer(data, &self.py_buf, PyBUF_SIMPLE) + data_len = self.py_buf.len + + errno = cparser.llhttp_execute( + self._cparser, + self.py_buf.buf, + data_len) + + if errno is cparser.HPE_PAUSED_UPGRADE: + cparser.llhttp_resume_after_upgrade(self._cparser) + + nb = cparser.llhttp_get_error_pos(self._cparser) - self.py_buf.buf + + PyBuffer_Release(&self.py_buf) + + if errno not in (cparser.HPE_OK, cparser.HPE_PAUSED_UPGRADE): + if self._payload_error == 0: + if self._last_error is not None: + ex = self._last_error + self._last_error = None + else: + after = cparser.llhttp_get_error_pos(self._cparser) + before = data[:after - self.py_buf.buf] + after_b = after.split(b"\r\n", 1)[0] + before = before.rsplit(b"\r\n", 1)[-1] + data = before + after_b + pointer = " " * (len(repr(before))-1) + "^" + ex = parser_error_from_errno(self._cparser, data, pointer) + self._payload = None + raise ex + + if self._messages: + messages = self._messages + self._messages = [] + else: + messages = () + + if self._upgraded: + return messages, True, data[nb:] + else: + return messages, False, b"" + + def set_upgraded(self, val): + self._upgraded = val + + +cdef class HttpRequestParser(HttpParser): + + def __init__( + self, protocol, loop, int limit, timer=None, + size_t max_line_size=8190, size_t max_headers=32768, + size_t max_field_size=8190, payload_exception=None, + bint response_with_body=True, bint read_until_eof=False, + bint auto_decompress=True, + ): + self._init(cparser.HTTP_REQUEST, protocol, loop, limit, timer, + max_line_size, max_headers, max_field_size, + payload_exception, response_with_body, read_until_eof, + auto_decompress) + + cdef object _on_status_complete(self): + cdef int idx1, idx2 + if not self._buf: + return + self._path = self._buf.decode('utf-8', 'surrogateescape') + try: + idx3 = len(self._path) + if self._cparser.method == cparser.HTTP_CONNECT: + # authority-form, + # https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.3 + self._url = URL.build(authority=self._path, encoded=True) + elif idx3 > 1 and self._path[0] == '/': + # origin-form, + # https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.1 + idx1 = self._path.find("?") + if idx1 == -1: + query = "" + idx2 = self._path.find("#") + if idx2 == -1: + path = self._path + fragment = "" + else: + path = self._path[0: idx2] + fragment = self._path[idx2+1:] + + else: + path = self._path[0:idx1] + idx1 += 1 + idx2 = self._path.find("#", idx1+1) + if idx2 == -1: + query = self._path[idx1:] + fragment = "" + else: + query = self._path[idx1: idx2] + fragment = self._path[idx2+1:] + + self._url = URL.build( + path=path, + query_string=query, + fragment=fragment, + encoded=True, + ) + else: + # absolute-form for proxy maybe, + # https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.2 + self._url = URL(self._path, encoded=True) + finally: + PyByteArray_Resize(self._buf, 0) + + +cdef class HttpResponseParser(HttpParser): + + def __init__( + self, protocol, loop, int limit, timer=None, + size_t max_line_size=8190, size_t max_headers=32768, + size_t max_field_size=8190, payload_exception=None, + bint response_with_body=True, bint read_until_eof=False, + bint auto_decompress=True + ): + self._init(cparser.HTTP_RESPONSE, protocol, loop, limit, timer, + max_line_size, max_headers, max_field_size, + payload_exception, response_with_body, read_until_eof, + auto_decompress) + # Use strict parsing on dev mode, so users are warned about broken servers. + if not DEBUG: + cparser.llhttp_set_lenient_headers(self._cparser, 1) + cparser.llhttp_set_lenient_optional_cr_before_lf(self._cparser, 1) + cparser.llhttp_set_lenient_spaces_after_chunk_size(self._cparser, 1) + + cdef object _on_status_complete(self): + if self._buf: + self._reason = self._buf.decode('utf-8', 'surrogateescape') + PyByteArray_Resize(self._buf, 0) + else: + self._reason = self._reason or '' + +cdef int cb_on_message_begin(cparser.llhttp_t* parser) except -1: + cdef HttpParser pyparser = parser.data + + pyparser._started = True + pyparser._headers = [] + pyparser._raw_headers = [] + PyByteArray_Resize(pyparser._buf, 0) + pyparser._path = None + pyparser._reason = None + return 0 + + +cdef int cb_on_url(cparser.llhttp_t* parser, + const char *at, size_t length) except -1: + cdef HttpParser pyparser = parser.data + try: + if length > pyparser._max_line_size: + raise LineTooLong( + 'Status line is too long', pyparser._max_line_size, length) + extend(pyparser._buf, at, length) + except BaseException as ex: + pyparser._last_error = ex + return -1 + else: + return 0 + + +cdef int cb_on_status(cparser.llhttp_t* parser, + const char *at, size_t length) except -1: + cdef HttpParser pyparser = parser.data + cdef str reason + try: + if length > pyparser._max_line_size: + raise LineTooLong( + 'Status line is too long', pyparser._max_line_size, length) + extend(pyparser._buf, at, length) + except BaseException as ex: + pyparser._last_error = ex + return -1 + else: + return 0 + + +cdef int cb_on_header_field(cparser.llhttp_t* parser, + const char *at, size_t length) except -1: + cdef HttpParser pyparser = parser.data + cdef Py_ssize_t size + try: + pyparser._on_status_complete() + size = len(pyparser._raw_name) + length + if size > pyparser._max_field_size: + raise LineTooLong( + 'Header name is too long', pyparser._max_field_size, size) + pyparser._on_header_field(at, length) + except BaseException as ex: + pyparser._last_error = ex + return -1 + else: + return 0 + + +cdef int cb_on_header_value(cparser.llhttp_t* parser, + const char *at, size_t length) except -1: + cdef HttpParser pyparser = parser.data + cdef Py_ssize_t size + try: + size = len(pyparser._raw_value) + length + if size > pyparser._max_field_size: + raise LineTooLong( + 'Header value is too long', pyparser._max_field_size, size) + pyparser._on_header_value(at, length) + except BaseException as ex: + pyparser._last_error = ex + return -1 + else: + return 0 + + +cdef int cb_on_headers_complete(cparser.llhttp_t* parser) except -1: + cdef HttpParser pyparser = parser.data + try: + pyparser._on_status_complete() + pyparser._on_headers_complete() + except BaseException as exc: + pyparser._last_error = exc + return -1 + else: + if pyparser._upgraded or pyparser._cparser.method == cparser.HTTP_CONNECT: + return 2 + else: + return 0 + + +cdef int cb_on_body(cparser.llhttp_t* parser, + const char *at, size_t length) except -1: + cdef HttpParser pyparser = parser.data + cdef bytes body = at[:length] + try: + pyparser._payload.feed_data(body, length) + except BaseException as underlying_exc: + reraised_exc = underlying_exc + if pyparser._payload_exception is not None: + reraised_exc = pyparser._payload_exception(str(underlying_exc)) + + set_exception(pyparser._payload, reraised_exc, underlying_exc) + + pyparser._payload_error = 1 + return -1 + else: + return 0 + + +cdef int cb_on_message_complete(cparser.llhttp_t* parser) except -1: + cdef HttpParser pyparser = parser.data + try: + pyparser._started = False + pyparser._on_message_complete() + except BaseException as exc: + pyparser._last_error = exc + return -1 + else: + return 0 + + +cdef int cb_on_chunk_header(cparser.llhttp_t* parser) except -1: + cdef HttpParser pyparser = parser.data + try: + pyparser._on_chunk_header() + except BaseException as exc: + pyparser._last_error = exc + return -1 + else: + return 0 + + +cdef int cb_on_chunk_complete(cparser.llhttp_t* parser) except -1: + cdef HttpParser pyparser = parser.data + try: + pyparser._on_chunk_complete() + except BaseException as exc: + pyparser._last_error = exc + return -1 + else: + return 0 + + +cdef parser_error_from_errno(cparser.llhttp_t* parser, data, pointer): + cdef cparser.llhttp_errno_t errno = cparser.llhttp_get_errno(parser) + cdef bytes desc = cparser.llhttp_get_error_reason(parser) + + err_msg = "{}:\n\n {!r}\n {}".format(desc.decode("latin-1"), data, pointer) + + if errno in {cparser.HPE_CB_MESSAGE_BEGIN, + cparser.HPE_CB_HEADERS_COMPLETE, + cparser.HPE_CB_MESSAGE_COMPLETE, + cparser.HPE_CB_CHUNK_HEADER, + cparser.HPE_CB_CHUNK_COMPLETE, + cparser.HPE_INVALID_CONSTANT, + cparser.HPE_INVALID_HEADER_TOKEN, + cparser.HPE_INVALID_CONTENT_LENGTH, + cparser.HPE_INVALID_CHUNK_SIZE, + cparser.HPE_INVALID_EOF_STATE, + cparser.HPE_INVALID_TRANSFER_ENCODING}: + return BadHttpMessage(err_msg) + elif errno == cparser.HPE_INVALID_METHOD: + return BadHttpMethod(error=err_msg) + elif errno in {cparser.HPE_INVALID_STATUS, + cparser.HPE_INVALID_VERSION}: + return BadStatusLine(error=err_msg) + elif errno == cparser.HPE_INVALID_URL: + return InvalidURLError(err_msg) + + return BadHttpMessage(err_msg) diff --git a/venv/lib/python3.12/site-packages/aiohttp/_http_writer.cpython-312-darwin.so b/venv/lib/python3.12/site-packages/aiohttp/_http_writer.cpython-312-darwin.so new file mode 100755 index 0000000000000000000000000000000000000000..bed1828c97ab47e741bcc72606ed70cf199d786a GIT binary patch literal 99216 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

    {TisF4`&-FNdT(KWZ7o4r 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/_http_writer.pyx b/venv/lib/python3.12/site-packages/aiohttp/_http_writer.pyx new file mode 100644 index 00000000..4a3ae1f9 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/_http_writer.pyx @@ -0,0 +1,160 @@ +from cpython.bytes cimport PyBytes_FromStringAndSize +from cpython.exc cimport PyErr_NoMemory +from cpython.mem cimport PyMem_Free, PyMem_Malloc, PyMem_Realloc +from cpython.object cimport PyObject_Str +from libc.stdint cimport uint8_t, uint64_t +from libc.string cimport memcpy + +from multidict import istr + +DEF BUF_SIZE = 16 * 1024 # 16KiB +cdef char BUFFER[BUF_SIZE] + +cdef object _istr = istr + + +# ----------------- writer --------------------------- + +cdef struct Writer: + char *buf + Py_ssize_t size + Py_ssize_t pos + + +cdef inline void _init_writer(Writer* writer): + writer.buf = &BUFFER[0] + writer.size = BUF_SIZE + writer.pos = 0 + + +cdef inline void _release_writer(Writer* writer): + if writer.buf != BUFFER: + PyMem_Free(writer.buf) + + +cdef inline int _write_byte(Writer* writer, uint8_t ch): + cdef char * buf + cdef Py_ssize_t size + + if writer.pos == writer.size: + # reallocate + size = writer.size + BUF_SIZE + if writer.buf == BUFFER: + buf = PyMem_Malloc(size) + if buf == NULL: + PyErr_NoMemory() + return -1 + memcpy(buf, writer.buf, writer.size) + else: + buf = PyMem_Realloc(writer.buf, size) + if buf == NULL: + PyErr_NoMemory() + return -1 + writer.buf = buf + writer.size = size + writer.buf[writer.pos] = ch + writer.pos += 1 + return 0 + + +cdef inline int _write_utf8(Writer* writer, Py_UCS4 symbol): + cdef uint64_t utf = symbol + + if utf < 0x80: + return _write_byte(writer, utf) + elif utf < 0x800: + if _write_byte(writer, (0xc0 | (utf >> 6))) < 0: + return -1 + return _write_byte(writer, (0x80 | (utf & 0x3f))) + elif 0xD800 <= utf <= 0xDFFF: + # surogate pair, ignored + return 0 + elif utf < 0x10000: + if _write_byte(writer, (0xe0 | (utf >> 12))) < 0: + return -1 + if _write_byte(writer, (0x80 | ((utf >> 6) & 0x3f))) < 0: + return -1 + return _write_byte(writer, (0x80 | (utf & 0x3f))) + elif utf > 0x10FFFF: + # symbol is too large + return 0 + else: + if _write_byte(writer, (0xf0 | (utf >> 18))) < 0: + return -1 + if _write_byte(writer, + (0x80 | ((utf >> 12) & 0x3f))) < 0: + return -1 + if _write_byte(writer, + (0x80 | ((utf >> 6) & 0x3f))) < 0: + return -1 + return _write_byte(writer, (0x80 | (utf & 0x3f))) + + +cdef inline int _write_str(Writer* writer, str s): + cdef Py_UCS4 ch + for ch in s: + if _write_utf8(writer, ch) < 0: + return -1 + + +cdef inline int _write_str_raise_on_nlcr(Writer* writer, object s): + cdef Py_UCS4 ch + cdef str out_str + if type(s) is str: + out_str = s + elif type(s) is _istr: + out_str = PyObject_Str(s) + elif not isinstance(s, str): + raise TypeError("Cannot serialize non-str key {!r}".format(s)) + else: + out_str = str(s) + + for ch in out_str: + if ch == 0x0D or ch == 0x0A: + raise ValueError( + "Newline or carriage return detected in headers. " + "Potential header injection attack." + ) + if _write_utf8(writer, ch) < 0: + return -1 + + +# --------------- _serialize_headers ---------------------- + +def _serialize_headers(str status_line, headers): + cdef Writer writer + cdef object key + cdef object val + + _init_writer(&writer) + + try: + if _write_str(&writer, status_line) < 0: + raise + if _write_byte(&writer, b'\r') < 0: + raise + if _write_byte(&writer, b'\n') < 0: + raise + + for key, val in headers.items(): + if _write_str_raise_on_nlcr(&writer, key) < 0: + raise + if _write_byte(&writer, b':') < 0: + raise + if _write_byte(&writer, b' ') < 0: + raise + if _write_str_raise_on_nlcr(&writer, val) < 0: + raise + if _write_byte(&writer, b'\r') < 0: + raise + if _write_byte(&writer, b'\n') < 0: + raise + + if _write_byte(&writer, b'\r') < 0: + raise + if _write_byte(&writer, b'\n') < 0: + raise + + return PyBytes_FromStringAndSize(writer.buf, writer.pos) + finally: + _release_writer(&writer) diff --git a/venv/lib/python3.12/site-packages/aiohttp/_websocket/.hash/mask.pxd.hash b/venv/lib/python3.12/site-packages/aiohttp/_websocket/.hash/mask.pxd.hash new file mode 100644 index 00000000..d1cf0be2 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/_websocket/.hash/mask.pxd.hash @@ -0,0 +1 @@ +b01999d409b29bd916e067bc963d5f2d9ee63cfc9ae0bccb769910131417bf93 \ No newline at end of file diff --git a/venv/lib/python3.12/site-packages/aiohttp/_websocket/.hash/mask.pyx.hash b/venv/lib/python3.12/site-packages/aiohttp/_websocket/.hash/mask.pyx.hash new file mode 100644 index 00000000..2262da15 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/_websocket/.hash/mask.pyx.hash @@ -0,0 +1 @@ +0478ceb55d0ed30ef1a7da742cd003449bc69a07cf9fdb06789bd2b347cbfffe \ No newline at end of file diff --git a/venv/lib/python3.12/site-packages/aiohttp/_websocket/.hash/reader_c.pxd.hash b/venv/lib/python3.12/site-packages/aiohttp/_websocket/.hash/reader_c.pxd.hash new file mode 100644 index 00000000..d341fc54 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/_websocket/.hash/reader_c.pxd.hash @@ -0,0 +1 @@ +9e5fe78ed0ebce5414d2b8e01868d90c1facc20b84d2d5ff6c23e86e44a155ae \ No newline at end of file diff --git a/venv/lib/python3.12/site-packages/aiohttp/_websocket/__init__.py b/venv/lib/python3.12/site-packages/aiohttp/_websocket/__init__.py new file mode 100644 index 00000000..836257cc --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/_websocket/__init__.py @@ -0,0 +1 @@ +"""WebSocket protocol versions 13 and 8.""" diff --git a/venv/lib/python3.12/site-packages/aiohttp/_websocket/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/_websocket/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2baf98cb562981b480b7faca70e565999a45b67d GIT binary patch literal 280 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 a`<+|`C;1=8jGlV*%X)*Sh5cnShVqZ`5Vl4D literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/_websocket/__pycache__/models.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/_websocket/__pycache__/models.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..78b494a523ed02f23a20859d8f6a64668f1b03bf GIT binary patch literal 3490 zcmb7GU2I!P6`pI~YhT;(PvZQvh22`arNtGs`?shpyQPlfX5Bj1S=(tgS1ebK?<8^R z*k#dG2P3=RH^f!6UV@)fY5qC>)odf3at;cJyhKr8=}4QUunDE1_ zs(Ve3?lZl5kLlC>W{(~){d%wwhz7ZDGM}u}ESdx(l>Y?YE^i_H8R0Joe?|Bk!ZyOE z2%jPBAnYPML-;#@77cOLFsg8B!{A=SSg4tc6_k4ny~@3#SvZ@Km`qIZ zz<4fO$R@KHBbCc#b38Pm$d+K%%^hK(#e#OOXUlRT!9A*Fg`JwNNWZgC#;ZP(+*O*(A}md3%pK;2lq z!Thif0Z1cj6kwUOJpSfzt9PJzr8RK4skMf_v?2F*Fg(=Ebi~0U&1~z)%Nz1gdzfeo z=o`Fql^yM_TmoUQ?D23MRR13jsSGhk(f!n=2dG;QQdJL8kKRkYdLQ-a;f6Qr+%^F;;gHHi#fJzB35O-sR zT9;^>T%nBB7<(CaB8(V8>6I=V0l}IASSC-ygWwHcpgGd=hnkn$l4$k>o2hLV3HCQf zTmC-i>gjE!p8A3~GK?cp5`Z18zyOZJj-K8-srFy-hcCEJ0R@(wIe_P`n;_IlWmCcw zKoyW2LUK{JNDdHML|dKj!^tleQ~t4JD%4ArS&1q$4xC}SK$1=OGK8Uq8ubX5Qp*A^ zbJ+&Ra@j1}MKIGXn-w9PDwSH%wAi;`E_X3%FS2S0-Hruo2r%N?!5p#*Y3jCgo6LiJ zuyj*fo|S?NVsFAP zq7E)wv@#<$Xdx9N5f*`p%kx&Px)cD$wvQLX_66v%!T?S3sh5NXRtl?A_op_4M>o`? z!ZBLZcYvyb8$4(j#cH)?7cpH}hQVZ5gdx|t)3O;$ViS$T(2)n}^-a_voQ2Oq;d`Xz z4ZoLt>h-^uZu!D1$$M{Z%7>nwzwnDIKfm%BQIyEqJL}dueUM+DfBe#!ZPYwEw~JMq zK)A>Y1loIzAR)fLk3#J%1k`a-$U>$v`B-6Fr0~tw1VgMav-F=tbl5`c^qw>IB z%1z;IS^7^YSh$Ww#C3{6`h=jz-3x77vrDiCt%Tg@7PJ?(cg_R+NLm#B+>xZXi+D73&wE8T7(FMNv&Kh+lB#Ydl>YhlcjNl$1qBjq6Ln! z@W()@reFojKx=8}#pA`g>s*CS3vbEiP15Q=bXWd?=VR4>&;3|EwAR0N^S9~=Vf#J) z!$^Ye7Ux24f_`HZ9Rg1#B*{G5iT`>QdXbnBN!zI?4JPz~{^4ck;ruKRf>nTidFnoLCG0gFw}$HBK+Vw^zFM+`+W*JT4-s;i2f{p~?JPkm0Sl z;&s|4>#KVvdH!CU>kjGgRRhYrn334qu>Qe&JApccJbV_qdKr9js=ZazM~}4UB|+vg zg=Z&2GH@4!Qph^(C?O&OUQgymz@Q;q%$4beO)cg_#R!6UFT8>hUT?10;*knosnVMe zb55hO7apVSBxrOVQ!I}9zK$N>Z=DYAN!=<@@xm2;5l1<2#xK-2+V8=O>^rawn%nvb zz_wG8Bu>8m3Gw}&9Qp%EJ|W3J9*h3w%pHZ9(t5 z_upOr#)HO__@&43OOKBIO5TW#Z4PJ~q;J=yN+(vPb_rCwgOU_mX*?rP2{-%;E7m_~ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/_websocket/__pycache__/reader.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/_websocket/__pycache__/reader.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7a55214228b368106b4ed7461fa95f19d61bf0e2 GIT binary patch literal 776 zcmZ`$J8aWX6n*~0c77O;2vAhXQduIAyrxyF4hRW_2m&H$aS@FrWI6UDv1*EaFMg%2`p8wHzKr9ZybFKr1Oj$Zwe}oJR5#<>s$`jO8 zv3ZC>#V0t#CU%qoB7u#)K&fpihG!`|)p2@AnMsQKo!y3Bzt^ZgXtwT-*#+8a>y3l` zMoVqBTk4oeQ8u}_biQMR#$JRXl*mhLo}g7emx#Jk*FX6S0pRpXMN$ zbjp%hVBL?2n9f(0K1=W2IP7DONGW}3Nzd2JxkOsHnE%q(XZkbJ1)OiXJ|OzJcu%pqzlU@7(#f4}Y;-MwsNlBqpP)JzBJ+G%r=FyISOA} re literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/_websocket/__pycache__/reader_c.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/_websocket/__pycache__/reader_c.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..261fda6066cc1958f113f943d99c85aa57ff14a7 GIT binary patch literal 17639 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/_websocket/__pycache__/writer.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiohttp/_websocket/__pycache__/writer.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2f3012cb64d7aac658489defcd8218215c39d9e1 GIT binary patch literal 6390 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 List[bytes]: + return [bytes(a ^ b for a in range(256)) for b in range(256)] + + +def _websocket_mask_python(mask: bytes, data: bytearray) -> None: + """Websocket masking function. + + `mask` is a `bytes` object of length 4; `data` is a `bytearray` + object of any length. The contents of `data` are masked with `mask`, + as specified in section 5.3 of RFC 6455. + + Note that this function mutates the `data` argument. + + This pure-python implementation may be replaced by an optimized + version when available. + + """ + assert isinstance(data, bytearray), data + assert len(mask) == 4, mask + + if data: + _XOR_TABLE = _xor_table() + a, b, c, d = (_XOR_TABLE[n] for n in mask) + data[::4] = data[::4].translate(a) + data[1::4] = data[1::4].translate(b) + data[2::4] = data[2::4].translate(c) + data[3::4] = data[3::4].translate(d) + + +if TYPE_CHECKING or NO_EXTENSIONS: # pragma: no cover + websocket_mask = _websocket_mask_python +else: + try: + from .mask import _websocket_mask_cython # type: ignore[import-not-found] + + websocket_mask = _websocket_mask_cython + except ImportError: # pragma: no cover + websocket_mask = _websocket_mask_python + + +_WS_EXT_RE: Final[Pattern[str]] = re.compile( + r"^(?:;\s*(?:" + r"(server_no_context_takeover)|" + r"(client_no_context_takeover)|" + r"(server_max_window_bits(?:=(\d+))?)|" + r"(client_max_window_bits(?:=(\d+))?)))*$" +) + +_WS_EXT_RE_SPLIT: Final[Pattern[str]] = re.compile(r"permessage-deflate([^,]+)?") + + +def ws_ext_parse(extstr: Optional[str], isserver: bool = False) -> Tuple[int, bool]: + if not extstr: + return 0, False + + compress = 0 + notakeover = False + for ext in _WS_EXT_RE_SPLIT.finditer(extstr): + defext = ext.group(1) + # Return compress = 15 when get `permessage-deflate` + if not defext: + compress = 15 + break + match = _WS_EXT_RE.match(defext) + if match: + compress = 15 + if isserver: + # Server never fail to detect compress handshake. + # Server does not need to send max wbit to client + if match.group(4): + compress = int(match.group(4)) + # Group3 must match if group4 matches + # Compress wbit 8 does not support in zlib + # If compress level not support, + # CONTINUE to next extension + if compress > 15 or compress < 9: + compress = 0 + continue + if match.group(1): + notakeover = True + # Ignore regex group 5 & 6 for client_max_window_bits + break + else: + if match.group(6): + compress = int(match.group(6)) + # Group5 must match if group6 matches + # Compress wbit 8 does not support in zlib + # If compress level not support, + # FAIL the parse progress + if compress > 15 or compress < 9: + raise WSHandshakeError("Invalid window size") + if match.group(2): + notakeover = True + # Ignore regex group 5 & 6 for client_max_window_bits + break + # Return Fail if client side and not match + elif not isserver: + raise WSHandshakeError("Extension for deflate not supported" + ext.group(1)) + + return compress, notakeover + + +def ws_ext_gen( + compress: int = 15, isserver: bool = False, server_notakeover: bool = False +) -> str: + # client_notakeover=False not used for server + # compress wbit 8 does not support in zlib + if compress < 9 or compress > 15: + raise ValueError( + "Compress wbits must between 9 and 15, zlib does not support wbits=8" + ) + enabledext = ["permessage-deflate"] + if not isserver: + enabledext.append("client_max_window_bits") + + if compress < 15: + enabledext.append("server_max_window_bits=" + str(compress)) + if server_notakeover: + enabledext.append("server_no_context_takeover") + # if client_notakeover: + # enabledext.append('client_no_context_takeover') + return "; ".join(enabledext) diff --git a/venv/lib/python3.12/site-packages/aiohttp/_websocket/mask.cpython-312-darwin.so b/venv/lib/python3.12/site-packages/aiohttp/_websocket/mask.cpython-312-darwin.so new file mode 100755 index 0000000000000000000000000000000000000000..8c7d236d0419cb6681de337d894bbbad41728f9e GIT binary patch literal 79832 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 S=*HLXxNp>|z`Of@#r_`xxH|y= literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/_websocket/mask.pxd b/venv/lib/python3.12/site-packages/aiohttp/_websocket/mask.pxd new file mode 100644 index 00000000..90983de9 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/_websocket/mask.pxd @@ -0,0 +1,3 @@ +"""Cython declarations for websocket masking.""" + +cpdef void _websocket_mask_cython(bytes mask, bytearray data) diff --git a/venv/lib/python3.12/site-packages/aiohttp/_websocket/mask.pyx b/venv/lib/python3.12/site-packages/aiohttp/_websocket/mask.pyx new file mode 100644 index 00000000..2d956c88 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/_websocket/mask.pyx @@ -0,0 +1,48 @@ +from cpython cimport PyBytes_AsString + + +#from cpython cimport PyByteArray_AsString # cython still not exports that +cdef extern from "Python.h": + char* PyByteArray_AsString(bytearray ba) except NULL + +from libc.stdint cimport uint32_t, uint64_t, uintmax_t + + +cpdef void _websocket_mask_cython(bytes mask, bytearray data): + """Note, this function mutates its `data` argument + """ + cdef: + Py_ssize_t data_len, i + # bit operations on signed integers are implementation-specific + unsigned char * in_buf + const unsigned char * mask_buf + uint32_t uint32_msk + uint64_t uint64_msk + + assert len(mask) == 4 + + data_len = len(data) + in_buf = PyByteArray_AsString(data) + mask_buf = PyBytes_AsString(mask) + uint32_msk = (mask_buf)[0] + + # TODO: align in_data ptr to achieve even faster speeds + # does it need in python ?! malloc() always aligns to sizeof(long) bytes + + if sizeof(size_t) >= 8: + uint64_msk = uint32_msk + uint64_msk = (uint64_msk << 32) | uint32_msk + + while data_len >= 8: + (in_buf)[0] ^= uint64_msk + in_buf += 8 + data_len -= 8 + + + while data_len >= 4: + (in_buf)[0] ^= uint32_msk + in_buf += 4 + data_len -= 4 + + for i in range(0, data_len): + in_buf[i] ^= mask_buf[i] diff --git a/venv/lib/python3.12/site-packages/aiohttp/_websocket/models.py b/venv/lib/python3.12/site-packages/aiohttp/_websocket/models.py new file mode 100644 index 00000000..7e89b965 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/_websocket/models.py @@ -0,0 +1,84 @@ +"""Models for WebSocket protocol versions 13 and 8.""" + +import json +from enum import IntEnum +from typing import Any, Callable, Final, NamedTuple, Optional, cast + +WS_DEFLATE_TRAILING: Final[bytes] = bytes([0x00, 0x00, 0xFF, 0xFF]) + + +class WSCloseCode(IntEnum): + OK = 1000 + GOING_AWAY = 1001 + PROTOCOL_ERROR = 1002 + UNSUPPORTED_DATA = 1003 + ABNORMAL_CLOSURE = 1006 + INVALID_TEXT = 1007 + POLICY_VIOLATION = 1008 + MESSAGE_TOO_BIG = 1009 + MANDATORY_EXTENSION = 1010 + INTERNAL_ERROR = 1011 + SERVICE_RESTART = 1012 + TRY_AGAIN_LATER = 1013 + BAD_GATEWAY = 1014 + + +class WSMsgType(IntEnum): + # websocket spec types + CONTINUATION = 0x0 + TEXT = 0x1 + BINARY = 0x2 + PING = 0x9 + PONG = 0xA + CLOSE = 0x8 + + # aiohttp specific types + CLOSING = 0x100 + CLOSED = 0x101 + ERROR = 0x102 + + text = TEXT + binary = BINARY + ping = PING + pong = PONG + close = CLOSE + closing = CLOSING + closed = CLOSED + error = ERROR + + +class WSMessage(NamedTuple): + type: WSMsgType + # To type correctly, this would need some kind of tagged union for each type. + data: Any + extra: Optional[str] + + def json(self, *, loads: Callable[[Any], Any] = json.loads) -> Any: + """Return parsed JSON data. + + .. versionadded:: 0.22 + """ + return loads(self.data) + + +# Constructing the tuple directly to avoid the overhead of +# the lambda and arg processing since NamedTuples are constructed +# with a run time built lambda +# https://github.com/python/cpython/blob/d83fcf8371f2f33c7797bc8f5423a8bca8c46e5c/Lib/collections/__init__.py#L441 +WS_CLOSED_MESSAGE = tuple.__new__(WSMessage, (WSMsgType.CLOSED, None, None)) +WS_CLOSING_MESSAGE = tuple.__new__(WSMessage, (WSMsgType.CLOSING, None, None)) + + +class WebSocketError(Exception): + """WebSocket protocol parser error.""" + + def __init__(self, code: int, message: str) -> None: + self.code = code + super().__init__(code, message) + + def __str__(self) -> str: + return cast(str, self.args[1]) + + +class WSHandshakeError(Exception): + """WebSocket protocol handshake error.""" diff --git a/venv/lib/python3.12/site-packages/aiohttp/_websocket/reader.py b/venv/lib/python3.12/site-packages/aiohttp/_websocket/reader.py new file mode 100644 index 00000000..23f32265 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/_websocket/reader.py @@ -0,0 +1,31 @@ +"""Reader for WebSocket protocol versions 13 and 8.""" + +from typing import TYPE_CHECKING + +from ..helpers import NO_EXTENSIONS + +if TYPE_CHECKING or NO_EXTENSIONS: # pragma: no cover + from .reader_py import ( + WebSocketDataQueue as WebSocketDataQueuePython, + WebSocketReader as WebSocketReaderPython, + ) + + WebSocketReader = WebSocketReaderPython + WebSocketDataQueue = WebSocketDataQueuePython +else: + try: + from .reader_c import ( # type: ignore[import-not-found] + WebSocketDataQueue as WebSocketDataQueueCython, + WebSocketReader as WebSocketReaderCython, + ) + + WebSocketReader = WebSocketReaderCython + WebSocketDataQueue = WebSocketDataQueueCython + except ImportError: # pragma: no cover + from .reader_py import ( + WebSocketDataQueue as WebSocketDataQueuePython, + WebSocketReader as WebSocketReaderPython, + ) + + WebSocketReader = WebSocketReaderPython + WebSocketDataQueue = WebSocketDataQueuePython diff --git a/venv/lib/python3.12/site-packages/aiohttp/_websocket/reader_c.cpython-312-darwin.so b/venv/lib/python3.12/site-packages/aiohttp/_websocket/reader_c.cpython-312-darwin.so new file mode 100755 index 0000000000000000000000000000000000000000..7768399b7479752bb7a7489d7e3d531d233b6f32 GIT binary patch literal 225616 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 z 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 J4>^~?{{h+}%1HnK literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiohttp/_websocket/reader_c.pxd b/venv/lib/python3.12/site-packages/aiohttp/_websocket/reader_c.pxd new file mode 100644 index 00000000..a7620d8e --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/_websocket/reader_c.pxd @@ -0,0 +1,110 @@ +import cython + +from .mask cimport _websocket_mask_cython as websocket_mask + + +cdef unsigned int READ_HEADER +cdef unsigned int READ_PAYLOAD_LENGTH +cdef unsigned int READ_PAYLOAD_MASK +cdef unsigned int READ_PAYLOAD + +cdef int OP_CODE_NOT_SET +cdef int OP_CODE_CONTINUATION +cdef int OP_CODE_TEXT +cdef int OP_CODE_BINARY +cdef int OP_CODE_CLOSE +cdef int OP_CODE_PING +cdef int OP_CODE_PONG + +cdef int COMPRESSED_NOT_SET +cdef int COMPRESSED_FALSE +cdef int COMPRESSED_TRUE + +cdef object UNPACK_LEN3 +cdef object UNPACK_CLOSE_CODE +cdef object TUPLE_NEW + +cdef object WSMsgType +cdef object WSMessage + +cdef object WS_MSG_TYPE_TEXT +cdef object WS_MSG_TYPE_BINARY + +cdef set ALLOWED_CLOSE_CODES +cdef set MESSAGE_TYPES_WITH_CONTENT + +cdef tuple EMPTY_FRAME +cdef tuple EMPTY_FRAME_ERROR + +cdef class WebSocketDataQueue: + + cdef unsigned int _size + cdef public object _protocol + cdef unsigned int _limit + cdef object _loop + cdef bint _eof + cdef object _waiter + cdef object _exception + cdef public object _buffer + cdef object _get_buffer + cdef object _put_buffer + + cdef void _release_waiter(self) + + cpdef void feed_data(self, object data, unsigned int size) + + @cython.locals(size="unsigned int") + cdef _read_from_buffer(self) + +cdef class WebSocketReader: + + cdef WebSocketDataQueue queue + cdef unsigned int _max_msg_size + + cdef Exception _exc + cdef bytearray _partial + cdef unsigned int _state + + cdef int _opcode + cdef bint _frame_fin + cdef int _frame_opcode + cdef list _payload_fragments + cdef Py_ssize_t _frame_payload_len + + cdef bytes _tail + cdef bint _has_mask + cdef bytes _frame_mask + cdef Py_ssize_t _payload_bytes_to_read + cdef unsigned int _payload_len_flag + cdef int _compressed + cdef object _decompressobj + cdef bint _compress + + cpdef tuple feed_data(self, object data) + + @cython.locals( + is_continuation=bint, + fin=bint, + has_partial=bint, + payload_merged=bytes, + ) + cpdef void _handle_frame(self, bint fin, int opcode, object payload, int compressed) except * + + @cython.locals( + start_pos=Py_ssize_t, + data_len=Py_ssize_t, + length=Py_ssize_t, + chunk_size=Py_ssize_t, + chunk_len=Py_ssize_t, + data_len=Py_ssize_t, + data_cstr="const unsigned char *", + first_byte="unsigned char", + second_byte="unsigned char", + f_start_pos=Py_ssize_t, + f_end_pos=Py_ssize_t, + has_mask=bint, + fin=bint, + had_fragments=Py_ssize_t, + payload_bytearray=bytearray, + ) + cpdef void _feed_data(self, bytes data) except * diff --git a/venv/lib/python3.12/site-packages/aiohttp/_websocket/reader_c.py b/venv/lib/python3.12/site-packages/aiohttp/_websocket/reader_c.py new file mode 100644 index 00000000..f0060fd7 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/_websocket/reader_c.py @@ -0,0 +1,468 @@ +"""Reader for WebSocket protocol versions 13 and 8.""" + +import asyncio +import builtins +from collections import deque +from typing import Deque, Final, Optional, Set, Tuple, Union + +from ..base_protocol import BaseProtocol +from ..compression_utils import ZLibDecompressor +from ..helpers import _EXC_SENTINEL, set_exception +from ..streams import EofStream +from .helpers import UNPACK_CLOSE_CODE, UNPACK_LEN3, websocket_mask +from .models import ( + WS_DEFLATE_TRAILING, + WebSocketError, + WSCloseCode, + WSMessage, + WSMsgType, +) + +ALLOWED_CLOSE_CODES: Final[Set[int]] = {int(i) for i in WSCloseCode} + +# States for the reader, used to parse the WebSocket frame +# integer values are used so they can be cythonized +READ_HEADER = 1 +READ_PAYLOAD_LENGTH = 2 +READ_PAYLOAD_MASK = 3 +READ_PAYLOAD = 4 + +WS_MSG_TYPE_BINARY = WSMsgType.BINARY +WS_MSG_TYPE_TEXT = WSMsgType.TEXT + +# WSMsgType values unpacked so they can by cythonized to ints +OP_CODE_NOT_SET = -1 +OP_CODE_CONTINUATION = WSMsgType.CONTINUATION.value +OP_CODE_TEXT = WSMsgType.TEXT.value +OP_CODE_BINARY = WSMsgType.BINARY.value +OP_CODE_CLOSE = WSMsgType.CLOSE.value +OP_CODE_PING = WSMsgType.PING.value +OP_CODE_PONG = WSMsgType.PONG.value + +EMPTY_FRAME_ERROR = (True, b"") +EMPTY_FRAME = (False, b"") + +COMPRESSED_NOT_SET = -1 +COMPRESSED_FALSE = 0 +COMPRESSED_TRUE = 1 + +TUPLE_NEW = tuple.__new__ + +cython_int = int # Typed to int in Python, but cython with use a signed int in the pxd + + +class WebSocketDataQueue: + """WebSocketDataQueue resumes and pauses an underlying stream. + + It is a destination for WebSocket data. + """ + + def __init__( + self, protocol: BaseProtocol, limit: int, *, loop: asyncio.AbstractEventLoop + ) -> None: + self._size = 0 + self._protocol = protocol + self._limit = limit * 2 + self._loop = loop + self._eof = False + self._waiter: Optional[asyncio.Future[None]] = None + self._exception: Union[BaseException, None] = None + self._buffer: Deque[Tuple[WSMessage, int]] = deque() + self._get_buffer = self._buffer.popleft + self._put_buffer = self._buffer.append + + def is_eof(self) -> bool: + return self._eof + + def exception(self) -> Optional[BaseException]: + return self._exception + + def set_exception( + self, + exc: "BaseException", + exc_cause: builtins.BaseException = _EXC_SENTINEL, + ) -> None: + self._eof = True + self._exception = exc + if (waiter := self._waiter) is not None: + self._waiter = None + set_exception(waiter, exc, exc_cause) + + def _release_waiter(self) -> None: + if (waiter := self._waiter) is None: + return + self._waiter = None + if not waiter.done(): + waiter.set_result(None) + + def feed_eof(self) -> None: + self._eof = True + self._release_waiter() + self._exception = None # Break cyclic references + + def feed_data(self, data: "WSMessage", size: "cython_int") -> None: + self._size += size + self._put_buffer((data, size)) + self._release_waiter() + if self._size > self._limit and not self._protocol._reading_paused: + self._protocol.pause_reading() + + async def read(self) -> WSMessage: + if not self._buffer and not self._eof: + assert not self._waiter + self._waiter = self._loop.create_future() + try: + await self._waiter + except (asyncio.CancelledError, asyncio.TimeoutError): + self._waiter = None + raise + return self._read_from_buffer() + + def _read_from_buffer(self) -> WSMessage: + if self._buffer: + data, size = self._get_buffer() + self._size -= size + if self._size < self._limit and self._protocol._reading_paused: + self._protocol.resume_reading() + return data + if self._exception is not None: + raise self._exception + raise EofStream + + +class WebSocketReader: + def __init__( + self, queue: WebSocketDataQueue, max_msg_size: int, compress: bool = True + ) -> None: + self.queue = queue + self._max_msg_size = max_msg_size + + self._exc: Optional[Exception] = None + self._partial = bytearray() + self._state = READ_HEADER + + self._opcode: int = OP_CODE_NOT_SET + self._frame_fin = False + self._frame_opcode: int = OP_CODE_NOT_SET + self._payload_fragments: list[bytes] = [] + self._frame_payload_len = 0 + + self._tail: bytes = b"" + self._has_mask = False + self._frame_mask: Optional[bytes] = None + self._payload_bytes_to_read = 0 + self._payload_len_flag = 0 + self._compressed: int = COMPRESSED_NOT_SET + self._decompressobj: Optional[ZLibDecompressor] = None + self._compress = compress + + def feed_eof(self) -> None: + self.queue.feed_eof() + + # data can be bytearray on Windows because proactor event loop uses bytearray + # and asyncio types this to Union[bytes, bytearray, memoryview] so we need + # coerce data to bytes if it is not + def feed_data( + self, data: Union[bytes, bytearray, memoryview] + ) -> Tuple[bool, bytes]: + if type(data) is not bytes: + data = bytes(data) + + if self._exc is not None: + return True, data + + try: + self._feed_data(data) + except Exception as exc: + self._exc = exc + set_exception(self.queue, exc) + return EMPTY_FRAME_ERROR + + return EMPTY_FRAME + + def _handle_frame( + self, + fin: bool, + opcode: Union[int, cython_int], # Union intended: Cython pxd uses C int + payload: Union[bytes, bytearray], + compressed: Union[int, cython_int], # Union intended: Cython pxd uses C int + ) -> None: + msg: WSMessage + if opcode in {OP_CODE_TEXT, OP_CODE_BINARY, OP_CODE_CONTINUATION}: + # load text/binary + if not fin: + # got partial frame payload + if opcode != OP_CODE_CONTINUATION: + self._opcode = opcode + self._partial += payload + if self._max_msg_size and len(self._partial) >= self._max_msg_size: + raise WebSocketError( + WSCloseCode.MESSAGE_TOO_BIG, + f"Message size {len(self._partial)} " + f"exceeds limit {self._max_msg_size}", + ) + return + + has_partial = bool(self._partial) + if opcode == OP_CODE_CONTINUATION: + if self._opcode == OP_CODE_NOT_SET: + raise WebSocketError( + WSCloseCode.PROTOCOL_ERROR, + "Continuation frame for non started message", + ) + opcode = self._opcode + self._opcode = OP_CODE_NOT_SET + # previous frame was non finished + # we should get continuation opcode + elif has_partial: + raise WebSocketError( + WSCloseCode.PROTOCOL_ERROR, + "The opcode in non-fin frame is expected " + f"to be zero, got {opcode!r}", + ) + + assembled_payload: Union[bytes, bytearray] + if has_partial: + assembled_payload = self._partial + payload + self._partial.clear() + else: + assembled_payload = payload + + if self._max_msg_size and len(assembled_payload) >= self._max_msg_size: + raise WebSocketError( + WSCloseCode.MESSAGE_TOO_BIG, + f"Message size {len(assembled_payload)} " + f"exceeds limit {self._max_msg_size}", + ) + + # Decompress process must to be done after all packets + # received. + if compressed: + if not self._decompressobj: + self._decompressobj = ZLibDecompressor(suppress_deflate_header=True) + payload_merged = self._decompressobj.decompress_sync( + assembled_payload + WS_DEFLATE_TRAILING, self._max_msg_size + ) + if self._decompressobj.unconsumed_tail: + left = len(self._decompressobj.unconsumed_tail) + raise WebSocketError( + WSCloseCode.MESSAGE_TOO_BIG, + f"Decompressed message size {self._max_msg_size + left}" + f" exceeds limit {self._max_msg_size}", + ) + elif type(assembled_payload) is bytes: + payload_merged = assembled_payload + else: + payload_merged = bytes(assembled_payload) + + if opcode == OP_CODE_TEXT: + try: + text = payload_merged.decode("utf-8") + except UnicodeDecodeError as exc: + raise WebSocketError( + WSCloseCode.INVALID_TEXT, "Invalid UTF-8 text message" + ) from exc + + # XXX: The Text and Binary messages here can be a performance + # bottleneck, so we use tuple.__new__ to improve performance. + # This is not type safe, but many tests should fail in + # test_client_ws_functional.py if this is wrong. + self.queue.feed_data( + TUPLE_NEW(WSMessage, (WS_MSG_TYPE_TEXT, text, "")), + len(payload_merged), + ) + else: + self.queue.feed_data( + TUPLE_NEW(WSMessage, (WS_MSG_TYPE_BINARY, payload_merged, "")), + len(payload_merged), + ) + elif opcode == OP_CODE_CLOSE: + if len(payload) >= 2: + close_code = UNPACK_CLOSE_CODE(payload[:2])[0] + if close_code < 3000 and close_code not in ALLOWED_CLOSE_CODES: + raise WebSocketError( + WSCloseCode.PROTOCOL_ERROR, + f"Invalid close code: {close_code}", + ) + try: + close_message = payload[2:].decode("utf-8") + except UnicodeDecodeError as exc: + raise WebSocketError( + WSCloseCode.INVALID_TEXT, "Invalid UTF-8 text message" + ) from exc + msg = TUPLE_NEW(WSMessage, (WSMsgType.CLOSE, close_code, close_message)) + elif payload: + raise WebSocketError( + WSCloseCode.PROTOCOL_ERROR, + f"Invalid close frame: {fin} {opcode} {payload!r}", + ) + else: + msg = TUPLE_NEW(WSMessage, (WSMsgType.CLOSE, 0, "")) + + self.queue.feed_data(msg, 0) + elif opcode == OP_CODE_PING: + msg = TUPLE_NEW(WSMessage, (WSMsgType.PING, payload, "")) + self.queue.feed_data(msg, len(payload)) + elif opcode == OP_CODE_PONG: + msg = TUPLE_NEW(WSMessage, (WSMsgType.PONG, payload, "")) + self.queue.feed_data(msg, len(payload)) + else: + raise WebSocketError( + WSCloseCode.PROTOCOL_ERROR, f"Unexpected opcode={opcode!r}" + ) + + def _feed_data(self, data: bytes) -> None: + """Return the next frame from the socket.""" + if self._tail: + data, self._tail = self._tail + data, b"" + + start_pos: int = 0 + data_len = len(data) + data_cstr = data + + while True: + # read header + if self._state == READ_HEADER: + if data_len - start_pos < 2: + break + first_byte = data_cstr[start_pos] + second_byte = data_cstr[start_pos + 1] + start_pos += 2 + + fin = (first_byte >> 7) & 1 + rsv1 = (first_byte >> 6) & 1 + rsv2 = (first_byte >> 5) & 1 + rsv3 = (first_byte >> 4) & 1 + opcode = first_byte & 0xF + + # frame-fin = %x0 ; more frames of this message follow + # / %x1 ; final frame of this message + # frame-rsv1 = %x0 ; + # 1 bit, MUST be 0 unless negotiated otherwise + # frame-rsv2 = %x0 ; + # 1 bit, MUST be 0 unless negotiated otherwise + # frame-rsv3 = %x0 ; + # 1 bit, MUST be 0 unless negotiated otherwise + # + # Remove rsv1 from this test for deflate development + if rsv2 or rsv3 or (rsv1 and not self._compress): + raise WebSocketError( + WSCloseCode.PROTOCOL_ERROR, + "Received frame with non-zero reserved bits", + ) + + if opcode > 0x7 and fin == 0: + raise WebSocketError( + WSCloseCode.PROTOCOL_ERROR, + "Received fragmented control frame", + ) + + has_mask = (second_byte >> 7) & 1 + length = second_byte & 0x7F + + # Control frames MUST have a payload + # length of 125 bytes or less + if opcode > 0x7 and length > 125: + raise WebSocketError( + WSCloseCode.PROTOCOL_ERROR, + "Control frame payload cannot be larger than 125 bytes", + ) + + # Set compress status if last package is FIN + # OR set compress status if this is first fragment + # Raise error if not first fragment with rsv1 = 0x1 + if self._frame_fin or self._compressed == COMPRESSED_NOT_SET: + self._compressed = COMPRESSED_TRUE if rsv1 else COMPRESSED_FALSE + elif rsv1: + raise WebSocketError( + WSCloseCode.PROTOCOL_ERROR, + "Received frame with non-zero reserved bits", + ) + + self._frame_fin = bool(fin) + self._frame_opcode = opcode + self._has_mask = bool(has_mask) + self._payload_len_flag = length + self._state = READ_PAYLOAD_LENGTH + + # read payload length + if self._state == READ_PAYLOAD_LENGTH: + len_flag = self._payload_len_flag + if len_flag == 126: + if data_len - start_pos < 2: + break + first_byte = data_cstr[start_pos] + second_byte = data_cstr[start_pos + 1] + start_pos += 2 + self._payload_bytes_to_read = first_byte << 8 | second_byte + elif len_flag > 126: + if data_len - start_pos < 8: + break + self._payload_bytes_to_read = UNPACK_LEN3(data, start_pos)[0] + start_pos += 8 + else: + self._payload_bytes_to_read = len_flag + + self._state = READ_PAYLOAD_MASK if self._has_mask else READ_PAYLOAD + + # read payload mask + if self._state == READ_PAYLOAD_MASK: + if data_len - start_pos < 4: + break + self._frame_mask = data_cstr[start_pos : start_pos + 4] + start_pos += 4 + self._state = READ_PAYLOAD + + if self._state == READ_PAYLOAD: + chunk_len = data_len - start_pos + if self._payload_bytes_to_read >= chunk_len: + f_end_pos = data_len + self._payload_bytes_to_read -= chunk_len + else: + f_end_pos = start_pos + self._payload_bytes_to_read + self._payload_bytes_to_read = 0 + + had_fragments = self._frame_payload_len + self._frame_payload_len += f_end_pos - start_pos + f_start_pos = start_pos + start_pos = f_end_pos + + if self._payload_bytes_to_read != 0: + # If we don't have a complete frame, we need to save the + # data for the next call to feed_data. + self._payload_fragments.append(data_cstr[f_start_pos:f_end_pos]) + break + + payload: Union[bytes, bytearray] + if had_fragments: + # We have to join the payload fragments get the payload + self._payload_fragments.append(data_cstr[f_start_pos:f_end_pos]) + if self._has_mask: + assert self._frame_mask is not None + payload_bytearray = bytearray(b"".join(self._payload_fragments)) + websocket_mask(self._frame_mask, payload_bytearray) + payload = payload_bytearray + else: + payload = b"".join(self._payload_fragments) + self._payload_fragments.clear() + elif self._has_mask: + assert self._frame_mask is not None + payload_bytearray = data_cstr[f_start_pos:f_end_pos] # type: ignore[assignment] + if type(payload_bytearray) is not bytearray: # pragma: no branch + # Cython will do the conversion for us + # but we need to do it for Python and we + # will always get here in Python + payload_bytearray = bytearray(payload_bytearray) + websocket_mask(self._frame_mask, payload_bytearray) + payload = payload_bytearray + else: + payload = data_cstr[f_start_pos:f_end_pos] + + self._handle_frame( + self._frame_fin, self._frame_opcode, payload, self._compressed + ) + self._frame_payload_len = 0 + self._state = READ_HEADER + + # XXX: Cython needs slices to be bounded, so we can't omit the slice end here. + self._tail = data_cstr[start_pos:data_len] if start_pos < data_len else b"" diff --git a/venv/lib/python3.12/site-packages/aiohttp/_websocket/reader_py.py b/venv/lib/python3.12/site-packages/aiohttp/_websocket/reader_py.py new file mode 100644 index 00000000..f0060fd7 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/_websocket/reader_py.py @@ -0,0 +1,468 @@ +"""Reader for WebSocket protocol versions 13 and 8.""" + +import asyncio +import builtins +from collections import deque +from typing import Deque, Final, Optional, Set, Tuple, Union + +from ..base_protocol import BaseProtocol +from ..compression_utils import ZLibDecompressor +from ..helpers import _EXC_SENTINEL, set_exception +from ..streams import EofStream +from .helpers import UNPACK_CLOSE_CODE, UNPACK_LEN3, websocket_mask +from .models import ( + WS_DEFLATE_TRAILING, + WebSocketError, + WSCloseCode, + WSMessage, + WSMsgType, +) + +ALLOWED_CLOSE_CODES: Final[Set[int]] = {int(i) for i in WSCloseCode} + +# States for the reader, used to parse the WebSocket frame +# integer values are used so they can be cythonized +READ_HEADER = 1 +READ_PAYLOAD_LENGTH = 2 +READ_PAYLOAD_MASK = 3 +READ_PAYLOAD = 4 + +WS_MSG_TYPE_BINARY = WSMsgType.BINARY +WS_MSG_TYPE_TEXT = WSMsgType.TEXT + +# WSMsgType values unpacked so they can by cythonized to ints +OP_CODE_NOT_SET = -1 +OP_CODE_CONTINUATION = WSMsgType.CONTINUATION.value +OP_CODE_TEXT = WSMsgType.TEXT.value +OP_CODE_BINARY = WSMsgType.BINARY.value +OP_CODE_CLOSE = WSMsgType.CLOSE.value +OP_CODE_PING = WSMsgType.PING.value +OP_CODE_PONG = WSMsgType.PONG.value + +EMPTY_FRAME_ERROR = (True, b"") +EMPTY_FRAME = (False, b"") + +COMPRESSED_NOT_SET = -1 +COMPRESSED_FALSE = 0 +COMPRESSED_TRUE = 1 + +TUPLE_NEW = tuple.__new__ + +cython_int = int # Typed to int in Python, but cython with use a signed int in the pxd + + +class WebSocketDataQueue: + """WebSocketDataQueue resumes and pauses an underlying stream. + + It is a destination for WebSocket data. + """ + + def __init__( + self, protocol: BaseProtocol, limit: int, *, loop: asyncio.AbstractEventLoop + ) -> None: + self._size = 0 + self._protocol = protocol + self._limit = limit * 2 + self._loop = loop + self._eof = False + self._waiter: Optional[asyncio.Future[None]] = None + self._exception: Union[BaseException, None] = None + self._buffer: Deque[Tuple[WSMessage, int]] = deque() + self._get_buffer = self._buffer.popleft + self._put_buffer = self._buffer.append + + def is_eof(self) -> bool: + return self._eof + + def exception(self) -> Optional[BaseException]: + return self._exception + + def set_exception( + self, + exc: "BaseException", + exc_cause: builtins.BaseException = _EXC_SENTINEL, + ) -> None: + self._eof = True + self._exception = exc + if (waiter := self._waiter) is not None: + self._waiter = None + set_exception(waiter, exc, exc_cause) + + def _release_waiter(self) -> None: + if (waiter := self._waiter) is None: + return + self._waiter = None + if not waiter.done(): + waiter.set_result(None) + + def feed_eof(self) -> None: + self._eof = True + self._release_waiter() + self._exception = None # Break cyclic references + + def feed_data(self, data: "WSMessage", size: "cython_int") -> None: + self._size += size + self._put_buffer((data, size)) + self._release_waiter() + if self._size > self._limit and not self._protocol._reading_paused: + self._protocol.pause_reading() + + async def read(self) -> WSMessage: + if not self._buffer and not self._eof: + assert not self._waiter + self._waiter = self._loop.create_future() + try: + await self._waiter + except (asyncio.CancelledError, asyncio.TimeoutError): + self._waiter = None + raise + return self._read_from_buffer() + + def _read_from_buffer(self) -> WSMessage: + if self._buffer: + data, size = self._get_buffer() + self._size -= size + if self._size < self._limit and self._protocol._reading_paused: + self._protocol.resume_reading() + return data + if self._exception is not None: + raise self._exception + raise EofStream + + +class WebSocketReader: + def __init__( + self, queue: WebSocketDataQueue, max_msg_size: int, compress: bool = True + ) -> None: + self.queue = queue + self._max_msg_size = max_msg_size + + self._exc: Optional[Exception] = None + self._partial = bytearray() + self._state = READ_HEADER + + self._opcode: int = OP_CODE_NOT_SET + self._frame_fin = False + self._frame_opcode: int = OP_CODE_NOT_SET + self._payload_fragments: list[bytes] = [] + self._frame_payload_len = 0 + + self._tail: bytes = b"" + self._has_mask = False + self._frame_mask: Optional[bytes] = None + self._payload_bytes_to_read = 0 + self._payload_len_flag = 0 + self._compressed: int = COMPRESSED_NOT_SET + self._decompressobj: Optional[ZLibDecompressor] = None + self._compress = compress + + def feed_eof(self) -> None: + self.queue.feed_eof() + + # data can be bytearray on Windows because proactor event loop uses bytearray + # and asyncio types this to Union[bytes, bytearray, memoryview] so we need + # coerce data to bytes if it is not + def feed_data( + self, data: Union[bytes, bytearray, memoryview] + ) -> Tuple[bool, bytes]: + if type(data) is not bytes: + data = bytes(data) + + if self._exc is not None: + return True, data + + try: + self._feed_data(data) + except Exception as exc: + self._exc = exc + set_exception(self.queue, exc) + return EMPTY_FRAME_ERROR + + return EMPTY_FRAME + + def _handle_frame( + self, + fin: bool, + opcode: Union[int, cython_int], # Union intended: Cython pxd uses C int + payload: Union[bytes, bytearray], + compressed: Union[int, cython_int], # Union intended: Cython pxd uses C int + ) -> None: + msg: WSMessage + if opcode in {OP_CODE_TEXT, OP_CODE_BINARY, OP_CODE_CONTINUATION}: + # load text/binary + if not fin: + # got partial frame payload + if opcode != OP_CODE_CONTINUATION: + self._opcode = opcode + self._partial += payload + if self._max_msg_size and len(self._partial) >= self._max_msg_size: + raise WebSocketError( + WSCloseCode.MESSAGE_TOO_BIG, + f"Message size {len(self._partial)} " + f"exceeds limit {self._max_msg_size}", + ) + return + + has_partial = bool(self._partial) + if opcode == OP_CODE_CONTINUATION: + if self._opcode == OP_CODE_NOT_SET: + raise WebSocketError( + WSCloseCode.PROTOCOL_ERROR, + "Continuation frame for non started message", + ) + opcode = self._opcode + self._opcode = OP_CODE_NOT_SET + # previous frame was non finished + # we should get continuation opcode + elif has_partial: + raise WebSocketError( + WSCloseCode.PROTOCOL_ERROR, + "The opcode in non-fin frame is expected " + f"to be zero, got {opcode!r}", + ) + + assembled_payload: Union[bytes, bytearray] + if has_partial: + assembled_payload = self._partial + payload + self._partial.clear() + else: + assembled_payload = payload + + if self._max_msg_size and len(assembled_payload) >= self._max_msg_size: + raise WebSocketError( + WSCloseCode.MESSAGE_TOO_BIG, + f"Message size {len(assembled_payload)} " + f"exceeds limit {self._max_msg_size}", + ) + + # Decompress process must to be done after all packets + # received. + if compressed: + if not self._decompressobj: + self._decompressobj = ZLibDecompressor(suppress_deflate_header=True) + payload_merged = self._decompressobj.decompress_sync( + assembled_payload + WS_DEFLATE_TRAILING, self._max_msg_size + ) + if self._decompressobj.unconsumed_tail: + left = len(self._decompressobj.unconsumed_tail) + raise WebSocketError( + WSCloseCode.MESSAGE_TOO_BIG, + f"Decompressed message size {self._max_msg_size + left}" + f" exceeds limit {self._max_msg_size}", + ) + elif type(assembled_payload) is bytes: + payload_merged = assembled_payload + else: + payload_merged = bytes(assembled_payload) + + if opcode == OP_CODE_TEXT: + try: + text = payload_merged.decode("utf-8") + except UnicodeDecodeError as exc: + raise WebSocketError( + WSCloseCode.INVALID_TEXT, "Invalid UTF-8 text message" + ) from exc + + # XXX: The Text and Binary messages here can be a performance + # bottleneck, so we use tuple.__new__ to improve performance. + # This is not type safe, but many tests should fail in + # test_client_ws_functional.py if this is wrong. + self.queue.feed_data( + TUPLE_NEW(WSMessage, (WS_MSG_TYPE_TEXT, text, "")), + len(payload_merged), + ) + else: + self.queue.feed_data( + TUPLE_NEW(WSMessage, (WS_MSG_TYPE_BINARY, payload_merged, "")), + len(payload_merged), + ) + elif opcode == OP_CODE_CLOSE: + if len(payload) >= 2: + close_code = UNPACK_CLOSE_CODE(payload[:2])[0] + if close_code < 3000 and close_code not in ALLOWED_CLOSE_CODES: + raise WebSocketError( + WSCloseCode.PROTOCOL_ERROR, + f"Invalid close code: {close_code}", + ) + try: + close_message = payload[2:].decode("utf-8") + except UnicodeDecodeError as exc: + raise WebSocketError( + WSCloseCode.INVALID_TEXT, "Invalid UTF-8 text message" + ) from exc + msg = TUPLE_NEW(WSMessage, (WSMsgType.CLOSE, close_code, close_message)) + elif payload: + raise WebSocketError( + WSCloseCode.PROTOCOL_ERROR, + f"Invalid close frame: {fin} {opcode} {payload!r}", + ) + else: + msg = TUPLE_NEW(WSMessage, (WSMsgType.CLOSE, 0, "")) + + self.queue.feed_data(msg, 0) + elif opcode == OP_CODE_PING: + msg = TUPLE_NEW(WSMessage, (WSMsgType.PING, payload, "")) + self.queue.feed_data(msg, len(payload)) + elif opcode == OP_CODE_PONG: + msg = TUPLE_NEW(WSMessage, (WSMsgType.PONG, payload, "")) + self.queue.feed_data(msg, len(payload)) + else: + raise WebSocketError( + WSCloseCode.PROTOCOL_ERROR, f"Unexpected opcode={opcode!r}" + ) + + def _feed_data(self, data: bytes) -> None: + """Return the next frame from the socket.""" + if self._tail: + data, self._tail = self._tail + data, b"" + + start_pos: int = 0 + data_len = len(data) + data_cstr = data + + while True: + # read header + if self._state == READ_HEADER: + if data_len - start_pos < 2: + break + first_byte = data_cstr[start_pos] + second_byte = data_cstr[start_pos + 1] + start_pos += 2 + + fin = (first_byte >> 7) & 1 + rsv1 = (first_byte >> 6) & 1 + rsv2 = (first_byte >> 5) & 1 + rsv3 = (first_byte >> 4) & 1 + opcode = first_byte & 0xF + + # frame-fin = %x0 ; more frames of this message follow + # / %x1 ; final frame of this message + # frame-rsv1 = %x0 ; + # 1 bit, MUST be 0 unless negotiated otherwise + # frame-rsv2 = %x0 ; + # 1 bit, MUST be 0 unless negotiated otherwise + # frame-rsv3 = %x0 ; + # 1 bit, MUST be 0 unless negotiated otherwise + # + # Remove rsv1 from this test for deflate development + if rsv2 or rsv3 or (rsv1 and not self._compress): + raise WebSocketError( + WSCloseCode.PROTOCOL_ERROR, + "Received frame with non-zero reserved bits", + ) + + if opcode > 0x7 and fin == 0: + raise WebSocketError( + WSCloseCode.PROTOCOL_ERROR, + "Received fragmented control frame", + ) + + has_mask = (second_byte >> 7) & 1 + length = second_byte & 0x7F + + # Control frames MUST have a payload + # length of 125 bytes or less + if opcode > 0x7 and length > 125: + raise WebSocketError( + WSCloseCode.PROTOCOL_ERROR, + "Control frame payload cannot be larger than 125 bytes", + ) + + # Set compress status if last package is FIN + # OR set compress status if this is first fragment + # Raise error if not first fragment with rsv1 = 0x1 + if self._frame_fin or self._compressed == COMPRESSED_NOT_SET: + self._compressed = COMPRESSED_TRUE if rsv1 else COMPRESSED_FALSE + elif rsv1: + raise WebSocketError( + WSCloseCode.PROTOCOL_ERROR, + "Received frame with non-zero reserved bits", + ) + + self._frame_fin = bool(fin) + self._frame_opcode = opcode + self._has_mask = bool(has_mask) + self._payload_len_flag = length + self._state = READ_PAYLOAD_LENGTH + + # read payload length + if self._state == READ_PAYLOAD_LENGTH: + len_flag = self._payload_len_flag + if len_flag == 126: + if data_len - start_pos < 2: + break + first_byte = data_cstr[start_pos] + second_byte = data_cstr[start_pos + 1] + start_pos += 2 + self._payload_bytes_to_read = first_byte << 8 | second_byte + elif len_flag > 126: + if data_len - start_pos < 8: + break + self._payload_bytes_to_read = UNPACK_LEN3(data, start_pos)[0] + start_pos += 8 + else: + self._payload_bytes_to_read = len_flag + + self._state = READ_PAYLOAD_MASK if self._has_mask else READ_PAYLOAD + + # read payload mask + if self._state == READ_PAYLOAD_MASK: + if data_len - start_pos < 4: + break + self._frame_mask = data_cstr[start_pos : start_pos + 4] + start_pos += 4 + self._state = READ_PAYLOAD + + if self._state == READ_PAYLOAD: + chunk_len = data_len - start_pos + if self._payload_bytes_to_read >= chunk_len: + f_end_pos = data_len + self._payload_bytes_to_read -= chunk_len + else: + f_end_pos = start_pos + self._payload_bytes_to_read + self._payload_bytes_to_read = 0 + + had_fragments = self._frame_payload_len + self._frame_payload_len += f_end_pos - start_pos + f_start_pos = start_pos + start_pos = f_end_pos + + if self._payload_bytes_to_read != 0: + # If we don't have a complete frame, we need to save the + # data for the next call to feed_data. + self._payload_fragments.append(data_cstr[f_start_pos:f_end_pos]) + break + + payload: Union[bytes, bytearray] + if had_fragments: + # We have to join the payload fragments get the payload + self._payload_fragments.append(data_cstr[f_start_pos:f_end_pos]) + if self._has_mask: + assert self._frame_mask is not None + payload_bytearray = bytearray(b"".join(self._payload_fragments)) + websocket_mask(self._frame_mask, payload_bytearray) + payload = payload_bytearray + else: + payload = b"".join(self._payload_fragments) + self._payload_fragments.clear() + elif self._has_mask: + assert self._frame_mask is not None + payload_bytearray = data_cstr[f_start_pos:f_end_pos] # type: ignore[assignment] + if type(payload_bytearray) is not bytearray: # pragma: no branch + # Cython will do the conversion for us + # but we need to do it for Python and we + # will always get here in Python + payload_bytearray = bytearray(payload_bytearray) + websocket_mask(self._frame_mask, payload_bytearray) + payload = payload_bytearray + else: + payload = data_cstr[f_start_pos:f_end_pos] + + self._handle_frame( + self._frame_fin, self._frame_opcode, payload, self._compressed + ) + self._frame_payload_len = 0 + self._state = READ_HEADER + + # XXX: Cython needs slices to be bounded, so we can't omit the slice end here. + self._tail = data_cstr[start_pos:data_len] if start_pos < data_len else b"" diff --git a/venv/lib/python3.12/site-packages/aiohttp/_websocket/writer.py b/venv/lib/python3.12/site-packages/aiohttp/_websocket/writer.py new file mode 100644 index 00000000..fc2cf32b --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/_websocket/writer.py @@ -0,0 +1,177 @@ +"""WebSocket protocol versions 13 and 8.""" + +import asyncio +import random +import zlib +from functools import partial +from typing import Any, Final, Optional, Union + +from ..base_protocol import BaseProtocol +from ..client_exceptions import ClientConnectionResetError +from ..compression_utils import ZLibCompressor +from .helpers import ( + MASK_LEN, + MSG_SIZE, + PACK_CLOSE_CODE, + PACK_LEN1, + PACK_LEN2, + PACK_LEN3, + PACK_RANDBITS, + websocket_mask, +) +from .models import WS_DEFLATE_TRAILING, WSMsgType + +DEFAULT_LIMIT: Final[int] = 2**16 + +# For websockets, keeping latency low is extremely important as implementations +# generally expect to be able to send and receive messages quickly. We use a +# larger chunk size than the default to reduce the number of executor calls +# since the executor is a significant source of latency and overhead when +# the chunks are small. A size of 5KiB was chosen because it is also the +# same value python-zlib-ng choose to use as the threshold to release the GIL. + +WEBSOCKET_MAX_SYNC_CHUNK_SIZE = 5 * 1024 + + +class WebSocketWriter: + """WebSocket writer. + + The writer is responsible for sending messages to the client. It is + created by the protocol when a connection is established. The writer + should avoid implementing any application logic and should only be + concerned with the low-level details of the WebSocket protocol. + """ + + def __init__( + self, + protocol: BaseProtocol, + transport: asyncio.Transport, + *, + use_mask: bool = False, + limit: int = DEFAULT_LIMIT, + random: random.Random = random.Random(), + compress: int = 0, + notakeover: bool = False, + ) -> None: + """Initialize a WebSocket writer.""" + self.protocol = protocol + self.transport = transport + self.use_mask = use_mask + self.get_random_bits = partial(random.getrandbits, 32) + self.compress = compress + self.notakeover = notakeover + self._closing = False + self._limit = limit + self._output_size = 0 + self._compressobj: Any = None # actually compressobj + + async def send_frame( + self, message: bytes, opcode: int, compress: Optional[int] = None + ) -> None: + """Send a frame over the websocket with message as its payload.""" + if self._closing and not (opcode & WSMsgType.CLOSE): + raise ClientConnectionResetError("Cannot write to closing transport") + + # RSV are the reserved bits in the frame header. They are used to + # indicate that the frame is using an extension. + # https://datatracker.ietf.org/doc/html/rfc6455#section-5.2 + rsv = 0 + # Only compress larger packets (disabled) + # Does small packet needs to be compressed? + # if self.compress and opcode < 8 and len(message) > 124: + if (compress or self.compress) and opcode < 8: + # RSV1 (rsv = 0x40) is set for compressed frames + # https://datatracker.ietf.org/doc/html/rfc7692#section-7.2.3.1 + rsv = 0x40 + + if compress: + # Do not set self._compress if compressing is for this frame + compressobj = self._make_compress_obj(compress) + else: # self.compress + if not self._compressobj: + self._compressobj = self._make_compress_obj(self.compress) + compressobj = self._compressobj + + message = ( + await compressobj.compress(message) + + compressobj.flush( + zlib.Z_FULL_FLUSH if self.notakeover else zlib.Z_SYNC_FLUSH + ) + ).removesuffix(WS_DEFLATE_TRAILING) + # Its critical that we do not return control to the event + # loop until we have finished sending all the compressed + # data. Otherwise we could end up mixing compressed frames + # if there are multiple coroutines compressing data. + + msg_length = len(message) + + use_mask = self.use_mask + mask_bit = 0x80 if use_mask else 0 + + # Depending on the message length, the header is assembled differently. + # The first byte is reserved for the opcode and the RSV bits. + first_byte = 0x80 | rsv | opcode + if msg_length < 126: + header = PACK_LEN1(first_byte, msg_length | mask_bit) + header_len = 2 + elif msg_length < 65536: + header = PACK_LEN2(first_byte, 126 | mask_bit, msg_length) + header_len = 4 + else: + header = PACK_LEN3(first_byte, 127 | mask_bit, msg_length) + header_len = 10 + + if self.transport.is_closing(): + raise ClientConnectionResetError("Cannot write to closing transport") + + # https://datatracker.ietf.org/doc/html/rfc6455#section-5.3 + # If we are using a mask, we need to generate it randomly + # and apply it to the message before sending it. A mask is + # a 32-bit value that is applied to the message using a + # bitwise XOR operation. It is used to prevent certain types + # of attacks on the websocket protocol. The mask is only used + # when aiohttp is acting as a client. Servers do not use a mask. + if use_mask: + mask = PACK_RANDBITS(self.get_random_bits()) + message = bytearray(message) + websocket_mask(mask, message) + self.transport.write(header + mask + message) + self._output_size += MASK_LEN + elif msg_length > MSG_SIZE: + self.transport.write(header) + self.transport.write(message) + else: + self.transport.write(header + message) + + self._output_size += header_len + msg_length + + # It is safe to return control to the event loop when using compression + # after this point as we have already sent or buffered all the data. + + # Once we have written output_size up to the limit, we call the + # drain helper which waits for the transport to be ready to accept + # more data. This is a flow control mechanism to prevent the buffer + # from growing too large. The drain helper will return right away + # if the writer is not paused. + if self._output_size > self._limit: + self._output_size = 0 + if self.protocol._paused: + await self.protocol._drain_helper() + + def _make_compress_obj(self, compress: int) -> ZLibCompressor: + return ZLibCompressor( + level=zlib.Z_BEST_SPEED, + wbits=-compress, + max_sync_chunk_size=WEBSOCKET_MAX_SYNC_CHUNK_SIZE, + ) + + async def close(self, code: int = 1000, message: Union[bytes, str] = b"") -> None: + """Close the websocket, sending the specified code and message.""" + if isinstance(message, str): + message = message.encode("utf-8") + try: + await self.send_frame( + PACK_CLOSE_CODE(code) + message, opcode=WSMsgType.CLOSE + ) + finally: + self._closing = True diff --git a/venv/lib/python3.12/site-packages/aiohttp/abc.py b/venv/lib/python3.12/site-packages/aiohttp/abc.py new file mode 100644 index 00000000..5794a910 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/abc.py @@ -0,0 +1,253 @@ +import asyncio +import logging +import socket +import zlib +from abc import ABC, abstractmethod +from collections.abc import Sized +from http.cookies import BaseCookie, Morsel +from typing import ( + TYPE_CHECKING, + Any, + Awaitable, + Callable, + Dict, + Generator, + Iterable, + List, + Optional, + Tuple, + TypedDict, + Union, +) + +from multidict import CIMultiDict +from yarl import URL + +from .typedefs import LooseCookies + +if TYPE_CHECKING: + from .web_app import Application + from .web_exceptions import HTTPException + from .web_request import BaseRequest, Request + from .web_response import StreamResponse +else: + BaseRequest = Request = Application = StreamResponse = None + HTTPException = None + + +class AbstractRouter(ABC): + def __init__(self) -> None: + self._frozen = False + + def post_init(self, app: Application) -> None: + """Post init stage. + + Not an abstract method for sake of backward compatibility, + but if the router wants to be aware of the application + it can override this. + """ + + @property + def frozen(self) -> bool: + return self._frozen + + def freeze(self) -> None: + """Freeze router.""" + self._frozen = True + + @abstractmethod + async def resolve(self, request: Request) -> "AbstractMatchInfo": + """Return MATCH_INFO for given request""" + + +class AbstractMatchInfo(ABC): + + __slots__ = () + + @property # pragma: no branch + @abstractmethod + def handler(self) -> Callable[[Request], Awaitable[StreamResponse]]: + """Execute matched request handler""" + + @property + @abstractmethod + def expect_handler( + self, + ) -> Callable[[Request], Awaitable[Optional[StreamResponse]]]: + """Expect handler for 100-continue processing""" + + @property # pragma: no branch + @abstractmethod + def http_exception(self) -> Optional[HTTPException]: + """HTTPException instance raised on router's resolving, or None""" + + @abstractmethod # pragma: no branch + def get_info(self) -> Dict[str, Any]: + """Return a dict with additional info useful for introspection""" + + @property # pragma: no branch + @abstractmethod + def apps(self) -> Tuple[Application, ...]: + """Stack of nested applications. + + Top level application is left-most element. + + """ + + @abstractmethod + def add_app(self, app: Application) -> None: + """Add application to the nested apps stack.""" + + @abstractmethod + def freeze(self) -> None: + """Freeze the match info. + + The method is called after route resolution. + + After the call .add_app() is forbidden. + + """ + + +class AbstractView(ABC): + """Abstract class based view.""" + + def __init__(self, request: Request) -> None: + self._request = request + + @property + def request(self) -> Request: + """Request instance.""" + return self._request + + @abstractmethod + def __await__(self) -> Generator[Any, None, StreamResponse]: + """Execute the view handler.""" + + +class ResolveResult(TypedDict): + """Resolve result. + + This is the result returned from an AbstractResolver's + resolve method. + + :param hostname: The hostname that was provided. + :param host: The IP address that was resolved. + :param port: The port that was resolved. + :param family: The address family that was resolved. + :param proto: The protocol that was resolved. + :param flags: The flags that were resolved. + """ + + hostname: str + host: str + port: int + family: int + proto: int + flags: int + + +class AbstractResolver(ABC): + """Abstract DNS resolver.""" + + @abstractmethod + async def resolve( + self, host: str, port: int = 0, family: socket.AddressFamily = socket.AF_INET + ) -> List[ResolveResult]: + """Return IP address for given hostname""" + + @abstractmethod + async def close(self) -> None: + """Release resolver""" + + +if TYPE_CHECKING: + IterableBase = Iterable[Morsel[str]] +else: + IterableBase = Iterable + + +ClearCookiePredicate = Callable[["Morsel[str]"], bool] + + +class AbstractCookieJar(Sized, IterableBase): + """Abstract Cookie Jar.""" + + def __init__(self, *, loop: Optional[asyncio.AbstractEventLoop] = None) -> None: + self._loop = loop or asyncio.get_running_loop() + + @property + @abstractmethod + def quote_cookie(self) -> bool: + """Return True if cookies should be quoted.""" + + @abstractmethod + def clear(self, predicate: Optional[ClearCookiePredicate] = None) -> None: + """Clear all cookies if no predicate is passed.""" + + @abstractmethod + def clear_domain(self, domain: str) -> None: + """Clear all cookies for domain and all subdomains.""" + + @abstractmethod + def update_cookies(self, cookies: LooseCookies, response_url: URL = URL()) -> None: + """Update cookies.""" + + @abstractmethod + def filter_cookies(self, request_url: URL) -> "BaseCookie[str]": + """Return the jar's cookies filtered by their attributes.""" + + +class AbstractStreamWriter(ABC): + """Abstract stream writer.""" + + buffer_size: int = 0 + output_size: int = 0 + length: Optional[int] = 0 + + @abstractmethod + async def write(self, chunk: Union[bytes, bytearray, memoryview]) -> None: + """Write chunk into stream.""" + + @abstractmethod + async def write_eof(self, chunk: bytes = b"") -> None: + """Write last chunk.""" + + @abstractmethod + async def drain(self) -> None: + """Flush the write buffer.""" + + @abstractmethod + def enable_compression( + self, encoding: str = "deflate", strategy: int = zlib.Z_DEFAULT_STRATEGY + ) -> None: + """Enable HTTP body compression""" + + @abstractmethod + def enable_chunking(self) -> None: + """Enable HTTP chunked mode""" + + @abstractmethod + async def write_headers( + self, status_line: str, headers: "CIMultiDict[str]" + ) -> None: + """Write HTTP headers""" + + +class AbstractAccessLogger(ABC): + """Abstract writer to access log.""" + + __slots__ = ("logger", "log_format") + + def __init__(self, logger: logging.Logger, log_format: str) -> None: + self.logger = logger + self.log_format = log_format + + @abstractmethod + def log(self, request: BaseRequest, response: StreamResponse, time: float) -> None: + """Emit log to logger.""" + + @property + def enabled(self) -> bool: + """Check if logger is enabled.""" + return True diff --git a/venv/lib/python3.12/site-packages/aiohttp/base_protocol.py b/venv/lib/python3.12/site-packages/aiohttp/base_protocol.py new file mode 100644 index 00000000..b0a67ed6 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/base_protocol.py @@ -0,0 +1,100 @@ +import asyncio +from typing import Optional, cast + +from .client_exceptions import ClientConnectionResetError +from .helpers import set_exception +from .tcp_helpers import tcp_nodelay + + +class BaseProtocol(asyncio.Protocol): + __slots__ = ( + "_loop", + "_paused", + "_drain_waiter", + "_connection_lost", + "_reading_paused", + "transport", + ) + + def __init__(self, loop: asyncio.AbstractEventLoop) -> None: + self._loop: asyncio.AbstractEventLoop = loop + self._paused = False + self._drain_waiter: Optional[asyncio.Future[None]] = None + self._reading_paused = False + + self.transport: Optional[asyncio.Transport] = None + + @property + def connected(self) -> bool: + """Return True if the connection is open.""" + return self.transport is not None + + @property + def writing_paused(self) -> bool: + return self._paused + + def pause_writing(self) -> None: + assert not self._paused + self._paused = True + + def resume_writing(self) -> None: + assert self._paused + self._paused = False + + waiter = self._drain_waiter + if waiter is not None: + self._drain_waiter = None + if not waiter.done(): + waiter.set_result(None) + + def pause_reading(self) -> None: + if not self._reading_paused and self.transport is not None: + try: + self.transport.pause_reading() + except (AttributeError, NotImplementedError, RuntimeError): + pass + self._reading_paused = True + + def resume_reading(self) -> None: + if self._reading_paused and self.transport is not None: + try: + self.transport.resume_reading() + except (AttributeError, NotImplementedError, RuntimeError): + pass + self._reading_paused = False + + def connection_made(self, transport: asyncio.BaseTransport) -> None: + tr = cast(asyncio.Transport, transport) + tcp_nodelay(tr, True) + self.transport = tr + + def connection_lost(self, exc: Optional[BaseException]) -> None: + # Wake up the writer if currently paused. + self.transport = None + if not self._paused: + return + waiter = self._drain_waiter + if waiter is None: + return + self._drain_waiter = None + if waiter.done(): + return + if exc is None: + waiter.set_result(None) + else: + set_exception( + waiter, + ConnectionError("Connection lost"), + exc, + ) + + async def _drain_helper(self) -> None: + if self.transport is None: + raise ClientConnectionResetError("Connection lost") + if not self._paused: + return + waiter = self._drain_waiter + if waiter is None: + waiter = self._loop.create_future() + self._drain_waiter = waiter + await asyncio.shield(waiter) diff --git a/venv/lib/python3.12/site-packages/aiohttp/client.py b/venv/lib/python3.12/site-packages/aiohttp/client.py new file mode 100644 index 00000000..7c788e82 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/client.py @@ -0,0 +1,1550 @@ +"""HTTP Client for asyncio.""" + +import asyncio +import base64 +import hashlib +import json +import os +import sys +import traceback +import warnings +from contextlib import suppress +from types import TracebackType +from typing import ( + TYPE_CHECKING, + Any, + Awaitable, + Callable, + Coroutine, + Final, + FrozenSet, + Generator, + Generic, + Iterable, + List, + Mapping, + Optional, + Set, + Tuple, + Type, + TypedDict, + TypeVar, + Union, +) + +import attr +from multidict import CIMultiDict, MultiDict, MultiDictProxy, istr +from yarl import URL + +from . import hdrs, http, payload +from ._websocket.reader import WebSocketDataQueue +from .abc import AbstractCookieJar +from .client_exceptions import ( + ClientConnectionError, + ClientConnectionResetError, + ClientConnectorCertificateError, + ClientConnectorDNSError, + ClientConnectorError, + ClientConnectorSSLError, + ClientError, + ClientHttpProxyError, + ClientOSError, + ClientPayloadError, + ClientProxyConnectionError, + ClientResponseError, + ClientSSLError, + ConnectionTimeoutError, + ContentTypeError, + InvalidURL, + InvalidUrlClientError, + InvalidUrlRedirectClientError, + NonHttpUrlClientError, + NonHttpUrlRedirectClientError, + RedirectClientError, + ServerConnectionError, + ServerDisconnectedError, + ServerFingerprintMismatch, + ServerTimeoutError, + SocketTimeoutError, + TooManyRedirects, + WSMessageTypeError, + WSServerHandshakeError, +) +from .client_reqrep import ( + ClientRequest as ClientRequest, + ClientResponse as ClientResponse, + Fingerprint as Fingerprint, + RequestInfo as RequestInfo, + _merge_ssl_params, +) +from .client_ws import ( + DEFAULT_WS_CLIENT_TIMEOUT, + ClientWebSocketResponse as ClientWebSocketResponse, + ClientWSTimeout as ClientWSTimeout, +) +from .connector import ( + HTTP_AND_EMPTY_SCHEMA_SET, + BaseConnector as BaseConnector, + NamedPipeConnector as NamedPipeConnector, + TCPConnector as TCPConnector, + UnixConnector as UnixConnector, +) +from .cookiejar import CookieJar +from .helpers import ( + _SENTINEL, + DEBUG, + EMPTY_BODY_METHODS, + BasicAuth, + TimeoutHandle, + get_env_proxy_for_url, + sentinel, + strip_auth_from_url, +) +from .http import WS_KEY, HttpVersion, WebSocketReader, WebSocketWriter +from .http_websocket import WSHandshakeError, ws_ext_gen, ws_ext_parse +from .tracing import Trace, TraceConfig +from .typedefs import JSONEncoder, LooseCookies, LooseHeaders, Query, StrOrURL + +__all__ = ( + # client_exceptions + "ClientConnectionError", + "ClientConnectionResetError", + "ClientConnectorCertificateError", + "ClientConnectorDNSError", + "ClientConnectorError", + "ClientConnectorSSLError", + "ClientError", + "ClientHttpProxyError", + "ClientOSError", + "ClientPayloadError", + "ClientProxyConnectionError", + "ClientResponseError", + "ClientSSLError", + "ConnectionTimeoutError", + "ContentTypeError", + "InvalidURL", + "InvalidUrlClientError", + "RedirectClientError", + "NonHttpUrlClientError", + "InvalidUrlRedirectClientError", + "NonHttpUrlRedirectClientError", + "ServerConnectionError", + "ServerDisconnectedError", + "ServerFingerprintMismatch", + "ServerTimeoutError", + "SocketTimeoutError", + "TooManyRedirects", + "WSServerHandshakeError", + # client_reqrep + "ClientRequest", + "ClientResponse", + "Fingerprint", + "RequestInfo", + # connector + "BaseConnector", + "TCPConnector", + "UnixConnector", + "NamedPipeConnector", + # client_ws + "ClientWebSocketResponse", + # client + "ClientSession", + "ClientTimeout", + "ClientWSTimeout", + "request", + "WSMessageTypeError", +) + + +if TYPE_CHECKING: + from ssl import SSLContext +else: + SSLContext = None + +if sys.version_info >= (3, 11) and TYPE_CHECKING: + from typing import Unpack + + +class _RequestOptions(TypedDict, total=False): + params: Query + data: Any + json: Any + cookies: Union[LooseCookies, None] + headers: Union[LooseHeaders, None] + skip_auto_headers: Union[Iterable[str], None] + auth: Union[BasicAuth, None] + allow_redirects: bool + max_redirects: int + compress: Union[str, bool, None] + chunked: Union[bool, None] + expect100: bool + raise_for_status: Union[None, bool, Callable[[ClientResponse], Awaitable[None]]] + read_until_eof: bool + proxy: Union[StrOrURL, None] + proxy_auth: Union[BasicAuth, None] + timeout: "Union[ClientTimeout, _SENTINEL, None]" + ssl: Union[SSLContext, bool, Fingerprint] + server_hostname: Union[str, None] + proxy_headers: Union[LooseHeaders, None] + trace_request_ctx: Union[Mapping[str, Any], None] + read_bufsize: Union[int, None] + auto_decompress: Union[bool, None] + max_line_size: Union[int, None] + max_field_size: Union[int, None] + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class ClientTimeout: + total: Optional[float] = None + connect: Optional[float] = None + sock_read: Optional[float] = None + sock_connect: Optional[float] = None + ceil_threshold: float = 5 + + # pool_queue_timeout: Optional[float] = None + # dns_resolution_timeout: Optional[float] = None + # socket_connect_timeout: Optional[float] = None + # connection_acquiring_timeout: Optional[float] = None + # new_connection_timeout: Optional[float] = None + # http_header_timeout: Optional[float] = None + # response_body_timeout: Optional[float] = None + + # to create a timeout specific for a single request, either + # - create a completely new one to overwrite the default + # - or use http://www.attrs.org/en/stable/api.html#attr.evolve + # to overwrite the defaults + + +# 5 Minute default read timeout +DEFAULT_TIMEOUT: Final[ClientTimeout] = ClientTimeout(total=5 * 60, sock_connect=30) + +# https://www.rfc-editor.org/rfc/rfc9110#section-9.2.2 +IDEMPOTENT_METHODS = frozenset({"GET", "HEAD", "OPTIONS", "TRACE", "PUT", "DELETE"}) + +_RetType = TypeVar("_RetType", ClientResponse, ClientWebSocketResponse) +_CharsetResolver = Callable[[ClientResponse, bytes], str] + + +class ClientSession: + """First-class interface for making HTTP requests.""" + + ATTRS = frozenset( + [ + "_base_url", + "_base_url_origin", + "_source_traceback", + "_connector", + "_loop", + "_cookie_jar", + "_connector_owner", + "_default_auth", + "_version", + "_json_serialize", + "_requote_redirect_url", + "_timeout", + "_raise_for_status", + "_auto_decompress", + "_trust_env", + "_default_headers", + "_skip_auto_headers", + "_request_class", + "_response_class", + "_ws_response_class", + "_trace_configs", + "_read_bufsize", + "_max_line_size", + "_max_field_size", + "_resolve_charset", + "_default_proxy", + "_default_proxy_auth", + "_retry_connection", + "requote_redirect_url", + ] + ) + + _source_traceback: Optional[traceback.StackSummary] = None + _connector: Optional[BaseConnector] = None + + def __init__( + self, + base_url: Optional[StrOrURL] = None, + *, + connector: Optional[BaseConnector] = None, + loop: Optional[asyncio.AbstractEventLoop] = None, + cookies: Optional[LooseCookies] = None, + headers: Optional[LooseHeaders] = None, + proxy: Optional[StrOrURL] = None, + proxy_auth: Optional[BasicAuth] = None, + skip_auto_headers: Optional[Iterable[str]] = None, + auth: Optional[BasicAuth] = None, + json_serialize: JSONEncoder = json.dumps, + request_class: Type[ClientRequest] = ClientRequest, + response_class: Type[ClientResponse] = ClientResponse, + ws_response_class: Type[ClientWebSocketResponse] = ClientWebSocketResponse, + version: HttpVersion = http.HttpVersion11, + cookie_jar: Optional[AbstractCookieJar] = None, + connector_owner: bool = True, + raise_for_status: Union[ + bool, Callable[[ClientResponse], Awaitable[None]] + ] = False, + read_timeout: Union[float, _SENTINEL] = sentinel, + conn_timeout: Optional[float] = None, + timeout: Union[object, ClientTimeout] = sentinel, + auto_decompress: bool = True, + trust_env: bool = False, + requote_redirect_url: bool = True, + trace_configs: Optional[List[TraceConfig]] = None, + read_bufsize: int = 2**16, + max_line_size: int = 8190, + max_field_size: int = 8190, + fallback_charset_resolver: _CharsetResolver = lambda r, b: "utf-8", + ) -> None: + # We initialise _connector to None immediately, as it's referenced in __del__() + # and could cause issues if an exception occurs during initialisation. + self._connector: Optional[BaseConnector] = None + + if loop is None: + if connector is not None: + loop = connector._loop + + loop = loop or asyncio.get_running_loop() + + if base_url is None or isinstance(base_url, URL): + self._base_url: Optional[URL] = base_url + self._base_url_origin = None if base_url is None else base_url.origin() + else: + self._base_url = URL(base_url) + self._base_url_origin = self._base_url.origin() + assert self._base_url.absolute, "Only absolute URLs are supported" + if self._base_url is not None and not self._base_url.path.endswith("/"): + raise ValueError("base_url must have a trailing '/'") + + if timeout is sentinel or timeout is None: + self._timeout = DEFAULT_TIMEOUT + if read_timeout is not sentinel: + warnings.warn( + "read_timeout is deprecated, use timeout argument instead", + DeprecationWarning, + stacklevel=2, + ) + self._timeout = attr.evolve(self._timeout, total=read_timeout) + if conn_timeout is not None: + self._timeout = attr.evolve(self._timeout, connect=conn_timeout) + warnings.warn( + "conn_timeout is deprecated, use timeout argument instead", + DeprecationWarning, + stacklevel=2, + ) + else: + if not isinstance(timeout, ClientTimeout): + raise ValueError( + f"timeout parameter cannot be of {type(timeout)} type, " + "please use 'timeout=ClientTimeout(...)'", + ) + self._timeout = timeout + if read_timeout is not sentinel: + raise ValueError( + "read_timeout and timeout parameters " + "conflict, please setup " + "timeout.read" + ) + if conn_timeout is not None: + raise ValueError( + "conn_timeout and timeout parameters " + "conflict, please setup " + "timeout.connect" + ) + + if connector is None: + connector = TCPConnector(loop=loop) + + if connector._loop is not loop: + raise RuntimeError("Session and connector has to use same event loop") + + self._loop = loop + + if loop.get_debug(): + self._source_traceback = traceback.extract_stack(sys._getframe(1)) + + if cookie_jar is None: + cookie_jar = CookieJar(loop=loop) + self._cookie_jar = cookie_jar + + if cookies: + self._cookie_jar.update_cookies(cookies) + + self._connector = connector + self._connector_owner = connector_owner + self._default_auth = auth + self._version = version + self._json_serialize = json_serialize + self._raise_for_status = raise_for_status + self._auto_decompress = auto_decompress + self._trust_env = trust_env + self._requote_redirect_url = requote_redirect_url + self._read_bufsize = read_bufsize + self._max_line_size = max_line_size + self._max_field_size = max_field_size + + # Convert to list of tuples + if headers: + real_headers: CIMultiDict[str] = CIMultiDict(headers) + else: + real_headers = CIMultiDict() + self._default_headers: CIMultiDict[str] = real_headers + if skip_auto_headers is not None: + self._skip_auto_headers = frozenset(istr(i) for i in skip_auto_headers) + else: + self._skip_auto_headers = frozenset() + + self._request_class = request_class + self._response_class = response_class + self._ws_response_class = ws_response_class + + self._trace_configs = trace_configs or [] + for trace_config in self._trace_configs: + trace_config.freeze() + + self._resolve_charset = fallback_charset_resolver + + self._default_proxy = proxy + self._default_proxy_auth = proxy_auth + self._retry_connection: bool = True + + def __init_subclass__(cls: Type["ClientSession"]) -> None: + warnings.warn( + "Inheritance class {} from ClientSession " + "is discouraged".format(cls.__name__), + DeprecationWarning, + stacklevel=2, + ) + + if DEBUG: + + def __setattr__(self, name: str, val: Any) -> None: + if name not in self.ATTRS: + warnings.warn( + "Setting custom ClientSession.{} attribute " + "is discouraged".format(name), + DeprecationWarning, + stacklevel=2, + ) + super().__setattr__(name, val) + + def __del__(self, _warnings: Any = warnings) -> None: + if not self.closed: + kwargs = {"source": self} + _warnings.warn( + f"Unclosed client session {self!r}", ResourceWarning, **kwargs + ) + context = {"client_session": self, "message": "Unclosed client session"} + if self._source_traceback is not None: + context["source_traceback"] = self._source_traceback + self._loop.call_exception_handler(context) + + if sys.version_info >= (3, 11) and TYPE_CHECKING: + + def request( + self, + method: str, + url: StrOrURL, + **kwargs: Unpack[_RequestOptions], + ) -> "_RequestContextManager": ... + + else: + + def request( + self, method: str, url: StrOrURL, **kwargs: Any + ) -> "_RequestContextManager": + """Perform HTTP request.""" + return _RequestContextManager(self._request(method, url, **kwargs)) + + def _build_url(self, str_or_url: StrOrURL) -> URL: + url = URL(str_or_url) + if self._base_url is None: + return url + else: + assert not url.absolute + return self._base_url.join(url) + + async def _request( + self, + method: str, + str_or_url: StrOrURL, + *, + params: Query = None, + data: Any = None, + json: Any = None, + cookies: Optional[LooseCookies] = None, + headers: Optional[LooseHeaders] = None, + skip_auto_headers: Optional[Iterable[str]] = None, + auth: Optional[BasicAuth] = None, + allow_redirects: bool = True, + max_redirects: int = 10, + compress: Union[str, bool, None] = None, + chunked: Optional[bool] = None, + expect100: bool = False, + raise_for_status: Union[ + None, bool, Callable[[ClientResponse], Awaitable[None]] + ] = None, + read_until_eof: bool = True, + proxy: Optional[StrOrURL] = None, + proxy_auth: Optional[BasicAuth] = None, + timeout: Union[ClientTimeout, _SENTINEL] = sentinel, + verify_ssl: Optional[bool] = None, + fingerprint: Optional[bytes] = None, + ssl_context: Optional[SSLContext] = None, + ssl: Union[SSLContext, bool, Fingerprint] = True, + server_hostname: Optional[str] = None, + proxy_headers: Optional[LooseHeaders] = None, + trace_request_ctx: Optional[Mapping[str, Any]] = None, + read_bufsize: Optional[int] = None, + auto_decompress: Optional[bool] = None, + max_line_size: Optional[int] = None, + max_field_size: Optional[int] = None, + ) -> ClientResponse: + + # NOTE: timeout clamps existing connect and read timeouts. We cannot + # set the default to None because we need to detect if the user wants + # to use the existing timeouts by setting timeout to None. + + if self.closed: + raise RuntimeError("Session is closed") + + ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint) + + if data is not None and json is not None: + raise ValueError( + "data and json parameters can not be used at the same time" + ) + elif json is not None: + data = payload.JsonPayload(json, dumps=self._json_serialize) + + if not isinstance(chunked, bool) and chunked is not None: + warnings.warn("Chunk size is deprecated #1615", DeprecationWarning) + + redirects = 0 + history: List[ClientResponse] = [] + version = self._version + params = params or {} + + # Merge with default headers and transform to CIMultiDict + headers = self._prepare_headers(headers) + + try: + url = self._build_url(str_or_url) + except ValueError as e: + raise InvalidUrlClientError(str_or_url) from e + + assert self._connector is not None + if url.scheme not in self._connector.allowed_protocol_schema_set: + raise NonHttpUrlClientError(url) + + skip_headers: Optional[Iterable[istr]] + if skip_auto_headers is not None: + skip_headers = { + istr(i) for i in skip_auto_headers + } | self._skip_auto_headers + elif self._skip_auto_headers: + skip_headers = self._skip_auto_headers + else: + skip_headers = None + + if proxy is None: + proxy = self._default_proxy + if proxy_auth is None: + proxy_auth = self._default_proxy_auth + + if proxy is None: + proxy_headers = None + else: + proxy_headers = self._prepare_headers(proxy_headers) + try: + proxy = URL(proxy) + except ValueError as e: + raise InvalidURL(proxy) from e + + if timeout is sentinel: + real_timeout: ClientTimeout = self._timeout + else: + if not isinstance(timeout, ClientTimeout): + real_timeout = ClientTimeout(total=timeout) + else: + real_timeout = timeout + # timeout is cumulative for all request operations + # (request, redirects, responses, data consuming) + tm = TimeoutHandle( + self._loop, real_timeout.total, ceil_threshold=real_timeout.ceil_threshold + ) + handle = tm.start() + + if read_bufsize is None: + read_bufsize = self._read_bufsize + + if auto_decompress is None: + auto_decompress = self._auto_decompress + + if max_line_size is None: + max_line_size = self._max_line_size + + if max_field_size is None: + max_field_size = self._max_field_size + + traces = [ + Trace( + self, + trace_config, + trace_config.trace_config_ctx(trace_request_ctx=trace_request_ctx), + ) + for trace_config in self._trace_configs + ] + + for trace in traces: + await trace.send_request_start(method, url.update_query(params), headers) + + timer = tm.timer() + try: + with timer: + # https://www.rfc-editor.org/rfc/rfc9112.html#name-retrying-requests + retry_persistent_connection = ( + self._retry_connection and method in IDEMPOTENT_METHODS + ) + while True: + url, auth_from_url = strip_auth_from_url(url) + if not url.raw_host: + # NOTE: Bail early, otherwise, causes `InvalidURL` through + # NOTE: `self._request_class()` below. + err_exc_cls = ( + InvalidUrlRedirectClientError + if redirects + else InvalidUrlClientError + ) + raise err_exc_cls(url) + # If `auth` was passed for an already authenticated URL, + # disallow only if this is the initial URL; this is to avoid issues + # with sketchy redirects that are not the caller's responsibility + if not history and (auth and auth_from_url): + raise ValueError( + "Cannot combine AUTH argument with " + "credentials encoded in URL" + ) + + # Override the auth with the one from the URL only if we + # have no auth, or if we got an auth from a redirect URL + if auth is None or (history and auth_from_url is not None): + auth = auth_from_url + + if ( + auth is None + and self._default_auth + and ( + not self._base_url or self._base_url_origin == url.origin() + ) + ): + auth = self._default_auth + # It would be confusing if we support explicit + # Authorization header with auth argument + if ( + headers is not None + and auth is not None + and hdrs.AUTHORIZATION in headers + ): + raise ValueError( + "Cannot combine AUTHORIZATION header " + "with AUTH argument or credentials " + "encoded in URL" + ) + + all_cookies = self._cookie_jar.filter_cookies(url) + + if cookies is not None: + tmp_cookie_jar = CookieJar( + quote_cookie=self._cookie_jar.quote_cookie + ) + tmp_cookie_jar.update_cookies(cookies) + req_cookies = tmp_cookie_jar.filter_cookies(url) + if req_cookies: + all_cookies.load(req_cookies) + + if proxy is not None: + proxy = URL(proxy) + elif self._trust_env: + with suppress(LookupError): + proxy, proxy_auth = get_env_proxy_for_url(url) + + req = self._request_class( + method, + url, + params=params, + headers=headers, + skip_auto_headers=skip_headers, + data=data, + cookies=all_cookies, + auth=auth, + version=version, + compress=compress, + chunked=chunked, + expect100=expect100, + loop=self._loop, + response_class=self._response_class, + proxy=proxy, + proxy_auth=proxy_auth, + timer=timer, + session=self, + ssl=ssl if ssl is not None else True, + server_hostname=server_hostname, + proxy_headers=proxy_headers, + traces=traces, + trust_env=self.trust_env, + ) + + # connection timeout + try: + conn = await self._connector.connect( + req, traces=traces, timeout=real_timeout + ) + except asyncio.TimeoutError as exc: + raise ConnectionTimeoutError( + f"Connection timeout to host {url}" + ) from exc + + assert conn.transport is not None + + assert conn.protocol is not None + conn.protocol.set_response_params( + timer=timer, + skip_payload=method in EMPTY_BODY_METHODS, + read_until_eof=read_until_eof, + auto_decompress=auto_decompress, + read_timeout=real_timeout.sock_read, + read_bufsize=read_bufsize, + timeout_ceil_threshold=self._connector._timeout_ceil_threshold, + max_line_size=max_line_size, + max_field_size=max_field_size, + ) + + try: + try: + resp = await req.send(conn) + try: + await resp.start(conn) + except BaseException: + resp.close() + raise + except BaseException: + conn.close() + raise + except (ClientOSError, ServerDisconnectedError): + if retry_persistent_connection: + retry_persistent_connection = False + continue + raise + except ClientError: + raise + except OSError as exc: + if exc.errno is None and isinstance(exc, asyncio.TimeoutError): + raise + raise ClientOSError(*exc.args) from exc + + if cookies := resp._cookies: + self._cookie_jar.update_cookies(cookies, resp.url) + + # redirects + if resp.status in (301, 302, 303, 307, 308) and allow_redirects: + + for trace in traces: + await trace.send_request_redirect( + method, url.update_query(params), headers, resp + ) + + redirects += 1 + history.append(resp) + if max_redirects and redirects >= max_redirects: + resp.close() + raise TooManyRedirects( + history[0].request_info, tuple(history) + ) + + # For 301 and 302, mimic IE, now changed in RFC + # https://github.com/kennethreitz/requests/pull/269 + if (resp.status == 303 and resp.method != hdrs.METH_HEAD) or ( + resp.status in (301, 302) and resp.method == hdrs.METH_POST + ): + method = hdrs.METH_GET + data = None + if headers.get(hdrs.CONTENT_LENGTH): + headers.pop(hdrs.CONTENT_LENGTH) + + r_url = resp.headers.get(hdrs.LOCATION) or resp.headers.get( + hdrs.URI + ) + if r_url is None: + # see github.com/aio-libs/aiohttp/issues/2022 + break + else: + # reading from correct redirection + # response is forbidden + resp.release() + + try: + parsed_redirect_url = URL( + r_url, encoded=not self._requote_redirect_url + ) + except ValueError as e: + raise InvalidUrlRedirectClientError( + r_url, + "Server attempted redirecting to a location that does not look like a URL", + ) from e + + scheme = parsed_redirect_url.scheme + if scheme not in HTTP_AND_EMPTY_SCHEMA_SET: + resp.close() + raise NonHttpUrlRedirectClientError(r_url) + elif not scheme: + parsed_redirect_url = url.join(parsed_redirect_url) + + try: + redirect_origin = parsed_redirect_url.origin() + except ValueError as origin_val_err: + raise InvalidUrlRedirectClientError( + parsed_redirect_url, + "Invalid redirect URL origin", + ) from origin_val_err + + if url.origin() != redirect_origin: + auth = None + headers.pop(hdrs.AUTHORIZATION, None) + + url = parsed_redirect_url + params = {} + resp.release() + continue + + break + + # check response status + if raise_for_status is None: + raise_for_status = self._raise_for_status + + if raise_for_status is None: + pass + elif callable(raise_for_status): + await raise_for_status(resp) + elif raise_for_status: + resp.raise_for_status() + + # register connection + if handle is not None: + if resp.connection is not None: + resp.connection.add_callback(handle.cancel) + else: + handle.cancel() + + resp._history = tuple(history) + + for trace in traces: + await trace.send_request_end( + method, url.update_query(params), headers, resp + ) + return resp + + except BaseException as e: + # cleanup timer + tm.close() + if handle: + handle.cancel() + handle = None + + for trace in traces: + await trace.send_request_exception( + method, url.update_query(params), headers, e + ) + raise + + def ws_connect( + self, + url: StrOrURL, + *, + method: str = hdrs.METH_GET, + protocols: Iterable[str] = (), + timeout: Union[ClientWSTimeout, _SENTINEL] = sentinel, + receive_timeout: Optional[float] = None, + autoclose: bool = True, + autoping: bool = True, + heartbeat: Optional[float] = None, + auth: Optional[BasicAuth] = None, + origin: Optional[str] = None, + params: Query = None, + headers: Optional[LooseHeaders] = None, + proxy: Optional[StrOrURL] = None, + proxy_auth: Optional[BasicAuth] = None, + ssl: Union[SSLContext, bool, Fingerprint] = True, + verify_ssl: Optional[bool] = None, + fingerprint: Optional[bytes] = None, + ssl_context: Optional[SSLContext] = None, + server_hostname: Optional[str] = None, + proxy_headers: Optional[LooseHeaders] = None, + compress: int = 0, + max_msg_size: int = 4 * 1024 * 1024, + ) -> "_WSRequestContextManager": + """Initiate websocket connection.""" + return _WSRequestContextManager( + self._ws_connect( + url, + method=method, + protocols=protocols, + timeout=timeout, + receive_timeout=receive_timeout, + autoclose=autoclose, + autoping=autoping, + heartbeat=heartbeat, + auth=auth, + origin=origin, + params=params, + headers=headers, + proxy=proxy, + proxy_auth=proxy_auth, + ssl=ssl, + verify_ssl=verify_ssl, + fingerprint=fingerprint, + ssl_context=ssl_context, + server_hostname=server_hostname, + proxy_headers=proxy_headers, + compress=compress, + max_msg_size=max_msg_size, + ) + ) + + async def _ws_connect( + self, + url: StrOrURL, + *, + method: str = hdrs.METH_GET, + protocols: Iterable[str] = (), + timeout: Union[ClientWSTimeout, _SENTINEL] = sentinel, + receive_timeout: Optional[float] = None, + autoclose: bool = True, + autoping: bool = True, + heartbeat: Optional[float] = None, + auth: Optional[BasicAuth] = None, + origin: Optional[str] = None, + params: Query = None, + headers: Optional[LooseHeaders] = None, + proxy: Optional[StrOrURL] = None, + proxy_auth: Optional[BasicAuth] = None, + ssl: Union[SSLContext, bool, Fingerprint] = True, + verify_ssl: Optional[bool] = None, + fingerprint: Optional[bytes] = None, + ssl_context: Optional[SSLContext] = None, + server_hostname: Optional[str] = None, + proxy_headers: Optional[LooseHeaders] = None, + compress: int = 0, + max_msg_size: int = 4 * 1024 * 1024, + ) -> ClientWebSocketResponse: + if timeout is not sentinel: + if isinstance(timeout, ClientWSTimeout): + ws_timeout = timeout + else: + warnings.warn( + "parameter 'timeout' of type 'float' " + "is deprecated, please use " + "'timeout=ClientWSTimeout(ws_close=...)'", + DeprecationWarning, + stacklevel=2, + ) + ws_timeout = ClientWSTimeout(ws_close=timeout) + else: + ws_timeout = DEFAULT_WS_CLIENT_TIMEOUT + if receive_timeout is not None: + warnings.warn( + "float parameter 'receive_timeout' " + "is deprecated, please use parameter " + "'timeout=ClientWSTimeout(ws_receive=...)'", + DeprecationWarning, + stacklevel=2, + ) + ws_timeout = attr.evolve(ws_timeout, ws_receive=receive_timeout) + + if headers is None: + real_headers: CIMultiDict[str] = CIMultiDict() + else: + real_headers = CIMultiDict(headers) + + default_headers = { + hdrs.UPGRADE: "websocket", + hdrs.CONNECTION: "Upgrade", + hdrs.SEC_WEBSOCKET_VERSION: "13", + } + + for key, value in default_headers.items(): + real_headers.setdefault(key, value) + + sec_key = base64.b64encode(os.urandom(16)) + real_headers[hdrs.SEC_WEBSOCKET_KEY] = sec_key.decode() + + if protocols: + real_headers[hdrs.SEC_WEBSOCKET_PROTOCOL] = ",".join(protocols) + if origin is not None: + real_headers[hdrs.ORIGIN] = origin + if compress: + extstr = ws_ext_gen(compress=compress) + real_headers[hdrs.SEC_WEBSOCKET_EXTENSIONS] = extstr + + # For the sake of backward compatibility, if user passes in None, convert it to True + if ssl is None: + warnings.warn( + "ssl=None is deprecated, please use ssl=True", + DeprecationWarning, + stacklevel=2, + ) + ssl = True + ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint) + + # send request + resp = await self.request( + method, + url, + params=params, + headers=real_headers, + read_until_eof=False, + auth=auth, + proxy=proxy, + proxy_auth=proxy_auth, + ssl=ssl, + server_hostname=server_hostname, + proxy_headers=proxy_headers, + ) + + try: + # check handshake + if resp.status != 101: + raise WSServerHandshakeError( + resp.request_info, + resp.history, + message="Invalid response status", + status=resp.status, + headers=resp.headers, + ) + + if resp.headers.get(hdrs.UPGRADE, "").lower() != "websocket": + raise WSServerHandshakeError( + resp.request_info, + resp.history, + message="Invalid upgrade header", + status=resp.status, + headers=resp.headers, + ) + + if resp.headers.get(hdrs.CONNECTION, "").lower() != "upgrade": + raise WSServerHandshakeError( + resp.request_info, + resp.history, + message="Invalid connection header", + status=resp.status, + headers=resp.headers, + ) + + # key calculation + r_key = resp.headers.get(hdrs.SEC_WEBSOCKET_ACCEPT, "") + match = base64.b64encode(hashlib.sha1(sec_key + WS_KEY).digest()).decode() + if r_key != match: + raise WSServerHandshakeError( + resp.request_info, + resp.history, + message="Invalid challenge response", + status=resp.status, + headers=resp.headers, + ) + + # websocket protocol + protocol = None + if protocols and hdrs.SEC_WEBSOCKET_PROTOCOL in resp.headers: + resp_protocols = [ + proto.strip() + for proto in resp.headers[hdrs.SEC_WEBSOCKET_PROTOCOL].split(",") + ] + + for proto in resp_protocols: + if proto in protocols: + protocol = proto + break + + # websocket compress + notakeover = False + if compress: + compress_hdrs = resp.headers.get(hdrs.SEC_WEBSOCKET_EXTENSIONS) + if compress_hdrs: + try: + compress, notakeover = ws_ext_parse(compress_hdrs) + except WSHandshakeError as exc: + raise WSServerHandshakeError( + resp.request_info, + resp.history, + message=exc.args[0], + status=resp.status, + headers=resp.headers, + ) from exc + else: + compress = 0 + notakeover = False + + conn = resp.connection + assert conn is not None + conn_proto = conn.protocol + assert conn_proto is not None + + # For WS connection the read_timeout must be either receive_timeout or greater + # None == no timeout, i.e. infinite timeout, so None is the max timeout possible + if ws_timeout.ws_receive is None: + # Reset regardless + conn_proto.read_timeout = None + elif conn_proto.read_timeout is not None: + conn_proto.read_timeout = max( + ws_timeout.ws_receive, conn_proto.read_timeout + ) + + transport = conn.transport + assert transport is not None + reader = WebSocketDataQueue(conn_proto, 2**16, loop=self._loop) + conn_proto.set_parser(WebSocketReader(reader, max_msg_size), reader) + writer = WebSocketWriter( + conn_proto, + transport, + use_mask=True, + compress=compress, + notakeover=notakeover, + ) + except BaseException: + resp.close() + raise + else: + return self._ws_response_class( + reader, + writer, + protocol, + resp, + ws_timeout, + autoclose, + autoping, + self._loop, + heartbeat=heartbeat, + compress=compress, + client_notakeover=notakeover, + ) + + def _prepare_headers(self, headers: Optional[LooseHeaders]) -> "CIMultiDict[str]": + """Add default headers and transform it to CIMultiDict""" + # Convert headers to MultiDict + result = CIMultiDict(self._default_headers) + if headers: + if not isinstance(headers, (MultiDictProxy, MultiDict)): + headers = CIMultiDict(headers) + added_names: Set[str] = set() + for key, value in headers.items(): + if key in added_names: + result.add(key, value) + else: + result[key] = value + added_names.add(key) + return result + + if sys.version_info >= (3, 11) and TYPE_CHECKING: + + def get( + self, + url: StrOrURL, + **kwargs: Unpack[_RequestOptions], + ) -> "_RequestContextManager": ... + + def options( + self, + url: StrOrURL, + **kwargs: Unpack[_RequestOptions], + ) -> "_RequestContextManager": ... + + def head( + self, + url: StrOrURL, + **kwargs: Unpack[_RequestOptions], + ) -> "_RequestContextManager": ... + + def post( + self, + url: StrOrURL, + **kwargs: Unpack[_RequestOptions], + ) -> "_RequestContextManager": ... + + def put( + self, + url: StrOrURL, + **kwargs: Unpack[_RequestOptions], + ) -> "_RequestContextManager": ... + + def patch( + self, + url: StrOrURL, + **kwargs: Unpack[_RequestOptions], + ) -> "_RequestContextManager": ... + + def delete( + self, + url: StrOrURL, + **kwargs: Unpack[_RequestOptions], + ) -> "_RequestContextManager": ... + + else: + + def get( + self, url: StrOrURL, *, allow_redirects: bool = True, **kwargs: Any + ) -> "_RequestContextManager": + """Perform HTTP GET request.""" + return _RequestContextManager( + self._request( + hdrs.METH_GET, url, allow_redirects=allow_redirects, **kwargs + ) + ) + + def options( + self, url: StrOrURL, *, allow_redirects: bool = True, **kwargs: Any + ) -> "_RequestContextManager": + """Perform HTTP OPTIONS request.""" + return _RequestContextManager( + self._request( + hdrs.METH_OPTIONS, url, allow_redirects=allow_redirects, **kwargs + ) + ) + + def head( + self, url: StrOrURL, *, allow_redirects: bool = False, **kwargs: Any + ) -> "_RequestContextManager": + """Perform HTTP HEAD request.""" + return _RequestContextManager( + self._request( + hdrs.METH_HEAD, url, allow_redirects=allow_redirects, **kwargs + ) + ) + + def post( + self, url: StrOrURL, *, data: Any = None, **kwargs: Any + ) -> "_RequestContextManager": + """Perform HTTP POST request.""" + return _RequestContextManager( + self._request(hdrs.METH_POST, url, data=data, **kwargs) + ) + + def put( + self, url: StrOrURL, *, data: Any = None, **kwargs: Any + ) -> "_RequestContextManager": + """Perform HTTP PUT request.""" + return _RequestContextManager( + self._request(hdrs.METH_PUT, url, data=data, **kwargs) + ) + + def patch( + self, url: StrOrURL, *, data: Any = None, **kwargs: Any + ) -> "_RequestContextManager": + """Perform HTTP PATCH request.""" + return _RequestContextManager( + self._request(hdrs.METH_PATCH, url, data=data, **kwargs) + ) + + def delete(self, url: StrOrURL, **kwargs: Any) -> "_RequestContextManager": + """Perform HTTP DELETE request.""" + return _RequestContextManager( + self._request(hdrs.METH_DELETE, url, **kwargs) + ) + + async def close(self) -> None: + """Close underlying connector. + + Release all acquired resources. + """ + if not self.closed: + if self._connector is not None and self._connector_owner: + await self._connector.close() + self._connector = None + + @property + def closed(self) -> bool: + """Is client session closed. + + A readonly property. + """ + return self._connector is None or self._connector.closed + + @property + def connector(self) -> Optional[BaseConnector]: + """Connector instance used for the session.""" + return self._connector + + @property + def cookie_jar(self) -> AbstractCookieJar: + """The session cookies.""" + return self._cookie_jar + + @property + def version(self) -> Tuple[int, int]: + """The session HTTP protocol version.""" + return self._version + + @property + def requote_redirect_url(self) -> bool: + """Do URL requoting on redirection handling.""" + return self._requote_redirect_url + + @requote_redirect_url.setter + def requote_redirect_url(self, val: bool) -> None: + """Do URL requoting on redirection handling.""" + warnings.warn( + "session.requote_redirect_url modification is deprecated #2778", + DeprecationWarning, + stacklevel=2, + ) + self._requote_redirect_url = val + + @property + def loop(self) -> asyncio.AbstractEventLoop: + """Session's loop.""" + warnings.warn( + "client.loop property is deprecated", DeprecationWarning, stacklevel=2 + ) + return self._loop + + @property + def timeout(self) -> ClientTimeout: + """Timeout for the session.""" + return self._timeout + + @property + def headers(self) -> "CIMultiDict[str]": + """The default headers of the client session.""" + return self._default_headers + + @property + def skip_auto_headers(self) -> FrozenSet[istr]: + """Headers for which autogeneration should be skipped""" + return self._skip_auto_headers + + @property + def auth(self) -> Optional[BasicAuth]: + """An object that represents HTTP Basic Authorization""" + return self._default_auth + + @property + def json_serialize(self) -> JSONEncoder: + """Json serializer callable""" + return self._json_serialize + + @property + def connector_owner(self) -> bool: + """Should connector be closed on session closing""" + return self._connector_owner + + @property + def raise_for_status( + self, + ) -> Union[bool, Callable[[ClientResponse], Awaitable[None]]]: + """Should `ClientResponse.raise_for_status()` be called for each response.""" + return self._raise_for_status + + @property + def auto_decompress(self) -> bool: + """Should the body response be automatically decompressed.""" + return self._auto_decompress + + @property + def trust_env(self) -> bool: + """ + Should proxies information from environment or netrc be trusted. + + Information is from HTTP_PROXY / HTTPS_PROXY environment variables + or ~/.netrc file if present. + """ + return self._trust_env + + @property + def trace_configs(self) -> List[TraceConfig]: + """A list of TraceConfig instances used for client tracing""" + return self._trace_configs + + def detach(self) -> None: + """Detach connector from session without closing the former. + + Session is switched to closed state anyway. + """ + self._connector = None + + def __enter__(self) -> None: + raise TypeError("Use async with instead") + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + # __exit__ should exist in pair with __enter__ but never executed + pass # pragma: no cover + + async def __aenter__(self) -> "ClientSession": + return self + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + await self.close() + + +class _BaseRequestContextManager(Coroutine[Any, Any, _RetType], Generic[_RetType]): + + __slots__ = ("_coro", "_resp") + + def __init__(self, coro: Coroutine["asyncio.Future[Any]", None, _RetType]) -> None: + self._coro: Coroutine["asyncio.Future[Any]", None, _RetType] = coro + + def send(self, arg: None) -> "asyncio.Future[Any]": + return self._coro.send(arg) + + def throw(self, *args: Any, **kwargs: Any) -> "asyncio.Future[Any]": + return self._coro.throw(*args, **kwargs) + + def close(self) -> None: + return self._coro.close() + + def __await__(self) -> Generator[Any, None, _RetType]: + ret = self._coro.__await__() + return ret + + def __iter__(self) -> Generator[Any, None, _RetType]: + return self.__await__() + + async def __aenter__(self) -> _RetType: + self._resp: _RetType = await self._coro + return await self._resp.__aenter__() + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc: Optional[BaseException], + tb: Optional[TracebackType], + ) -> None: + await self._resp.__aexit__(exc_type, exc, tb) + + +_RequestContextManager = _BaseRequestContextManager[ClientResponse] +_WSRequestContextManager = _BaseRequestContextManager[ClientWebSocketResponse] + + +class _SessionRequestContextManager: + + __slots__ = ("_coro", "_resp", "_session") + + def __init__( + self, + coro: Coroutine["asyncio.Future[Any]", None, ClientResponse], + session: ClientSession, + ) -> None: + self._coro = coro + self._resp: Optional[ClientResponse] = None + self._session = session + + async def __aenter__(self) -> ClientResponse: + try: + self._resp = await self._coro + except BaseException: + await self._session.close() + raise + else: + return self._resp + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc: Optional[BaseException], + tb: Optional[TracebackType], + ) -> None: + assert self._resp is not None + self._resp.close() + await self._session.close() + + +if sys.version_info >= (3, 11) and TYPE_CHECKING: + + def request( + method: str, + url: StrOrURL, + *, + version: HttpVersion = http.HttpVersion11, + connector: Optional[BaseConnector] = None, + loop: Optional[asyncio.AbstractEventLoop] = None, + **kwargs: Unpack[_RequestOptions], + ) -> _SessionRequestContextManager: ... + +else: + + def request( + method: str, + url: StrOrURL, + *, + version: HttpVersion = http.HttpVersion11, + connector: Optional[BaseConnector] = None, + loop: Optional[asyncio.AbstractEventLoop] = None, + **kwargs: Any, + ) -> _SessionRequestContextManager: + """Constructs and sends a request. + + Returns response object. + method - HTTP method + url - request url + params - (optional) Dictionary or bytes to be sent in the query + string of the new request + data - (optional) Dictionary, bytes, or file-like object to + send in the body of the request + json - (optional) Any json compatible python object + headers - (optional) Dictionary of HTTP Headers to send with + the request + cookies - (optional) Dict object to send with the request + auth - (optional) BasicAuth named tuple represent HTTP Basic Auth + auth - aiohttp.helpers.BasicAuth + allow_redirects - (optional) If set to False, do not follow + redirects + version - Request HTTP version. + compress - Set to True if request has to be compressed + with deflate encoding. + chunked - Set to chunk size for chunked transfer encoding. + expect100 - Expect 100-continue response from server. + connector - BaseConnector sub-class instance to support + connection pooling. + read_until_eof - Read response until eof if response + does not have Content-Length header. + loop - Optional event loop. + timeout - Optional ClientTimeout settings structure, 5min + total timeout by default. + Usage:: + >>> import aiohttp + >>> async with aiohttp.request('GET', 'http://python.org/') as resp: + ... print(resp) + ... data = await resp.read() + + """ + connector_owner = False + if connector is None: + connector_owner = True + connector = TCPConnector(loop=loop, force_close=True) + + session = ClientSession( + loop=loop, + cookies=kwargs.pop("cookies", None), + version=version, + timeout=kwargs.pop("timeout", sentinel), + connector=connector, + connector_owner=connector_owner, + ) + + return _SessionRequestContextManager( + session._request(method, url, **kwargs), + session, + ) diff --git a/venv/lib/python3.12/site-packages/aiohttp/client_exceptions.py b/venv/lib/python3.12/site-packages/aiohttp/client_exceptions.py new file mode 100644 index 00000000..1d298e9a --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/client_exceptions.py @@ -0,0 +1,421 @@ +"""HTTP related errors.""" + +import asyncio +import warnings +from typing import TYPE_CHECKING, Optional, Tuple, Union + +from multidict import MultiMapping + +from .typedefs import StrOrURL + +if TYPE_CHECKING: + import ssl + + SSLContext = ssl.SSLContext +else: + try: + import ssl + + SSLContext = ssl.SSLContext + except ImportError: # pragma: no cover + ssl = SSLContext = None # type: ignore[assignment] + +if TYPE_CHECKING: + from .client_reqrep import ClientResponse, ConnectionKey, Fingerprint, RequestInfo + from .http_parser import RawResponseMessage +else: + RequestInfo = ClientResponse = ConnectionKey = RawResponseMessage = None + +__all__ = ( + "ClientError", + "ClientConnectionError", + "ClientConnectionResetError", + "ClientOSError", + "ClientConnectorError", + "ClientProxyConnectionError", + "ClientSSLError", + "ClientConnectorDNSError", + "ClientConnectorSSLError", + "ClientConnectorCertificateError", + "ConnectionTimeoutError", + "SocketTimeoutError", + "ServerConnectionError", + "ServerTimeoutError", + "ServerDisconnectedError", + "ServerFingerprintMismatch", + "ClientResponseError", + "ClientHttpProxyError", + "WSServerHandshakeError", + "ContentTypeError", + "ClientPayloadError", + "InvalidURL", + "InvalidUrlClientError", + "RedirectClientError", + "NonHttpUrlClientError", + "InvalidUrlRedirectClientError", + "NonHttpUrlRedirectClientError", + "WSMessageTypeError", +) + + +class ClientError(Exception): + """Base class for client connection errors.""" + + +class ClientResponseError(ClientError): + """Base class for exceptions that occur after getting a response. + + request_info: An instance of RequestInfo. + history: A sequence of responses, if redirects occurred. + status: HTTP status code. + message: Error message. + headers: Response headers. + """ + + def __init__( + self, + request_info: RequestInfo, + history: Tuple[ClientResponse, ...], + *, + code: Optional[int] = None, + status: Optional[int] = None, + message: str = "", + headers: Optional[MultiMapping[str]] = None, + ) -> None: + self.request_info = request_info + if code is not None: + if status is not None: + raise ValueError( + "Both code and status arguments are provided; " + "code is deprecated, use status instead" + ) + warnings.warn( + "code argument is deprecated, use status instead", + DeprecationWarning, + stacklevel=2, + ) + if status is not None: + self.status = status + elif code is not None: + self.status = code + else: + self.status = 0 + self.message = message + self.headers = headers + self.history = history + self.args = (request_info, history) + + def __str__(self) -> str: + return "{}, message={!r}, url={!r}".format( + self.status, + self.message, + str(self.request_info.real_url), + ) + + def __repr__(self) -> str: + args = f"{self.request_info!r}, {self.history!r}" + if self.status != 0: + args += f", status={self.status!r}" + if self.message != "": + args += f", message={self.message!r}" + if self.headers is not None: + args += f", headers={self.headers!r}" + return f"{type(self).__name__}({args})" + + @property + def code(self) -> int: + warnings.warn( + "code property is deprecated, use status instead", + DeprecationWarning, + stacklevel=2, + ) + return self.status + + @code.setter + def code(self, value: int) -> None: + warnings.warn( + "code property is deprecated, use status instead", + DeprecationWarning, + stacklevel=2, + ) + self.status = value + + +class ContentTypeError(ClientResponseError): + """ContentType found is not valid.""" + + +class WSServerHandshakeError(ClientResponseError): + """websocket server handshake error.""" + + +class ClientHttpProxyError(ClientResponseError): + """HTTP proxy error. + + Raised in :class:`aiohttp.connector.TCPConnector` if + proxy responds with status other than ``200 OK`` + on ``CONNECT`` request. + """ + + +class TooManyRedirects(ClientResponseError): + """Client was redirected too many times.""" + + +class ClientConnectionError(ClientError): + """Base class for client socket errors.""" + + +class ClientConnectionResetError(ClientConnectionError, ConnectionResetError): + """ConnectionResetError""" + + +class ClientOSError(ClientConnectionError, OSError): + """OSError error.""" + + +class ClientConnectorError(ClientOSError): + """Client connector error. + + Raised in :class:`aiohttp.connector.TCPConnector` if + a connection can not be established. + """ + + def __init__(self, connection_key: ConnectionKey, os_error: OSError) -> None: + self._conn_key = connection_key + self._os_error = os_error + super().__init__(os_error.errno, os_error.strerror) + self.args = (connection_key, os_error) + + @property + def os_error(self) -> OSError: + return self._os_error + + @property + def host(self) -> str: + return self._conn_key.host + + @property + def port(self) -> Optional[int]: + return self._conn_key.port + + @property + def ssl(self) -> Union[SSLContext, bool, "Fingerprint"]: + return self._conn_key.ssl + + def __str__(self) -> str: + return "Cannot connect to host {0.host}:{0.port} ssl:{1} [{2}]".format( + self, "default" if self.ssl is True else self.ssl, self.strerror + ) + + # OSError.__reduce__ does too much black magick + __reduce__ = BaseException.__reduce__ + + +class ClientConnectorDNSError(ClientConnectorError): + """DNS resolution failed during client connection. + + Raised in :class:`aiohttp.connector.TCPConnector` if + DNS resolution fails. + """ + + +class ClientProxyConnectionError(ClientConnectorError): + """Proxy connection error. + + Raised in :class:`aiohttp.connector.TCPConnector` if + connection to proxy can not be established. + """ + + +class UnixClientConnectorError(ClientConnectorError): + """Unix connector error. + + Raised in :py:class:`aiohttp.connector.UnixConnector` + if connection to unix socket can not be established. + """ + + def __init__( + self, path: str, connection_key: ConnectionKey, os_error: OSError + ) -> None: + self._path = path + super().__init__(connection_key, os_error) + + @property + def path(self) -> str: + return self._path + + def __str__(self) -> str: + return "Cannot connect to unix socket {0.path} ssl:{1} [{2}]".format( + self, "default" if self.ssl is True else self.ssl, self.strerror + ) + + +class ServerConnectionError(ClientConnectionError): + """Server connection errors.""" + + +class ServerDisconnectedError(ServerConnectionError): + """Server disconnected.""" + + def __init__(self, message: Union[RawResponseMessage, str, None] = None) -> None: + if message is None: + message = "Server disconnected" + + self.args = (message,) + self.message = message + + +class ServerTimeoutError(ServerConnectionError, asyncio.TimeoutError): + """Server timeout error.""" + + +class ConnectionTimeoutError(ServerTimeoutError): + """Connection timeout error.""" + + +class SocketTimeoutError(ServerTimeoutError): + """Socket timeout error.""" + + +class ServerFingerprintMismatch(ServerConnectionError): + """SSL certificate does not match expected fingerprint.""" + + def __init__(self, expected: bytes, got: bytes, host: str, port: int) -> None: + self.expected = expected + self.got = got + self.host = host + self.port = port + self.args = (expected, got, host, port) + + def __repr__(self) -> str: + return "<{} expected={!r} got={!r} host={!r} port={!r}>".format( + self.__class__.__name__, self.expected, self.got, self.host, self.port + ) + + +class ClientPayloadError(ClientError): + """Response payload error.""" + + +class InvalidURL(ClientError, ValueError): + """Invalid URL. + + URL used for fetching is malformed, e.g. it doesn't contains host + part. + """ + + # Derive from ValueError for backward compatibility + + def __init__(self, url: StrOrURL, description: Union[str, None] = None) -> None: + # The type of url is not yarl.URL because the exception can be raised + # on URL(url) call + self._url = url + self._description = description + + if description: + super().__init__(url, description) + else: + super().__init__(url) + + @property + def url(self) -> StrOrURL: + return self._url + + @property + def description(self) -> "str | None": + return self._description + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} {self}>" + + def __str__(self) -> str: + if self._description: + return f"{self._url} - {self._description}" + return str(self._url) + + +class InvalidUrlClientError(InvalidURL): + """Invalid URL client error.""" + + +class RedirectClientError(ClientError): + """Client redirect error.""" + + +class NonHttpUrlClientError(ClientError): + """Non http URL client error.""" + + +class InvalidUrlRedirectClientError(InvalidUrlClientError, RedirectClientError): + """Invalid URL redirect client error.""" + + +class NonHttpUrlRedirectClientError(NonHttpUrlClientError, RedirectClientError): + """Non http URL redirect client error.""" + + +class ClientSSLError(ClientConnectorError): + """Base error for ssl.*Errors.""" + + +if ssl is not None: + cert_errors = (ssl.CertificateError,) + cert_errors_bases = ( + ClientSSLError, + ssl.CertificateError, + ) + + ssl_errors = (ssl.SSLError,) + ssl_error_bases = (ClientSSLError, ssl.SSLError) +else: # pragma: no cover + cert_errors = tuple() + cert_errors_bases = ( + ClientSSLError, + ValueError, + ) + + ssl_errors = tuple() + ssl_error_bases = (ClientSSLError,) + + +class ClientConnectorSSLError(*ssl_error_bases): # type: ignore[misc] + """Response ssl error.""" + + +class ClientConnectorCertificateError(*cert_errors_bases): # type: ignore[misc] + """Response certificate error.""" + + def __init__( + self, connection_key: ConnectionKey, certificate_error: Exception + ) -> None: + self._conn_key = connection_key + self._certificate_error = certificate_error + self.args = (connection_key, certificate_error) + + @property + def certificate_error(self) -> Exception: + return self._certificate_error + + @property + def host(self) -> str: + return self._conn_key.host + + @property + def port(self) -> Optional[int]: + return self._conn_key.port + + @property + def ssl(self) -> bool: + return self._conn_key.is_ssl + + def __str__(self) -> str: + return ( + "Cannot connect to host {0.host}:{0.port} ssl:{0.ssl} " + "[{0.certificate_error.__class__.__name__}: " + "{0.certificate_error.args}]".format(self) + ) + + +class WSMessageTypeError(TypeError): + """WebSocket message type is not valid.""" diff --git a/venv/lib/python3.12/site-packages/aiohttp/client_proto.py b/venv/lib/python3.12/site-packages/aiohttp/client_proto.py new file mode 100644 index 00000000..2d64b3f3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/client_proto.py @@ -0,0 +1,308 @@ +import asyncio +from contextlib import suppress +from typing import Any, Optional, Tuple + +from .base_protocol import BaseProtocol +from .client_exceptions import ( + ClientOSError, + ClientPayloadError, + ServerDisconnectedError, + SocketTimeoutError, +) +from .helpers import ( + _EXC_SENTINEL, + EMPTY_BODY_STATUS_CODES, + BaseTimerContext, + set_exception, +) +from .http import HttpResponseParser, RawResponseMessage +from .http_exceptions import HttpProcessingError +from .streams import EMPTY_PAYLOAD, DataQueue, StreamReader + + +class ResponseHandler(BaseProtocol, DataQueue[Tuple[RawResponseMessage, StreamReader]]): + """Helper class to adapt between Protocol and StreamReader.""" + + def __init__(self, loop: asyncio.AbstractEventLoop) -> None: + BaseProtocol.__init__(self, loop=loop) + DataQueue.__init__(self, loop) + + self._should_close = False + + self._payload: Optional[StreamReader] = None + self._skip_payload = False + self._payload_parser = None + + self._timer = None + + self._tail = b"" + self._upgraded = False + self._parser: Optional[HttpResponseParser] = None + + self._read_timeout: Optional[float] = None + self._read_timeout_handle: Optional[asyncio.TimerHandle] = None + + self._timeout_ceil_threshold: Optional[float] = 5 + + @property + def upgraded(self) -> bool: + return self._upgraded + + @property + def should_close(self) -> bool: + return bool( + self._should_close + or (self._payload is not None and not self._payload.is_eof()) + or self._upgraded + or self._exception is not None + or self._payload_parser is not None + or self._buffer + or self._tail + ) + + def force_close(self) -> None: + self._should_close = True + + def close(self) -> None: + self._exception = None # Break cyclic references + transport = self.transport + if transport is not None: + transport.close() + self.transport = None + self._payload = None + self._drop_timeout() + + def is_connected(self) -> bool: + return self.transport is not None and not self.transport.is_closing() + + def connection_lost(self, exc: Optional[BaseException]) -> None: + self._drop_timeout() + + original_connection_error = exc + reraised_exc = original_connection_error + + connection_closed_cleanly = original_connection_error is None + + if self._payload_parser is not None: + with suppress(Exception): # FIXME: log this somehow? + self._payload_parser.feed_eof() + + uncompleted = None + if self._parser is not None: + try: + uncompleted = self._parser.feed_eof() + except Exception as underlying_exc: + if self._payload is not None: + client_payload_exc_msg = ( + f"Response payload is not completed: {underlying_exc !r}" + ) + if not connection_closed_cleanly: + client_payload_exc_msg = ( + f"{client_payload_exc_msg !s}. " + f"{original_connection_error !r}" + ) + set_exception( + self._payload, + ClientPayloadError(client_payload_exc_msg), + underlying_exc, + ) + + if not self.is_eof(): + if isinstance(original_connection_error, OSError): + reraised_exc = ClientOSError(*original_connection_error.args) + if connection_closed_cleanly: + reraised_exc = ServerDisconnectedError(uncompleted) + # assigns self._should_close to True as side effect, + # we do it anyway below + underlying_non_eof_exc = ( + _EXC_SENTINEL + if connection_closed_cleanly + else original_connection_error + ) + assert underlying_non_eof_exc is not None + assert reraised_exc is not None + self.set_exception(reraised_exc, underlying_non_eof_exc) + + self._should_close = True + self._parser = None + self._payload = None + self._payload_parser = None + self._reading_paused = False + + super().connection_lost(reraised_exc) + + def eof_received(self) -> None: + # should call parser.feed_eof() most likely + self._drop_timeout() + + def pause_reading(self) -> None: + super().pause_reading() + self._drop_timeout() + + def resume_reading(self) -> None: + super().resume_reading() + self._reschedule_timeout() + + def set_exception( + self, + exc: BaseException, + exc_cause: BaseException = _EXC_SENTINEL, + ) -> None: + self._should_close = True + self._drop_timeout() + super().set_exception(exc, exc_cause) + + def set_parser(self, parser: Any, payload: Any) -> None: + # TODO: actual types are: + # parser: WebSocketReader + # payload: WebSocketDataQueue + # but they are not generi enough + # Need an ABC for both types + self._payload = payload + self._payload_parser = parser + + self._drop_timeout() + + if self._tail: + data, self._tail = self._tail, b"" + self.data_received(data) + + def set_response_params( + self, + *, + timer: Optional[BaseTimerContext] = None, + skip_payload: bool = False, + read_until_eof: bool = False, + auto_decompress: bool = True, + read_timeout: Optional[float] = None, + read_bufsize: int = 2**16, + timeout_ceil_threshold: float = 5, + max_line_size: int = 8190, + max_field_size: int = 8190, + ) -> None: + self._skip_payload = skip_payload + + self._read_timeout = read_timeout + + self._timeout_ceil_threshold = timeout_ceil_threshold + + self._parser = HttpResponseParser( + self, + self._loop, + read_bufsize, + timer=timer, + payload_exception=ClientPayloadError, + response_with_body=not skip_payload, + read_until_eof=read_until_eof, + auto_decompress=auto_decompress, + max_line_size=max_line_size, + max_field_size=max_field_size, + ) + + if self._tail: + data, self._tail = self._tail, b"" + self.data_received(data) + + def _drop_timeout(self) -> None: + if self._read_timeout_handle is not None: + self._read_timeout_handle.cancel() + self._read_timeout_handle = None + + def _reschedule_timeout(self) -> None: + timeout = self._read_timeout + if self._read_timeout_handle is not None: + self._read_timeout_handle.cancel() + + if timeout: + self._read_timeout_handle = self._loop.call_later( + timeout, self._on_read_timeout + ) + else: + self._read_timeout_handle = None + + def start_timeout(self) -> None: + self._reschedule_timeout() + + @property + def read_timeout(self) -> Optional[float]: + return self._read_timeout + + @read_timeout.setter + def read_timeout(self, read_timeout: Optional[float]) -> None: + self._read_timeout = read_timeout + + def _on_read_timeout(self) -> None: + exc = SocketTimeoutError("Timeout on reading data from socket") + self.set_exception(exc) + if self._payload is not None: + set_exception(self._payload, exc) + + def data_received(self, data: bytes) -> None: + self._reschedule_timeout() + + if not data: + return + + # custom payload parser - currently always WebSocketReader + if self._payload_parser is not None: + eof, tail = self._payload_parser.feed_data(data) + if eof: + self._payload = None + self._payload_parser = None + + if tail: + self.data_received(tail) + return + + if self._upgraded or self._parser is None: + # i.e. websocket connection, websocket parser is not set yet + self._tail += data + return + + # parse http messages + try: + messages, upgraded, tail = self._parser.feed_data(data) + except BaseException as underlying_exc: + if self.transport is not None: + # connection.release() could be called BEFORE + # data_received(), the transport is already + # closed in this case + self.transport.close() + # should_close is True after the call + if isinstance(underlying_exc, HttpProcessingError): + exc = HttpProcessingError( + code=underlying_exc.code, + message=underlying_exc.message, + headers=underlying_exc.headers, + ) + else: + exc = HttpProcessingError() + self.set_exception(exc, underlying_exc) + return + + self._upgraded = upgraded + + payload: Optional[StreamReader] = None + for message, payload in messages: + if message.should_close: + self._should_close = True + + self._payload = payload + + if self._skip_payload or message.code in EMPTY_BODY_STATUS_CODES: + self.feed_data((message, EMPTY_PAYLOAD), 0) + else: + self.feed_data((message, payload), 0) + + if payload is not None: + # new message(s) was processed + # register timeout handler unsubscribing + # either on end-of-stream or immediately for + # EMPTY_PAYLOAD + if payload is not EMPTY_PAYLOAD: + payload.on_eof(self._drop_timeout) + else: + self._drop_timeout() + + if upgraded and tail: + self.data_received(tail) diff --git a/venv/lib/python3.12/site-packages/aiohttp/client_reqrep.py b/venv/lib/python3.12/site-packages/aiohttp/client_reqrep.py new file mode 100644 index 00000000..43b48063 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/client_reqrep.py @@ -0,0 +1,1315 @@ +import asyncio +import codecs +import contextlib +import functools +import io +import re +import sys +import traceback +import warnings +from hashlib import md5, sha1, sha256 +from http.cookies import CookieError, Morsel, SimpleCookie +from types import MappingProxyType, TracebackType +from typing import ( + TYPE_CHECKING, + Any, + Callable, + Dict, + Iterable, + List, + Mapping, + NamedTuple, + Optional, + Tuple, + Type, + Union, +) + +import attr +from multidict import CIMultiDict, CIMultiDictProxy, MultiDict, MultiDictProxy +from yarl import URL + +from . import hdrs, helpers, http, multipart, payload +from .abc import AbstractStreamWriter +from .client_exceptions import ( + ClientConnectionError, + ClientOSError, + ClientResponseError, + ContentTypeError, + InvalidURL, + ServerFingerprintMismatch, +) +from .compression_utils import HAS_BROTLI +from .formdata import FormData +from .helpers import ( + _SENTINEL, + BaseTimerContext, + BasicAuth, + HeadersMixin, + TimerNoop, + basicauth_from_netrc, + netrc_from_env, + noop, + reify, + set_exception, + set_result, +) +from .http import ( + SERVER_SOFTWARE, + HttpVersion, + HttpVersion10, + HttpVersion11, + StreamWriter, +) +from .log import client_logger +from .streams import StreamReader +from .typedefs import ( + DEFAULT_JSON_DECODER, + JSONDecoder, + LooseCookies, + LooseHeaders, + Query, + RawHeaders, +) + +if TYPE_CHECKING: + import ssl + from ssl import SSLContext +else: + try: + import ssl + from ssl import SSLContext + except ImportError: # pragma: no cover + ssl = None # type: ignore[assignment] + SSLContext = object # type: ignore[misc,assignment] + + +__all__ = ("ClientRequest", "ClientResponse", "RequestInfo", "Fingerprint") + + +if TYPE_CHECKING: + from .client import ClientSession + from .connector import Connection + from .tracing import Trace + + +_CONTAINS_CONTROL_CHAR_RE = re.compile(r"[^-!#$%&'*+.^_`|~0-9a-zA-Z]") +json_re = re.compile(r"^application/(?:[\w.+-]+?\+)?json") + + +def _gen_default_accept_encoding() -> str: + return "gzip, deflate, br" if HAS_BROTLI else "gzip, deflate" + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class ContentDisposition: + type: Optional[str] + parameters: "MappingProxyType[str, str]" + filename: Optional[str] + + +class _RequestInfo(NamedTuple): + url: URL + method: str + headers: "CIMultiDictProxy[str]" + real_url: URL + + +class RequestInfo(_RequestInfo): + + def __new__( + cls, + url: URL, + method: str, + headers: "CIMultiDictProxy[str]", + real_url: URL = _SENTINEL, # type: ignore[assignment] + ) -> "RequestInfo": + """Create a new RequestInfo instance. + + For backwards compatibility, the real_url parameter is optional. + """ + return tuple.__new__( + cls, (url, method, headers, url if real_url is _SENTINEL else real_url) + ) + + +class Fingerprint: + HASHFUNC_BY_DIGESTLEN = { + 16: md5, + 20: sha1, + 32: sha256, + } + + def __init__(self, fingerprint: bytes) -> None: + digestlen = len(fingerprint) + hashfunc = self.HASHFUNC_BY_DIGESTLEN.get(digestlen) + if not hashfunc: + raise ValueError("fingerprint has invalid length") + elif hashfunc is md5 or hashfunc is sha1: + raise ValueError("md5 and sha1 are insecure and not supported. Use sha256.") + self._hashfunc = hashfunc + self._fingerprint = fingerprint + + @property + def fingerprint(self) -> bytes: + return self._fingerprint + + def check(self, transport: asyncio.Transport) -> None: + if not transport.get_extra_info("sslcontext"): + return + sslobj = transport.get_extra_info("ssl_object") + cert = sslobj.getpeercert(binary_form=True) + got = self._hashfunc(cert).digest() + if got != self._fingerprint: + host, port, *_ = transport.get_extra_info("peername") + raise ServerFingerprintMismatch(self._fingerprint, got, host, port) + + +if ssl is not None: + SSL_ALLOWED_TYPES = (ssl.SSLContext, bool, Fingerprint, type(None)) +else: # pragma: no cover + SSL_ALLOWED_TYPES = (bool, type(None)) + + +def _merge_ssl_params( + ssl: Union["SSLContext", bool, Fingerprint], + verify_ssl: Optional[bool], + ssl_context: Optional["SSLContext"], + fingerprint: Optional[bytes], +) -> Union["SSLContext", bool, Fingerprint]: + if ssl is None: + ssl = True # Double check for backwards compatibility + if verify_ssl is not None and not verify_ssl: + warnings.warn( + "verify_ssl is deprecated, use ssl=False instead", + DeprecationWarning, + stacklevel=3, + ) + if ssl is not True: + raise ValueError( + "verify_ssl, ssl_context, fingerprint and ssl " + "parameters are mutually exclusive" + ) + else: + ssl = False + if ssl_context is not None: + warnings.warn( + "ssl_context is deprecated, use ssl=context instead", + DeprecationWarning, + stacklevel=3, + ) + if ssl is not True: + raise ValueError( + "verify_ssl, ssl_context, fingerprint and ssl " + "parameters are mutually exclusive" + ) + else: + ssl = ssl_context + if fingerprint is not None: + warnings.warn( + "fingerprint is deprecated, use ssl=Fingerprint(fingerprint) instead", + DeprecationWarning, + stacklevel=3, + ) + if ssl is not True: + raise ValueError( + "verify_ssl, ssl_context, fingerprint and ssl " + "parameters are mutually exclusive" + ) + else: + ssl = Fingerprint(fingerprint) + if not isinstance(ssl, SSL_ALLOWED_TYPES): + raise TypeError( + "ssl should be SSLContext, bool, Fingerprint or None, " + "got {!r} instead.".format(ssl) + ) + return ssl + + +_SSL_SCHEMES = frozenset(("https", "wss")) + + +# ConnectionKey is a NamedTuple because it is used as a key in a dict +# and a set in the connector. Since a NamedTuple is a tuple it uses +# the fast native tuple __hash__ and __eq__ implementation in CPython. +class ConnectionKey(NamedTuple): + # the key should contain an information about used proxy / TLS + # to prevent reusing wrong connections from a pool + host: str + port: Optional[int] + is_ssl: bool + ssl: Union[SSLContext, bool, Fingerprint] + proxy: Optional[URL] + proxy_auth: Optional[BasicAuth] + proxy_headers_hash: Optional[int] # hash(CIMultiDict) + + +def _is_expected_content_type( + response_content_type: str, expected_content_type: str +) -> bool: + if expected_content_type == "application/json": + return json_re.match(response_content_type) is not None + return expected_content_type in response_content_type + + +class ClientRequest: + GET_METHODS = { + hdrs.METH_GET, + hdrs.METH_HEAD, + hdrs.METH_OPTIONS, + hdrs.METH_TRACE, + } + POST_METHODS = {hdrs.METH_PATCH, hdrs.METH_POST, hdrs.METH_PUT} + ALL_METHODS = GET_METHODS.union(POST_METHODS).union({hdrs.METH_DELETE}) + + DEFAULT_HEADERS = { + hdrs.ACCEPT: "*/*", + hdrs.ACCEPT_ENCODING: _gen_default_accept_encoding(), + } + + # Type of body depends on PAYLOAD_REGISTRY, which is dynamic. + body: Any = b"" + auth = None + response = None + + __writer = None # async task for streaming data + _continue = None # waiter future for '100 Continue' response + + _skip_auto_headers: Optional["CIMultiDict[None]"] = None + + # N.B. + # Adding __del__ method with self._writer closing doesn't make sense + # because _writer is instance method, thus it keeps a reference to self. + # Until writer has finished finalizer will not be called. + + def __init__( + self, + method: str, + url: URL, + *, + params: Query = None, + headers: Optional[LooseHeaders] = None, + skip_auto_headers: Optional[Iterable[str]] = None, + data: Any = None, + cookies: Optional[LooseCookies] = None, + auth: Optional[BasicAuth] = None, + version: http.HttpVersion = http.HttpVersion11, + compress: Union[str, bool, None] = None, + chunked: Optional[bool] = None, + expect100: bool = False, + loop: Optional[asyncio.AbstractEventLoop] = None, + response_class: Optional[Type["ClientResponse"]] = None, + proxy: Optional[URL] = None, + proxy_auth: Optional[BasicAuth] = None, + timer: Optional[BaseTimerContext] = None, + session: Optional["ClientSession"] = None, + ssl: Union[SSLContext, bool, Fingerprint] = True, + proxy_headers: Optional[LooseHeaders] = None, + traces: Optional[List["Trace"]] = None, + trust_env: bool = False, + server_hostname: Optional[str] = None, + ): + if loop is None: + loop = asyncio.get_event_loop() + if match := _CONTAINS_CONTROL_CHAR_RE.search(method): + raise ValueError( + f"Method cannot contain non-token characters {method!r} " + f"(found at least {match.group()!r})" + ) + # URL forbids subclasses, so a simple type check is enough. + assert type(url) is URL, url + if proxy is not None: + assert type(proxy) is URL, proxy + # FIXME: session is None in tests only, need to fix tests + # assert session is not None + if TYPE_CHECKING: + assert session is not None + self._session = session + if params: + url = url.extend_query(params) + self.original_url = url + self.url = url.with_fragment(None) if url.raw_fragment else url + self.method = method.upper() + self.chunked = chunked + self.compress = compress + self.loop = loop + self.length = None + if response_class is None: + real_response_class = ClientResponse + else: + real_response_class = response_class + self.response_class: Type[ClientResponse] = real_response_class + self._timer = timer if timer is not None else TimerNoop() + self._ssl = ssl if ssl is not None else True + self.server_hostname = server_hostname + + if loop.get_debug(): + self._source_traceback = traceback.extract_stack(sys._getframe(1)) + + self.update_version(version) + self.update_host(url) + self.update_headers(headers) + self.update_auto_headers(skip_auto_headers) + self.update_cookies(cookies) + self.update_content_encoding(data) + self.update_auth(auth, trust_env) + self.update_proxy(proxy, proxy_auth, proxy_headers) + + self.update_body_from_data(data) + if data is not None or self.method not in self.GET_METHODS: + self.update_transfer_encoding() + self.update_expect_continue(expect100) + self._traces = [] if traces is None else traces + + def __reset_writer(self, _: object = None) -> None: + self.__writer = None + + @property + def skip_auto_headers(self) -> CIMultiDict[None]: + return self._skip_auto_headers or CIMultiDict() + + @property + def _writer(self) -> Optional["asyncio.Task[None]"]: + return self.__writer + + @_writer.setter + def _writer(self, writer: "asyncio.Task[None]") -> None: + if self.__writer is not None: + self.__writer.remove_done_callback(self.__reset_writer) + self.__writer = writer + writer.add_done_callback(self.__reset_writer) + + def is_ssl(self) -> bool: + return self.url.scheme in _SSL_SCHEMES + + @property + def ssl(self) -> Union["SSLContext", bool, Fingerprint]: + return self._ssl + + @property + def connection_key(self) -> ConnectionKey: + if proxy_headers := self.proxy_headers: + h: Optional[int] = hash(tuple(proxy_headers.items())) + else: + h = None + url = self.url + return tuple.__new__( + ConnectionKey, + ( + url.raw_host or "", + url.port, + url.scheme in _SSL_SCHEMES, + self._ssl, + self.proxy, + self.proxy_auth, + h, + ), + ) + + @property + def host(self) -> str: + ret = self.url.raw_host + assert ret is not None + return ret + + @property + def port(self) -> Optional[int]: + return self.url.port + + @property + def request_info(self) -> RequestInfo: + headers: CIMultiDictProxy[str] = CIMultiDictProxy(self.headers) + # These are created on every request, so we use a NamedTuple + # for performance reasons. We don't use the RequestInfo.__new__ + # method because it has a different signature which is provided + # for backwards compatibility only. + return tuple.__new__( + RequestInfo, (self.url, self.method, headers, self.original_url) + ) + + def update_host(self, url: URL) -> None: + """Update destination host, port and connection type (ssl).""" + # get host/port + if not url.raw_host: + raise InvalidURL(url) + + # basic auth info + if url.raw_user or url.raw_password: + self.auth = helpers.BasicAuth(url.user or "", url.password or "") + + def update_version(self, version: Union[http.HttpVersion, str]) -> None: + """Convert request version to two elements tuple. + + parser HTTP version '1.1' => (1, 1) + """ + if isinstance(version, str): + v = [part.strip() for part in version.split(".", 1)] + try: + version = http.HttpVersion(int(v[0]), int(v[1])) + except ValueError: + raise ValueError( + f"Can not parse http version number: {version}" + ) from None + self.version = version + + def update_headers(self, headers: Optional[LooseHeaders]) -> None: + """Update request headers.""" + self.headers: CIMultiDict[str] = CIMultiDict() + + # Build the host header + host = self.url.host_port_subcomponent + + # host_port_subcomponent is None when the URL is a relative URL. + # but we know we do not have a relative URL here. + assert host is not None + self.headers[hdrs.HOST] = host + + if not headers: + return + + if isinstance(headers, (dict, MultiDictProxy, MultiDict)): + headers = headers.items() + + for key, value in headers: # type: ignore[misc] + # A special case for Host header + if key in hdrs.HOST_ALL: + self.headers[key] = value + else: + self.headers.add(key, value) + + def update_auto_headers(self, skip_auto_headers: Optional[Iterable[str]]) -> None: + if skip_auto_headers is not None: + self._skip_auto_headers = CIMultiDict( + (hdr, None) for hdr in sorted(skip_auto_headers) + ) + used_headers = self.headers.copy() + used_headers.extend(self._skip_auto_headers) # type: ignore[arg-type] + else: + # Fast path when there are no headers to skip + # which is the most common case. + used_headers = self.headers + + for hdr, val in self.DEFAULT_HEADERS.items(): + if hdr not in used_headers: + self.headers[hdr] = val + + if hdrs.USER_AGENT not in used_headers: + self.headers[hdrs.USER_AGENT] = SERVER_SOFTWARE + + def update_cookies(self, cookies: Optional[LooseCookies]) -> None: + """Update request cookies header.""" + if not cookies: + return + + c = SimpleCookie() + if hdrs.COOKIE in self.headers: + c.load(self.headers.get(hdrs.COOKIE, "")) + del self.headers[hdrs.COOKIE] + + if isinstance(cookies, Mapping): + iter_cookies = cookies.items() + else: + iter_cookies = cookies # type: ignore[assignment] + for name, value in iter_cookies: + if isinstance(value, Morsel): + # Preserve coded_value + mrsl_val = value.get(value.key, Morsel()) + mrsl_val.set(value.key, value.value, value.coded_value) + c[name] = mrsl_val + else: + c[name] = value # type: ignore[assignment] + + self.headers[hdrs.COOKIE] = c.output(header="", sep=";").strip() + + def update_content_encoding(self, data: Any) -> None: + """Set request content encoding.""" + if not data: + # Don't compress an empty body. + self.compress = None + return + + if self.headers.get(hdrs.CONTENT_ENCODING): + if self.compress: + raise ValueError( + "compress can not be set if Content-Encoding header is set" + ) + elif self.compress: + if not isinstance(self.compress, str): + self.compress = "deflate" + self.headers[hdrs.CONTENT_ENCODING] = self.compress + self.chunked = True # enable chunked, no need to deal with length + + def update_transfer_encoding(self) -> None: + """Analyze transfer-encoding header.""" + te = self.headers.get(hdrs.TRANSFER_ENCODING, "").lower() + + if "chunked" in te: + if self.chunked: + raise ValueError( + "chunked can not be set " + 'if "Transfer-Encoding: chunked" header is set' + ) + + elif self.chunked: + if hdrs.CONTENT_LENGTH in self.headers: + raise ValueError( + "chunked can not be set if Content-Length header is set" + ) + + self.headers[hdrs.TRANSFER_ENCODING] = "chunked" + else: + if hdrs.CONTENT_LENGTH not in self.headers: + self.headers[hdrs.CONTENT_LENGTH] = str(len(self.body)) + + def update_auth(self, auth: Optional[BasicAuth], trust_env: bool = False) -> None: + """Set basic auth.""" + if auth is None: + auth = self.auth + if auth is None and trust_env and self.url.host is not None: + netrc_obj = netrc_from_env() + with contextlib.suppress(LookupError): + auth = basicauth_from_netrc(netrc_obj, self.url.host) + if auth is None: + return + + if not isinstance(auth, helpers.BasicAuth): + raise TypeError("BasicAuth() tuple is required instead") + + self.headers[hdrs.AUTHORIZATION] = auth.encode() + + def update_body_from_data(self, body: Any) -> None: + if body is None: + return + + # FormData + if isinstance(body, FormData): + body = body() + + try: + body = payload.PAYLOAD_REGISTRY.get(body, disposition=None) + except payload.LookupError: + body = FormData(body)() + + self.body = body + + # enable chunked encoding if needed + if not self.chunked and hdrs.CONTENT_LENGTH not in self.headers: + if (size := body.size) is not None: + self.headers[hdrs.CONTENT_LENGTH] = str(size) + else: + self.chunked = True + + # copy payload headers + assert body.headers + headers = self.headers + skip_headers = self._skip_auto_headers + for key, value in body.headers.items(): + if key in headers or (skip_headers is not None and key in skip_headers): + continue + headers[key] = value + + def update_expect_continue(self, expect: bool = False) -> None: + if expect: + self.headers[hdrs.EXPECT] = "100-continue" + elif ( + hdrs.EXPECT in self.headers + and self.headers[hdrs.EXPECT].lower() == "100-continue" + ): + expect = True + + if expect: + self._continue = self.loop.create_future() + + def update_proxy( + self, + proxy: Optional[URL], + proxy_auth: Optional[BasicAuth], + proxy_headers: Optional[LooseHeaders], + ) -> None: + self.proxy = proxy + if proxy is None: + self.proxy_auth = None + self.proxy_headers = None + return + + if proxy_auth and not isinstance(proxy_auth, helpers.BasicAuth): + raise ValueError("proxy_auth must be None or BasicAuth() tuple") + self.proxy_auth = proxy_auth + + if proxy_headers is not None and not isinstance( + proxy_headers, (MultiDict, MultiDictProxy) + ): + proxy_headers = CIMultiDict(proxy_headers) + self.proxy_headers = proxy_headers + + async def write_bytes( + self, writer: AbstractStreamWriter, conn: "Connection" + ) -> None: + """Support coroutines that yields bytes objects.""" + # 100 response + if self._continue is not None: + await writer.drain() + await self._continue + + protocol = conn.protocol + assert protocol is not None + try: + if isinstance(self.body, payload.Payload): + await self.body.write(writer) + else: + if isinstance(self.body, (bytes, bytearray)): + self.body = (self.body,) + + for chunk in self.body: + await writer.write(chunk) + except OSError as underlying_exc: + reraised_exc = underlying_exc + + exc_is_not_timeout = underlying_exc.errno is not None or not isinstance( + underlying_exc, asyncio.TimeoutError + ) + if exc_is_not_timeout: + reraised_exc = ClientOSError( + underlying_exc.errno, + f"Can not write request body for {self.url !s}", + ) + + set_exception(protocol, reraised_exc, underlying_exc) + except asyncio.CancelledError: + # Body hasn't been fully sent, so connection can't be reused. + conn.close() + raise + except Exception as underlying_exc: + set_exception( + protocol, + ClientConnectionError( + f"Failed to send bytes into the underlying connection {conn !s}", + ), + underlying_exc, + ) + else: + await writer.write_eof() + protocol.start_timeout() + + async def send(self, conn: "Connection") -> "ClientResponse": + # Specify request target: + # - CONNECT request must send authority form URI + # - not CONNECT proxy must send absolute form URI + # - most common is origin form URI + if self.method == hdrs.METH_CONNECT: + connect_host = self.url.host_subcomponent + assert connect_host is not None + path = f"{connect_host}:{self.url.port}" + elif self.proxy and not self.is_ssl(): + path = str(self.url) + else: + path = self.url.raw_path_qs + + protocol = conn.protocol + assert protocol is not None + writer = StreamWriter( + protocol, + self.loop, + on_chunk_sent=( + functools.partial(self._on_chunk_request_sent, self.method, self.url) + if self._traces + else None + ), + on_headers_sent=( + functools.partial(self._on_headers_request_sent, self.method, self.url) + if self._traces + else None + ), + ) + + if self.compress: + writer.enable_compression(self.compress) # type: ignore[arg-type] + + if self.chunked is not None: + writer.enable_chunking() + + # set default content-type + if ( + self.method in self.POST_METHODS + and ( + self._skip_auto_headers is None + or hdrs.CONTENT_TYPE not in self._skip_auto_headers + ) + and hdrs.CONTENT_TYPE not in self.headers + ): + self.headers[hdrs.CONTENT_TYPE] = "application/octet-stream" + + v = self.version + if hdrs.CONNECTION not in self.headers: + if conn._connector.force_close: + if v == HttpVersion11: + self.headers[hdrs.CONNECTION] = "close" + elif v == HttpVersion10: + self.headers[hdrs.CONNECTION] = "keep-alive" + + # status + headers + status_line = f"{self.method} {path} HTTP/{v.major}.{v.minor}" + await writer.write_headers(status_line, self.headers) + task: Optional["asyncio.Task[None]"] + if self.body or self._continue is not None or protocol.writing_paused: + coro = self.write_bytes(writer, conn) + if sys.version_info >= (3, 12): + # Optimization for Python 3.12, try to write + # bytes immediately to avoid having to schedule + # the task on the event loop. + task = asyncio.Task(coro, loop=self.loop, eager_start=True) + else: + task = self.loop.create_task(coro) + if task.done(): + task = None + else: + self._writer = task + else: + # We have nothing to write because + # - there is no body + # - the protocol does not have writing paused + # - we are not waiting for a 100-continue response + protocol.start_timeout() + writer.set_eof() + task = None + response_class = self.response_class + assert response_class is not None + self.response = response_class( + self.method, + self.original_url, + writer=task, + continue100=self._continue, + timer=self._timer, + request_info=self.request_info, + traces=self._traces, + loop=self.loop, + session=self._session, + ) + return self.response + + async def close(self) -> None: + if self.__writer is not None: + try: + await self.__writer + except asyncio.CancelledError: + if ( + sys.version_info >= (3, 11) + and (task := asyncio.current_task()) + and task.cancelling() + ): + raise + + def terminate(self) -> None: + if self.__writer is not None: + if not self.loop.is_closed(): + self.__writer.cancel() + self.__writer.remove_done_callback(self.__reset_writer) + self.__writer = None + + async def _on_chunk_request_sent(self, method: str, url: URL, chunk: bytes) -> None: + for trace in self._traces: + await trace.send_request_chunk_sent(method, url, chunk) + + async def _on_headers_request_sent( + self, method: str, url: URL, headers: "CIMultiDict[str]" + ) -> None: + for trace in self._traces: + await trace.send_request_headers(method, url, headers) + + +_CONNECTION_CLOSED_EXCEPTION = ClientConnectionError("Connection closed") + + +class ClientResponse(HeadersMixin): + + # Some of these attributes are None when created, + # but will be set by the start() method. + # As the end user will likely never see the None values, we cheat the types below. + # from the Status-Line of the response + version: Optional[HttpVersion] = None # HTTP-Version + status: int = None # type: ignore[assignment] # Status-Code + reason: Optional[str] = None # Reason-Phrase + + content: StreamReader = None # type: ignore[assignment] # Payload stream + _body: Optional[bytes] = None + _headers: CIMultiDictProxy[str] = None # type: ignore[assignment] + _history: Tuple["ClientResponse", ...] = () + _raw_headers: RawHeaders = None # type: ignore[assignment] + + _connection: Optional["Connection"] = None # current connection + _cookies: Optional[SimpleCookie] = None + _continue: Optional["asyncio.Future[bool]"] = None + _source_traceback: Optional[traceback.StackSummary] = None + _session: Optional["ClientSession"] = None + # set up by ClientRequest after ClientResponse object creation + # post-init stage allows to not change ctor signature + _closed = True # to allow __del__ for non-initialized properly response + _released = False + _in_context = False + + _resolve_charset: Callable[["ClientResponse", bytes], str] = lambda *_: "utf-8" + + __writer: Optional["asyncio.Task[None]"] = None + + def __init__( + self, + method: str, + url: URL, + *, + writer: "Optional[asyncio.Task[None]]", + continue100: Optional["asyncio.Future[bool]"], + timer: BaseTimerContext, + request_info: RequestInfo, + traces: List["Trace"], + loop: asyncio.AbstractEventLoop, + session: "ClientSession", + ) -> None: + # URL forbids subclasses, so a simple type check is enough. + assert type(url) is URL + + self.method = method + + self._real_url = url + self._url = url.with_fragment(None) if url.raw_fragment else url + if writer is not None: + self._writer = writer + if continue100 is not None: + self._continue = continue100 + self._request_info = request_info + self._timer = timer if timer is not None else TimerNoop() + self._cache: Dict[str, Any] = {} + self._traces = traces + self._loop = loop + # Save reference to _resolve_charset, so that get_encoding() will still + # work after the response has finished reading the body. + # TODO: Fix session=None in tests (see ClientRequest.__init__). + if session is not None: + # store a reference to session #1985 + self._session = session + self._resolve_charset = session._resolve_charset + if loop.get_debug(): + self._source_traceback = traceback.extract_stack(sys._getframe(1)) + + def __reset_writer(self, _: object = None) -> None: + self.__writer = None + + @property + def _writer(self) -> Optional["asyncio.Task[None]"]: + """The writer task for streaming data. + + _writer is only provided for backwards compatibility + for subclasses that may need to access it. + """ + return self.__writer + + @_writer.setter + def _writer(self, writer: Optional["asyncio.Task[None]"]) -> None: + """Set the writer task for streaming data.""" + if self.__writer is not None: + self.__writer.remove_done_callback(self.__reset_writer) + self.__writer = writer + if writer is None: + return + if writer.done(): + # The writer is already done, so we can clear it immediately. + self.__writer = None + else: + writer.add_done_callback(self.__reset_writer) + + @property + def cookies(self) -> SimpleCookie: + if self._cookies is None: + self._cookies = SimpleCookie() + return self._cookies + + @cookies.setter + def cookies(self, cookies: SimpleCookie) -> None: + self._cookies = cookies + + @reify + def url(self) -> URL: + return self._url + + @reify + def url_obj(self) -> URL: + warnings.warn("Deprecated, use .url #1654", DeprecationWarning, stacklevel=2) + return self._url + + @reify + def real_url(self) -> URL: + return self._real_url + + @reify + def host(self) -> str: + assert self._url.host is not None + return self._url.host + + @reify + def headers(self) -> "CIMultiDictProxy[str]": + return self._headers + + @reify + def raw_headers(self) -> RawHeaders: + return self._raw_headers + + @reify + def request_info(self) -> RequestInfo: + return self._request_info + + @reify + def content_disposition(self) -> Optional[ContentDisposition]: + raw = self._headers.get(hdrs.CONTENT_DISPOSITION) + if raw is None: + return None + disposition_type, params_dct = multipart.parse_content_disposition(raw) + params = MappingProxyType(params_dct) + filename = multipart.content_disposition_filename(params) + return ContentDisposition(disposition_type, params, filename) + + def __del__(self, _warnings: Any = warnings) -> None: + if self._closed: + return + + if self._connection is not None: + self._connection.release() + self._cleanup_writer() + + if self._loop.get_debug(): + kwargs = {"source": self} + _warnings.warn(f"Unclosed response {self!r}", ResourceWarning, **kwargs) + context = {"client_response": self, "message": "Unclosed response"} + if self._source_traceback: + context["source_traceback"] = self._source_traceback + self._loop.call_exception_handler(context) + + def __repr__(self) -> str: + out = io.StringIO() + ascii_encodable_url = str(self.url) + if self.reason: + ascii_encodable_reason = self.reason.encode( + "ascii", "backslashreplace" + ).decode("ascii") + else: + ascii_encodable_reason = "None" + print( + "".format( + ascii_encodable_url, self.status, ascii_encodable_reason + ), + file=out, + ) + print(self.headers, file=out) + return out.getvalue() + + @property + def connection(self) -> Optional["Connection"]: + return self._connection + + @reify + def history(self) -> Tuple["ClientResponse", ...]: + """A sequence of of responses, if redirects occurred.""" + return self._history + + @reify + def links(self) -> "MultiDictProxy[MultiDictProxy[Union[str, URL]]]": + links_str = ", ".join(self.headers.getall("link", [])) + + if not links_str: + return MultiDictProxy(MultiDict()) + + links: MultiDict[MultiDictProxy[Union[str, URL]]] = MultiDict() + + for val in re.split(r",(?=\s*<)", links_str): + match = re.match(r"\s*<(.*)>(.*)", val) + if match is None: # pragma: no cover + # the check exists to suppress mypy error + continue + url, params_str = match.groups() + params = params_str.split(";")[1:] + + link: MultiDict[Union[str, URL]] = MultiDict() + + for param in params: + match = re.match(r"^\s*(\S*)\s*=\s*(['\"]?)(.*?)(\2)\s*$", param, re.M) + if match is None: # pragma: no cover + # the check exists to suppress mypy error + continue + key, _, value, _ = match.groups() + + link.add(key, value) + + key = link.get("rel", url) + + link.add("url", self.url.join(URL(url))) + + links.add(str(key), MultiDictProxy(link)) + + return MultiDictProxy(links) + + async def start(self, connection: "Connection") -> "ClientResponse": + """Start response processing.""" + self._closed = False + self._protocol = connection.protocol + self._connection = connection + + with self._timer: + while True: + # read response + try: + protocol = self._protocol + message, payload = await protocol.read() # type: ignore[union-attr] + except http.HttpProcessingError as exc: + raise ClientResponseError( + self.request_info, + self.history, + status=exc.code, + message=exc.message, + headers=exc.headers, + ) from exc + + if message.code < 100 or message.code > 199 or message.code == 101: + break + + if self._continue is not None: + set_result(self._continue, True) + self._continue = None + + # payload eof handler + payload.on_eof(self._response_eof) + + # response status + self.version = message.version + self.status = message.code + self.reason = message.reason + + # headers + self._headers = message.headers # type is CIMultiDictProxy + self._raw_headers = message.raw_headers # type is Tuple[bytes, bytes] + + # payload + self.content = payload + + # cookies + if cookie_hdrs := self.headers.getall(hdrs.SET_COOKIE, ()): + cookies = SimpleCookie() + for hdr in cookie_hdrs: + try: + cookies.load(hdr) + except CookieError as exc: + client_logger.warning("Can not load response cookies: %s", exc) + self._cookies = cookies + return self + + def _response_eof(self) -> None: + if self._closed: + return + + # protocol could be None because connection could be detached + protocol = self._connection and self._connection.protocol + if protocol is not None and protocol.upgraded: + return + + self._closed = True + self._cleanup_writer() + self._release_connection() + + @property + def closed(self) -> bool: + return self._closed + + def close(self) -> None: + if not self._released: + self._notify_content() + + self._closed = True + if self._loop is None or self._loop.is_closed(): + return + + self._cleanup_writer() + if self._connection is not None: + self._connection.close() + self._connection = None + + def release(self) -> Any: + if not self._released: + self._notify_content() + + self._closed = True + + self._cleanup_writer() + self._release_connection() + return noop() + + @property + def ok(self) -> bool: + """Returns ``True`` if ``status`` is less than ``400``, ``False`` if not. + + This is **not** a check for ``200 OK`` but a check that the response + status is under 400. + """ + return 400 > self.status + + def raise_for_status(self) -> None: + if not self.ok: + # reason should always be not None for a started response + assert self.reason is not None + + # If we're in a context we can rely on __aexit__() to release as the + # exception propagates. + if not self._in_context: + self.release() + + raise ClientResponseError( + self.request_info, + self.history, + status=self.status, + message=self.reason, + headers=self.headers, + ) + + def _release_connection(self) -> None: + if self._connection is not None: + if self.__writer is None: + self._connection.release() + self._connection = None + else: + self.__writer.add_done_callback(lambda f: self._release_connection()) + + async def _wait_released(self) -> None: + if self.__writer is not None: + try: + await self.__writer + except asyncio.CancelledError: + if ( + sys.version_info >= (3, 11) + and (task := asyncio.current_task()) + and task.cancelling() + ): + raise + self._release_connection() + + def _cleanup_writer(self) -> None: + if self.__writer is not None: + self.__writer.cancel() + self._session = None + + def _notify_content(self) -> None: + content = self.content + if content and content.exception() is None: + set_exception(content, _CONNECTION_CLOSED_EXCEPTION) + self._released = True + + async def wait_for_close(self) -> None: + if self.__writer is not None: + try: + await self.__writer + except asyncio.CancelledError: + if ( + sys.version_info >= (3, 11) + and (task := asyncio.current_task()) + and task.cancelling() + ): + raise + self.release() + + async def read(self) -> bytes: + """Read response payload.""" + if self._body is None: + try: + self._body = await self.content.read() + for trace in self._traces: + await trace.send_response_chunk_received( + self.method, self.url, self._body + ) + except BaseException: + self.close() + raise + elif self._released: # Response explicitly released + raise ClientConnectionError("Connection closed") + + protocol = self._connection and self._connection.protocol + if protocol is None or not protocol.upgraded: + await self._wait_released() # Underlying connection released + return self._body + + def get_encoding(self) -> str: + ctype = self.headers.get(hdrs.CONTENT_TYPE, "").lower() + mimetype = helpers.parse_mimetype(ctype) + + encoding = mimetype.parameters.get("charset") + if encoding: + with contextlib.suppress(LookupError, ValueError): + return codecs.lookup(encoding).name + + if mimetype.type == "application" and ( + mimetype.subtype == "json" or mimetype.subtype == "rdap" + ): + # RFC 7159 states that the default encoding is UTF-8. + # RFC 7483 defines application/rdap+json + return "utf-8" + + if self._body is None: + raise RuntimeError( + "Cannot compute fallback encoding of a not yet read body" + ) + + return self._resolve_charset(self, self._body) + + async def text(self, encoding: Optional[str] = None, errors: str = "strict") -> str: + """Read response payload and decode.""" + if self._body is None: + await self.read() + + if encoding is None: + encoding = self.get_encoding() + + return self._body.decode(encoding, errors=errors) # type: ignore[union-attr] + + async def json( + self, + *, + encoding: Optional[str] = None, + loads: JSONDecoder = DEFAULT_JSON_DECODER, + content_type: Optional[str] = "application/json", + ) -> Any: + """Read and decodes JSON response.""" + if self._body is None: + await self.read() + + if content_type: + ctype = self.headers.get(hdrs.CONTENT_TYPE, "").lower() + if not _is_expected_content_type(ctype, content_type): + raise ContentTypeError( + self.request_info, + self.history, + status=self.status, + message=( + "Attempt to decode JSON with unexpected mimetype: %s" % ctype + ), + headers=self.headers, + ) + + stripped = self._body.strip() # type: ignore[union-attr] + if not stripped: + return None + + if encoding is None: + encoding = self.get_encoding() + + return loads(stripped.decode(encoding)) + + async def __aenter__(self) -> "ClientResponse": + self._in_context = True + return self + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + self._in_context = False + # similar to _RequestContextManager, we do not need to check + # for exceptions, response object can close connection + # if state is broken + self.release() + await self.wait_for_close() diff --git a/venv/lib/python3.12/site-packages/aiohttp/client_ws.py b/venv/lib/python3.12/site-packages/aiohttp/client_ws.py new file mode 100644 index 00000000..daa57d19 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/client_ws.py @@ -0,0 +1,428 @@ +"""WebSocket client for asyncio.""" + +import asyncio +import sys +from types import TracebackType +from typing import Any, Optional, Type, cast + +import attr + +from ._websocket.reader import WebSocketDataQueue +from .client_exceptions import ClientError, ServerTimeoutError, WSMessageTypeError +from .client_reqrep import ClientResponse +from .helpers import calculate_timeout_when, set_result +from .http import ( + WS_CLOSED_MESSAGE, + WS_CLOSING_MESSAGE, + WebSocketError, + WSCloseCode, + WSMessage, + WSMsgType, +) +from .http_websocket import _INTERNAL_RECEIVE_TYPES, WebSocketWriter +from .streams import EofStream +from .typedefs import ( + DEFAULT_JSON_DECODER, + DEFAULT_JSON_ENCODER, + JSONDecoder, + JSONEncoder, +) + +if sys.version_info >= (3, 11): + import asyncio as async_timeout +else: + import async_timeout + + +@attr.s(frozen=True, slots=True) +class ClientWSTimeout: + ws_receive = attr.ib(type=Optional[float], default=None) + ws_close = attr.ib(type=Optional[float], default=None) + + +DEFAULT_WS_CLIENT_TIMEOUT = ClientWSTimeout(ws_receive=None, ws_close=10.0) + + +class ClientWebSocketResponse: + def __init__( + self, + reader: WebSocketDataQueue, + writer: WebSocketWriter, + protocol: Optional[str], + response: ClientResponse, + timeout: ClientWSTimeout, + autoclose: bool, + autoping: bool, + loop: asyncio.AbstractEventLoop, + *, + heartbeat: Optional[float] = None, + compress: int = 0, + client_notakeover: bool = False, + ) -> None: + self._response = response + self._conn = response.connection + + self._writer = writer + self._reader = reader + self._protocol = protocol + self._closed = False + self._closing = False + self._close_code: Optional[int] = None + self._timeout = timeout + self._autoclose = autoclose + self._autoping = autoping + self._heartbeat = heartbeat + self._heartbeat_cb: Optional[asyncio.TimerHandle] = None + self._heartbeat_when: float = 0.0 + if heartbeat is not None: + self._pong_heartbeat = heartbeat / 2.0 + self._pong_response_cb: Optional[asyncio.TimerHandle] = None + self._loop = loop + self._waiting: bool = False + self._close_wait: Optional[asyncio.Future[None]] = None + self._exception: Optional[BaseException] = None + self._compress = compress + self._client_notakeover = client_notakeover + self._ping_task: Optional[asyncio.Task[None]] = None + + self._reset_heartbeat() + + def _cancel_heartbeat(self) -> None: + self._cancel_pong_response_cb() + if self._heartbeat_cb is not None: + self._heartbeat_cb.cancel() + self._heartbeat_cb = None + if self._ping_task is not None: + self._ping_task.cancel() + self._ping_task = None + + def _cancel_pong_response_cb(self) -> None: + if self._pong_response_cb is not None: + self._pong_response_cb.cancel() + self._pong_response_cb = None + + def _reset_heartbeat(self) -> None: + if self._heartbeat is None: + return + self._cancel_pong_response_cb() + loop = self._loop + assert loop is not None + conn = self._conn + timeout_ceil_threshold = ( + conn._connector._timeout_ceil_threshold if conn is not None else 5 + ) + now = loop.time() + when = calculate_timeout_when(now, self._heartbeat, timeout_ceil_threshold) + self._heartbeat_when = when + if self._heartbeat_cb is None: + # We do not cancel the previous heartbeat_cb here because + # it generates a significant amount of TimerHandle churn + # which causes asyncio to rebuild the heap frequently. + # Instead _send_heartbeat() will reschedule the next + # heartbeat if it fires too early. + self._heartbeat_cb = loop.call_at(when, self._send_heartbeat) + + def _send_heartbeat(self) -> None: + self._heartbeat_cb = None + loop = self._loop + now = loop.time() + if now < self._heartbeat_when: + # Heartbeat fired too early, reschedule + self._heartbeat_cb = loop.call_at( + self._heartbeat_when, self._send_heartbeat + ) + return + + conn = self._conn + timeout_ceil_threshold = ( + conn._connector._timeout_ceil_threshold if conn is not None else 5 + ) + when = calculate_timeout_when(now, self._pong_heartbeat, timeout_ceil_threshold) + self._cancel_pong_response_cb() + self._pong_response_cb = loop.call_at(when, self._pong_not_received) + + coro = self._writer.send_frame(b"", WSMsgType.PING) + if sys.version_info >= (3, 12): + # Optimization for Python 3.12, try to send the ping + # immediately to avoid having to schedule + # the task on the event loop. + ping_task = asyncio.Task(coro, loop=loop, eager_start=True) + else: + ping_task = loop.create_task(coro) + + if not ping_task.done(): + self._ping_task = ping_task + ping_task.add_done_callback(self._ping_task_done) + else: + self._ping_task_done(ping_task) + + def _ping_task_done(self, task: "asyncio.Task[None]") -> None: + """Callback for when the ping task completes.""" + if not task.cancelled() and (exc := task.exception()): + self._handle_ping_pong_exception(exc) + self._ping_task = None + + def _pong_not_received(self) -> None: + self._handle_ping_pong_exception( + ServerTimeoutError(f"No PONG received after {self._pong_heartbeat} seconds") + ) + + def _handle_ping_pong_exception(self, exc: BaseException) -> None: + """Handle exceptions raised during ping/pong processing.""" + if self._closed: + return + self._set_closed() + self._close_code = WSCloseCode.ABNORMAL_CLOSURE + self._exception = exc + self._response.close() + if self._waiting and not self._closing: + self._reader.feed_data(WSMessage(WSMsgType.ERROR, exc, None), 0) + + def _set_closed(self) -> None: + """Set the connection to closed. + + Cancel any heartbeat timers and set the closed flag. + """ + self._closed = True + self._cancel_heartbeat() + + def _set_closing(self) -> None: + """Set the connection to closing. + + Cancel any heartbeat timers and set the closing flag. + """ + self._closing = True + self._cancel_heartbeat() + + @property + def closed(self) -> bool: + return self._closed + + @property + def close_code(self) -> Optional[int]: + return self._close_code + + @property + def protocol(self) -> Optional[str]: + return self._protocol + + @property + def compress(self) -> int: + return self._compress + + @property + def client_notakeover(self) -> bool: + return self._client_notakeover + + def get_extra_info(self, name: str, default: Any = None) -> Any: + """extra info from connection transport""" + conn = self._response.connection + if conn is None: + return default + transport = conn.transport + if transport is None: + return default + return transport.get_extra_info(name, default) + + def exception(self) -> Optional[BaseException]: + return self._exception + + async def ping(self, message: bytes = b"") -> None: + await self._writer.send_frame(message, WSMsgType.PING) + + async def pong(self, message: bytes = b"") -> None: + await self._writer.send_frame(message, WSMsgType.PONG) + + async def send_frame( + self, message: bytes, opcode: WSMsgType, compress: Optional[int] = None + ) -> None: + """Send a frame over the websocket.""" + await self._writer.send_frame(message, opcode, compress) + + async def send_str(self, data: str, compress: Optional[int] = None) -> None: + if not isinstance(data, str): + raise TypeError("data argument must be str (%r)" % type(data)) + await self._writer.send_frame( + data.encode("utf-8"), WSMsgType.TEXT, compress=compress + ) + + async def send_bytes(self, data: bytes, compress: Optional[int] = None) -> None: + if not isinstance(data, (bytes, bytearray, memoryview)): + raise TypeError("data argument must be byte-ish (%r)" % type(data)) + await self._writer.send_frame(data, WSMsgType.BINARY, compress=compress) + + async def send_json( + self, + data: Any, + compress: Optional[int] = None, + *, + dumps: JSONEncoder = DEFAULT_JSON_ENCODER, + ) -> None: + await self.send_str(dumps(data), compress=compress) + + async def close(self, *, code: int = WSCloseCode.OK, message: bytes = b"") -> bool: + # we need to break `receive()` cycle first, + # `close()` may be called from different task + if self._waiting and not self._closing: + assert self._loop is not None + self._close_wait = self._loop.create_future() + self._set_closing() + self._reader.feed_data(WS_CLOSING_MESSAGE, 0) + await self._close_wait + + if self._closed: + return False + + self._set_closed() + try: + await self._writer.close(code, message) + except asyncio.CancelledError: + self._close_code = WSCloseCode.ABNORMAL_CLOSURE + self._response.close() + raise + except Exception as exc: + self._close_code = WSCloseCode.ABNORMAL_CLOSURE + self._exception = exc + self._response.close() + return True + + if self._close_code: + self._response.close() + return True + + while True: + try: + async with async_timeout.timeout(self._timeout.ws_close): + msg = await self._reader.read() + except asyncio.CancelledError: + self._close_code = WSCloseCode.ABNORMAL_CLOSURE + self._response.close() + raise + except Exception as exc: + self._close_code = WSCloseCode.ABNORMAL_CLOSURE + self._exception = exc + self._response.close() + return True + + if msg.type is WSMsgType.CLOSE: + self._close_code = msg.data + self._response.close() + return True + + async def receive(self, timeout: Optional[float] = None) -> WSMessage: + receive_timeout = timeout or self._timeout.ws_receive + + while True: + if self._waiting: + raise RuntimeError("Concurrent call to receive() is not allowed") + + if self._closed: + return WS_CLOSED_MESSAGE + elif self._closing: + await self.close() + return WS_CLOSED_MESSAGE + + try: + self._waiting = True + try: + if receive_timeout: + # Entering the context manager and creating + # Timeout() object can take almost 50% of the + # run time in this loop so we avoid it if + # there is no read timeout. + async with async_timeout.timeout(receive_timeout): + msg = await self._reader.read() + else: + msg = await self._reader.read() + self._reset_heartbeat() + finally: + self._waiting = False + if self._close_wait: + set_result(self._close_wait, None) + except (asyncio.CancelledError, asyncio.TimeoutError): + self._close_code = WSCloseCode.ABNORMAL_CLOSURE + raise + except EofStream: + self._close_code = WSCloseCode.OK + await self.close() + return WSMessage(WSMsgType.CLOSED, None, None) + except ClientError: + # Likely ServerDisconnectedError when connection is lost + self._set_closed() + self._close_code = WSCloseCode.ABNORMAL_CLOSURE + return WS_CLOSED_MESSAGE + except WebSocketError as exc: + self._close_code = exc.code + await self.close(code=exc.code) + return WSMessage(WSMsgType.ERROR, exc, None) + except Exception as exc: + self._exception = exc + self._set_closing() + self._close_code = WSCloseCode.ABNORMAL_CLOSURE + await self.close() + return WSMessage(WSMsgType.ERROR, exc, None) + + if msg.type not in _INTERNAL_RECEIVE_TYPES: + # If its not a close/closing/ping/pong message + # we can return it immediately + return msg + + if msg.type is WSMsgType.CLOSE: + self._set_closing() + self._close_code = msg.data + if not self._closed and self._autoclose: + await self.close() + elif msg.type is WSMsgType.CLOSING: + self._set_closing() + elif msg.type is WSMsgType.PING and self._autoping: + await self.pong(msg.data) + continue + elif msg.type is WSMsgType.PONG and self._autoping: + continue + + return msg + + async def receive_str(self, *, timeout: Optional[float] = None) -> str: + msg = await self.receive(timeout) + if msg.type is not WSMsgType.TEXT: + raise WSMessageTypeError( + f"Received message {msg.type}:{msg.data!r} is not WSMsgType.TEXT" + ) + return cast(str, msg.data) + + async def receive_bytes(self, *, timeout: Optional[float] = None) -> bytes: + msg = await self.receive(timeout) + if msg.type is not WSMsgType.BINARY: + raise WSMessageTypeError( + f"Received message {msg.type}:{msg.data!r} is not WSMsgType.BINARY" + ) + return cast(bytes, msg.data) + + async def receive_json( + self, + *, + loads: JSONDecoder = DEFAULT_JSON_DECODER, + timeout: Optional[float] = None, + ) -> Any: + data = await self.receive_str(timeout=timeout) + return loads(data) + + def __aiter__(self) -> "ClientWebSocketResponse": + return self + + async def __anext__(self) -> WSMessage: + msg = await self.receive() + if msg.type in (WSMsgType.CLOSE, WSMsgType.CLOSING, WSMsgType.CLOSED): + raise StopAsyncIteration + return msg + + async def __aenter__(self) -> "ClientWebSocketResponse": + return self + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + await self.close() diff --git a/venv/lib/python3.12/site-packages/aiohttp/compression_utils.py b/venv/lib/python3.12/site-packages/aiohttp/compression_utils.py new file mode 100644 index 00000000..ebe8857f --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/compression_utils.py @@ -0,0 +1,173 @@ +import asyncio +import zlib +from concurrent.futures import Executor +from typing import Optional, cast + +try: + try: + import brotlicffi as brotli + except ImportError: + import brotli + + HAS_BROTLI = True +except ImportError: # pragma: no cover + HAS_BROTLI = False + +MAX_SYNC_CHUNK_SIZE = 1024 + + +def encoding_to_mode( + encoding: Optional[str] = None, + suppress_deflate_header: bool = False, +) -> int: + if encoding == "gzip": + return 16 + zlib.MAX_WBITS + + return -zlib.MAX_WBITS if suppress_deflate_header else zlib.MAX_WBITS + + +class ZlibBaseHandler: + def __init__( + self, + mode: int, + executor: Optional[Executor] = None, + max_sync_chunk_size: Optional[int] = MAX_SYNC_CHUNK_SIZE, + ): + self._mode = mode + self._executor = executor + self._max_sync_chunk_size = max_sync_chunk_size + + +class ZLibCompressor(ZlibBaseHandler): + def __init__( + self, + encoding: Optional[str] = None, + suppress_deflate_header: bool = False, + level: Optional[int] = None, + wbits: Optional[int] = None, + strategy: int = zlib.Z_DEFAULT_STRATEGY, + executor: Optional[Executor] = None, + max_sync_chunk_size: Optional[int] = MAX_SYNC_CHUNK_SIZE, + ): + super().__init__( + mode=( + encoding_to_mode(encoding, suppress_deflate_header) + if wbits is None + else wbits + ), + executor=executor, + max_sync_chunk_size=max_sync_chunk_size, + ) + if level is None: + self._compressor = zlib.compressobj(wbits=self._mode, strategy=strategy) + else: + self._compressor = zlib.compressobj( + wbits=self._mode, strategy=strategy, level=level + ) + self._compress_lock = asyncio.Lock() + + def compress_sync(self, data: bytes) -> bytes: + return self._compressor.compress(data) + + async def compress(self, data: bytes) -> bytes: + """Compress the data and returned the compressed bytes. + + Note that flush() must be called after the last call to compress() + + If the data size is large than the max_sync_chunk_size, the compression + will be done in the executor. Otherwise, the compression will be done + in the event loop. + """ + async with self._compress_lock: + # To ensure the stream is consistent in the event + # there are multiple writers, we need to lock + # the compressor so that only one writer can + # compress at a time. + if ( + self._max_sync_chunk_size is not None + and len(data) > self._max_sync_chunk_size + ): + return await asyncio.get_running_loop().run_in_executor( + self._executor, self._compressor.compress, data + ) + return self.compress_sync(data) + + def flush(self, mode: int = zlib.Z_FINISH) -> bytes: + return self._compressor.flush(mode) + + +class ZLibDecompressor(ZlibBaseHandler): + def __init__( + self, + encoding: Optional[str] = None, + suppress_deflate_header: bool = False, + executor: Optional[Executor] = None, + max_sync_chunk_size: Optional[int] = MAX_SYNC_CHUNK_SIZE, + ): + super().__init__( + mode=encoding_to_mode(encoding, suppress_deflate_header), + executor=executor, + max_sync_chunk_size=max_sync_chunk_size, + ) + self._decompressor = zlib.decompressobj(wbits=self._mode) + + def decompress_sync(self, data: bytes, max_length: int = 0) -> bytes: + return self._decompressor.decompress(data, max_length) + + async def decompress(self, data: bytes, max_length: int = 0) -> bytes: + """Decompress the data and return the decompressed bytes. + + If the data size is large than the max_sync_chunk_size, the decompression + will be done in the executor. Otherwise, the decompression will be done + in the event loop. + """ + if ( + self._max_sync_chunk_size is not None + and len(data) > self._max_sync_chunk_size + ): + return await asyncio.get_running_loop().run_in_executor( + self._executor, self._decompressor.decompress, data, max_length + ) + return self.decompress_sync(data, max_length) + + def flush(self, length: int = 0) -> bytes: + return ( + self._decompressor.flush(length) + if length > 0 + else self._decompressor.flush() + ) + + @property + def eof(self) -> bool: + return self._decompressor.eof + + @property + def unconsumed_tail(self) -> bytes: + return self._decompressor.unconsumed_tail + + @property + def unused_data(self) -> bytes: + return self._decompressor.unused_data + + +class BrotliDecompressor: + # Supports both 'brotlipy' and 'Brotli' packages + # since they share an import name. The top branches + # are for 'brotlipy' and bottom branches for 'Brotli' + def __init__(self) -> None: + if not HAS_BROTLI: + raise RuntimeError( + "The brotli decompression is not available. " + "Please install `Brotli` module" + ) + self._obj = brotli.Decompressor() + + def decompress_sync(self, data: bytes) -> bytes: + if hasattr(self._obj, "decompress"): + return cast(bytes, self._obj.decompress(data)) + return cast(bytes, self._obj.process(data)) + + def flush(self) -> bytes: + if hasattr(self._obj, "flush"): + return cast(bytes, self._obj.flush()) + return b"" diff --git a/venv/lib/python3.12/site-packages/aiohttp/connector.py b/venv/lib/python3.12/site-packages/aiohttp/connector.py new file mode 100644 index 00000000..7d5bcf75 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/connector.py @@ -0,0 +1,1658 @@ +import asyncio +import functools +import random +import socket +import sys +import traceback +import warnings +from collections import OrderedDict, defaultdict, deque +from contextlib import suppress +from http import HTTPStatus +from itertools import chain, cycle, islice +from time import monotonic +from types import TracebackType +from typing import ( + TYPE_CHECKING, + Any, + Awaitable, + Callable, + DefaultDict, + Deque, + Dict, + Iterator, + List, + Literal, + Optional, + Sequence, + Set, + Tuple, + Type, + Union, + cast, +) + +import aiohappyeyeballs + +from . import hdrs, helpers +from .abc import AbstractResolver, ResolveResult +from .client_exceptions import ( + ClientConnectionError, + ClientConnectorCertificateError, + ClientConnectorDNSError, + ClientConnectorError, + ClientConnectorSSLError, + ClientHttpProxyError, + ClientProxyConnectionError, + ServerFingerprintMismatch, + UnixClientConnectorError, + cert_errors, + ssl_errors, +) +from .client_proto import ResponseHandler +from .client_reqrep import ClientRequest, Fingerprint, _merge_ssl_params +from .helpers import ( + ceil_timeout, + is_ip_address, + noop, + sentinel, + set_exception, + set_result, +) +from .resolver import DefaultResolver + +if TYPE_CHECKING: + import ssl + + SSLContext = ssl.SSLContext +else: + try: + import ssl + + SSLContext = ssl.SSLContext + except ImportError: # pragma: no cover + ssl = None # type: ignore[assignment] + SSLContext = object # type: ignore[misc,assignment] + +EMPTY_SCHEMA_SET = frozenset({""}) +HTTP_SCHEMA_SET = frozenset({"http", "https"}) +WS_SCHEMA_SET = frozenset({"ws", "wss"}) + +HTTP_AND_EMPTY_SCHEMA_SET = HTTP_SCHEMA_SET | EMPTY_SCHEMA_SET +HIGH_LEVEL_SCHEMA_SET = HTTP_AND_EMPTY_SCHEMA_SET | WS_SCHEMA_SET + +NEEDS_CLEANUP_CLOSED = (3, 13, 0) <= sys.version_info < ( + 3, + 13, + 1, +) or sys.version_info < (3, 12, 7) +# Cleanup closed is no longer needed after https://github.com/python/cpython/pull/118960 +# which first appeared in Python 3.12.7 and 3.13.1 + + +__all__ = ("BaseConnector", "TCPConnector", "UnixConnector", "NamedPipeConnector") + + +if TYPE_CHECKING: + from .client import ClientTimeout + from .client_reqrep import ConnectionKey + from .tracing import Trace + + +class _DeprecationWaiter: + __slots__ = ("_awaitable", "_awaited") + + def __init__(self, awaitable: Awaitable[Any]) -> None: + self._awaitable = awaitable + self._awaited = False + + def __await__(self) -> Any: + self._awaited = True + return self._awaitable.__await__() + + def __del__(self) -> None: + if not self._awaited: + warnings.warn( + "Connector.close() is a coroutine, " + "please use await connector.close()", + DeprecationWarning, + ) + + +class Connection: + + _source_traceback = None + + def __init__( + self, + connector: "BaseConnector", + key: "ConnectionKey", + protocol: ResponseHandler, + loop: asyncio.AbstractEventLoop, + ) -> None: + self._key = key + self._connector = connector + self._loop = loop + self._protocol: Optional[ResponseHandler] = protocol + self._callbacks: List[Callable[[], None]] = [] + + if loop.get_debug(): + self._source_traceback = traceback.extract_stack(sys._getframe(1)) + + def __repr__(self) -> str: + return f"Connection<{self._key}>" + + def __del__(self, _warnings: Any = warnings) -> None: + if self._protocol is not None: + kwargs = {"source": self} + _warnings.warn(f"Unclosed connection {self!r}", ResourceWarning, **kwargs) + if self._loop.is_closed(): + return + + self._connector._release(self._key, self._protocol, should_close=True) + + context = {"client_connection": self, "message": "Unclosed connection"} + if self._source_traceback is not None: + context["source_traceback"] = self._source_traceback + self._loop.call_exception_handler(context) + + def __bool__(self) -> Literal[True]: + """Force subclasses to not be falsy, to make checks simpler.""" + return True + + @property + def loop(self) -> asyncio.AbstractEventLoop: + warnings.warn( + "connector.loop property is deprecated", DeprecationWarning, stacklevel=2 + ) + return self._loop + + @property + def transport(self) -> Optional[asyncio.Transport]: + if self._protocol is None: + return None + return self._protocol.transport + + @property + def protocol(self) -> Optional[ResponseHandler]: + return self._protocol + + def add_callback(self, callback: Callable[[], None]) -> None: + if callback is not None: + self._callbacks.append(callback) + + def _notify_release(self) -> None: + callbacks, self._callbacks = self._callbacks[:], [] + + for cb in callbacks: + with suppress(Exception): + cb() + + def close(self) -> None: + self._notify_release() + + if self._protocol is not None: + self._connector._release(self._key, self._protocol, should_close=True) + self._protocol = None + + def release(self) -> None: + self._notify_release() + + if self._protocol is not None: + self._connector._release(self._key, self._protocol) + self._protocol = None + + @property + def closed(self) -> bool: + return self._protocol is None or not self._protocol.is_connected() + + +class _TransportPlaceholder: + """placeholder for BaseConnector.connect function""" + + __slots__ = () + + def close(self) -> None: + """Close the placeholder transport.""" + + +class BaseConnector: + """Base connector class. + + keepalive_timeout - (optional) Keep-alive timeout. + force_close - Set to True to force close and do reconnect + after each request (and between redirects). + limit - The total number of simultaneous connections. + limit_per_host - Number of simultaneous connections to one host. + enable_cleanup_closed - Enables clean-up closed ssl transports. + Disabled by default. + timeout_ceil_threshold - Trigger ceiling of timeout values when + it's above timeout_ceil_threshold. + loop - Optional event loop. + """ + + _closed = True # prevent AttributeError in __del__ if ctor was failed + _source_traceback = None + + # abort transport after 2 seconds (cleanup broken connections) + _cleanup_closed_period = 2.0 + + allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET + + def __init__( + self, + *, + keepalive_timeout: Union[object, None, float] = sentinel, + force_close: bool = False, + limit: int = 100, + limit_per_host: int = 0, + enable_cleanup_closed: bool = False, + loop: Optional[asyncio.AbstractEventLoop] = None, + timeout_ceil_threshold: float = 5, + ) -> None: + + if force_close: + if keepalive_timeout is not None and keepalive_timeout is not sentinel: + raise ValueError( + "keepalive_timeout cannot be set if force_close is True" + ) + else: + if keepalive_timeout is sentinel: + keepalive_timeout = 15.0 + + loop = loop or asyncio.get_running_loop() + self._timeout_ceil_threshold = timeout_ceil_threshold + + self._closed = False + if loop.get_debug(): + self._source_traceback = traceback.extract_stack(sys._getframe(1)) + + # Connection pool of reusable connections. + # We use a deque to store connections because it has O(1) popleft() + # and O(1) append() operations to implement a FIFO queue. + self._conns: DefaultDict[ + ConnectionKey, Deque[Tuple[ResponseHandler, float]] + ] = defaultdict(deque) + self._limit = limit + self._limit_per_host = limit_per_host + self._acquired: Set[ResponseHandler] = set() + self._acquired_per_host: DefaultDict[ConnectionKey, Set[ResponseHandler]] = ( + defaultdict(set) + ) + self._keepalive_timeout = cast(float, keepalive_timeout) + self._force_close = force_close + + # {host_key: FIFO list of waiters} + # The FIFO is implemented with an OrderedDict with None keys because + # python does not have an ordered set. + self._waiters: DefaultDict[ + ConnectionKey, OrderedDict[asyncio.Future[None], None] + ] = defaultdict(OrderedDict) + + self._loop = loop + self._factory = functools.partial(ResponseHandler, loop=loop) + + # start keep-alive connection cleanup task + self._cleanup_handle: Optional[asyncio.TimerHandle] = None + + # start cleanup closed transports task + self._cleanup_closed_handle: Optional[asyncio.TimerHandle] = None + + if enable_cleanup_closed and not NEEDS_CLEANUP_CLOSED: + warnings.warn( + "enable_cleanup_closed ignored because " + "https://github.com/python/cpython/pull/118960 is fixed " + f"in Python version {sys.version_info}", + DeprecationWarning, + stacklevel=2, + ) + enable_cleanup_closed = False + + self._cleanup_closed_disabled = not enable_cleanup_closed + self._cleanup_closed_transports: List[Optional[asyncio.Transport]] = [] + self._cleanup_closed() + + def __del__(self, _warnings: Any = warnings) -> None: + if self._closed: + return + if not self._conns: + return + + conns = [repr(c) for c in self._conns.values()] + + self._close() + + kwargs = {"source": self} + _warnings.warn(f"Unclosed connector {self!r}", ResourceWarning, **kwargs) + context = { + "connector": self, + "connections": conns, + "message": "Unclosed connector", + } + if self._source_traceback is not None: + context["source_traceback"] = self._source_traceback + self._loop.call_exception_handler(context) + + def __enter__(self) -> "BaseConnector": + warnings.warn( + '"with Connector():" is deprecated, ' + 'use "async with Connector():" instead', + DeprecationWarning, + ) + return self + + def __exit__(self, *exc: Any) -> None: + self._close() + + async def __aenter__(self) -> "BaseConnector": + return self + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]] = None, + exc_value: Optional[BaseException] = None, + exc_traceback: Optional[TracebackType] = None, + ) -> None: + await self.close() + + @property + def force_close(self) -> bool: + """Ultimately close connection on releasing if True.""" + return self._force_close + + @property + def limit(self) -> int: + """The total number for simultaneous connections. + + If limit is 0 the connector has no limit. + The default limit size is 100. + """ + return self._limit + + @property + def limit_per_host(self) -> int: + """The limit for simultaneous connections to the same endpoint. + + Endpoints are the same if they are have equal + (host, port, is_ssl) triple. + """ + return self._limit_per_host + + def _cleanup(self) -> None: + """Cleanup unused transports.""" + if self._cleanup_handle: + self._cleanup_handle.cancel() + # _cleanup_handle should be unset, otherwise _release() will not + # recreate it ever! + self._cleanup_handle = None + + now = monotonic() + timeout = self._keepalive_timeout + + if self._conns: + connections = defaultdict(deque) + deadline = now - timeout + for key, conns in self._conns.items(): + alive: Deque[Tuple[ResponseHandler, float]] = deque() + for proto, use_time in conns: + if proto.is_connected() and use_time - deadline >= 0: + alive.append((proto, use_time)) + continue + transport = proto.transport + proto.close() + if not self._cleanup_closed_disabled and key.is_ssl: + self._cleanup_closed_transports.append(transport) + + if alive: + connections[key] = alive + + self._conns = connections + + if self._conns: + self._cleanup_handle = helpers.weakref_handle( + self, + "_cleanup", + timeout, + self._loop, + timeout_ceil_threshold=self._timeout_ceil_threshold, + ) + + def _cleanup_closed(self) -> None: + """Double confirmation for transport close. + + Some broken ssl servers may leave socket open without proper close. + """ + if self._cleanup_closed_handle: + self._cleanup_closed_handle.cancel() + + for transport in self._cleanup_closed_transports: + if transport is not None: + transport.abort() + + self._cleanup_closed_transports = [] + + if not self._cleanup_closed_disabled: + self._cleanup_closed_handle = helpers.weakref_handle( + self, + "_cleanup_closed", + self._cleanup_closed_period, + self._loop, + timeout_ceil_threshold=self._timeout_ceil_threshold, + ) + + def close(self) -> Awaitable[None]: + """Close all opened transports.""" + self._close() + return _DeprecationWaiter(noop()) + + def _close(self) -> None: + if self._closed: + return + + self._closed = True + + try: + if self._loop.is_closed(): + return + + # cancel cleanup task + if self._cleanup_handle: + self._cleanup_handle.cancel() + + # cancel cleanup close task + if self._cleanup_closed_handle: + self._cleanup_closed_handle.cancel() + + for data in self._conns.values(): + for proto, t0 in data: + proto.close() + + for proto in self._acquired: + proto.close() + + for transport in self._cleanup_closed_transports: + if transport is not None: + transport.abort() + + finally: + self._conns.clear() + self._acquired.clear() + for keyed_waiters in self._waiters.values(): + for keyed_waiter in keyed_waiters: + keyed_waiter.cancel() + self._waiters.clear() + self._cleanup_handle = None + self._cleanup_closed_transports.clear() + self._cleanup_closed_handle = None + + @property + def closed(self) -> bool: + """Is connector closed. + + A readonly property. + """ + return self._closed + + def _available_connections(self, key: "ConnectionKey") -> int: + """ + Return number of available connections. + + The limit, limit_per_host and the connection key are taken into account. + + If it returns less than 1 means that there are no connections + available. + """ + # check total available connections + # If there are no limits, this will always return 1 + total_remain = 1 + + if self._limit and (total_remain := self._limit - len(self._acquired)) <= 0: + return total_remain + + # check limit per host + if host_remain := self._limit_per_host: + if acquired := self._acquired_per_host.get(key): + host_remain -= len(acquired) + if total_remain > host_remain: + return host_remain + + return total_remain + + async def connect( + self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout" + ) -> Connection: + """Get from pool or create new connection.""" + key = req.connection_key + if (conn := await self._get(key, traces)) is not None: + # If we do not have to wait and we can get a connection from the pool + # we can avoid the timeout ceil logic and directly return the connection + return conn + + async with ceil_timeout(timeout.connect, timeout.ceil_threshold): + if self._available_connections(key) <= 0: + await self._wait_for_available_connection(key, traces) + if (conn := await self._get(key, traces)) is not None: + return conn + + placeholder = cast(ResponseHandler, _TransportPlaceholder()) + self._acquired.add(placeholder) + if self._limit_per_host: + self._acquired_per_host[key].add(placeholder) + + try: + # Traces are done inside the try block to ensure that the + # that the placeholder is still cleaned up if an exception + # is raised. + if traces: + for trace in traces: + await trace.send_connection_create_start() + proto = await self._create_connection(req, traces, timeout) + if traces: + for trace in traces: + await trace.send_connection_create_end() + except BaseException: + self._release_acquired(key, placeholder) + raise + else: + if self._closed: + proto.close() + raise ClientConnectionError("Connector is closed.") + + # The connection was successfully created, drop the placeholder + # and add the real connection to the acquired set. There should + # be no awaits after the proto is added to the acquired set + # to ensure that the connection is not left in the acquired set + # on cancellation. + self._acquired.remove(placeholder) + self._acquired.add(proto) + if self._limit_per_host: + acquired_per_host = self._acquired_per_host[key] + acquired_per_host.remove(placeholder) + acquired_per_host.add(proto) + return Connection(self, key, proto, self._loop) + + async def _wait_for_available_connection( + self, key: "ConnectionKey", traces: List["Trace"] + ) -> None: + """Wait for an available connection slot.""" + # We loop here because there is a race between + # the connection limit check and the connection + # being acquired. If the connection is acquired + # between the check and the await statement, we + # need to loop again to check if the connection + # slot is still available. + attempts = 0 + while True: + fut: asyncio.Future[None] = self._loop.create_future() + keyed_waiters = self._waiters[key] + keyed_waiters[fut] = None + if attempts: + # If we have waited before, we need to move the waiter + # to the front of the queue as otherwise we might get + # starved and hit the timeout. + keyed_waiters.move_to_end(fut, last=False) + + try: + # Traces happen in the try block to ensure that the + # the waiter is still cleaned up if an exception is raised. + if traces: + for trace in traces: + await trace.send_connection_queued_start() + await fut + if traces: + for trace in traces: + await trace.send_connection_queued_end() + finally: + # pop the waiter from the queue if its still + # there and not already removed by _release_waiter + keyed_waiters.pop(fut, None) + if not self._waiters.get(key, True): + del self._waiters[key] + + if self._available_connections(key) > 0: + break + attempts += 1 + + async def _get( + self, key: "ConnectionKey", traces: List["Trace"] + ) -> Optional[Connection]: + """Get next reusable connection for the key or None. + + The connection will be marked as acquired. + """ + if (conns := self._conns.get(key)) is None: + return None + + t1 = monotonic() + while conns: + proto, t0 = conns.popleft() + # We will we reuse the connection if its connected and + # the keepalive timeout has not been exceeded + if proto.is_connected() and t1 - t0 <= self._keepalive_timeout: + if not conns: + # The very last connection was reclaimed: drop the key + del self._conns[key] + self._acquired.add(proto) + if self._limit_per_host: + self._acquired_per_host[key].add(proto) + if traces: + for trace in traces: + try: + await trace.send_connection_reuseconn() + except BaseException: + self._release_acquired(key, proto) + raise + return Connection(self, key, proto, self._loop) + + # Connection cannot be reused, close it + transport = proto.transport + proto.close() + # only for SSL transports + if not self._cleanup_closed_disabled and key.is_ssl: + self._cleanup_closed_transports.append(transport) + + # No more connections: drop the key + del self._conns[key] + return None + + def _release_waiter(self) -> None: + """ + Iterates over all waiters until one to be released is found. + + The one to be released is not finished and + belongs to a host that has available connections. + """ + if not self._waiters: + return + + # Having the dict keys ordered this avoids to iterate + # at the same order at each call. + queues = list(self._waiters) + random.shuffle(queues) + + for key in queues: + if self._available_connections(key) < 1: + continue + + waiters = self._waiters[key] + while waiters: + waiter, _ = waiters.popitem(last=False) + if not waiter.done(): + waiter.set_result(None) + return + + def _release_acquired(self, key: "ConnectionKey", proto: ResponseHandler) -> None: + """Release acquired connection.""" + if self._closed: + # acquired connection is already released on connector closing + return + + self._acquired.discard(proto) + if self._limit_per_host and (conns := self._acquired_per_host.get(key)): + conns.discard(proto) + if not conns: + del self._acquired_per_host[key] + self._release_waiter() + + def _release( + self, + key: "ConnectionKey", + protocol: ResponseHandler, + *, + should_close: bool = False, + ) -> None: + if self._closed: + # acquired connection is already released on connector closing + return + + self._release_acquired(key, protocol) + + if self._force_close or should_close or protocol.should_close: + transport = protocol.transport + protocol.close() + + if key.is_ssl and not self._cleanup_closed_disabled: + self._cleanup_closed_transports.append(transport) + return + + self._conns[key].append((protocol, monotonic())) + + if self._cleanup_handle is None: + self._cleanup_handle = helpers.weakref_handle( + self, + "_cleanup", + self._keepalive_timeout, + self._loop, + timeout_ceil_threshold=self._timeout_ceil_threshold, + ) + + async def _create_connection( + self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout" + ) -> ResponseHandler: + raise NotImplementedError() + + +class _DNSCacheTable: + def __init__(self, ttl: Optional[float] = None) -> None: + self._addrs_rr: Dict[Tuple[str, int], Tuple[Iterator[ResolveResult], int]] = {} + self._timestamps: Dict[Tuple[str, int], float] = {} + self._ttl = ttl + + def __contains__(self, host: object) -> bool: + return host in self._addrs_rr + + def add(self, key: Tuple[str, int], addrs: List[ResolveResult]) -> None: + self._addrs_rr[key] = (cycle(addrs), len(addrs)) + + if self._ttl is not None: + self._timestamps[key] = monotonic() + + def remove(self, key: Tuple[str, int]) -> None: + self._addrs_rr.pop(key, None) + + if self._ttl is not None: + self._timestamps.pop(key, None) + + def clear(self) -> None: + self._addrs_rr.clear() + self._timestamps.clear() + + def next_addrs(self, key: Tuple[str, int]) -> List[ResolveResult]: + loop, length = self._addrs_rr[key] + addrs = list(islice(loop, length)) + # Consume one more element to shift internal state of `cycle` + next(loop) + return addrs + + def expired(self, key: Tuple[str, int]) -> bool: + if self._ttl is None: + return False + + return self._timestamps[key] + self._ttl < monotonic() + + +def _make_ssl_context(verified: bool) -> SSLContext: + """Create SSL context. + + This method is not async-friendly and should be called from a thread + because it will load certificates from disk and do other blocking I/O. + """ + if ssl is None: + # No ssl support + return None + if verified: + sslcontext = ssl.create_default_context() + else: + sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + sslcontext.options |= ssl.OP_NO_SSLv2 + sslcontext.options |= ssl.OP_NO_SSLv3 + sslcontext.check_hostname = False + sslcontext.verify_mode = ssl.CERT_NONE + sslcontext.options |= ssl.OP_NO_COMPRESSION + sslcontext.set_default_verify_paths() + sslcontext.set_alpn_protocols(("http/1.1",)) + return sslcontext + + +# The default SSLContext objects are created at import time +# since they do blocking I/O to load certificates from disk, +# and imports should always be done before the event loop starts +# or in a thread. +_SSL_CONTEXT_VERIFIED = _make_ssl_context(True) +_SSL_CONTEXT_UNVERIFIED = _make_ssl_context(False) + + +class TCPConnector(BaseConnector): + """TCP connector. + + verify_ssl - Set to True to check ssl certifications. + fingerprint - Pass the binary sha256 + digest of the expected certificate in DER format to verify + that the certificate the server presents matches. See also + https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning + resolver - Enable DNS lookups and use this + resolver + use_dns_cache - Use memory cache for DNS lookups. + ttl_dns_cache - Max seconds having cached a DNS entry, None forever. + family - socket address family + local_addr - local tuple of (host, port) to bind socket to + + keepalive_timeout - (optional) Keep-alive timeout. + force_close - Set to True to force close and do reconnect + after each request (and between redirects). + limit - The total number of simultaneous connections. + limit_per_host - Number of simultaneous connections to one host. + enable_cleanup_closed - Enables clean-up closed ssl transports. + Disabled by default. + happy_eyeballs_delay - This is the “Connection Attempt Delay” + as defined in RFC 8305. To disable + the happy eyeballs algorithm, set to None. + interleave - “First Address Family Count” as defined in RFC 8305 + loop - Optional event loop. + """ + + allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({"tcp"}) + + def __init__( + self, + *, + verify_ssl: bool = True, + fingerprint: Optional[bytes] = None, + use_dns_cache: bool = True, + ttl_dns_cache: Optional[int] = 10, + family: socket.AddressFamily = socket.AddressFamily.AF_UNSPEC, + ssl_context: Optional[SSLContext] = None, + ssl: Union[bool, Fingerprint, SSLContext] = True, + local_addr: Optional[Tuple[str, int]] = None, + resolver: Optional[AbstractResolver] = None, + keepalive_timeout: Union[None, float, object] = sentinel, + force_close: bool = False, + limit: int = 100, + limit_per_host: int = 0, + enable_cleanup_closed: bool = False, + loop: Optional[asyncio.AbstractEventLoop] = None, + timeout_ceil_threshold: float = 5, + happy_eyeballs_delay: Optional[float] = 0.25, + interleave: Optional[int] = None, + ): + super().__init__( + keepalive_timeout=keepalive_timeout, + force_close=force_close, + limit=limit, + limit_per_host=limit_per_host, + enable_cleanup_closed=enable_cleanup_closed, + loop=loop, + timeout_ceil_threshold=timeout_ceil_threshold, + ) + + self._ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint) + if resolver is None: + resolver = DefaultResolver(loop=self._loop) + self._resolver = resolver + + self._use_dns_cache = use_dns_cache + self._cached_hosts = _DNSCacheTable(ttl=ttl_dns_cache) + self._throttle_dns_futures: Dict[ + Tuple[str, int], Set["asyncio.Future[None]"] + ] = {} + self._family = family + self._local_addr_infos = aiohappyeyeballs.addr_to_addr_infos(local_addr) + self._happy_eyeballs_delay = happy_eyeballs_delay + self._interleave = interleave + self._resolve_host_tasks: Set["asyncio.Task[List[ResolveResult]]"] = set() + + def close(self) -> Awaitable[None]: + """Close all ongoing DNS calls.""" + for fut in chain.from_iterable(self._throttle_dns_futures.values()): + fut.cancel() + + for t in self._resolve_host_tasks: + t.cancel() + + return super().close() + + @property + def family(self) -> int: + """Socket family like AF_INET.""" + return self._family + + @property + def use_dns_cache(self) -> bool: + """True if local DNS caching is enabled.""" + return self._use_dns_cache + + def clear_dns_cache( + self, host: Optional[str] = None, port: Optional[int] = None + ) -> None: + """Remove specified host/port or clear all dns local cache.""" + if host is not None and port is not None: + self._cached_hosts.remove((host, port)) + elif host is not None or port is not None: + raise ValueError("either both host and port or none of them are allowed") + else: + self._cached_hosts.clear() + + async def _resolve_host( + self, host: str, port: int, traces: Optional[Sequence["Trace"]] = None + ) -> List[ResolveResult]: + """Resolve host and return list of addresses.""" + if is_ip_address(host): + return [ + { + "hostname": host, + "host": host, + "port": port, + "family": self._family, + "proto": 0, + "flags": 0, + } + ] + + if not self._use_dns_cache: + + if traces: + for trace in traces: + await trace.send_dns_resolvehost_start(host) + + res = await self._resolver.resolve(host, port, family=self._family) + + if traces: + for trace in traces: + await trace.send_dns_resolvehost_end(host) + + return res + + key = (host, port) + if key in self._cached_hosts and not self._cached_hosts.expired(key): + # get result early, before any await (#4014) + result = self._cached_hosts.next_addrs(key) + + if traces: + for trace in traces: + await trace.send_dns_cache_hit(host) + return result + + futures: Set["asyncio.Future[None]"] + # + # If multiple connectors are resolving the same host, we wait + # for the first one to resolve and then use the result for all of them. + # We use a throttle to ensure that we only resolve the host once + # and then use the result for all the waiters. + # + if key in self._throttle_dns_futures: + # get futures early, before any await (#4014) + futures = self._throttle_dns_futures[key] + future: asyncio.Future[None] = self._loop.create_future() + futures.add(future) + if traces: + for trace in traces: + await trace.send_dns_cache_hit(host) + try: + await future + finally: + futures.discard(future) + return self._cached_hosts.next_addrs(key) + + # update dict early, before any await (#4014) + self._throttle_dns_futures[key] = futures = set() + # In this case we need to create a task to ensure that we can shield + # the task from cancellation as cancelling this lookup should not cancel + # the underlying lookup or else the cancel event will get broadcast to + # all the waiters across all connections. + # + coro = self._resolve_host_with_throttle(key, host, port, futures, traces) + loop = asyncio.get_running_loop() + if sys.version_info >= (3, 12): + # Optimization for Python 3.12, try to send immediately + resolved_host_task = asyncio.Task(coro, loop=loop, eager_start=True) + else: + resolved_host_task = loop.create_task(coro) + + if not resolved_host_task.done(): + self._resolve_host_tasks.add(resolved_host_task) + resolved_host_task.add_done_callback(self._resolve_host_tasks.discard) + + try: + return await asyncio.shield(resolved_host_task) + except asyncio.CancelledError: + + def drop_exception(fut: "asyncio.Future[List[ResolveResult]]") -> None: + with suppress(Exception, asyncio.CancelledError): + fut.result() + + resolved_host_task.add_done_callback(drop_exception) + raise + + async def _resolve_host_with_throttle( + self, + key: Tuple[str, int], + host: str, + port: int, + futures: Set["asyncio.Future[None]"], + traces: Optional[Sequence["Trace"]], + ) -> List[ResolveResult]: + """Resolve host and set result for all waiters. + + This method must be run in a task and shielded from cancellation + to avoid cancelling the underlying lookup. + """ + try: + if traces: + for trace in traces: + await trace.send_dns_cache_miss(host) + + for trace in traces: + await trace.send_dns_resolvehost_start(host) + + addrs = await self._resolver.resolve(host, port, family=self._family) + if traces: + for trace in traces: + await trace.send_dns_resolvehost_end(host) + + self._cached_hosts.add(key, addrs) + for fut in futures: + set_result(fut, None) + except BaseException as e: + # any DNS exception is set for the waiters to raise the same exception. + # This coro is always run in task that is shielded from cancellation so + # we should never be propagating cancellation here. + for fut in futures: + set_exception(fut, e) + raise + finally: + self._throttle_dns_futures.pop(key) + + return self._cached_hosts.next_addrs(key) + + async def _create_connection( + self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout" + ) -> ResponseHandler: + """Create connection. + + Has same keyword arguments as BaseEventLoop.create_connection. + """ + if req.proxy: + _, proto = await self._create_proxy_connection(req, traces, timeout) + else: + _, proto = await self._create_direct_connection(req, traces, timeout) + + return proto + + def _get_ssl_context(self, req: ClientRequest) -> Optional[SSLContext]: + """Logic to get the correct SSL context + + 0. if req.ssl is false, return None + + 1. if ssl_context is specified in req, use it + 2. if _ssl_context is specified in self, use it + 3. otherwise: + 1. if verify_ssl is not specified in req, use self.ssl_context + (will generate a default context according to self.verify_ssl) + 2. if verify_ssl is True in req, generate a default SSL context + 3. if verify_ssl is False in req, generate a SSL context that + won't verify + """ + if not req.is_ssl(): + return None + + if ssl is None: # pragma: no cover + raise RuntimeError("SSL is not supported.") + sslcontext = req.ssl + if isinstance(sslcontext, ssl.SSLContext): + return sslcontext + if sslcontext is not True: + # not verified or fingerprinted + return _SSL_CONTEXT_UNVERIFIED + sslcontext = self._ssl + if isinstance(sslcontext, ssl.SSLContext): + return sslcontext + if sslcontext is not True: + # not verified or fingerprinted + return _SSL_CONTEXT_UNVERIFIED + return _SSL_CONTEXT_VERIFIED + + def _get_fingerprint(self, req: ClientRequest) -> Optional["Fingerprint"]: + ret = req.ssl + if isinstance(ret, Fingerprint): + return ret + ret = self._ssl + if isinstance(ret, Fingerprint): + return ret + return None + + async def _wrap_create_connection( + self, + *args: Any, + addr_infos: List[aiohappyeyeballs.AddrInfoType], + req: ClientRequest, + timeout: "ClientTimeout", + client_error: Type[Exception] = ClientConnectorError, + **kwargs: Any, + ) -> Tuple[asyncio.Transport, ResponseHandler]: + try: + async with ceil_timeout( + timeout.sock_connect, ceil_threshold=timeout.ceil_threshold + ): + sock = await aiohappyeyeballs.start_connection( + addr_infos=addr_infos, + local_addr_infos=self._local_addr_infos, + happy_eyeballs_delay=self._happy_eyeballs_delay, + interleave=self._interleave, + loop=self._loop, + ) + return await self._loop.create_connection(*args, **kwargs, sock=sock) + except cert_errors as exc: + raise ClientConnectorCertificateError(req.connection_key, exc) from exc + except ssl_errors as exc: + raise ClientConnectorSSLError(req.connection_key, exc) from exc + except OSError as exc: + if exc.errno is None and isinstance(exc, asyncio.TimeoutError): + raise + raise client_error(req.connection_key, exc) from exc + + async def _wrap_existing_connection( + self, + *args: Any, + req: ClientRequest, + timeout: "ClientTimeout", + client_error: Type[Exception] = ClientConnectorError, + **kwargs: Any, + ) -> Tuple[asyncio.Transport, ResponseHandler]: + try: + async with ceil_timeout( + timeout.sock_connect, ceil_threshold=timeout.ceil_threshold + ): + return await self._loop.create_connection(*args, **kwargs) + except cert_errors as exc: + raise ClientConnectorCertificateError(req.connection_key, exc) from exc + except ssl_errors as exc: + raise ClientConnectorSSLError(req.connection_key, exc) from exc + except OSError as exc: + if exc.errno is None and isinstance(exc, asyncio.TimeoutError): + raise + raise client_error(req.connection_key, exc) from exc + + def _fail_on_no_start_tls(self, req: "ClientRequest") -> None: + """Raise a :py:exc:`RuntimeError` on missing ``start_tls()``. + + It is necessary for TLS-in-TLS so that it is possible to + send HTTPS queries through HTTPS proxies. + + This doesn't affect regular HTTP requests, though. + """ + if not req.is_ssl(): + return + + proxy_url = req.proxy + assert proxy_url is not None + if proxy_url.scheme != "https": + return + + self._check_loop_for_start_tls() + + def _check_loop_for_start_tls(self) -> None: + try: + self._loop.start_tls + except AttributeError as attr_exc: + raise RuntimeError( + "An HTTPS request is being sent through an HTTPS proxy. " + "This needs support for TLS in TLS but it is not implemented " + "in your runtime for the stdlib asyncio.\n\n" + "Please upgrade to Python 3.11 or higher. For more details, " + "please see:\n" + "* https://bugs.python.org/issue37179\n" + "* https://github.com/python/cpython/pull/28073\n" + "* https://docs.aiohttp.org/en/stable/" + "client_advanced.html#proxy-support\n" + "* https://github.com/aio-libs/aiohttp/discussions/6044\n", + ) from attr_exc + + def _loop_supports_start_tls(self) -> bool: + try: + self._check_loop_for_start_tls() + except RuntimeError: + return False + else: + return True + + def _warn_about_tls_in_tls( + self, + underlying_transport: asyncio.Transport, + req: ClientRequest, + ) -> None: + """Issue a warning if the requested URL has HTTPS scheme.""" + if req.request_info.url.scheme != "https": + return + + # Check if uvloop is being used, which supports TLS in TLS, + # otherwise assume that asyncio's native transport is being used. + if type(underlying_transport).__module__.startswith("uvloop"): + return + + # Support in asyncio was added in Python 3.11 (bpo-44011) + asyncio_supports_tls_in_tls = sys.version_info >= (3, 11) or getattr( + underlying_transport, + "_start_tls_compatible", + False, + ) + + if asyncio_supports_tls_in_tls: + return + + warnings.warn( + "An HTTPS request is being sent through an HTTPS proxy. " + "This support for TLS in TLS is known to be disabled " + "in the stdlib asyncio (Python <3.11). This is why you'll probably see " + "an error in the log below.\n\n" + "It is possible to enable it via monkeypatching. " + "For more details, see:\n" + "* https://bugs.python.org/issue37179\n" + "* https://github.com/python/cpython/pull/28073\n\n" + "You can temporarily patch this as follows:\n" + "* https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support\n" + "* https://github.com/aio-libs/aiohttp/discussions/6044\n", + RuntimeWarning, + source=self, + # Why `4`? At least 3 of the calls in the stack originate + # from the methods in this class. + stacklevel=3, + ) + + async def _start_tls_connection( + self, + underlying_transport: asyncio.Transport, + req: ClientRequest, + timeout: "ClientTimeout", + client_error: Type[Exception] = ClientConnectorError, + ) -> Tuple[asyncio.BaseTransport, ResponseHandler]: + """Wrap the raw TCP transport with TLS.""" + tls_proto = self._factory() # Create a brand new proto for TLS + sslcontext = self._get_ssl_context(req) + if TYPE_CHECKING: + # _start_tls_connection is unreachable in the current code path + # if sslcontext is None. + assert sslcontext is not None + + try: + async with ceil_timeout( + timeout.sock_connect, ceil_threshold=timeout.ceil_threshold + ): + try: + tls_transport = await self._loop.start_tls( + underlying_transport, + tls_proto, + sslcontext, + server_hostname=req.server_hostname or req.host, + ssl_handshake_timeout=timeout.total, + ) + except BaseException: + # We need to close the underlying transport since + # `start_tls()` probably failed before it had a + # chance to do this: + underlying_transport.close() + raise + if isinstance(tls_transport, asyncio.Transport): + fingerprint = self._get_fingerprint(req) + if fingerprint: + try: + fingerprint.check(tls_transport) + except ServerFingerprintMismatch: + tls_transport.close() + if not self._cleanup_closed_disabled: + self._cleanup_closed_transports.append(tls_transport) + raise + except cert_errors as exc: + raise ClientConnectorCertificateError(req.connection_key, exc) from exc + except ssl_errors as exc: + raise ClientConnectorSSLError(req.connection_key, exc) from exc + except OSError as exc: + if exc.errno is None and isinstance(exc, asyncio.TimeoutError): + raise + raise client_error(req.connection_key, exc) from exc + except TypeError as type_err: + # Example cause looks like this: + # TypeError: transport is not supported by start_tls() + + raise ClientConnectionError( + "Cannot initialize a TLS-in-TLS connection to host " + f"{req.host!s}:{req.port:d} through an underlying connection " + f"to an HTTPS proxy {req.proxy!s} ssl:{req.ssl or 'default'} " + f"[{type_err!s}]" + ) from type_err + else: + if tls_transport is None: + msg = "Failed to start TLS (possibly caused by closing transport)" + raise client_error(req.connection_key, OSError(msg)) + tls_proto.connection_made( + tls_transport + ) # Kick the state machine of the new TLS protocol + + return tls_transport, tls_proto + + def _convert_hosts_to_addr_infos( + self, hosts: List[ResolveResult] + ) -> List[aiohappyeyeballs.AddrInfoType]: + """Converts the list of hosts to a list of addr_infos. + + The list of hosts is the result of a DNS lookup. The list of + addr_infos is the result of a call to `socket.getaddrinfo()`. + """ + addr_infos: List[aiohappyeyeballs.AddrInfoType] = [] + for hinfo in hosts: + host = hinfo["host"] + is_ipv6 = ":" in host + family = socket.AF_INET6 if is_ipv6 else socket.AF_INET + if self._family and self._family != family: + continue + addr = (host, hinfo["port"], 0, 0) if is_ipv6 else (host, hinfo["port"]) + addr_infos.append( + (family, socket.SOCK_STREAM, socket.IPPROTO_TCP, "", addr) + ) + return addr_infos + + async def _create_direct_connection( + self, + req: ClientRequest, + traces: List["Trace"], + timeout: "ClientTimeout", + *, + client_error: Type[Exception] = ClientConnectorError, + ) -> Tuple[asyncio.Transport, ResponseHandler]: + sslcontext = self._get_ssl_context(req) + fingerprint = self._get_fingerprint(req) + + host = req.url.raw_host + assert host is not None + # Replace multiple trailing dots with a single one. + # A trailing dot is only present for fully-qualified domain names. + # See https://github.com/aio-libs/aiohttp/pull/7364. + if host.endswith(".."): + host = host.rstrip(".") + "." + port = req.port + assert port is not None + try: + # Cancelling this lookup should not cancel the underlying lookup + # or else the cancel event will get broadcast to all the waiters + # across all connections. + hosts = await self._resolve_host(host, port, traces=traces) + except OSError as exc: + if exc.errno is None and isinstance(exc, asyncio.TimeoutError): + raise + # in case of proxy it is not ClientProxyConnectionError + # it is problem of resolving proxy ip itself + raise ClientConnectorDNSError(req.connection_key, exc) from exc + + last_exc: Optional[Exception] = None + addr_infos = self._convert_hosts_to_addr_infos(hosts) + while addr_infos: + # Strip trailing dots, certificates contain FQDN without dots. + # See https://github.com/aio-libs/aiohttp/issues/3636 + server_hostname = ( + (req.server_hostname or host).rstrip(".") if sslcontext else None + ) + + try: + transp, proto = await self._wrap_create_connection( + self._factory, + timeout=timeout, + ssl=sslcontext, + addr_infos=addr_infos, + server_hostname=server_hostname, + req=req, + client_error=client_error, + ) + except (ClientConnectorError, asyncio.TimeoutError) as exc: + last_exc = exc + aiohappyeyeballs.pop_addr_infos_interleave(addr_infos, self._interleave) + continue + + if req.is_ssl() and fingerprint: + try: + fingerprint.check(transp) + except ServerFingerprintMismatch as exc: + transp.close() + if not self._cleanup_closed_disabled: + self._cleanup_closed_transports.append(transp) + last_exc = exc + # Remove the bad peer from the list of addr_infos + sock: socket.socket = transp.get_extra_info("socket") + bad_peer = sock.getpeername() + aiohappyeyeballs.remove_addr_infos(addr_infos, bad_peer) + continue + + return transp, proto + else: + assert last_exc is not None + raise last_exc + + async def _create_proxy_connection( + self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout" + ) -> Tuple[asyncio.BaseTransport, ResponseHandler]: + self._fail_on_no_start_tls(req) + runtime_has_start_tls = self._loop_supports_start_tls() + + headers: Dict[str, str] = {} + if req.proxy_headers is not None: + headers = req.proxy_headers # type: ignore[assignment] + headers[hdrs.HOST] = req.headers[hdrs.HOST] + + url = req.proxy + assert url is not None + proxy_req = ClientRequest( + hdrs.METH_GET, + url, + headers=headers, + auth=req.proxy_auth, + loop=self._loop, + ssl=req.ssl, + ) + + # create connection to proxy server + transport, proto = await self._create_direct_connection( + proxy_req, [], timeout, client_error=ClientProxyConnectionError + ) + + auth = proxy_req.headers.pop(hdrs.AUTHORIZATION, None) + if auth is not None: + if not req.is_ssl(): + req.headers[hdrs.PROXY_AUTHORIZATION] = auth + else: + proxy_req.headers[hdrs.PROXY_AUTHORIZATION] = auth + + if req.is_ssl(): + if runtime_has_start_tls: + self._warn_about_tls_in_tls(transport, req) + + # For HTTPS requests over HTTP proxy + # we must notify proxy to tunnel connection + # so we send CONNECT command: + # CONNECT www.python.org:443 HTTP/1.1 + # Host: www.python.org + # + # next we must do TLS handshake and so on + # to do this we must wrap raw socket into secure one + # asyncio handles this perfectly + proxy_req.method = hdrs.METH_CONNECT + proxy_req.url = req.url + key = req.connection_key._replace( + proxy=None, proxy_auth=None, proxy_headers_hash=None + ) + conn = Connection(self, key, proto, self._loop) + proxy_resp = await proxy_req.send(conn) + try: + protocol = conn._protocol + assert protocol is not None + + # read_until_eof=True will ensure the connection isn't closed + # once the response is received and processed allowing + # START_TLS to work on the connection below. + protocol.set_response_params( + read_until_eof=runtime_has_start_tls, + timeout_ceil_threshold=self._timeout_ceil_threshold, + ) + resp = await proxy_resp.start(conn) + except BaseException: + proxy_resp.close() + conn.close() + raise + else: + conn._protocol = None + try: + if resp.status != 200: + message = resp.reason + if message is None: + message = HTTPStatus(resp.status).phrase + raise ClientHttpProxyError( + proxy_resp.request_info, + resp.history, + status=resp.status, + message=message, + headers=resp.headers, + ) + if not runtime_has_start_tls: + rawsock = transport.get_extra_info("socket", default=None) + if rawsock is None: + raise RuntimeError( + "Transport does not expose socket instance" + ) + # Duplicate the socket, so now we can close proxy transport + rawsock = rawsock.dup() + except BaseException: + # It shouldn't be closed in `finally` because it's fed to + # `loop.start_tls()` and the docs say not to touch it after + # passing there. + transport.close() + raise + finally: + if not runtime_has_start_tls: + transport.close() + + if not runtime_has_start_tls: + # HTTP proxy with support for upgrade to HTTPS + sslcontext = self._get_ssl_context(req) + return await self._wrap_existing_connection( + self._factory, + timeout=timeout, + ssl=sslcontext, + sock=rawsock, + server_hostname=req.host, + req=req, + ) + + return await self._start_tls_connection( + # Access the old transport for the last time before it's + # closed and forgotten forever: + transport, + req=req, + timeout=timeout, + ) + finally: + proxy_resp.close() + + return transport, proto + + +class UnixConnector(BaseConnector): + """Unix socket connector. + + path - Unix socket path. + keepalive_timeout - (optional) Keep-alive timeout. + force_close - Set to True to force close and do reconnect + after each request (and between redirects). + limit - The total number of simultaneous connections. + limit_per_host - Number of simultaneous connections to one host. + loop - Optional event loop. + """ + + allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({"unix"}) + + def __init__( + self, + path: str, + force_close: bool = False, + keepalive_timeout: Union[object, float, None] = sentinel, + limit: int = 100, + limit_per_host: int = 0, + loop: Optional[asyncio.AbstractEventLoop] = None, + ) -> None: + super().__init__( + force_close=force_close, + keepalive_timeout=keepalive_timeout, + limit=limit, + limit_per_host=limit_per_host, + loop=loop, + ) + self._path = path + + @property + def path(self) -> str: + """Path to unix socket.""" + return self._path + + async def _create_connection( + self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout" + ) -> ResponseHandler: + try: + async with ceil_timeout( + timeout.sock_connect, ceil_threshold=timeout.ceil_threshold + ): + _, proto = await self._loop.create_unix_connection( + self._factory, self._path + ) + except OSError as exc: + if exc.errno is None and isinstance(exc, asyncio.TimeoutError): + raise + raise UnixClientConnectorError(self.path, req.connection_key, exc) from exc + + return proto + + +class NamedPipeConnector(BaseConnector): + """Named pipe connector. + + Only supported by the proactor event loop. + See also: https://docs.python.org/3/library/asyncio-eventloop.html + + path - Windows named pipe path. + keepalive_timeout - (optional) Keep-alive timeout. + force_close - Set to True to force close and do reconnect + after each request (and between redirects). + limit - The total number of simultaneous connections. + limit_per_host - Number of simultaneous connections to one host. + loop - Optional event loop. + """ + + allowed_protocol_schema_set = HIGH_LEVEL_SCHEMA_SET | frozenset({"npipe"}) + + def __init__( + self, + path: str, + force_close: bool = False, + keepalive_timeout: Union[object, float, None] = sentinel, + limit: int = 100, + limit_per_host: int = 0, + loop: Optional[asyncio.AbstractEventLoop] = None, + ) -> None: + super().__init__( + force_close=force_close, + keepalive_timeout=keepalive_timeout, + limit=limit, + limit_per_host=limit_per_host, + loop=loop, + ) + if not isinstance( + self._loop, asyncio.ProactorEventLoop # type: ignore[attr-defined] + ): + raise RuntimeError( + "Named Pipes only available in proactor loop under windows" + ) + self._path = path + + @property + def path(self) -> str: + """Path to the named pipe.""" + return self._path + + async def _create_connection( + self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout" + ) -> ResponseHandler: + try: + async with ceil_timeout( + timeout.sock_connect, ceil_threshold=timeout.ceil_threshold + ): + _, proto = await self._loop.create_pipe_connection( # type: ignore[attr-defined] + self._factory, self._path + ) + # the drain is required so that the connection_made is called + # and transport is set otherwise it is not set before the + # `assert conn.transport is not None` + # in client.py's _request method + await asyncio.sleep(0) + # other option is to manually set transport like + # `proto.transport = trans` + except OSError as exc: + if exc.errno is None and isinstance(exc, asyncio.TimeoutError): + raise + raise ClientConnectorError(req.connection_key, exc) from exc + + return cast(ResponseHandler, proto) diff --git a/venv/lib/python3.12/site-packages/aiohttp/cookiejar.py b/venv/lib/python3.12/site-packages/aiohttp/cookiejar.py new file mode 100644 index 00000000..f6b9a921 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/cookiejar.py @@ -0,0 +1,495 @@ +import asyncio +import calendar +import contextlib +import datetime +import heapq +import itertools +import os # noqa +import pathlib +import pickle +import re +import time +import warnings +from collections import defaultdict +from http.cookies import BaseCookie, Morsel, SimpleCookie +from typing import ( + DefaultDict, + Dict, + Iterable, + Iterator, + List, + Mapping, + Optional, + Set, + Tuple, + Union, + cast, +) + +from yarl import URL + +from .abc import AbstractCookieJar, ClearCookiePredicate +from .helpers import is_ip_address +from .typedefs import LooseCookies, PathLike, StrOrURL + +__all__ = ("CookieJar", "DummyCookieJar") + + +CookieItem = Union[str, "Morsel[str]"] + +# We cache these string methods here as their use is in performance critical code. +_FORMAT_PATH = "{}/{}".format +_FORMAT_DOMAIN_REVERSED = "{1}.{0}".format + +# The minimum number of scheduled cookie expirations before we start cleaning up +# the expiration heap. This is a performance optimization to avoid cleaning up the +# heap too often when there are only a few scheduled expirations. +_MIN_SCHEDULED_COOKIE_EXPIRATION = 100 + + +class CookieJar(AbstractCookieJar): + """Implements cookie storage adhering to RFC 6265.""" + + DATE_TOKENS_RE = re.compile( + r"[\x09\x20-\x2F\x3B-\x40\x5B-\x60\x7B-\x7E]*" + r"(?P[\x00-\x08\x0A-\x1F\d:a-zA-Z\x7F-\xFF]+)" + ) + + DATE_HMS_TIME_RE = re.compile(r"(\d{1,2}):(\d{1,2}):(\d{1,2})") + + DATE_DAY_OF_MONTH_RE = re.compile(r"(\d{1,2})") + + DATE_MONTH_RE = re.compile( + "(jan)|(feb)|(mar)|(apr)|(may)|(jun)|(jul)|(aug)|(sep)|(oct)|(nov)|(dec)", + re.I, + ) + + DATE_YEAR_RE = re.compile(r"(\d{2,4})") + + # calendar.timegm() fails for timestamps after datetime.datetime.max + # Minus one as a loss of precision occurs when timestamp() is called. + MAX_TIME = ( + int(datetime.datetime.max.replace(tzinfo=datetime.timezone.utc).timestamp()) - 1 + ) + try: + calendar.timegm(time.gmtime(MAX_TIME)) + except (OSError, ValueError): + # Hit the maximum representable time on Windows + # https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/localtime-localtime32-localtime64 + # Throws ValueError on PyPy 3.9, OSError elsewhere + MAX_TIME = calendar.timegm((3000, 12, 31, 23, 59, 59, -1, -1, -1)) + except OverflowError: + # #4515: datetime.max may not be representable on 32-bit platforms + MAX_TIME = 2**31 - 1 + # Avoid minuses in the future, 3x faster + SUB_MAX_TIME = MAX_TIME - 1 + + def __init__( + self, + *, + unsafe: bool = False, + quote_cookie: bool = True, + treat_as_secure_origin: Union[StrOrURL, List[StrOrURL], None] = None, + loop: Optional[asyncio.AbstractEventLoop] = None, + ) -> None: + super().__init__(loop=loop) + self._cookies: DefaultDict[Tuple[str, str], SimpleCookie] = defaultdict( + SimpleCookie + ) + self._morsel_cache: DefaultDict[Tuple[str, str], Dict[str, Morsel[str]]] = ( + defaultdict(dict) + ) + self._host_only_cookies: Set[Tuple[str, str]] = set() + self._unsafe = unsafe + self._quote_cookie = quote_cookie + if treat_as_secure_origin is None: + treat_as_secure_origin = [] + elif isinstance(treat_as_secure_origin, URL): + treat_as_secure_origin = [treat_as_secure_origin.origin()] + elif isinstance(treat_as_secure_origin, str): + treat_as_secure_origin = [URL(treat_as_secure_origin).origin()] + else: + treat_as_secure_origin = [ + URL(url).origin() if isinstance(url, str) else url.origin() + for url in treat_as_secure_origin + ] + self._treat_as_secure_origin = treat_as_secure_origin + self._expire_heap: List[Tuple[float, Tuple[str, str, str]]] = [] + self._expirations: Dict[Tuple[str, str, str], float] = {} + + @property + def quote_cookie(self) -> bool: + return self._quote_cookie + + def save(self, file_path: PathLike) -> None: + file_path = pathlib.Path(file_path) + with file_path.open(mode="wb") as f: + pickle.dump(self._cookies, f, pickle.HIGHEST_PROTOCOL) + + def load(self, file_path: PathLike) -> None: + file_path = pathlib.Path(file_path) + with file_path.open(mode="rb") as f: + self._cookies = pickle.load(f) + + def clear(self, predicate: Optional[ClearCookiePredicate] = None) -> None: + if predicate is None: + self._expire_heap.clear() + self._cookies.clear() + self._morsel_cache.clear() + self._host_only_cookies.clear() + self._expirations.clear() + return + + now = time.time() + to_del = [ + key + for (domain, path), cookie in self._cookies.items() + for name, morsel in cookie.items() + if ( + (key := (domain, path, name)) in self._expirations + and self._expirations[key] <= now + ) + or predicate(morsel) + ] + if to_del: + self._delete_cookies(to_del) + + def clear_domain(self, domain: str) -> None: + self.clear(lambda x: self._is_domain_match(domain, x["domain"])) + + def __iter__(self) -> "Iterator[Morsel[str]]": + self._do_expiration() + for val in self._cookies.values(): + yield from val.values() + + def __len__(self) -> int: + """Return number of cookies. + + This function does not iterate self to avoid unnecessary expiration + checks. + """ + return sum(len(cookie.values()) for cookie in self._cookies.values()) + + def _do_expiration(self) -> None: + """Remove expired cookies.""" + if not (expire_heap_len := len(self._expire_heap)): + return + + # If the expiration heap grows larger than the number expirations + # times two, we clean it up to avoid keeping expired entries in + # the heap and consuming memory. We guard this with a minimum + # threshold to avoid cleaning up the heap too often when there are + # only a few scheduled expirations. + if ( + expire_heap_len > _MIN_SCHEDULED_COOKIE_EXPIRATION + and expire_heap_len > len(self._expirations) * 2 + ): + # Remove any expired entries from the expiration heap + # that do not match the expiration time in the expirations + # as it means the cookie has been re-added to the heap + # with a different expiration time. + self._expire_heap = [ + entry + for entry in self._expire_heap + if self._expirations.get(entry[1]) == entry[0] + ] + heapq.heapify(self._expire_heap) + + now = time.time() + to_del: List[Tuple[str, str, str]] = [] + # Find any expired cookies and add them to the to-delete list + while self._expire_heap: + when, cookie_key = self._expire_heap[0] + if when > now: + break + heapq.heappop(self._expire_heap) + # Check if the cookie hasn't been re-added to the heap + # with a different expiration time as it will be removed + # later when it reaches the top of the heap and its + # expiration time is met. + if self._expirations.get(cookie_key) == when: + to_del.append(cookie_key) + + if to_del: + self._delete_cookies(to_del) + + def _delete_cookies(self, to_del: List[Tuple[str, str, str]]) -> None: + for domain, path, name in to_del: + self._host_only_cookies.discard((domain, name)) + self._cookies[(domain, path)].pop(name, None) + self._morsel_cache[(domain, path)].pop(name, None) + self._expirations.pop((domain, path, name), None) + + def _expire_cookie(self, when: float, domain: str, path: str, name: str) -> None: + cookie_key = (domain, path, name) + if self._expirations.get(cookie_key) == when: + # Avoid adding duplicates to the heap + return + heapq.heappush(self._expire_heap, (when, cookie_key)) + self._expirations[cookie_key] = when + + def update_cookies(self, cookies: LooseCookies, response_url: URL = URL()) -> None: + """Update cookies.""" + hostname = response_url.raw_host + + if not self._unsafe and is_ip_address(hostname): + # Don't accept cookies from IPs + return + + if isinstance(cookies, Mapping): + cookies = cookies.items() + + for name, cookie in cookies: + if not isinstance(cookie, Morsel): + tmp = SimpleCookie() + tmp[name] = cookie # type: ignore[assignment] + cookie = tmp[name] + + domain = cookie["domain"] + + # ignore domains with trailing dots + if domain and domain[-1] == ".": + domain = "" + del cookie["domain"] + + if not domain and hostname is not None: + # Set the cookie's domain to the response hostname + # and set its host-only-flag + self._host_only_cookies.add((hostname, name)) + domain = cookie["domain"] = hostname + + if domain and domain[0] == ".": + # Remove leading dot + domain = domain[1:] + cookie["domain"] = domain + + if hostname and not self._is_domain_match(domain, hostname): + # Setting cookies for different domains is not allowed + continue + + path = cookie["path"] + if not path or path[0] != "/": + # Set the cookie's path to the response path + path = response_url.path + if not path.startswith("/"): + path = "/" + else: + # Cut everything from the last slash to the end + path = "/" + path[1 : path.rfind("/")] + cookie["path"] = path + path = path.rstrip("/") + + if max_age := cookie["max-age"]: + try: + delta_seconds = int(max_age) + max_age_expiration = min(time.time() + delta_seconds, self.MAX_TIME) + self._expire_cookie(max_age_expiration, domain, path, name) + except ValueError: + cookie["max-age"] = "" + + elif expires := cookie["expires"]: + if expire_time := self._parse_date(expires): + self._expire_cookie(expire_time, domain, path, name) + else: + cookie["expires"] = "" + + key = (domain, path) + if self._cookies[key].get(name) != cookie: + # Don't blow away the cache if the same + # cookie gets set again + self._cookies[key][name] = cookie + self._morsel_cache[key].pop(name, None) + + self._do_expiration() + + def filter_cookies(self, request_url: URL = URL()) -> "BaseCookie[str]": + """Returns this jar's cookies filtered by their attributes.""" + filtered: Union[SimpleCookie, "BaseCookie[str]"] = ( + SimpleCookie() if self._quote_cookie else BaseCookie() + ) + if not self._cookies: + # Skip do_expiration() if there are no cookies. + return filtered + self._do_expiration() + if not self._cookies: + # Skip rest of function if no non-expired cookies. + return filtered + if type(request_url) is not URL: + warnings.warn( + "filter_cookies expects yarl.URL instances only," + f"and will stop working in 4.x, got {type(request_url)}", + DeprecationWarning, + stacklevel=2, + ) + request_url = URL(request_url) + hostname = request_url.raw_host or "" + + is_not_secure = request_url.scheme not in ("https", "wss") + if is_not_secure and self._treat_as_secure_origin: + request_origin = URL() + with contextlib.suppress(ValueError): + request_origin = request_url.origin() + is_not_secure = request_origin not in self._treat_as_secure_origin + + # Send shared cookie + for c in self._cookies[("", "")].values(): + filtered[c.key] = c.value + + if is_ip_address(hostname): + if not self._unsafe: + return filtered + domains: Iterable[str] = (hostname,) + else: + # Get all the subdomains that might match a cookie (e.g. "foo.bar.com", "bar.com", "com") + domains = itertools.accumulate( + reversed(hostname.split(".")), _FORMAT_DOMAIN_REVERSED + ) + + # Get all the path prefixes that might match a cookie (e.g. "", "/foo", "/foo/bar") + paths = itertools.accumulate(request_url.path.split("/"), _FORMAT_PATH) + # Create every combination of (domain, path) pairs. + pairs = itertools.product(domains, paths) + + path_len = len(request_url.path) + # Point 2: https://www.rfc-editor.org/rfc/rfc6265.html#section-5.4 + for p in pairs: + for name, cookie in self._cookies[p].items(): + domain = cookie["domain"] + + if (domain, name) in self._host_only_cookies and domain != hostname: + continue + + # Skip edge case when the cookie has a trailing slash but request doesn't. + if len(cookie["path"]) > path_len: + continue + + if is_not_secure and cookie["secure"]: + continue + + # We already built the Morsel so reuse it here + if name in self._morsel_cache[p]: + filtered[name] = self._morsel_cache[p][name] + continue + + # It's critical we use the Morsel so the coded_value + # (based on cookie version) is preserved + mrsl_val = cast("Morsel[str]", cookie.get(cookie.key, Morsel())) + mrsl_val.set(cookie.key, cookie.value, cookie.coded_value) + self._morsel_cache[p][name] = mrsl_val + filtered[name] = mrsl_val + + return filtered + + @staticmethod + def _is_domain_match(domain: str, hostname: str) -> bool: + """Implements domain matching adhering to RFC 6265.""" + if hostname == domain: + return True + + if not hostname.endswith(domain): + return False + + non_matching = hostname[: -len(domain)] + + if not non_matching.endswith("."): + return False + + return not is_ip_address(hostname) + + @classmethod + def _parse_date(cls, date_str: str) -> Optional[int]: + """Implements date string parsing adhering to RFC 6265.""" + if not date_str: + return None + + found_time = False + found_day = False + found_month = False + found_year = False + + hour = minute = second = 0 + day = 0 + month = 0 + year = 0 + + for token_match in cls.DATE_TOKENS_RE.finditer(date_str): + + token = token_match.group("token") + + if not found_time: + time_match = cls.DATE_HMS_TIME_RE.match(token) + if time_match: + found_time = True + hour, minute, second = (int(s) for s in time_match.groups()) + continue + + if not found_day: + day_match = cls.DATE_DAY_OF_MONTH_RE.match(token) + if day_match: + found_day = True + day = int(day_match.group()) + continue + + if not found_month: + month_match = cls.DATE_MONTH_RE.match(token) + if month_match: + found_month = True + assert month_match.lastindex is not None + month = month_match.lastindex + continue + + if not found_year: + year_match = cls.DATE_YEAR_RE.match(token) + if year_match: + found_year = True + year = int(year_match.group()) + + if 70 <= year <= 99: + year += 1900 + elif 0 <= year <= 69: + year += 2000 + + if False in (found_day, found_month, found_year, found_time): + return None + + if not 1 <= day <= 31: + return None + + if year < 1601 or hour > 23 or minute > 59 or second > 59: + return None + + return calendar.timegm((year, month, day, hour, minute, second, -1, -1, -1)) + + +class DummyCookieJar(AbstractCookieJar): + """Implements a dummy cookie storage. + + It can be used with the ClientSession when no cookie processing is needed. + + """ + + def __init__(self, *, loop: Optional[asyncio.AbstractEventLoop] = None) -> None: + super().__init__(loop=loop) + + def __iter__(self) -> "Iterator[Morsel[str]]": + while False: + yield None + + def __len__(self) -> int: + return 0 + + @property + def quote_cookie(self) -> bool: + return True + + def clear(self, predicate: Optional[ClearCookiePredicate] = None) -> None: + pass + + def clear_domain(self, domain: str) -> None: + pass + + def update_cookies(self, cookies: LooseCookies, response_url: URL = URL()) -> None: + pass + + def filter_cookies(self, request_url: URL) -> "BaseCookie[str]": + return SimpleCookie() diff --git a/venv/lib/python3.12/site-packages/aiohttp/formdata.py b/venv/lib/python3.12/site-packages/aiohttp/formdata.py new file mode 100644 index 00000000..73056f4b --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/formdata.py @@ -0,0 +1,182 @@ +import io +import warnings +from typing import Any, Iterable, List, Optional +from urllib.parse import urlencode + +from multidict import MultiDict, MultiDictProxy + +from . import hdrs, multipart, payload +from .helpers import guess_filename +from .payload import Payload + +__all__ = ("FormData",) + + +class FormData: + """Helper class for form body generation. + + Supports multipart/form-data and application/x-www-form-urlencoded. + """ + + def __init__( + self, + fields: Iterable[Any] = (), + quote_fields: bool = True, + charset: Optional[str] = None, + *, + default_to_multipart: bool = False, + ) -> None: + self._writer = multipart.MultipartWriter("form-data") + self._fields: List[Any] = [] + self._is_multipart = default_to_multipart + self._is_processed = False + self._quote_fields = quote_fields + self._charset = charset + + if isinstance(fields, dict): + fields = list(fields.items()) + elif not isinstance(fields, (list, tuple)): + fields = (fields,) + self.add_fields(*fields) + + @property + def is_multipart(self) -> bool: + return self._is_multipart + + def add_field( + self, + name: str, + value: Any, + *, + content_type: Optional[str] = None, + filename: Optional[str] = None, + content_transfer_encoding: Optional[str] = None, + ) -> None: + + if isinstance(value, io.IOBase): + self._is_multipart = True + elif isinstance(value, (bytes, bytearray, memoryview)): + msg = ( + "In v4, passing bytes will no longer create a file field. " + "Please explicitly use the filename parameter or pass a BytesIO object." + ) + if filename is None and content_transfer_encoding is None: + warnings.warn(msg, DeprecationWarning) + filename = name + + type_options: MultiDict[str] = MultiDict({"name": name}) + if filename is not None and not isinstance(filename, str): + raise TypeError("filename must be an instance of str. Got: %s" % filename) + if filename is None and isinstance(value, io.IOBase): + filename = guess_filename(value, name) + if filename is not None: + type_options["filename"] = filename + self._is_multipart = True + + headers = {} + if content_type is not None: + if not isinstance(content_type, str): + raise TypeError( + "content_type must be an instance of str. Got: %s" % content_type + ) + headers[hdrs.CONTENT_TYPE] = content_type + self._is_multipart = True + if content_transfer_encoding is not None: + if not isinstance(content_transfer_encoding, str): + raise TypeError( + "content_transfer_encoding must be an instance" + " of str. Got: %s" % content_transfer_encoding + ) + msg = ( + "content_transfer_encoding is deprecated. " + "To maintain compatibility with v4 please pass a BytesPayload." + ) + warnings.warn(msg, DeprecationWarning) + self._is_multipart = True + + self._fields.append((type_options, headers, value)) + + def add_fields(self, *fields: Any) -> None: + to_add = list(fields) + + while to_add: + rec = to_add.pop(0) + + if isinstance(rec, io.IOBase): + k = guess_filename(rec, "unknown") + self.add_field(k, rec) # type: ignore[arg-type] + + elif isinstance(rec, (MultiDictProxy, MultiDict)): + to_add.extend(rec.items()) + + elif isinstance(rec, (list, tuple)) and len(rec) == 2: + k, fp = rec + self.add_field(k, fp) # type: ignore[arg-type] + + else: + raise TypeError( + "Only io.IOBase, multidict and (name, file) " + "pairs allowed, use .add_field() for passing " + "more complex parameters, got {!r}".format(rec) + ) + + def _gen_form_urlencoded(self) -> payload.BytesPayload: + # form data (x-www-form-urlencoded) + data = [] + for type_options, _, value in self._fields: + data.append((type_options["name"], value)) + + charset = self._charset if self._charset is not None else "utf-8" + + if charset == "utf-8": + content_type = "application/x-www-form-urlencoded" + else: + content_type = "application/x-www-form-urlencoded; charset=%s" % charset + + return payload.BytesPayload( + urlencode(data, doseq=True, encoding=charset).encode(), + content_type=content_type, + ) + + def _gen_form_data(self) -> multipart.MultipartWriter: + """Encode a list of fields using the multipart/form-data MIME format""" + if self._is_processed: + raise RuntimeError("Form data has been processed already") + for dispparams, headers, value in self._fields: + try: + if hdrs.CONTENT_TYPE in headers: + part = payload.get_payload( + value, + content_type=headers[hdrs.CONTENT_TYPE], + headers=headers, + encoding=self._charset, + ) + else: + part = payload.get_payload( + value, headers=headers, encoding=self._charset + ) + except Exception as exc: + raise TypeError( + "Can not serialize value type: %r\n " + "headers: %r\n value: %r" % (type(value), headers, value) + ) from exc + + if dispparams: + part.set_content_disposition( + "form-data", quote_fields=self._quote_fields, **dispparams + ) + # FIXME cgi.FieldStorage doesn't likes body parts with + # Content-Length which were sent via chunked transfer encoding + assert part.headers is not None + part.headers.popall(hdrs.CONTENT_LENGTH, None) + + self._writer.append_payload(part) + + self._is_processed = True + return self._writer + + def __call__(self) -> Payload: + if self._is_multipart: + return self._gen_form_data() + else: + return self._gen_form_urlencoded() diff --git a/venv/lib/python3.12/site-packages/aiohttp/hdrs.py b/venv/lib/python3.12/site-packages/aiohttp/hdrs.py new file mode 100644 index 00000000..c8d6b35f --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/hdrs.py @@ -0,0 +1,121 @@ +"""HTTP Headers constants.""" + +# After changing the file content call ./tools/gen.py +# to regenerate the headers parser +import itertools +from typing import Final, Set + +from multidict import istr + +METH_ANY: Final[str] = "*" +METH_CONNECT: Final[str] = "CONNECT" +METH_HEAD: Final[str] = "HEAD" +METH_GET: Final[str] = "GET" +METH_DELETE: Final[str] = "DELETE" +METH_OPTIONS: Final[str] = "OPTIONS" +METH_PATCH: Final[str] = "PATCH" +METH_POST: Final[str] = "POST" +METH_PUT: Final[str] = "PUT" +METH_TRACE: Final[str] = "TRACE" + +METH_ALL: Final[Set[str]] = { + METH_CONNECT, + METH_HEAD, + METH_GET, + METH_DELETE, + METH_OPTIONS, + METH_PATCH, + METH_POST, + METH_PUT, + METH_TRACE, +} + +ACCEPT: Final[istr] = istr("Accept") +ACCEPT_CHARSET: Final[istr] = istr("Accept-Charset") +ACCEPT_ENCODING: Final[istr] = istr("Accept-Encoding") +ACCEPT_LANGUAGE: Final[istr] = istr("Accept-Language") +ACCEPT_RANGES: Final[istr] = istr("Accept-Ranges") +ACCESS_CONTROL_MAX_AGE: Final[istr] = istr("Access-Control-Max-Age") +ACCESS_CONTROL_ALLOW_CREDENTIALS: Final[istr] = istr("Access-Control-Allow-Credentials") +ACCESS_CONTROL_ALLOW_HEADERS: Final[istr] = istr("Access-Control-Allow-Headers") +ACCESS_CONTROL_ALLOW_METHODS: Final[istr] = istr("Access-Control-Allow-Methods") +ACCESS_CONTROL_ALLOW_ORIGIN: Final[istr] = istr("Access-Control-Allow-Origin") +ACCESS_CONTROL_EXPOSE_HEADERS: Final[istr] = istr("Access-Control-Expose-Headers") +ACCESS_CONTROL_REQUEST_HEADERS: Final[istr] = istr("Access-Control-Request-Headers") +ACCESS_CONTROL_REQUEST_METHOD: Final[istr] = istr("Access-Control-Request-Method") +AGE: Final[istr] = istr("Age") +ALLOW: Final[istr] = istr("Allow") +AUTHORIZATION: Final[istr] = istr("Authorization") +CACHE_CONTROL: Final[istr] = istr("Cache-Control") +CONNECTION: Final[istr] = istr("Connection") +CONTENT_DISPOSITION: Final[istr] = istr("Content-Disposition") +CONTENT_ENCODING: Final[istr] = istr("Content-Encoding") +CONTENT_LANGUAGE: Final[istr] = istr("Content-Language") +CONTENT_LENGTH: Final[istr] = istr("Content-Length") +CONTENT_LOCATION: Final[istr] = istr("Content-Location") +CONTENT_MD5: Final[istr] = istr("Content-MD5") +CONTENT_RANGE: Final[istr] = istr("Content-Range") +CONTENT_TRANSFER_ENCODING: Final[istr] = istr("Content-Transfer-Encoding") +CONTENT_TYPE: Final[istr] = istr("Content-Type") +COOKIE: Final[istr] = istr("Cookie") +DATE: Final[istr] = istr("Date") +DESTINATION: Final[istr] = istr("Destination") +DIGEST: Final[istr] = istr("Digest") +ETAG: Final[istr] = istr("Etag") +EXPECT: Final[istr] = istr("Expect") +EXPIRES: Final[istr] = istr("Expires") +FORWARDED: Final[istr] = istr("Forwarded") +FROM: Final[istr] = istr("From") +HOST: Final[istr] = istr("Host") +IF_MATCH: Final[istr] = istr("If-Match") +IF_MODIFIED_SINCE: Final[istr] = istr("If-Modified-Since") +IF_NONE_MATCH: Final[istr] = istr("If-None-Match") +IF_RANGE: Final[istr] = istr("If-Range") +IF_UNMODIFIED_SINCE: Final[istr] = istr("If-Unmodified-Since") +KEEP_ALIVE: Final[istr] = istr("Keep-Alive") +LAST_EVENT_ID: Final[istr] = istr("Last-Event-ID") +LAST_MODIFIED: Final[istr] = istr("Last-Modified") +LINK: Final[istr] = istr("Link") +LOCATION: Final[istr] = istr("Location") +MAX_FORWARDS: Final[istr] = istr("Max-Forwards") +ORIGIN: Final[istr] = istr("Origin") +PRAGMA: Final[istr] = istr("Pragma") +PROXY_AUTHENTICATE: Final[istr] = istr("Proxy-Authenticate") +PROXY_AUTHORIZATION: Final[istr] = istr("Proxy-Authorization") +RANGE: Final[istr] = istr("Range") +REFERER: Final[istr] = istr("Referer") +RETRY_AFTER: Final[istr] = istr("Retry-After") +SEC_WEBSOCKET_ACCEPT: Final[istr] = istr("Sec-WebSocket-Accept") +SEC_WEBSOCKET_VERSION: Final[istr] = istr("Sec-WebSocket-Version") +SEC_WEBSOCKET_PROTOCOL: Final[istr] = istr("Sec-WebSocket-Protocol") +SEC_WEBSOCKET_EXTENSIONS: Final[istr] = istr("Sec-WebSocket-Extensions") +SEC_WEBSOCKET_KEY: Final[istr] = istr("Sec-WebSocket-Key") +SEC_WEBSOCKET_KEY1: Final[istr] = istr("Sec-WebSocket-Key1") +SERVER: Final[istr] = istr("Server") +SET_COOKIE: Final[istr] = istr("Set-Cookie") +TE: Final[istr] = istr("TE") +TRAILER: Final[istr] = istr("Trailer") +TRANSFER_ENCODING: Final[istr] = istr("Transfer-Encoding") +UPGRADE: Final[istr] = istr("Upgrade") +URI: Final[istr] = istr("URI") +USER_AGENT: Final[istr] = istr("User-Agent") +VARY: Final[istr] = istr("Vary") +VIA: Final[istr] = istr("Via") +WANT_DIGEST: Final[istr] = istr("Want-Digest") +WARNING: Final[istr] = istr("Warning") +WWW_AUTHENTICATE: Final[istr] = istr("WWW-Authenticate") +X_FORWARDED_FOR: Final[istr] = istr("X-Forwarded-For") +X_FORWARDED_HOST: Final[istr] = istr("X-Forwarded-Host") +X_FORWARDED_PROTO: Final[istr] = istr("X-Forwarded-Proto") + +# These are the upper/lower case variants of the headers/methods +# Example: {'hOst', 'host', 'HoST', 'HOSt', 'hOsT', 'HosT', 'hoSt', ...} +METH_HEAD_ALL: Final = frozenset( + map("".join, itertools.product(*zip(METH_HEAD.upper(), METH_HEAD.lower()))) +) +METH_CONNECT_ALL: Final = frozenset( + map("".join, itertools.product(*zip(METH_CONNECT.upper(), METH_CONNECT.lower()))) +) +HOST_ALL: Final = frozenset( + map("".join, itertools.product(*zip(HOST.upper(), HOST.lower()))) +) diff --git a/venv/lib/python3.12/site-packages/aiohttp/helpers.py b/venv/lib/python3.12/site-packages/aiohttp/helpers.py new file mode 100644 index 00000000..ace4f0e9 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/helpers.py @@ -0,0 +1,958 @@ +"""Various helper functions""" + +import asyncio +import base64 +import binascii +import contextlib +import datetime +import enum +import functools +import inspect +import netrc +import os +import platform +import re +import sys +import time +import weakref +from collections import namedtuple +from contextlib import suppress +from email.parser import HeaderParser +from email.utils import parsedate +from math import ceil +from pathlib import Path +from types import MappingProxyType, TracebackType +from typing import ( + Any, + Callable, + ContextManager, + Dict, + Generator, + Generic, + Iterable, + Iterator, + List, + Mapping, + Optional, + Protocol, + Tuple, + Type, + TypeVar, + Union, + get_args, + overload, +) +from urllib.parse import quote +from urllib.request import getproxies, proxy_bypass + +import attr +from multidict import MultiDict, MultiDictProxy, MultiMapping +from propcache.api import under_cached_property as reify +from yarl import URL + +from . import hdrs +from .log import client_logger + +if sys.version_info >= (3, 11): + import asyncio as async_timeout +else: + import async_timeout + +__all__ = ("BasicAuth", "ChainMapProxy", "ETag", "reify") + +IS_MACOS = platform.system() == "Darwin" +IS_WINDOWS = platform.system() == "Windows" + +PY_310 = sys.version_info >= (3, 10) +PY_311 = sys.version_info >= (3, 11) + + +_T = TypeVar("_T") +_S = TypeVar("_S") + +_SENTINEL = enum.Enum("_SENTINEL", "sentinel") +sentinel = _SENTINEL.sentinel + +NO_EXTENSIONS = bool(os.environ.get("AIOHTTP_NO_EXTENSIONS")) + +# https://datatracker.ietf.org/doc/html/rfc9112#section-6.3-2.1 +EMPTY_BODY_STATUS_CODES = frozenset((204, 304, *range(100, 200))) +# https://datatracker.ietf.org/doc/html/rfc9112#section-6.3-2.1 +# https://datatracker.ietf.org/doc/html/rfc9112#section-6.3-2.2 +EMPTY_BODY_METHODS = hdrs.METH_HEAD_ALL + +DEBUG = sys.flags.dev_mode or ( + not sys.flags.ignore_environment and bool(os.environ.get("PYTHONASYNCIODEBUG")) +) + + +CHAR = {chr(i) for i in range(0, 128)} +CTL = {chr(i) for i in range(0, 32)} | { + chr(127), +} +SEPARATORS = { + "(", + ")", + "<", + ">", + "@", + ",", + ";", + ":", + "\\", + '"', + "/", + "[", + "]", + "?", + "=", + "{", + "}", + " ", + chr(9), +} +TOKEN = CHAR ^ CTL ^ SEPARATORS + + +class noop: + def __await__(self) -> Generator[None, None, None]: + yield + + +class BasicAuth(namedtuple("BasicAuth", ["login", "password", "encoding"])): + """Http basic authentication helper.""" + + def __new__( + cls, login: str, password: str = "", encoding: str = "latin1" + ) -> "BasicAuth": + if login is None: + raise ValueError("None is not allowed as login value") + + if password is None: + raise ValueError("None is not allowed as password value") + + if ":" in login: + raise ValueError('A ":" is not allowed in login (RFC 1945#section-11.1)') + + return super().__new__(cls, login, password, encoding) + + @classmethod + def decode(cls, auth_header: str, encoding: str = "latin1") -> "BasicAuth": + """Create a BasicAuth object from an Authorization HTTP header.""" + try: + auth_type, encoded_credentials = auth_header.split(" ", 1) + except ValueError: + raise ValueError("Could not parse authorization header.") + + if auth_type.lower() != "basic": + raise ValueError("Unknown authorization method %s" % auth_type) + + try: + decoded = base64.b64decode( + encoded_credentials.encode("ascii"), validate=True + ).decode(encoding) + except binascii.Error: + raise ValueError("Invalid base64 encoding.") + + try: + # RFC 2617 HTTP Authentication + # https://www.ietf.org/rfc/rfc2617.txt + # the colon must be present, but the username and password may be + # otherwise blank. + username, password = decoded.split(":", 1) + except ValueError: + raise ValueError("Invalid credentials.") + + return cls(username, password, encoding=encoding) + + @classmethod + def from_url(cls, url: URL, *, encoding: str = "latin1") -> Optional["BasicAuth"]: + """Create BasicAuth from url.""" + if not isinstance(url, URL): + raise TypeError("url should be yarl.URL instance") + # Check raw_user and raw_password first as yarl is likely + # to already have these values parsed from the netloc in the cache. + if url.raw_user is None and url.raw_password is None: + return None + return cls(url.user or "", url.password or "", encoding=encoding) + + def encode(self) -> str: + """Encode credentials.""" + creds = (f"{self.login}:{self.password}").encode(self.encoding) + return "Basic %s" % base64.b64encode(creds).decode(self.encoding) + + +def strip_auth_from_url(url: URL) -> Tuple[URL, Optional[BasicAuth]]: + """Remove user and password from URL if present and return BasicAuth object.""" + # Check raw_user and raw_password first as yarl is likely + # to already have these values parsed from the netloc in the cache. + if url.raw_user is None and url.raw_password is None: + return url, None + return url.with_user(None), BasicAuth(url.user or "", url.password or "") + + +def netrc_from_env() -> Optional[netrc.netrc]: + """Load netrc from file. + + Attempt to load it from the path specified by the env-var + NETRC or in the default location in the user's home directory. + + Returns None if it couldn't be found or fails to parse. + """ + netrc_env = os.environ.get("NETRC") + + if netrc_env is not None: + netrc_path = Path(netrc_env) + else: + try: + home_dir = Path.home() + except RuntimeError as e: # pragma: no cover + # if pathlib can't resolve home, it may raise a RuntimeError + client_logger.debug( + "Could not resolve home directory when " + "trying to look for .netrc file: %s", + e, + ) + return None + + netrc_path = home_dir / ("_netrc" if IS_WINDOWS else ".netrc") + + try: + return netrc.netrc(str(netrc_path)) + except netrc.NetrcParseError as e: + client_logger.warning("Could not parse .netrc file: %s", e) + except OSError as e: + netrc_exists = False + with contextlib.suppress(OSError): + netrc_exists = netrc_path.is_file() + # we couldn't read the file (doesn't exist, permissions, etc.) + if netrc_env or netrc_exists: + # only warn if the environment wanted us to load it, + # or it appears like the default file does actually exist + client_logger.warning("Could not read .netrc file: %s", e) + + return None + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class ProxyInfo: + proxy: URL + proxy_auth: Optional[BasicAuth] + + +def basicauth_from_netrc(netrc_obj: Optional[netrc.netrc], host: str) -> BasicAuth: + """ + Return :py:class:`~aiohttp.BasicAuth` credentials for ``host`` from ``netrc_obj``. + + :raises LookupError: if ``netrc_obj`` is :py:data:`None` or if no + entry is found for the ``host``. + """ + if netrc_obj is None: + raise LookupError("No .netrc file found") + auth_from_netrc = netrc_obj.authenticators(host) + + if auth_from_netrc is None: + raise LookupError(f"No entry for {host!s} found in the `.netrc` file.") + login, account, password = auth_from_netrc + + # TODO(PY311): username = login or account + # Up to python 3.10, account could be None if not specified, + # and login will be empty string if not specified. From 3.11, + # login and account will be empty string if not specified. + username = login if (login or account is None) else account + + # TODO(PY311): Remove this, as password will be empty string + # if not specified + if password is None: + password = "" + + return BasicAuth(username, password) + + +def proxies_from_env() -> Dict[str, ProxyInfo]: + proxy_urls = { + k: URL(v) + for k, v in getproxies().items() + if k in ("http", "https", "ws", "wss") + } + netrc_obj = netrc_from_env() + stripped = {k: strip_auth_from_url(v) for k, v in proxy_urls.items()} + ret = {} + for proto, val in stripped.items(): + proxy, auth = val + if proxy.scheme in ("https", "wss"): + client_logger.warning( + "%s proxies %s are not supported, ignoring", proxy.scheme.upper(), proxy + ) + continue + if netrc_obj and auth is None: + if proxy.host is not None: + try: + auth = basicauth_from_netrc(netrc_obj, proxy.host) + except LookupError: + auth = None + ret[proto] = ProxyInfo(proxy, auth) + return ret + + +def get_env_proxy_for_url(url: URL) -> Tuple[URL, Optional[BasicAuth]]: + """Get a permitted proxy for the given URL from the env.""" + if url.host is not None and proxy_bypass(url.host): + raise LookupError(f"Proxying is disallowed for `{url.host!r}`") + + proxies_in_env = proxies_from_env() + try: + proxy_info = proxies_in_env[url.scheme] + except KeyError: + raise LookupError(f"No proxies found for `{url!s}` in the env") + else: + return proxy_info.proxy, proxy_info.proxy_auth + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class MimeType: + type: str + subtype: str + suffix: str + parameters: "MultiDictProxy[str]" + + +@functools.lru_cache(maxsize=56) +def parse_mimetype(mimetype: str) -> MimeType: + """Parses a MIME type into its components. + + mimetype is a MIME type string. + + Returns a MimeType object. + + Example: + + >>> parse_mimetype('text/html; charset=utf-8') + MimeType(type='text', subtype='html', suffix='', + parameters={'charset': 'utf-8'}) + + """ + if not mimetype: + return MimeType( + type="", subtype="", suffix="", parameters=MultiDictProxy(MultiDict()) + ) + + parts = mimetype.split(";") + params: MultiDict[str] = MultiDict() + for item in parts[1:]: + if not item: + continue + key, _, value = item.partition("=") + params.add(key.lower().strip(), value.strip(' "')) + + fulltype = parts[0].strip().lower() + if fulltype == "*": + fulltype = "*/*" + + mtype, _, stype = fulltype.partition("/") + stype, _, suffix = stype.partition("+") + + return MimeType( + type=mtype, subtype=stype, suffix=suffix, parameters=MultiDictProxy(params) + ) + + +@functools.lru_cache(maxsize=56) +def parse_content_type(raw: str) -> Tuple[str, MappingProxyType[str, str]]: + """Parse Content-Type header. + + Returns a tuple of the parsed content type and a + MappingProxyType of parameters. + """ + msg = HeaderParser().parsestr(f"Content-Type: {raw}") + content_type = msg.get_content_type() + params = msg.get_params(()) + content_dict = dict(params[1:]) # First element is content type again + return content_type, MappingProxyType(content_dict) + + +def guess_filename(obj: Any, default: Optional[str] = None) -> Optional[str]: + name = getattr(obj, "name", None) + if name and isinstance(name, str) and name[0] != "<" and name[-1] != ">": + return Path(name).name + return default + + +not_qtext_re = re.compile(r"[^\041\043-\133\135-\176]") +QCONTENT = {chr(i) for i in range(0x20, 0x7F)} | {"\t"} + + +def quoted_string(content: str) -> str: + """Return 7-bit content as quoted-string. + + Format content into a quoted-string as defined in RFC5322 for + Internet Message Format. Notice that this is not the 8-bit HTTP + format, but the 7-bit email format. Content must be in usascii or + a ValueError is raised. + """ + if not (QCONTENT > set(content)): + raise ValueError(f"bad content for quoted-string {content!r}") + return not_qtext_re.sub(lambda x: "\\" + x.group(0), content) + + +def content_disposition_header( + disptype: str, quote_fields: bool = True, _charset: str = "utf-8", **params: str +) -> str: + """Sets ``Content-Disposition`` header for MIME. + + This is the MIME payload Content-Disposition header from RFC 2183 + and RFC 7579 section 4.2, not the HTTP Content-Disposition from + RFC 6266. + + disptype is a disposition type: inline, attachment, form-data. + Should be valid extension token (see RFC 2183) + + quote_fields performs value quoting to 7-bit MIME headers + according to RFC 7578. Set to quote_fields to False if recipient + can take 8-bit file names and field values. + + _charset specifies the charset to use when quote_fields is True. + + params is a dict with disposition params. + """ + if not disptype or not (TOKEN > set(disptype)): + raise ValueError(f"bad content disposition type {disptype!r}") + + value = disptype + if params: + lparams = [] + for key, val in params.items(): + if not key or not (TOKEN > set(key)): + raise ValueError(f"bad content disposition parameter {key!r}={val!r}") + if quote_fields: + if key.lower() == "filename": + qval = quote(val, "", encoding=_charset) + lparams.append((key, '"%s"' % qval)) + else: + try: + qval = quoted_string(val) + except ValueError: + qval = "".join( + (_charset, "''", quote(val, "", encoding=_charset)) + ) + lparams.append((key + "*", qval)) + else: + lparams.append((key, '"%s"' % qval)) + else: + qval = val.replace("\\", "\\\\").replace('"', '\\"') + lparams.append((key, '"%s"' % qval)) + sparams = "; ".join("=".join(pair) for pair in lparams) + value = "; ".join((value, sparams)) + return value + + +def is_ip_address(host: Optional[str]) -> bool: + """Check if host looks like an IP Address. + + This check is only meant as a heuristic to ensure that + a host is not a domain name. + """ + if not host: + return False + # For a host to be an ipv4 address, it must be all numeric. + # The host must contain a colon to be an IPv6 address. + return ":" in host or host.replace(".", "").isdigit() + + +_cached_current_datetime: Optional[int] = None +_cached_formatted_datetime = "" + + +def rfc822_formatted_time() -> str: + global _cached_current_datetime + global _cached_formatted_datetime + + now = int(time.time()) + if now != _cached_current_datetime: + # Weekday and month names for HTTP date/time formatting; + # always English! + # Tuples are constants stored in codeobject! + _weekdayname = ("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun") + _monthname = ( + "", # Dummy so we can use 1-based month numbers + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", + ) + + year, month, day, hh, mm, ss, wd, *tail = time.gmtime(now) + _cached_formatted_datetime = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % ( + _weekdayname[wd], + day, + _monthname[month], + year, + hh, + mm, + ss, + ) + _cached_current_datetime = now + return _cached_formatted_datetime + + +def _weakref_handle(info: "Tuple[weakref.ref[object], str]") -> None: + ref, name = info + ob = ref() + if ob is not None: + with suppress(Exception): + getattr(ob, name)() + + +def weakref_handle( + ob: object, + name: str, + timeout: float, + loop: asyncio.AbstractEventLoop, + timeout_ceil_threshold: float = 5, +) -> Optional[asyncio.TimerHandle]: + if timeout is not None and timeout > 0: + when = loop.time() + timeout + if timeout >= timeout_ceil_threshold: + when = ceil(when) + + return loop.call_at(when, _weakref_handle, (weakref.ref(ob), name)) + return None + + +def call_later( + cb: Callable[[], Any], + timeout: float, + loop: asyncio.AbstractEventLoop, + timeout_ceil_threshold: float = 5, +) -> Optional[asyncio.TimerHandle]: + if timeout is None or timeout <= 0: + return None + now = loop.time() + when = calculate_timeout_when(now, timeout, timeout_ceil_threshold) + return loop.call_at(when, cb) + + +def calculate_timeout_when( + loop_time: float, + timeout: float, + timeout_ceiling_threshold: float, +) -> float: + """Calculate when to execute a timeout.""" + when = loop_time + timeout + if timeout > timeout_ceiling_threshold: + return ceil(when) + return when + + +class TimeoutHandle: + """Timeout handle""" + + __slots__ = ("_timeout", "_loop", "_ceil_threshold", "_callbacks") + + def __init__( + self, + loop: asyncio.AbstractEventLoop, + timeout: Optional[float], + ceil_threshold: float = 5, + ) -> None: + self._timeout = timeout + self._loop = loop + self._ceil_threshold = ceil_threshold + self._callbacks: List[ + Tuple[Callable[..., None], Tuple[Any, ...], Dict[str, Any]] + ] = [] + + def register( + self, callback: Callable[..., None], *args: Any, **kwargs: Any + ) -> None: + self._callbacks.append((callback, args, kwargs)) + + def close(self) -> None: + self._callbacks.clear() + + def start(self) -> Optional[asyncio.TimerHandle]: + timeout = self._timeout + if timeout is not None and timeout > 0: + when = self._loop.time() + timeout + if timeout >= self._ceil_threshold: + when = ceil(when) + return self._loop.call_at(when, self.__call__) + else: + return None + + def timer(self) -> "BaseTimerContext": + if self._timeout is not None and self._timeout > 0: + timer = TimerContext(self._loop) + self.register(timer.timeout) + return timer + else: + return TimerNoop() + + def __call__(self) -> None: + for cb, args, kwargs in self._callbacks: + with suppress(Exception): + cb(*args, **kwargs) + + self._callbacks.clear() + + +class BaseTimerContext(ContextManager["BaseTimerContext"]): + + __slots__ = () + + def assert_timeout(self) -> None: + """Raise TimeoutError if timeout has been exceeded.""" + + +class TimerNoop(BaseTimerContext): + + __slots__ = () + + def __enter__(self) -> BaseTimerContext: + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + return + + +class TimerContext(BaseTimerContext): + """Low resolution timeout context manager""" + + __slots__ = ("_loop", "_tasks", "_cancelled", "_cancelling") + + def __init__(self, loop: asyncio.AbstractEventLoop) -> None: + self._loop = loop + self._tasks: List[asyncio.Task[Any]] = [] + self._cancelled = False + self._cancelling = 0 + + def assert_timeout(self) -> None: + """Raise TimeoutError if timer has already been cancelled.""" + if self._cancelled: + raise asyncio.TimeoutError from None + + def __enter__(self) -> BaseTimerContext: + task = asyncio.current_task(loop=self._loop) + if task is None: + raise RuntimeError("Timeout context manager should be used inside a task") + + if sys.version_info >= (3, 11): + # Remember if the task was already cancelling + # so when we __exit__ we can decide if we should + # raise asyncio.TimeoutError or let the cancellation propagate + self._cancelling = task.cancelling() + + if self._cancelled: + raise asyncio.TimeoutError from None + + self._tasks.append(task) + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> Optional[bool]: + enter_task: Optional[asyncio.Task[Any]] = None + if self._tasks: + enter_task = self._tasks.pop() + + if exc_type is asyncio.CancelledError and self._cancelled: + assert enter_task is not None + # The timeout was hit, and the task was cancelled + # so we need to uncancel the last task that entered the context manager + # since the cancellation should not leak out of the context manager + if sys.version_info >= (3, 11): + # If the task was already cancelling don't raise + # asyncio.TimeoutError and instead return None + # to allow the cancellation to propagate + if enter_task.uncancel() > self._cancelling: + return None + raise asyncio.TimeoutError from exc_val + return None + + def timeout(self) -> None: + if not self._cancelled: + for task in set(self._tasks): + task.cancel() + + self._cancelled = True + + +def ceil_timeout( + delay: Optional[float], ceil_threshold: float = 5 +) -> async_timeout.Timeout: + if delay is None or delay <= 0: + return async_timeout.timeout(None) + + loop = asyncio.get_running_loop() + now = loop.time() + when = now + delay + if delay > ceil_threshold: + when = ceil(when) + return async_timeout.timeout_at(when) + + +class HeadersMixin: + """Mixin for handling headers.""" + + ATTRS = frozenset(["_content_type", "_content_dict", "_stored_content_type"]) + + _headers: MultiMapping[str] + _content_type: Optional[str] = None + _content_dict: Optional[Dict[str, str]] = None + _stored_content_type: Union[str, None, _SENTINEL] = sentinel + + def _parse_content_type(self, raw: Optional[str]) -> None: + self._stored_content_type = raw + if raw is None: + # default value according to RFC 2616 + self._content_type = "application/octet-stream" + self._content_dict = {} + else: + content_type, content_mapping_proxy = parse_content_type(raw) + self._content_type = content_type + # _content_dict needs to be mutable so we can update it + self._content_dict = content_mapping_proxy.copy() + + @property + def content_type(self) -> str: + """The value of content part for Content-Type HTTP header.""" + raw = self._headers.get(hdrs.CONTENT_TYPE) + if self._stored_content_type != raw: + self._parse_content_type(raw) + assert self._content_type is not None + return self._content_type + + @property + def charset(self) -> Optional[str]: + """The value of charset part for Content-Type HTTP header.""" + raw = self._headers.get(hdrs.CONTENT_TYPE) + if self._stored_content_type != raw: + self._parse_content_type(raw) + assert self._content_dict is not None + return self._content_dict.get("charset") + + @property + def content_length(self) -> Optional[int]: + """The value of Content-Length HTTP header.""" + content_length = self._headers.get(hdrs.CONTENT_LENGTH) + return None if content_length is None else int(content_length) + + +def set_result(fut: "asyncio.Future[_T]", result: _T) -> None: + if not fut.done(): + fut.set_result(result) + + +_EXC_SENTINEL = BaseException() + + +class ErrorableProtocol(Protocol): + def set_exception( + self, + exc: BaseException, + exc_cause: BaseException = ..., + ) -> None: ... # pragma: no cover + + +def set_exception( + fut: "asyncio.Future[_T] | ErrorableProtocol", + exc: BaseException, + exc_cause: BaseException = _EXC_SENTINEL, +) -> None: + """Set future exception. + + If the future is marked as complete, this function is a no-op. + + :param exc_cause: An exception that is a direct cause of ``exc``. + Only set if provided. + """ + if asyncio.isfuture(fut) and fut.done(): + return + + exc_is_sentinel = exc_cause is _EXC_SENTINEL + exc_causes_itself = exc is exc_cause + if not exc_is_sentinel and not exc_causes_itself: + exc.__cause__ = exc_cause + + fut.set_exception(exc) + + +@functools.total_ordering +class AppKey(Generic[_T]): + """Keys for static typing support in Application.""" + + __slots__ = ("_name", "_t", "__orig_class__") + + # This may be set by Python when instantiating with a generic type. We need to + # support this, in order to support types that are not concrete classes, + # like Iterable, which can't be passed as the second parameter to __init__. + __orig_class__: Type[object] + + def __init__(self, name: str, t: Optional[Type[_T]] = None): + # Prefix with module name to help deduplicate key names. + frame = inspect.currentframe() + while frame: + if frame.f_code.co_name == "": + module: str = frame.f_globals["__name__"] + break + frame = frame.f_back + + self._name = module + "." + name + self._t = t + + def __lt__(self, other: object) -> bool: + if isinstance(other, AppKey): + return self._name < other._name + return True # Order AppKey above other types. + + def __repr__(self) -> str: + t = self._t + if t is None: + with suppress(AttributeError): + # Set to type arg. + t = get_args(self.__orig_class__)[0] + + if t is None: + t_repr = "<>" + elif isinstance(t, type): + if t.__module__ == "builtins": + t_repr = t.__qualname__ + else: + t_repr = f"{t.__module__}.{t.__qualname__}" + else: + t_repr = repr(t) + return f"" + + +class ChainMapProxy(Mapping[Union[str, AppKey[Any]], Any]): + __slots__ = ("_maps",) + + def __init__(self, maps: Iterable[Mapping[Union[str, AppKey[Any]], Any]]) -> None: + self._maps = tuple(maps) + + def __init_subclass__(cls) -> None: + raise TypeError( + "Inheritance class {} from ChainMapProxy " + "is forbidden".format(cls.__name__) + ) + + @overload # type: ignore[override] + def __getitem__(self, key: AppKey[_T]) -> _T: ... + + @overload + def __getitem__(self, key: str) -> Any: ... + + def __getitem__(self, key: Union[str, AppKey[_T]]) -> Any: + for mapping in self._maps: + try: + return mapping[key] + except KeyError: + pass + raise KeyError(key) + + @overload # type: ignore[override] + def get(self, key: AppKey[_T], default: _S) -> Union[_T, _S]: ... + + @overload + def get(self, key: AppKey[_T], default: None = ...) -> Optional[_T]: ... + + @overload + def get(self, key: str, default: Any = ...) -> Any: ... + + def get(self, key: Union[str, AppKey[_T]], default: Any = None) -> Any: + try: + return self[key] + except KeyError: + return default + + def __len__(self) -> int: + # reuses stored hash values if possible + return len(set().union(*self._maps)) + + def __iter__(self) -> Iterator[Union[str, AppKey[Any]]]: + d: Dict[Union[str, AppKey[Any]], Any] = {} + for mapping in reversed(self._maps): + # reuses stored hash values if possible + d.update(mapping) + return iter(d) + + def __contains__(self, key: object) -> bool: + return any(key in m for m in self._maps) + + def __bool__(self) -> bool: + return any(self._maps) + + def __repr__(self) -> str: + content = ", ".join(map(repr, self._maps)) + return f"ChainMapProxy({content})" + + +# https://tools.ietf.org/html/rfc7232#section-2.3 +_ETAGC = r"[!\x23-\x7E\x80-\xff]+" +_ETAGC_RE = re.compile(_ETAGC) +_QUOTED_ETAG = rf'(W/)?"({_ETAGC})"' +QUOTED_ETAG_RE = re.compile(_QUOTED_ETAG) +LIST_QUOTED_ETAG_RE = re.compile(rf"({_QUOTED_ETAG})(?:\s*,\s*|$)|(.)") + +ETAG_ANY = "*" + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class ETag: + value: str + is_weak: bool = False + + +def validate_etag_value(value: str) -> None: + if value != ETAG_ANY and not _ETAGC_RE.fullmatch(value): + raise ValueError( + f"Value {value!r} is not a valid etag. Maybe it contains '\"'?" + ) + + +def parse_http_date(date_str: Optional[str]) -> Optional[datetime.datetime]: + """Process a date string, return a datetime object""" + if date_str is not None: + timetuple = parsedate(date_str) + if timetuple is not None: + with suppress(ValueError): + return datetime.datetime(*timetuple[:6], tzinfo=datetime.timezone.utc) + return None + + +@functools.lru_cache +def must_be_empty_body(method: str, code: int) -> bool: + """Check if a request must return an empty body.""" + return ( + code in EMPTY_BODY_STATUS_CODES + or method in EMPTY_BODY_METHODS + or (200 <= code < 300 and method in hdrs.METH_CONNECT_ALL) + ) + + +def should_remove_content_length(method: str, code: int) -> bool: + """Check if a Content-Length header should be removed. + + This should always be a subset of must_be_empty_body + """ + # https://www.rfc-editor.org/rfc/rfc9110.html#section-8.6-8 + # https://www.rfc-editor.org/rfc/rfc9110.html#section-15.4.5-4 + return code in EMPTY_BODY_STATUS_CODES or ( + 200 <= code < 300 and method in hdrs.METH_CONNECT_ALL + ) diff --git a/venv/lib/python3.12/site-packages/aiohttp/http.py b/venv/lib/python3.12/site-packages/aiohttp/http.py new file mode 100644 index 00000000..a1feae2d --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/http.py @@ -0,0 +1,72 @@ +import sys +from http import HTTPStatus +from typing import Mapping, Tuple + +from . import __version__ +from .http_exceptions import HttpProcessingError as HttpProcessingError +from .http_parser import ( + HeadersParser as HeadersParser, + HttpParser as HttpParser, + HttpRequestParser as HttpRequestParser, + HttpResponseParser as HttpResponseParser, + RawRequestMessage as RawRequestMessage, + RawResponseMessage as RawResponseMessage, +) +from .http_websocket import ( + WS_CLOSED_MESSAGE as WS_CLOSED_MESSAGE, + WS_CLOSING_MESSAGE as WS_CLOSING_MESSAGE, + WS_KEY as WS_KEY, + WebSocketError as WebSocketError, + WebSocketReader as WebSocketReader, + WebSocketWriter as WebSocketWriter, + WSCloseCode as WSCloseCode, + WSMessage as WSMessage, + WSMsgType as WSMsgType, + ws_ext_gen as ws_ext_gen, + ws_ext_parse as ws_ext_parse, +) +from .http_writer import ( + HttpVersion as HttpVersion, + HttpVersion10 as HttpVersion10, + HttpVersion11 as HttpVersion11, + StreamWriter as StreamWriter, +) + +__all__ = ( + "HttpProcessingError", + "RESPONSES", + "SERVER_SOFTWARE", + # .http_writer + "StreamWriter", + "HttpVersion", + "HttpVersion10", + "HttpVersion11", + # .http_parser + "HeadersParser", + "HttpParser", + "HttpRequestParser", + "HttpResponseParser", + "RawRequestMessage", + "RawResponseMessage", + # .http_websocket + "WS_CLOSED_MESSAGE", + "WS_CLOSING_MESSAGE", + "WS_KEY", + "WebSocketReader", + "WebSocketWriter", + "ws_ext_gen", + "ws_ext_parse", + "WSMessage", + "WebSocketError", + "WSMsgType", + "WSCloseCode", +) + + +SERVER_SOFTWARE: str = "Python/{0[0]}.{0[1]} aiohttp/{1}".format( + sys.version_info, __version__ +) + +RESPONSES: Mapping[int, Tuple[str, str]] = { + v: (v.phrase, v.description) for v in HTTPStatus.__members__.values() +} diff --git a/venv/lib/python3.12/site-packages/aiohttp/http_exceptions.py b/venv/lib/python3.12/site-packages/aiohttp/http_exceptions.py new file mode 100644 index 00000000..b8dda999 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/http_exceptions.py @@ -0,0 +1,112 @@ +"""Low-level http related exceptions.""" + +from textwrap import indent +from typing import Optional, Union + +from .typedefs import _CIMultiDict + +__all__ = ("HttpProcessingError",) + + +class HttpProcessingError(Exception): + """HTTP error. + + Shortcut for raising HTTP errors with custom code, message and headers. + + code: HTTP Error code. + message: (optional) Error message. + headers: (optional) Headers to be sent in response, a list of pairs + """ + + code = 0 + message = "" + headers = None + + def __init__( + self, + *, + code: Optional[int] = None, + message: str = "", + headers: Optional[_CIMultiDict] = None, + ) -> None: + if code is not None: + self.code = code + self.headers = headers + self.message = message + + def __str__(self) -> str: + msg = indent(self.message, " ") + return f"{self.code}, message:\n{msg}" + + def __repr__(self) -> str: + return f"<{self.__class__.__name__}: {self.code}, message={self.message!r}>" + + +class BadHttpMessage(HttpProcessingError): + + code = 400 + message = "Bad Request" + + def __init__(self, message: str, *, headers: Optional[_CIMultiDict] = None) -> None: + super().__init__(message=message, headers=headers) + self.args = (message,) + + +class HttpBadRequest(BadHttpMessage): + + code = 400 + message = "Bad Request" + + +class PayloadEncodingError(BadHttpMessage): + """Base class for payload errors""" + + +class ContentEncodingError(PayloadEncodingError): + """Content encoding error.""" + + +class TransferEncodingError(PayloadEncodingError): + """transfer encoding error.""" + + +class ContentLengthError(PayloadEncodingError): + """Not enough data for satisfy content length header.""" + + +class LineTooLong(BadHttpMessage): + def __init__( + self, line: str, limit: str = "Unknown", actual_size: str = "Unknown" + ) -> None: + super().__init__( + f"Got more than {limit} bytes ({actual_size}) when reading {line}." + ) + self.args = (line, limit, actual_size) + + +class InvalidHeader(BadHttpMessage): + def __init__(self, hdr: Union[bytes, str]) -> None: + hdr_s = hdr.decode(errors="backslashreplace") if isinstance(hdr, bytes) else hdr + super().__init__(f"Invalid HTTP header: {hdr!r}") + self.hdr = hdr_s + self.args = (hdr,) + + +class BadStatusLine(BadHttpMessage): + def __init__(self, line: str = "", error: Optional[str] = None) -> None: + if not isinstance(line, str): + line = repr(line) + super().__init__(error or f"Bad status line {line!r}") + self.args = (line,) + self.line = line + + +class BadHttpMethod(BadStatusLine): + """Invalid HTTP method in status line.""" + + def __init__(self, line: str = "", error: Optional[str] = None) -> None: + super().__init__(line, error or f"Bad HTTP method in status line {line!r}") + + +class InvalidURLError(BadHttpMessage): + pass diff --git a/venv/lib/python3.12/site-packages/aiohttp/http_parser.py b/venv/lib/python3.12/site-packages/aiohttp/http_parser.py new file mode 100644 index 00000000..1b8b5b4d --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/http_parser.py @@ -0,0 +1,1046 @@ +import abc +import asyncio +import re +import string +from contextlib import suppress +from enum import IntEnum +from typing import ( + Any, + ClassVar, + Final, + Generic, + List, + Literal, + NamedTuple, + Optional, + Pattern, + Set, + Tuple, + Type, + TypeVar, + Union, +) + +from multidict import CIMultiDict, CIMultiDictProxy, istr +from yarl import URL + +from . import hdrs +from .base_protocol import BaseProtocol +from .compression_utils import HAS_BROTLI, BrotliDecompressor, ZLibDecompressor +from .helpers import ( + _EXC_SENTINEL, + DEBUG, + EMPTY_BODY_METHODS, + EMPTY_BODY_STATUS_CODES, + NO_EXTENSIONS, + BaseTimerContext, + set_exception, +) +from .http_exceptions import ( + BadHttpMessage, + BadHttpMethod, + BadStatusLine, + ContentEncodingError, + ContentLengthError, + InvalidHeader, + InvalidURLError, + LineTooLong, + TransferEncodingError, +) +from .http_writer import HttpVersion, HttpVersion10 +from .streams import EMPTY_PAYLOAD, StreamReader +from .typedefs import RawHeaders + +__all__ = ( + "HeadersParser", + "HttpParser", + "HttpRequestParser", + "HttpResponseParser", + "RawRequestMessage", + "RawResponseMessage", +) + +_SEP = Literal[b"\r\n", b"\n"] + +ASCIISET: Final[Set[str]] = set(string.printable) + +# See https://www.rfc-editor.org/rfc/rfc9110.html#name-overview +# and https://www.rfc-editor.org/rfc/rfc9110.html#name-tokens +# +# method = token +# tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / +# "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA +# token = 1*tchar +_TCHAR_SPECIALS: Final[str] = re.escape("!#$%&'*+-.^_`|~") +TOKENRE: Final[Pattern[str]] = re.compile(f"[0-9A-Za-z{_TCHAR_SPECIALS}]+") +VERSRE: Final[Pattern[str]] = re.compile(r"HTTP/(\d)\.(\d)", re.ASCII) +DIGITS: Final[Pattern[str]] = re.compile(r"\d+", re.ASCII) +HEXDIGITS: Final[Pattern[bytes]] = re.compile(rb"[0-9a-fA-F]+") + + +class RawRequestMessage(NamedTuple): + method: str + path: str + version: HttpVersion + headers: "CIMultiDictProxy[str]" + raw_headers: RawHeaders + should_close: bool + compression: Optional[str] + upgrade: bool + chunked: bool + url: URL + + +class RawResponseMessage(NamedTuple): + version: HttpVersion + code: int + reason: str + headers: CIMultiDictProxy[str] + raw_headers: RawHeaders + should_close: bool + compression: Optional[str] + upgrade: bool + chunked: bool + + +_MsgT = TypeVar("_MsgT", RawRequestMessage, RawResponseMessage) + + +class ParseState(IntEnum): + + PARSE_NONE = 0 + PARSE_LENGTH = 1 + PARSE_CHUNKED = 2 + PARSE_UNTIL_EOF = 3 + + +class ChunkState(IntEnum): + PARSE_CHUNKED_SIZE = 0 + PARSE_CHUNKED_CHUNK = 1 + PARSE_CHUNKED_CHUNK_EOF = 2 + PARSE_MAYBE_TRAILERS = 3 + PARSE_TRAILERS = 4 + + +class HeadersParser: + def __init__( + self, + max_line_size: int = 8190, + max_headers: int = 32768, + max_field_size: int = 8190, + lax: bool = False, + ) -> None: + self.max_line_size = max_line_size + self.max_headers = max_headers + self.max_field_size = max_field_size + self._lax = lax + + def parse_headers( + self, lines: List[bytes] + ) -> Tuple["CIMultiDictProxy[str]", RawHeaders]: + headers: CIMultiDict[str] = CIMultiDict() + # note: "raw" does not mean inclusion of OWS before/after the field value + raw_headers = [] + + lines_idx = 1 + line = lines[1] + line_count = len(lines) + + while line: + # Parse initial header name : value pair. + try: + bname, bvalue = line.split(b":", 1) + except ValueError: + raise InvalidHeader(line) from None + + if len(bname) == 0: + raise InvalidHeader(bname) + + # https://www.rfc-editor.org/rfc/rfc9112.html#section-5.1-2 + if {bname[0], bname[-1]} & {32, 9}: # {" ", "\t"} + raise InvalidHeader(line) + + bvalue = bvalue.lstrip(b" \t") + if len(bname) > self.max_field_size: + raise LineTooLong( + "request header name {}".format( + bname.decode("utf8", "backslashreplace") + ), + str(self.max_field_size), + str(len(bname)), + ) + name = bname.decode("utf-8", "surrogateescape") + if not TOKENRE.fullmatch(name): + raise InvalidHeader(bname) + + header_length = len(bvalue) + + # next line + lines_idx += 1 + line = lines[lines_idx] + + # consume continuation lines + continuation = self._lax and line and line[0] in (32, 9) # (' ', '\t') + + # Deprecated: https://www.rfc-editor.org/rfc/rfc9112.html#name-obsolete-line-folding + if continuation: + bvalue_lst = [bvalue] + while continuation: + header_length += len(line) + if header_length > self.max_field_size: + raise LineTooLong( + "request header field {}".format( + bname.decode("utf8", "backslashreplace") + ), + str(self.max_field_size), + str(header_length), + ) + bvalue_lst.append(line) + + # next line + lines_idx += 1 + if lines_idx < line_count: + line = lines[lines_idx] + if line: + continuation = line[0] in (32, 9) # (' ', '\t') + else: + line = b"" + break + bvalue = b"".join(bvalue_lst) + else: + if header_length > self.max_field_size: + raise LineTooLong( + "request header field {}".format( + bname.decode("utf8", "backslashreplace") + ), + str(self.max_field_size), + str(header_length), + ) + + bvalue = bvalue.strip(b" \t") + value = bvalue.decode("utf-8", "surrogateescape") + + # https://www.rfc-editor.org/rfc/rfc9110.html#section-5.5-5 + if "\n" in value or "\r" in value or "\x00" in value: + raise InvalidHeader(bvalue) + + headers.add(name, value) + raw_headers.append((bname, bvalue)) + + return (CIMultiDictProxy(headers), tuple(raw_headers)) + + +def _is_supported_upgrade(headers: CIMultiDictProxy[str]) -> bool: + """Check if the upgrade header is supported.""" + return headers.get(hdrs.UPGRADE, "").lower() in {"tcp", "websocket"} + + +class HttpParser(abc.ABC, Generic[_MsgT]): + lax: ClassVar[bool] = False + + def __init__( + self, + protocol: Optional[BaseProtocol] = None, + loop: Optional[asyncio.AbstractEventLoop] = None, + limit: int = 2**16, + max_line_size: int = 8190, + max_headers: int = 32768, + max_field_size: int = 8190, + timer: Optional[BaseTimerContext] = None, + code: Optional[int] = None, + method: Optional[str] = None, + payload_exception: Optional[Type[BaseException]] = None, + response_with_body: bool = True, + read_until_eof: bool = False, + auto_decompress: bool = True, + ) -> None: + self.protocol = protocol + self.loop = loop + self.max_line_size = max_line_size + self.max_headers = max_headers + self.max_field_size = max_field_size + self.timer = timer + self.code = code + self.method = method + self.payload_exception = payload_exception + self.response_with_body = response_with_body + self.read_until_eof = read_until_eof + + self._lines: List[bytes] = [] + self._tail = b"" + self._upgraded = False + self._payload = None + self._payload_parser: Optional[HttpPayloadParser] = None + self._auto_decompress = auto_decompress + self._limit = limit + self._headers_parser = HeadersParser( + max_line_size, max_headers, max_field_size, self.lax + ) + + @abc.abstractmethod + def parse_message(self, lines: List[bytes]) -> _MsgT: ... + + @abc.abstractmethod + def _is_chunked_te(self, te: str) -> bool: ... + + def feed_eof(self) -> Optional[_MsgT]: + if self._payload_parser is not None: + self._payload_parser.feed_eof() + self._payload_parser = None + else: + # try to extract partial message + if self._tail: + self._lines.append(self._tail) + + if self._lines: + if self._lines[-1] != "\r\n": + self._lines.append(b"") + with suppress(Exception): + return self.parse_message(self._lines) + return None + + def feed_data( + self, + data: bytes, + SEP: _SEP = b"\r\n", + EMPTY: bytes = b"", + CONTENT_LENGTH: istr = hdrs.CONTENT_LENGTH, + METH_CONNECT: str = hdrs.METH_CONNECT, + SEC_WEBSOCKET_KEY1: istr = hdrs.SEC_WEBSOCKET_KEY1, + ) -> Tuple[List[Tuple[_MsgT, StreamReader]], bool, bytes]: + + messages = [] + + if self._tail: + data, self._tail = self._tail + data, b"" + + data_len = len(data) + start_pos = 0 + loop = self.loop + + should_close = False + while start_pos < data_len: + + # read HTTP message (request/response line + headers), \r\n\r\n + # and split by lines + if self._payload_parser is None and not self._upgraded: + pos = data.find(SEP, start_pos) + # consume \r\n + if pos == start_pos and not self._lines: + start_pos = pos + len(SEP) + continue + + if pos >= start_pos: + if should_close: + raise BadHttpMessage("Data after `Connection: close`") + + # line found + line = data[start_pos:pos] + if SEP == b"\n": # For lax response parsing + line = line.rstrip(b"\r") + self._lines.append(line) + start_pos = pos + len(SEP) + + # \r\n\r\n found + if self._lines[-1] == EMPTY: + try: + msg: _MsgT = self.parse_message(self._lines) + finally: + self._lines.clear() + + def get_content_length() -> Optional[int]: + # payload length + length_hdr = msg.headers.get(CONTENT_LENGTH) + if length_hdr is None: + return None + + # Shouldn't allow +/- or other number formats. + # https://www.rfc-editor.org/rfc/rfc9110#section-8.6-2 + # msg.headers is already stripped of leading/trailing wsp + if not DIGITS.fullmatch(length_hdr): + raise InvalidHeader(CONTENT_LENGTH) + + return int(length_hdr) + + length = get_content_length() + # do not support old websocket spec + if SEC_WEBSOCKET_KEY1 in msg.headers: + raise InvalidHeader(SEC_WEBSOCKET_KEY1) + + self._upgraded = msg.upgrade and _is_supported_upgrade( + msg.headers + ) + + method = getattr(msg, "method", self.method) + # code is only present on responses + code = getattr(msg, "code", 0) + + assert self.protocol is not None + # calculate payload + empty_body = code in EMPTY_BODY_STATUS_CODES or bool( + method and method in EMPTY_BODY_METHODS + ) + if not empty_body and ( + ((length is not None and length > 0) or msg.chunked) + and not self._upgraded + ): + payload = StreamReader( + self.protocol, + timer=self.timer, + loop=loop, + limit=self._limit, + ) + payload_parser = HttpPayloadParser( + payload, + length=length, + chunked=msg.chunked, + method=method, + compression=msg.compression, + code=self.code, + response_with_body=self.response_with_body, + auto_decompress=self._auto_decompress, + lax=self.lax, + ) + if not payload_parser.done: + self._payload_parser = payload_parser + elif method == METH_CONNECT: + assert isinstance(msg, RawRequestMessage) + payload = StreamReader( + self.protocol, + timer=self.timer, + loop=loop, + limit=self._limit, + ) + self._upgraded = True + self._payload_parser = HttpPayloadParser( + payload, + method=msg.method, + compression=msg.compression, + auto_decompress=self._auto_decompress, + lax=self.lax, + ) + elif not empty_body and length is None and self.read_until_eof: + payload = StreamReader( + self.protocol, + timer=self.timer, + loop=loop, + limit=self._limit, + ) + payload_parser = HttpPayloadParser( + payload, + length=length, + chunked=msg.chunked, + method=method, + compression=msg.compression, + code=self.code, + response_with_body=self.response_with_body, + auto_decompress=self._auto_decompress, + lax=self.lax, + ) + if not payload_parser.done: + self._payload_parser = payload_parser + else: + payload = EMPTY_PAYLOAD + + messages.append((msg, payload)) + should_close = msg.should_close + else: + self._tail = data[start_pos:] + data = EMPTY + break + + # no parser, just store + elif self._payload_parser is None and self._upgraded: + assert not self._lines + break + + # feed payload + elif data and start_pos < data_len: + assert not self._lines + assert self._payload_parser is not None + try: + eof, data = self._payload_parser.feed_data(data[start_pos:], SEP) + except BaseException as underlying_exc: + reraised_exc = underlying_exc + if self.payload_exception is not None: + reraised_exc = self.payload_exception(str(underlying_exc)) + + set_exception( + self._payload_parser.payload, + reraised_exc, + underlying_exc, + ) + + eof = True + data = b"" + + if eof: + start_pos = 0 + data_len = len(data) + self._payload_parser = None + continue + else: + break + + if data and start_pos < data_len: + data = data[start_pos:] + else: + data = EMPTY + + return messages, self._upgraded, data + + def parse_headers( + self, lines: List[bytes] + ) -> Tuple[ + "CIMultiDictProxy[str]", RawHeaders, Optional[bool], Optional[str], bool, bool + ]: + """Parses RFC 5322 headers from a stream. + + Line continuations are supported. Returns list of header name + and value pairs. Header name is in upper case. + """ + headers, raw_headers = self._headers_parser.parse_headers(lines) + close_conn = None + encoding = None + upgrade = False + chunked = False + + # https://www.rfc-editor.org/rfc/rfc9110.html#section-5.5-6 + # https://www.rfc-editor.org/rfc/rfc9110.html#name-collected-abnf + singletons = ( + hdrs.CONTENT_LENGTH, + hdrs.CONTENT_LOCATION, + hdrs.CONTENT_RANGE, + hdrs.CONTENT_TYPE, + hdrs.ETAG, + hdrs.HOST, + hdrs.MAX_FORWARDS, + hdrs.SERVER, + hdrs.TRANSFER_ENCODING, + hdrs.USER_AGENT, + ) + bad_hdr = next((h for h in singletons if len(headers.getall(h, ())) > 1), None) + if bad_hdr is not None: + raise BadHttpMessage(f"Duplicate '{bad_hdr}' header found.") + + # keep-alive + conn = headers.get(hdrs.CONNECTION) + if conn: + v = conn.lower() + if v == "close": + close_conn = True + elif v == "keep-alive": + close_conn = False + # https://www.rfc-editor.org/rfc/rfc9110.html#name-101-switching-protocols + elif v == "upgrade" and headers.get(hdrs.UPGRADE): + upgrade = True + + # encoding + enc = headers.get(hdrs.CONTENT_ENCODING) + if enc: + enc = enc.lower() + if enc in ("gzip", "deflate", "br"): + encoding = enc + + # chunking + te = headers.get(hdrs.TRANSFER_ENCODING) + if te is not None: + if self._is_chunked_te(te): + chunked = True + + if hdrs.CONTENT_LENGTH in headers: + raise BadHttpMessage( + "Transfer-Encoding can't be present with Content-Length", + ) + + return (headers, raw_headers, close_conn, encoding, upgrade, chunked) + + def set_upgraded(self, val: bool) -> None: + """Set connection upgraded (to websocket) mode. + + :param bool val: new state. + """ + self._upgraded = val + + +class HttpRequestParser(HttpParser[RawRequestMessage]): + """Read request status line. + + Exception .http_exceptions.BadStatusLine + could be raised in case of any errors in status line. + Returns RawRequestMessage. + """ + + def parse_message(self, lines: List[bytes]) -> RawRequestMessage: + # request line + line = lines[0].decode("utf-8", "surrogateescape") + try: + method, path, version = line.split(" ", maxsplit=2) + except ValueError: + raise BadHttpMethod(line) from None + + if len(path) > self.max_line_size: + raise LineTooLong( + "Status line is too long", str(self.max_line_size), str(len(path)) + ) + + # method + if not TOKENRE.fullmatch(method): + raise BadHttpMethod(method) + + # version + match = VERSRE.fullmatch(version) + if match is None: + raise BadStatusLine(line) + version_o = HttpVersion(int(match.group(1)), int(match.group(2))) + + if method == "CONNECT": + # authority-form, + # https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.3 + url = URL.build(authority=path, encoded=True) + elif path.startswith("/"): + # origin-form, + # https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.1 + path_part, _hash_separator, url_fragment = path.partition("#") + path_part, _question_mark_separator, qs_part = path_part.partition("?") + + # NOTE: `yarl.URL.build()` is used to mimic what the Cython-based + # NOTE: parser does, otherwise it results into the same + # NOTE: HTTP Request-Line input producing different + # NOTE: `yarl.URL()` objects + url = URL.build( + path=path_part, + query_string=qs_part, + fragment=url_fragment, + encoded=True, + ) + elif path == "*" and method == "OPTIONS": + # asterisk-form, + url = URL(path, encoded=True) + else: + # absolute-form for proxy maybe, + # https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.2 + url = URL(path, encoded=True) + if url.scheme == "": + # not absolute-form + raise InvalidURLError( + path.encode(errors="surrogateescape").decode("latin1") + ) + + # read headers + ( + headers, + raw_headers, + close, + compression, + upgrade, + chunked, + ) = self.parse_headers(lines) + + if close is None: # then the headers weren't set in the request + if version_o <= HttpVersion10: # HTTP 1.0 must asks to not close + close = True + else: # HTTP 1.1 must ask to close. + close = False + + return RawRequestMessage( + method, + path, + version_o, + headers, + raw_headers, + close, + compression, + upgrade, + chunked, + url, + ) + + def _is_chunked_te(self, te: str) -> bool: + if te.rsplit(",", maxsplit=1)[-1].strip(" \t").lower() == "chunked": + return True + # https://www.rfc-editor.org/rfc/rfc9112#section-6.3-2.4.3 + raise BadHttpMessage("Request has invalid `Transfer-Encoding`") + + +class HttpResponseParser(HttpParser[RawResponseMessage]): + """Read response status line and headers. + + BadStatusLine could be raised in case of any errors in status line. + Returns RawResponseMessage. + """ + + # Lax mode should only be enabled on response parser. + lax = not DEBUG + + def feed_data( + self, + data: bytes, + SEP: Optional[_SEP] = None, + *args: Any, + **kwargs: Any, + ) -> Tuple[List[Tuple[RawResponseMessage, StreamReader]], bool, bytes]: + if SEP is None: + SEP = b"\r\n" if DEBUG else b"\n" + return super().feed_data(data, SEP, *args, **kwargs) + + def parse_message(self, lines: List[bytes]) -> RawResponseMessage: + line = lines[0].decode("utf-8", "surrogateescape") + try: + version, status = line.split(maxsplit=1) + except ValueError: + raise BadStatusLine(line) from None + + try: + status, reason = status.split(maxsplit=1) + except ValueError: + status = status.strip() + reason = "" + + if len(reason) > self.max_line_size: + raise LineTooLong( + "Status line is too long", str(self.max_line_size), str(len(reason)) + ) + + # version + match = VERSRE.fullmatch(version) + if match is None: + raise BadStatusLine(line) + version_o = HttpVersion(int(match.group(1)), int(match.group(2))) + + # The status code is a three-digit ASCII number, no padding + if len(status) != 3 or not DIGITS.fullmatch(status): + raise BadStatusLine(line) + status_i = int(status) + + # read headers + ( + headers, + raw_headers, + close, + compression, + upgrade, + chunked, + ) = self.parse_headers(lines) + + if close is None: + if version_o <= HttpVersion10: + close = True + # https://www.rfc-editor.org/rfc/rfc9112.html#name-message-body-length + elif 100 <= status_i < 200 or status_i in {204, 304}: + close = False + elif hdrs.CONTENT_LENGTH in headers or hdrs.TRANSFER_ENCODING in headers: + close = False + else: + # https://www.rfc-editor.org/rfc/rfc9112.html#section-6.3-2.8 + close = True + + return RawResponseMessage( + version_o, + status_i, + reason.strip(), + headers, + raw_headers, + close, + compression, + upgrade, + chunked, + ) + + def _is_chunked_te(self, te: str) -> bool: + # https://www.rfc-editor.org/rfc/rfc9112#section-6.3-2.4.2 + return te.rsplit(",", maxsplit=1)[-1].strip(" \t").lower() == "chunked" + + +class HttpPayloadParser: + def __init__( + self, + payload: StreamReader, + length: Optional[int] = None, + chunked: bool = False, + compression: Optional[str] = None, + code: Optional[int] = None, + method: Optional[str] = None, + response_with_body: bool = True, + auto_decompress: bool = True, + lax: bool = False, + ) -> None: + self._length = 0 + self._type = ParseState.PARSE_UNTIL_EOF + self._chunk = ChunkState.PARSE_CHUNKED_SIZE + self._chunk_size = 0 + self._chunk_tail = b"" + self._auto_decompress = auto_decompress + self._lax = lax + self.done = False + + # payload decompression wrapper + if response_with_body and compression and self._auto_decompress: + real_payload: Union[StreamReader, DeflateBuffer] = DeflateBuffer( + payload, compression + ) + else: + real_payload = payload + + # payload parser + if not response_with_body: + # don't parse payload if it's not expected to be received + self._type = ParseState.PARSE_NONE + real_payload.feed_eof() + self.done = True + elif chunked: + self._type = ParseState.PARSE_CHUNKED + elif length is not None: + self._type = ParseState.PARSE_LENGTH + self._length = length + if self._length == 0: + real_payload.feed_eof() + self.done = True + + self.payload = real_payload + + def feed_eof(self) -> None: + if self._type == ParseState.PARSE_UNTIL_EOF: + self.payload.feed_eof() + elif self._type == ParseState.PARSE_LENGTH: + raise ContentLengthError( + "Not enough data for satisfy content length header." + ) + elif self._type == ParseState.PARSE_CHUNKED: + raise TransferEncodingError( + "Not enough data for satisfy transfer length header." + ) + + def feed_data( + self, chunk: bytes, SEP: _SEP = b"\r\n", CHUNK_EXT: bytes = b";" + ) -> Tuple[bool, bytes]: + # Read specified amount of bytes + if self._type == ParseState.PARSE_LENGTH: + required = self._length + chunk_len = len(chunk) + + if required >= chunk_len: + self._length = required - chunk_len + self.payload.feed_data(chunk, chunk_len) + if self._length == 0: + self.payload.feed_eof() + return True, b"" + else: + self._length = 0 + self.payload.feed_data(chunk[:required], required) + self.payload.feed_eof() + return True, chunk[required:] + + # Chunked transfer encoding parser + elif self._type == ParseState.PARSE_CHUNKED: + if self._chunk_tail: + chunk = self._chunk_tail + chunk + self._chunk_tail = b"" + + while chunk: + + # read next chunk size + if self._chunk == ChunkState.PARSE_CHUNKED_SIZE: + pos = chunk.find(SEP) + if pos >= 0: + i = chunk.find(CHUNK_EXT, 0, pos) + if i >= 0: + size_b = chunk[:i] # strip chunk-extensions + # Verify no LF in the chunk-extension + if b"\n" in (ext := chunk[i:pos]): + exc = BadHttpMessage( + f"Unexpected LF in chunk-extension: {ext!r}" + ) + set_exception(self.payload, exc) + raise exc + else: + size_b = chunk[:pos] + + if self._lax: # Allow whitespace in lax mode. + size_b = size_b.strip() + + if not re.fullmatch(HEXDIGITS, size_b): + exc = TransferEncodingError( + chunk[:pos].decode("ascii", "surrogateescape") + ) + set_exception(self.payload, exc) + raise exc + size = int(bytes(size_b), 16) + + chunk = chunk[pos + len(SEP) :] + if size == 0: # eof marker + self._chunk = ChunkState.PARSE_MAYBE_TRAILERS + if self._lax and chunk.startswith(b"\r"): + chunk = chunk[1:] + else: + self._chunk = ChunkState.PARSE_CHUNKED_CHUNK + self._chunk_size = size + self.payload.begin_http_chunk_receiving() + else: + self._chunk_tail = chunk + return False, b"" + + # read chunk and feed buffer + if self._chunk == ChunkState.PARSE_CHUNKED_CHUNK: + required = self._chunk_size + chunk_len = len(chunk) + + if required > chunk_len: + self._chunk_size = required - chunk_len + self.payload.feed_data(chunk, chunk_len) + return False, b"" + else: + self._chunk_size = 0 + self.payload.feed_data(chunk[:required], required) + chunk = chunk[required:] + self._chunk = ChunkState.PARSE_CHUNKED_CHUNK_EOF + self.payload.end_http_chunk_receiving() + + # toss the CRLF at the end of the chunk + if self._chunk == ChunkState.PARSE_CHUNKED_CHUNK_EOF: + if self._lax and chunk.startswith(b"\r"): + chunk = chunk[1:] + if chunk[: len(SEP)] == SEP: + chunk = chunk[len(SEP) :] + self._chunk = ChunkState.PARSE_CHUNKED_SIZE + else: + self._chunk_tail = chunk + return False, b"" + + # if stream does not contain trailer, after 0\r\n + # we should get another \r\n otherwise + # trailers needs to be skipped until \r\n\r\n + if self._chunk == ChunkState.PARSE_MAYBE_TRAILERS: + head = chunk[: len(SEP)] + if head == SEP: + # end of stream + self.payload.feed_eof() + return True, chunk[len(SEP) :] + # Both CR and LF, or only LF may not be received yet. It is + # expected that CRLF or LF will be shown at the very first + # byte next time, otherwise trailers should come. The last + # CRLF which marks the end of response might not be + # contained in the same TCP segment which delivered the + # size indicator. + if not head: + return False, b"" + if head == SEP[:1]: + self._chunk_tail = head + return False, b"" + self._chunk = ChunkState.PARSE_TRAILERS + + # read and discard trailer up to the CRLF terminator + if self._chunk == ChunkState.PARSE_TRAILERS: + pos = chunk.find(SEP) + if pos >= 0: + chunk = chunk[pos + len(SEP) :] + self._chunk = ChunkState.PARSE_MAYBE_TRAILERS + else: + self._chunk_tail = chunk + return False, b"" + + # Read all bytes until eof + elif self._type == ParseState.PARSE_UNTIL_EOF: + self.payload.feed_data(chunk, len(chunk)) + + return False, b"" + + +class DeflateBuffer: + """DeflateStream decompress stream and feed data into specified stream.""" + + decompressor: Any + + def __init__(self, out: StreamReader, encoding: Optional[str]) -> None: + self.out = out + self.size = 0 + self.encoding = encoding + self._started_decoding = False + + self.decompressor: Union[BrotliDecompressor, ZLibDecompressor] + if encoding == "br": + if not HAS_BROTLI: # pragma: no cover + raise ContentEncodingError( + "Can not decode content-encoding: brotli (br). " + "Please install `Brotli`" + ) + self.decompressor = BrotliDecompressor() + else: + self.decompressor = ZLibDecompressor(encoding=encoding) + + def set_exception( + self, + exc: BaseException, + exc_cause: BaseException = _EXC_SENTINEL, + ) -> None: + set_exception(self.out, exc, exc_cause) + + def feed_data(self, chunk: bytes, size: int) -> None: + if not size: + return + + self.size += size + + # RFC1950 + # bits 0..3 = CM = 0b1000 = 8 = "deflate" + # bits 4..7 = CINFO = 1..7 = windows size. + if ( + not self._started_decoding + and self.encoding == "deflate" + and chunk[0] & 0xF != 8 + ): + # Change the decoder to decompress incorrectly compressed data + # Actually we should issue a warning about non-RFC-compliant data. + self.decompressor = ZLibDecompressor( + encoding=self.encoding, suppress_deflate_header=True + ) + + try: + chunk = self.decompressor.decompress_sync(chunk) + except Exception: + raise ContentEncodingError( + "Can not decode content-encoding: %s" % self.encoding + ) + + self._started_decoding = True + + if chunk: + self.out.feed_data(chunk, len(chunk)) + + def feed_eof(self) -> None: + chunk = self.decompressor.flush() + + if chunk or self.size > 0: + self.out.feed_data(chunk, len(chunk)) + if self.encoding == "deflate" and not self.decompressor.eof: + raise ContentEncodingError("deflate") + + self.out.feed_eof() + + def begin_http_chunk_receiving(self) -> None: + self.out.begin_http_chunk_receiving() + + def end_http_chunk_receiving(self) -> None: + self.out.end_http_chunk_receiving() + + +HttpRequestParserPy = HttpRequestParser +HttpResponseParserPy = HttpResponseParser +RawRequestMessagePy = RawRequestMessage +RawResponseMessagePy = RawResponseMessage + +try: + if not NO_EXTENSIONS: + from ._http_parser import ( # type: ignore[import-not-found,no-redef] + HttpRequestParser, + HttpResponseParser, + RawRequestMessage, + RawResponseMessage, + ) + + HttpRequestParserC = HttpRequestParser + HttpResponseParserC = HttpResponseParser + RawRequestMessageC = RawRequestMessage + RawResponseMessageC = RawResponseMessage +except ImportError: # pragma: no cover + pass diff --git a/venv/lib/python3.12/site-packages/aiohttp/http_websocket.py b/venv/lib/python3.12/site-packages/aiohttp/http_websocket.py new file mode 100644 index 00000000..6b4b30e0 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/http_websocket.py @@ -0,0 +1,36 @@ +"""WebSocket protocol versions 13 and 8.""" + +from ._websocket.helpers import WS_KEY, ws_ext_gen, ws_ext_parse +from ._websocket.models import ( + WS_CLOSED_MESSAGE, + WS_CLOSING_MESSAGE, + WebSocketError, + WSCloseCode, + WSHandshakeError, + WSMessage, + WSMsgType, +) +from ._websocket.reader import WebSocketReader +from ._websocket.writer import WebSocketWriter + +# Messages that the WebSocketResponse.receive needs to handle internally +_INTERNAL_RECEIVE_TYPES = frozenset( + (WSMsgType.CLOSE, WSMsgType.CLOSING, WSMsgType.PING, WSMsgType.PONG) +) + + +__all__ = ( + "WS_CLOSED_MESSAGE", + "WS_CLOSING_MESSAGE", + "WS_KEY", + "WebSocketReader", + "WebSocketWriter", + "WSMessage", + "WebSocketError", + "WSMsgType", + "WSCloseCode", + "ws_ext_gen", + "ws_ext_parse", + "WSHandshakeError", + "WSMessage", +) diff --git a/venv/lib/python3.12/site-packages/aiohttp/http_writer.py b/venv/lib/python3.12/site-packages/aiohttp/http_writer.py new file mode 100644 index 00000000..e031a977 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/http_writer.py @@ -0,0 +1,249 @@ +"""Http related parsers and protocol.""" + +import asyncio +import sys +import zlib +from typing import ( # noqa + Any, + Awaitable, + Callable, + Iterable, + List, + NamedTuple, + Optional, + Union, +) + +from multidict import CIMultiDict + +from .abc import AbstractStreamWriter +from .base_protocol import BaseProtocol +from .client_exceptions import ClientConnectionResetError +from .compression_utils import ZLibCompressor +from .helpers import NO_EXTENSIONS + +__all__ = ("StreamWriter", "HttpVersion", "HttpVersion10", "HttpVersion11") + + +MIN_PAYLOAD_FOR_WRITELINES = 2048 +IS_PY313_BEFORE_313_2 = (3, 13, 0) <= sys.version_info < (3, 13, 2) +IS_PY_BEFORE_312_9 = sys.version_info < (3, 12, 9) +SKIP_WRITELINES = IS_PY313_BEFORE_313_2 or IS_PY_BEFORE_312_9 +# writelines is not safe for use +# on Python 3.12+ until 3.12.9 +# on Python 3.13+ until 3.13.2 +# and on older versions it not any faster than write +# CVE-2024-12254: https://github.com/python/cpython/pull/127656 + + +class HttpVersion(NamedTuple): + major: int + minor: int + + +HttpVersion10 = HttpVersion(1, 0) +HttpVersion11 = HttpVersion(1, 1) + + +_T_OnChunkSent = Optional[Callable[[bytes], Awaitable[None]]] +_T_OnHeadersSent = Optional[Callable[["CIMultiDict[str]"], Awaitable[None]]] + + +class StreamWriter(AbstractStreamWriter): + + length: Optional[int] = None + chunked: bool = False + _eof: bool = False + _compress: Optional[ZLibCompressor] = None + + def __init__( + self, + protocol: BaseProtocol, + loop: asyncio.AbstractEventLoop, + on_chunk_sent: _T_OnChunkSent = None, + on_headers_sent: _T_OnHeadersSent = None, + ) -> None: + self._protocol = protocol + self.loop = loop + self._on_chunk_sent: _T_OnChunkSent = on_chunk_sent + self._on_headers_sent: _T_OnHeadersSent = on_headers_sent + + @property + def transport(self) -> Optional[asyncio.Transport]: + return self._protocol.transport + + @property + def protocol(self) -> BaseProtocol: + return self._protocol + + def enable_chunking(self) -> None: + self.chunked = True + + def enable_compression( + self, encoding: str = "deflate", strategy: int = zlib.Z_DEFAULT_STRATEGY + ) -> None: + self._compress = ZLibCompressor(encoding=encoding, strategy=strategy) + + def _write(self, chunk: Union[bytes, bytearray, memoryview]) -> None: + size = len(chunk) + self.buffer_size += size + self.output_size += size + transport = self._protocol.transport + if transport is None or transport.is_closing(): + raise ClientConnectionResetError("Cannot write to closing transport") + transport.write(chunk) + + def _writelines(self, chunks: Iterable[bytes]) -> None: + size = 0 + for chunk in chunks: + size += len(chunk) + self.buffer_size += size + self.output_size += size + transport = self._protocol.transport + if transport is None or transport.is_closing(): + raise ClientConnectionResetError("Cannot write to closing transport") + if SKIP_WRITELINES or size < MIN_PAYLOAD_FOR_WRITELINES: + transport.write(b"".join(chunks)) + else: + transport.writelines(chunks) + + async def write( + self, + chunk: Union[bytes, bytearray, memoryview], + *, + drain: bool = True, + LIMIT: int = 0x10000, + ) -> None: + """Writes chunk of data to a stream. + + write_eof() indicates end of stream. + writer can't be used after write_eof() method being called. + write() return drain future. + """ + if self._on_chunk_sent is not None: + await self._on_chunk_sent(chunk) + + if isinstance(chunk, memoryview): + if chunk.nbytes != len(chunk): + # just reshape it + chunk = chunk.cast("c") + + if self._compress is not None: + chunk = await self._compress.compress(chunk) + if not chunk: + return + + if self.length is not None: + chunk_len = len(chunk) + if self.length >= chunk_len: + self.length = self.length - chunk_len + else: + chunk = chunk[: self.length] + self.length = 0 + if not chunk: + return + + if chunk: + if self.chunked: + self._writelines( + (f"{len(chunk):x}\r\n".encode("ascii"), chunk, b"\r\n") + ) + else: + self._write(chunk) + + if self.buffer_size > LIMIT and drain: + self.buffer_size = 0 + await self.drain() + + async def write_headers( + self, status_line: str, headers: "CIMultiDict[str]" + ) -> None: + """Write request/response status and headers.""" + if self._on_headers_sent is not None: + await self._on_headers_sent(headers) + + # status + headers + buf = _serialize_headers(status_line, headers) + self._write(buf) + + def set_eof(self) -> None: + """Indicate that the message is complete.""" + self._eof = True + + async def write_eof(self, chunk: bytes = b"") -> None: + if self._eof: + return + + if chunk and self._on_chunk_sent is not None: + await self._on_chunk_sent(chunk) + + if self._compress: + chunks: List[bytes] = [] + chunks_len = 0 + if chunk and (compressed_chunk := await self._compress.compress(chunk)): + chunks_len = len(compressed_chunk) + chunks.append(compressed_chunk) + + flush_chunk = self._compress.flush() + chunks_len += len(flush_chunk) + chunks.append(flush_chunk) + assert chunks_len + + if self.chunked: + chunk_len_pre = f"{chunks_len:x}\r\n".encode("ascii") + self._writelines((chunk_len_pre, *chunks, b"\r\n0\r\n\r\n")) + elif len(chunks) > 1: + self._writelines(chunks) + else: + self._write(chunks[0]) + elif self.chunked: + if chunk: + chunk_len_pre = f"{len(chunk):x}\r\n".encode("ascii") + self._writelines((chunk_len_pre, chunk, b"\r\n0\r\n\r\n")) + else: + self._write(b"0\r\n\r\n") + elif chunk: + self._write(chunk) + + await self.drain() + + self._eof = True + + async def drain(self) -> None: + """Flush the write buffer. + + The intended use is to write + + await w.write(data) + await w.drain() + """ + protocol = self._protocol + if protocol.transport is not None and protocol._paused: + await protocol._drain_helper() + + +def _safe_header(string: str) -> str: + if "\r" in string or "\n" in string: + raise ValueError( + "Newline or carriage return detected in headers. " + "Potential header injection attack." + ) + return string + + +def _py_serialize_headers(status_line: str, headers: "CIMultiDict[str]") -> bytes: + headers_gen = (_safe_header(k) + ": " + _safe_header(v) for k, v in headers.items()) + line = status_line + "\r\n" + "\r\n".join(headers_gen) + "\r\n\r\n" + return line.encode("utf-8") + + +_serialize_headers = _py_serialize_headers + +try: + import aiohttp._http_writer as _http_writer # type: ignore[import-not-found] + + _c_serialize_headers = _http_writer._serialize_headers + if not NO_EXTENSIONS: + _serialize_headers = _c_serialize_headers +except ImportError: + pass diff --git a/venv/lib/python3.12/site-packages/aiohttp/log.py b/venv/lib/python3.12/site-packages/aiohttp/log.py new file mode 100644 index 00000000..3cecea2b --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/log.py @@ -0,0 +1,8 @@ +import logging + +access_logger = logging.getLogger("aiohttp.access") +client_logger = logging.getLogger("aiohttp.client") +internal_logger = logging.getLogger("aiohttp.internal") +server_logger = logging.getLogger("aiohttp.server") +web_logger = logging.getLogger("aiohttp.web") +ws_logger = logging.getLogger("aiohttp.websocket") diff --git a/venv/lib/python3.12/site-packages/aiohttp/multipart.py b/venv/lib/python3.12/site-packages/aiohttp/multipart.py new file mode 100644 index 00000000..bd4d8ae1 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/multipart.py @@ -0,0 +1,1071 @@ +import base64 +import binascii +import json +import re +import sys +import uuid +import warnings +import zlib +from collections import deque +from types import TracebackType +from typing import ( + TYPE_CHECKING, + Any, + Deque, + Dict, + Iterator, + List, + Mapping, + Optional, + Sequence, + Tuple, + Type, + Union, + cast, +) +from urllib.parse import parse_qsl, unquote, urlencode + +from multidict import CIMultiDict, CIMultiDictProxy + +from .compression_utils import ZLibCompressor, ZLibDecompressor +from .hdrs import ( + CONTENT_DISPOSITION, + CONTENT_ENCODING, + CONTENT_LENGTH, + CONTENT_TRANSFER_ENCODING, + CONTENT_TYPE, +) +from .helpers import CHAR, TOKEN, parse_mimetype, reify +from .http import HeadersParser +from .payload import ( + JsonPayload, + LookupError, + Order, + Payload, + StringPayload, + get_payload, + payload_type, +) +from .streams import StreamReader + +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing import TypeVar + + Self = TypeVar("Self", bound="BodyPartReader") + +__all__ = ( + "MultipartReader", + "MultipartWriter", + "BodyPartReader", + "BadContentDispositionHeader", + "BadContentDispositionParam", + "parse_content_disposition", + "content_disposition_filename", +) + + +if TYPE_CHECKING: + from .client_reqrep import ClientResponse + + +class BadContentDispositionHeader(RuntimeWarning): + pass + + +class BadContentDispositionParam(RuntimeWarning): + pass + + +def parse_content_disposition( + header: Optional[str], +) -> Tuple[Optional[str], Dict[str, str]]: + def is_token(string: str) -> bool: + return bool(string) and TOKEN >= set(string) + + def is_quoted(string: str) -> bool: + return string[0] == string[-1] == '"' + + def is_rfc5987(string: str) -> bool: + return is_token(string) and string.count("'") == 2 + + def is_extended_param(string: str) -> bool: + return string.endswith("*") + + def is_continuous_param(string: str) -> bool: + pos = string.find("*") + 1 + if not pos: + return False + substring = string[pos:-1] if string.endswith("*") else string[pos:] + return substring.isdigit() + + def unescape(text: str, *, chars: str = "".join(map(re.escape, CHAR))) -> str: + return re.sub(f"\\\\([{chars}])", "\\1", text) + + if not header: + return None, {} + + disptype, *parts = header.split(";") + if not is_token(disptype): + warnings.warn(BadContentDispositionHeader(header)) + return None, {} + + params: Dict[str, str] = {} + while parts: + item = parts.pop(0) + + if "=" not in item: + warnings.warn(BadContentDispositionHeader(header)) + return None, {} + + key, value = item.split("=", 1) + key = key.lower().strip() + value = value.lstrip() + + if key in params: + warnings.warn(BadContentDispositionHeader(header)) + return None, {} + + if not is_token(key): + warnings.warn(BadContentDispositionParam(item)) + continue + + elif is_continuous_param(key): + if is_quoted(value): + value = unescape(value[1:-1]) + elif not is_token(value): + warnings.warn(BadContentDispositionParam(item)) + continue + + elif is_extended_param(key): + if is_rfc5987(value): + encoding, _, value = value.split("'", 2) + encoding = encoding or "utf-8" + else: + warnings.warn(BadContentDispositionParam(item)) + continue + + try: + value = unquote(value, encoding, "strict") + except UnicodeDecodeError: # pragma: nocover + warnings.warn(BadContentDispositionParam(item)) + continue + + else: + failed = True + if is_quoted(value): + failed = False + value = unescape(value[1:-1].lstrip("\\/")) + elif is_token(value): + failed = False + elif parts: + # maybe just ; in filename, in any case this is just + # one case fix, for proper fix we need to redesign parser + _value = f"{value};{parts[0]}" + if is_quoted(_value): + parts.pop(0) + value = unescape(_value[1:-1].lstrip("\\/")) + failed = False + + if failed: + warnings.warn(BadContentDispositionHeader(header)) + return None, {} + + params[key] = value + + return disptype.lower(), params + + +def content_disposition_filename( + params: Mapping[str, str], name: str = "filename" +) -> Optional[str]: + name_suf = "%s*" % name + if not params: + return None + elif name_suf in params: + return params[name_suf] + elif name in params: + return params[name] + else: + parts = [] + fnparams = sorted( + (key, value) for key, value in params.items() if key.startswith(name_suf) + ) + for num, (key, value) in enumerate(fnparams): + _, tail = key.split("*", 1) + if tail.endswith("*"): + tail = tail[:-1] + if tail == str(num): + parts.append(value) + else: + break + if not parts: + return None + value = "".join(parts) + if "'" in value: + encoding, _, value = value.split("'", 2) + encoding = encoding or "utf-8" + return unquote(value, encoding, "strict") + return value + + +class MultipartResponseWrapper: + """Wrapper around the MultipartReader. + + It takes care about + underlying connection and close it when it needs in. + """ + + def __init__( + self, + resp: "ClientResponse", + stream: "MultipartReader", + ) -> None: + self.resp = resp + self.stream = stream + + def __aiter__(self) -> "MultipartResponseWrapper": + return self + + async def __anext__( + self, + ) -> Union["MultipartReader", "BodyPartReader"]: + part = await self.next() + if part is None: + raise StopAsyncIteration + return part + + def at_eof(self) -> bool: + """Returns True when all response data had been read.""" + return self.resp.content.at_eof() + + async def next( + self, + ) -> Optional[Union["MultipartReader", "BodyPartReader"]]: + """Emits next multipart reader object.""" + item = await self.stream.next() + if self.stream.at_eof(): + await self.release() + return item + + async def release(self) -> None: + """Release the connection gracefully. + + All remaining content is read to the void. + """ + await self.resp.release() + + +class BodyPartReader: + """Multipart reader for single body part.""" + + chunk_size = 8192 + + def __init__( + self, + boundary: bytes, + headers: "CIMultiDictProxy[str]", + content: StreamReader, + *, + subtype: str = "mixed", + default_charset: Optional[str] = None, + ) -> None: + self.headers = headers + self._boundary = boundary + self._boundary_len = len(boundary) + 2 # Boundary + \r\n + self._content = content + self._default_charset = default_charset + self._at_eof = False + self._is_form_data = subtype == "form-data" + # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8 + length = None if self._is_form_data else self.headers.get(CONTENT_LENGTH, None) + self._length = int(length) if length is not None else None + self._read_bytes = 0 + self._unread: Deque[bytes] = deque() + self._prev_chunk: Optional[bytes] = None + self._content_eof = 0 + self._cache: Dict[str, Any] = {} + + def __aiter__(self: Self) -> Self: + return self + + async def __anext__(self) -> bytes: + part = await self.next() + if part is None: + raise StopAsyncIteration + return part + + async def next(self) -> Optional[bytes]: + item = await self.read() + if not item: + return None + return item + + async def read(self, *, decode: bool = False) -> bytes: + """Reads body part data. + + decode: Decodes data following by encoding + method from Content-Encoding header. If it missed + data remains untouched + """ + if self._at_eof: + return b"" + data = bytearray() + while not self._at_eof: + data.extend(await self.read_chunk(self.chunk_size)) + if decode: + return self.decode(data) + return data + + async def read_chunk(self, size: int = chunk_size) -> bytes: + """Reads body part content chunk of the specified size. + + size: chunk size + """ + if self._at_eof: + return b"" + if self._length: + chunk = await self._read_chunk_from_length(size) + else: + chunk = await self._read_chunk_from_stream(size) + + # For the case of base64 data, we must read a fragment of size with a + # remainder of 0 by dividing by 4 for string without symbols \n or \r + encoding = self.headers.get(CONTENT_TRANSFER_ENCODING) + if encoding and encoding.lower() == "base64": + stripped_chunk = b"".join(chunk.split()) + remainder = len(stripped_chunk) % 4 + + while remainder != 0 and not self.at_eof(): + over_chunk_size = 4 - remainder + over_chunk = b"" + + if self._prev_chunk: + over_chunk = self._prev_chunk[:over_chunk_size] + self._prev_chunk = self._prev_chunk[len(over_chunk) :] + + if len(over_chunk) != over_chunk_size: + over_chunk += await self._content.read(4 - len(over_chunk)) + + if not over_chunk: + self._at_eof = True + + stripped_chunk += b"".join(over_chunk.split()) + chunk += over_chunk + remainder = len(stripped_chunk) % 4 + + self._read_bytes += len(chunk) + if self._read_bytes == self._length: + self._at_eof = True + if self._at_eof: + clrf = await self._content.readline() + assert ( + b"\r\n" == clrf + ), "reader did not read all the data or it is malformed" + return chunk + + async def _read_chunk_from_length(self, size: int) -> bytes: + # Reads body part content chunk of the specified size. + # The body part must has Content-Length header with proper value. + assert self._length is not None, "Content-Length required for chunked read" + chunk_size = min(size, self._length - self._read_bytes) + chunk = await self._content.read(chunk_size) + if self._content.at_eof(): + self._at_eof = True + return chunk + + async def _read_chunk_from_stream(self, size: int) -> bytes: + # Reads content chunk of body part with unknown length. + # The Content-Length header for body part is not necessary. + assert ( + size >= self._boundary_len + ), "Chunk size must be greater or equal than boundary length + 2" + first_chunk = self._prev_chunk is None + if first_chunk: + self._prev_chunk = await self._content.read(size) + + chunk = b"" + # content.read() may return less than size, so we need to loop to ensure + # we have enough data to detect the boundary. + while len(chunk) < self._boundary_len: + chunk += await self._content.read(size) + self._content_eof += int(self._content.at_eof()) + assert self._content_eof < 3, "Reading after EOF" + if self._content_eof: + break + if len(chunk) > size: + self._content.unread_data(chunk[size:]) + chunk = chunk[:size] + + assert self._prev_chunk is not None + window = self._prev_chunk + chunk + sub = b"\r\n" + self._boundary + if first_chunk: + idx = window.find(sub) + else: + idx = window.find(sub, max(0, len(self._prev_chunk) - len(sub))) + if idx >= 0: + # pushing boundary back to content + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=DeprecationWarning) + self._content.unread_data(window[idx:]) + if size > idx: + self._prev_chunk = self._prev_chunk[:idx] + chunk = window[len(self._prev_chunk) : idx] + if not chunk: + self._at_eof = True + result = self._prev_chunk + self._prev_chunk = chunk + return result + + async def readline(self) -> bytes: + """Reads body part by line by line.""" + if self._at_eof: + return b"" + + if self._unread: + line = self._unread.popleft() + else: + line = await self._content.readline() + + if line.startswith(self._boundary): + # the very last boundary may not come with \r\n, + # so set single rules for everyone + sline = line.rstrip(b"\r\n") + boundary = self._boundary + last_boundary = self._boundary + b"--" + # ensure that we read exactly the boundary, not something alike + if sline == boundary or sline == last_boundary: + self._at_eof = True + self._unread.append(line) + return b"" + else: + next_line = await self._content.readline() + if next_line.startswith(self._boundary): + line = line[:-2] # strip CRLF but only once + self._unread.append(next_line) + + return line + + async def release(self) -> None: + """Like read(), but reads all the data to the void.""" + if self._at_eof: + return + while not self._at_eof: + await self.read_chunk(self.chunk_size) + + async def text(self, *, encoding: Optional[str] = None) -> str: + """Like read(), but assumes that body part contains text data.""" + data = await self.read(decode=True) + # see https://www.w3.org/TR/html5/forms.html#multipart/form-data-encoding-algorithm + # and https://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#dom-xmlhttprequest-send + encoding = encoding or self.get_charset(default="utf-8") + return data.decode(encoding) + + async def json(self, *, encoding: Optional[str] = None) -> Optional[Dict[str, Any]]: + """Like read(), but assumes that body parts contains JSON data.""" + data = await self.read(decode=True) + if not data: + return None + encoding = encoding or self.get_charset(default="utf-8") + return cast(Dict[str, Any], json.loads(data.decode(encoding))) + + async def form(self, *, encoding: Optional[str] = None) -> List[Tuple[str, str]]: + """Like read(), but assumes that body parts contain form urlencoded data.""" + data = await self.read(decode=True) + if not data: + return [] + if encoding is not None: + real_encoding = encoding + else: + real_encoding = self.get_charset(default="utf-8") + try: + decoded_data = data.rstrip().decode(real_encoding) + except UnicodeDecodeError: + raise ValueError("data cannot be decoded with %s encoding" % real_encoding) + + return parse_qsl( + decoded_data, + keep_blank_values=True, + encoding=real_encoding, + ) + + def at_eof(self) -> bool: + """Returns True if the boundary was reached or False otherwise.""" + return self._at_eof + + def decode(self, data: bytes) -> bytes: + """Decodes data. + + Decoding is done according the specified Content-Encoding + or Content-Transfer-Encoding headers value. + """ + if CONTENT_TRANSFER_ENCODING in self.headers: + data = self._decode_content_transfer(data) + # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8 + if not self._is_form_data and CONTENT_ENCODING in self.headers: + return self._decode_content(data) + return data + + def _decode_content(self, data: bytes) -> bytes: + encoding = self.headers.get(CONTENT_ENCODING, "").lower() + if encoding == "identity": + return data + if encoding in {"deflate", "gzip"}: + return ZLibDecompressor( + encoding=encoding, + suppress_deflate_header=True, + ).decompress_sync(data) + + raise RuntimeError(f"unknown content encoding: {encoding}") + + def _decode_content_transfer(self, data: bytes) -> bytes: + encoding = self.headers.get(CONTENT_TRANSFER_ENCODING, "").lower() + + if encoding == "base64": + return base64.b64decode(data) + elif encoding == "quoted-printable": + return binascii.a2b_qp(data) + elif encoding in ("binary", "8bit", "7bit"): + return data + else: + raise RuntimeError(f"unknown content transfer encoding: {encoding}") + + def get_charset(self, default: str) -> str: + """Returns charset parameter from Content-Type header or default.""" + ctype = self.headers.get(CONTENT_TYPE, "") + mimetype = parse_mimetype(ctype) + return mimetype.parameters.get("charset", self._default_charset or default) + + @reify + def name(self) -> Optional[str]: + """Returns name specified in Content-Disposition header. + + If the header is missing or malformed, returns None. + """ + _, params = parse_content_disposition(self.headers.get(CONTENT_DISPOSITION)) + return content_disposition_filename(params, "name") + + @reify + def filename(self) -> Optional[str]: + """Returns filename specified in Content-Disposition header. + + Returns None if the header is missing or malformed. + """ + _, params = parse_content_disposition(self.headers.get(CONTENT_DISPOSITION)) + return content_disposition_filename(params, "filename") + + +@payload_type(BodyPartReader, order=Order.try_first) +class BodyPartReaderPayload(Payload): + _value: BodyPartReader + + def __init__(self, value: BodyPartReader, *args: Any, **kwargs: Any) -> None: + super().__init__(value, *args, **kwargs) + + params: Dict[str, str] = {} + if value.name is not None: + params["name"] = value.name + if value.filename is not None: + params["filename"] = value.filename + + if params: + self.set_content_disposition("attachment", True, **params) + + def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: + raise TypeError("Unable to decode.") + + async def write(self, writer: Any) -> None: + field = self._value + chunk = await field.read_chunk(size=2**16) + while chunk: + await writer.write(field.decode(chunk)) + chunk = await field.read_chunk(size=2**16) + + +class MultipartReader: + """Multipart body reader.""" + + #: Response wrapper, used when multipart readers constructs from response. + response_wrapper_cls = MultipartResponseWrapper + #: Multipart reader class, used to handle multipart/* body parts. + #: None points to type(self) + multipart_reader_cls: Optional[Type["MultipartReader"]] = None + #: Body part reader class for non multipart/* content types. + part_reader_cls = BodyPartReader + + def __init__(self, headers: Mapping[str, str], content: StreamReader) -> None: + self._mimetype = parse_mimetype(headers[CONTENT_TYPE]) + assert self._mimetype.type == "multipart", "multipart/* content type expected" + if "boundary" not in self._mimetype.parameters: + raise ValueError( + "boundary missed for Content-Type: %s" % headers[CONTENT_TYPE] + ) + + self.headers = headers + self._boundary = ("--" + self._get_boundary()).encode() + self._content = content + self._default_charset: Optional[str] = None + self._last_part: Optional[Union["MultipartReader", BodyPartReader]] = None + self._at_eof = False + self._at_bof = True + self._unread: List[bytes] = [] + + def __aiter__(self: Self) -> Self: + return self + + async def __anext__( + self, + ) -> Optional[Union["MultipartReader", BodyPartReader]]: + part = await self.next() + if part is None: + raise StopAsyncIteration + return part + + @classmethod + def from_response( + cls, + response: "ClientResponse", + ) -> MultipartResponseWrapper: + """Constructs reader instance from HTTP response. + + :param response: :class:`~aiohttp.client.ClientResponse` instance + """ + obj = cls.response_wrapper_cls( + response, cls(response.headers, response.content) + ) + return obj + + def at_eof(self) -> bool: + """Returns True if the final boundary was reached, false otherwise.""" + return self._at_eof + + async def next( + self, + ) -> Optional[Union["MultipartReader", BodyPartReader]]: + """Emits the next multipart body part.""" + # So, if we're at BOF, we need to skip till the boundary. + if self._at_eof: + return None + await self._maybe_release_last_part() + if self._at_bof: + await self._read_until_first_boundary() + self._at_bof = False + else: + await self._read_boundary() + if self._at_eof: # we just read the last boundary, nothing to do there + return None + + part = await self.fetch_next_part() + # https://datatracker.ietf.org/doc/html/rfc7578#section-4.6 + if ( + self._last_part is None + and self._mimetype.subtype == "form-data" + and isinstance(part, BodyPartReader) + ): + _, params = parse_content_disposition(part.headers.get(CONTENT_DISPOSITION)) + if params.get("name") == "_charset_": + # Longest encoding in https://encoding.spec.whatwg.org/encodings.json + # is 19 characters, so 32 should be more than enough for any valid encoding. + charset = await part.read_chunk(32) + if len(charset) > 31: + raise RuntimeError("Invalid default charset") + self._default_charset = charset.strip().decode() + part = await self.fetch_next_part() + self._last_part = part + return self._last_part + + async def release(self) -> None: + """Reads all the body parts to the void till the final boundary.""" + while not self._at_eof: + item = await self.next() + if item is None: + break + await item.release() + + async def fetch_next_part( + self, + ) -> Union["MultipartReader", BodyPartReader]: + """Returns the next body part reader.""" + headers = await self._read_headers() + return self._get_part_reader(headers) + + def _get_part_reader( + self, + headers: "CIMultiDictProxy[str]", + ) -> Union["MultipartReader", BodyPartReader]: + """Dispatches the response by the `Content-Type` header. + + Returns a suitable reader instance. + + :param dict headers: Response headers + """ + ctype = headers.get(CONTENT_TYPE, "") + mimetype = parse_mimetype(ctype) + + if mimetype.type == "multipart": + if self.multipart_reader_cls is None: + return type(self)(headers, self._content) + return self.multipart_reader_cls(headers, self._content) + else: + return self.part_reader_cls( + self._boundary, + headers, + self._content, + subtype=self._mimetype.subtype, + default_charset=self._default_charset, + ) + + def _get_boundary(self) -> str: + boundary = self._mimetype.parameters["boundary"] + if len(boundary) > 70: + raise ValueError("boundary %r is too long (70 chars max)" % boundary) + + return boundary + + async def _readline(self) -> bytes: + if self._unread: + return self._unread.pop() + return await self._content.readline() + + async def _read_until_first_boundary(self) -> None: + while True: + chunk = await self._readline() + if chunk == b"": + raise ValueError( + "Could not find starting boundary %r" % (self._boundary) + ) + chunk = chunk.rstrip() + if chunk == self._boundary: + return + elif chunk == self._boundary + b"--": + self._at_eof = True + return + + async def _read_boundary(self) -> None: + chunk = (await self._readline()).rstrip() + if chunk == self._boundary: + pass + elif chunk == self._boundary + b"--": + self._at_eof = True + epilogue = await self._readline() + next_line = await self._readline() + + # the epilogue is expected and then either the end of input or the + # parent multipart boundary, if the parent boundary is found then + # it should be marked as unread and handed to the parent for + # processing + if next_line[:2] == b"--": + self._unread.append(next_line) + # otherwise the request is likely missing an epilogue and both + # lines should be passed to the parent for processing + # (this handles the old behavior gracefully) + else: + self._unread.extend([next_line, epilogue]) + else: + raise ValueError(f"Invalid boundary {chunk!r}, expected {self._boundary!r}") + + async def _read_headers(self) -> "CIMultiDictProxy[str]": + lines = [b""] + while True: + chunk = await self._content.readline() + chunk = chunk.strip() + lines.append(chunk) + if not chunk: + break + parser = HeadersParser() + headers, raw_headers = parser.parse_headers(lines) + return headers + + async def _maybe_release_last_part(self) -> None: + """Ensures that the last read body part is read completely.""" + if self._last_part is not None: + if not self._last_part.at_eof(): + await self._last_part.release() + self._unread.extend(self._last_part._unread) + self._last_part = None + + +_Part = Tuple[Payload, str, str] + + +class MultipartWriter(Payload): + """Multipart body writer.""" + + _value: None + + def __init__(self, subtype: str = "mixed", boundary: Optional[str] = None) -> None: + boundary = boundary if boundary is not None else uuid.uuid4().hex + # The underlying Payload API demands a str (utf-8), not bytes, + # so we need to ensure we don't lose anything during conversion. + # As a result, require the boundary to be ASCII only. + # In both situations. + + try: + self._boundary = boundary.encode("ascii") + except UnicodeEncodeError: + raise ValueError("boundary should contain ASCII only chars") from None + ctype = f"multipart/{subtype}; boundary={self._boundary_value}" + + super().__init__(None, content_type=ctype) + + self._parts: List[_Part] = [] + self._is_form_data = subtype == "form-data" + + def __enter__(self) -> "MultipartWriter": + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + pass + + def __iter__(self) -> Iterator[_Part]: + return iter(self._parts) + + def __len__(self) -> int: + return len(self._parts) + + def __bool__(self) -> bool: + return True + + _valid_tchar_regex = re.compile(rb"\A[!#$%&'*+\-.^_`|~\w]+\Z") + _invalid_qdtext_char_regex = re.compile(rb"[\x00-\x08\x0A-\x1F\x7F]") + + @property + def _boundary_value(self) -> str: + """Wrap boundary parameter value in quotes, if necessary. + + Reads self.boundary and returns a unicode string. + """ + # Refer to RFCs 7231, 7230, 5234. + # + # parameter = token "=" ( token / quoted-string ) + # token = 1*tchar + # quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE + # qdtext = HTAB / SP / %x21 / %x23-5B / %x5D-7E / obs-text + # obs-text = %x80-FF + # quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text ) + # tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" + # / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" + # / DIGIT / ALPHA + # ; any VCHAR, except delimiters + # VCHAR = %x21-7E + value = self._boundary + if re.match(self._valid_tchar_regex, value): + return value.decode("ascii") # cannot fail + + if re.search(self._invalid_qdtext_char_regex, value): + raise ValueError("boundary value contains invalid characters") + + # escape %x5C and %x22 + quoted_value_content = value.replace(b"\\", b"\\\\") + quoted_value_content = quoted_value_content.replace(b'"', b'\\"') + + return '"' + quoted_value_content.decode("ascii") + '"' + + @property + def boundary(self) -> str: + return self._boundary.decode("ascii") + + def append(self, obj: Any, headers: Optional[Mapping[str, str]] = None) -> Payload: + if headers is None: + headers = CIMultiDict() + + if isinstance(obj, Payload): + obj.headers.update(headers) + return self.append_payload(obj) + else: + try: + payload = get_payload(obj, headers=headers) + except LookupError: + raise TypeError("Cannot create payload from %r" % obj) + else: + return self.append_payload(payload) + + def append_payload(self, payload: Payload) -> Payload: + """Adds a new body part to multipart writer.""" + encoding: Optional[str] = None + te_encoding: Optional[str] = None + if self._is_form_data: + # https://datatracker.ietf.org/doc/html/rfc7578#section-4.7 + # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8 + assert ( + not {CONTENT_ENCODING, CONTENT_LENGTH, CONTENT_TRANSFER_ENCODING} + & payload.headers.keys() + ) + # Set default Content-Disposition in case user doesn't create one + if CONTENT_DISPOSITION not in payload.headers: + name = f"section-{len(self._parts)}" + payload.set_content_disposition("form-data", name=name) + else: + # compression + encoding = payload.headers.get(CONTENT_ENCODING, "").lower() + if encoding and encoding not in ("deflate", "gzip", "identity"): + raise RuntimeError(f"unknown content encoding: {encoding}") + if encoding == "identity": + encoding = None + + # te encoding + te_encoding = payload.headers.get(CONTENT_TRANSFER_ENCODING, "").lower() + if te_encoding not in ("", "base64", "quoted-printable", "binary"): + raise RuntimeError(f"unknown content transfer encoding: {te_encoding}") + if te_encoding == "binary": + te_encoding = None + + # size + size = payload.size + if size is not None and not (encoding or te_encoding): + payload.headers[CONTENT_LENGTH] = str(size) + + self._parts.append((payload, encoding, te_encoding)) # type: ignore[arg-type] + return payload + + def append_json( + self, obj: Any, headers: Optional[Mapping[str, str]] = None + ) -> Payload: + """Helper to append JSON part.""" + if headers is None: + headers = CIMultiDict() + + return self.append_payload(JsonPayload(obj, headers=headers)) + + def append_form( + self, + obj: Union[Sequence[Tuple[str, str]], Mapping[str, str]], + headers: Optional[Mapping[str, str]] = None, + ) -> Payload: + """Helper to append form urlencoded part.""" + assert isinstance(obj, (Sequence, Mapping)) + + if headers is None: + headers = CIMultiDict() + + if isinstance(obj, Mapping): + obj = list(obj.items()) + data = urlencode(obj, doseq=True) + + return self.append_payload( + StringPayload( + data, headers=headers, content_type="application/x-www-form-urlencoded" + ) + ) + + @property + def size(self) -> Optional[int]: + """Size of the payload.""" + total = 0 + for part, encoding, te_encoding in self._parts: + if encoding or te_encoding or part.size is None: + return None + + total += int( + 2 + + len(self._boundary) + + 2 + + part.size # b'--'+self._boundary+b'\r\n' + + len(part._binary_headers) + + 2 # b'\r\n' + ) + + total += 2 + len(self._boundary) + 4 # b'--'+self._boundary+b'--\r\n' + return total + + def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: + return "".join( + "--" + + self.boundary + + "\r\n" + + part._binary_headers.decode(encoding, errors) + + part.decode() + for part, _e, _te in self._parts + ) + + async def write(self, writer: Any, close_boundary: bool = True) -> None: + """Write body.""" + for part, encoding, te_encoding in self._parts: + if self._is_form_data: + # https://datatracker.ietf.org/doc/html/rfc7578#section-4.2 + assert CONTENT_DISPOSITION in part.headers + assert "name=" in part.headers[CONTENT_DISPOSITION] + + await writer.write(b"--" + self._boundary + b"\r\n") + await writer.write(part._binary_headers) + + if encoding or te_encoding: + w = MultipartPayloadWriter(writer) + if encoding: + w.enable_compression(encoding) + if te_encoding: + w.enable_encoding(te_encoding) + await part.write(w) # type: ignore[arg-type] + await w.write_eof() + else: + await part.write(writer) + + await writer.write(b"\r\n") + + if close_boundary: + await writer.write(b"--" + self._boundary + b"--\r\n") + + +class MultipartPayloadWriter: + def __init__(self, writer: Any) -> None: + self._writer = writer + self._encoding: Optional[str] = None + self._compress: Optional[ZLibCompressor] = None + self._encoding_buffer: Optional[bytearray] = None + + def enable_encoding(self, encoding: str) -> None: + if encoding == "base64": + self._encoding = encoding + self._encoding_buffer = bytearray() + elif encoding == "quoted-printable": + self._encoding = "quoted-printable" + + def enable_compression( + self, encoding: str = "deflate", strategy: int = zlib.Z_DEFAULT_STRATEGY + ) -> None: + self._compress = ZLibCompressor( + encoding=encoding, + suppress_deflate_header=True, + strategy=strategy, + ) + + async def write_eof(self) -> None: + if self._compress is not None: + chunk = self._compress.flush() + if chunk: + self._compress = None + await self.write(chunk) + + if self._encoding == "base64": + if self._encoding_buffer: + await self._writer.write(base64.b64encode(self._encoding_buffer)) + + async def write(self, chunk: bytes) -> None: + if self._compress is not None: + if chunk: + chunk = await self._compress.compress(chunk) + if not chunk: + return + + if self._encoding == "base64": + buf = self._encoding_buffer + assert buf is not None + buf.extend(chunk) + + if buf: + div, mod = divmod(len(buf), 3) + enc_chunk, self._encoding_buffer = (buf[: div * 3], buf[div * 3 :]) + if enc_chunk: + b64chunk = base64.b64encode(enc_chunk) + await self._writer.write(b64chunk) + elif self._encoding == "quoted-printable": + await self._writer.write(binascii.b2a_qp(chunk)) + else: + await self._writer.write(chunk) diff --git a/venv/lib/python3.12/site-packages/aiohttp/payload.py b/venv/lib/python3.12/site-packages/aiohttp/payload.py new file mode 100644 index 00000000..3f6d3672 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/payload.py @@ -0,0 +1,519 @@ +import asyncio +import enum +import io +import json +import mimetypes +import os +import sys +import warnings +from abc import ABC, abstractmethod +from itertools import chain +from typing import ( + IO, + TYPE_CHECKING, + Any, + Dict, + Final, + Iterable, + Optional, + TextIO, + Tuple, + Type, + Union, +) + +from multidict import CIMultiDict + +from . import hdrs +from .abc import AbstractStreamWriter +from .helpers import ( + _SENTINEL, + content_disposition_header, + guess_filename, + parse_mimetype, + sentinel, +) +from .streams import StreamReader +from .typedefs import JSONEncoder, _CIMultiDict + +__all__ = ( + "PAYLOAD_REGISTRY", + "get_payload", + "payload_type", + "Payload", + "BytesPayload", + "StringPayload", + "IOBasePayload", + "BytesIOPayload", + "BufferedReaderPayload", + "TextIOPayload", + "StringIOPayload", + "JsonPayload", + "AsyncIterablePayload", +) + +TOO_LARGE_BYTES_BODY: Final[int] = 2**20 # 1 MB + +if TYPE_CHECKING: + from typing import List + + +class LookupError(Exception): + pass + + +class Order(str, enum.Enum): + normal = "normal" + try_first = "try_first" + try_last = "try_last" + + +def get_payload(data: Any, *args: Any, **kwargs: Any) -> "Payload": + return PAYLOAD_REGISTRY.get(data, *args, **kwargs) + + +def register_payload( + factory: Type["Payload"], type: Any, *, order: Order = Order.normal +) -> None: + PAYLOAD_REGISTRY.register(factory, type, order=order) + + +class payload_type: + def __init__(self, type: Any, *, order: Order = Order.normal) -> None: + self.type = type + self.order = order + + def __call__(self, factory: Type["Payload"]) -> Type["Payload"]: + register_payload(factory, self.type, order=self.order) + return factory + + +PayloadType = Type["Payload"] +_PayloadRegistryItem = Tuple[PayloadType, Any] + + +class PayloadRegistry: + """Payload registry. + + note: we need zope.interface for more efficient adapter search + """ + + __slots__ = ("_first", "_normal", "_last", "_normal_lookup") + + def __init__(self) -> None: + self._first: List[_PayloadRegistryItem] = [] + self._normal: List[_PayloadRegistryItem] = [] + self._last: List[_PayloadRegistryItem] = [] + self._normal_lookup: Dict[Any, PayloadType] = {} + + def get( + self, + data: Any, + *args: Any, + _CHAIN: "Type[chain[_PayloadRegistryItem]]" = chain, + **kwargs: Any, + ) -> "Payload": + if self._first: + for factory, type_ in self._first: + if isinstance(data, type_): + return factory(data, *args, **kwargs) + # Try the fast lookup first + if lookup_factory := self._normal_lookup.get(type(data)): + return lookup_factory(data, *args, **kwargs) + # Bail early if its already a Payload + if isinstance(data, Payload): + return data + # Fallback to the slower linear search + for factory, type_ in _CHAIN(self._normal, self._last): + if isinstance(data, type_): + return factory(data, *args, **kwargs) + raise LookupError() + + def register( + self, factory: PayloadType, type: Any, *, order: Order = Order.normal + ) -> None: + if order is Order.try_first: + self._first.append((factory, type)) + elif order is Order.normal: + self._normal.append((factory, type)) + if isinstance(type, Iterable): + for t in type: + self._normal_lookup[t] = factory + else: + self._normal_lookup[type] = factory + elif order is Order.try_last: + self._last.append((factory, type)) + else: + raise ValueError(f"Unsupported order {order!r}") + + +class Payload(ABC): + + _default_content_type: str = "application/octet-stream" + _size: Optional[int] = None + + def __init__( + self, + value: Any, + headers: Optional[ + Union[_CIMultiDict, Dict[str, str], Iterable[Tuple[str, str]]] + ] = None, + content_type: Union[str, None, _SENTINEL] = sentinel, + filename: Optional[str] = None, + encoding: Optional[str] = None, + **kwargs: Any, + ) -> None: + self._encoding = encoding + self._filename = filename + self._headers: _CIMultiDict = CIMultiDict() + self._value = value + if content_type is not sentinel and content_type is not None: + self._headers[hdrs.CONTENT_TYPE] = content_type + elif self._filename is not None: + if sys.version_info >= (3, 13): + guesser = mimetypes.guess_file_type + else: + guesser = mimetypes.guess_type + content_type = guesser(self._filename)[0] + if content_type is None: + content_type = self._default_content_type + self._headers[hdrs.CONTENT_TYPE] = content_type + else: + self._headers[hdrs.CONTENT_TYPE] = self._default_content_type + if headers: + self._headers.update(headers) + + @property + def size(self) -> Optional[int]: + """Size of the payload.""" + return self._size + + @property + def filename(self) -> Optional[str]: + """Filename of the payload.""" + return self._filename + + @property + def headers(self) -> _CIMultiDict: + """Custom item headers""" + return self._headers + + @property + def _binary_headers(self) -> bytes: + return ( + "".join([k + ": " + v + "\r\n" for k, v in self.headers.items()]).encode( + "utf-8" + ) + + b"\r\n" + ) + + @property + def encoding(self) -> Optional[str]: + """Payload encoding""" + return self._encoding + + @property + def content_type(self) -> str: + """Content type""" + return self._headers[hdrs.CONTENT_TYPE] + + def set_content_disposition( + self, + disptype: str, + quote_fields: bool = True, + _charset: str = "utf-8", + **params: Any, + ) -> None: + """Sets ``Content-Disposition`` header.""" + self._headers[hdrs.CONTENT_DISPOSITION] = content_disposition_header( + disptype, quote_fields=quote_fields, _charset=_charset, **params + ) + + @abstractmethod + def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: + """Return string representation of the value. + + This is named decode() to allow compatibility with bytes objects. + """ + + @abstractmethod + async def write(self, writer: AbstractStreamWriter) -> None: + """Write payload. + + writer is an AbstractStreamWriter instance: + """ + + +class BytesPayload(Payload): + _value: bytes + + def __init__( + self, value: Union[bytes, bytearray, memoryview], *args: Any, **kwargs: Any + ) -> None: + if "content_type" not in kwargs: + kwargs["content_type"] = "application/octet-stream" + + super().__init__(value, *args, **kwargs) + + if isinstance(value, memoryview): + self._size = value.nbytes + elif isinstance(value, (bytes, bytearray)): + self._size = len(value) + else: + raise TypeError(f"value argument must be byte-ish, not {type(value)!r}") + + if self._size > TOO_LARGE_BYTES_BODY: + kwargs = {"source": self} + warnings.warn( + "Sending a large body directly with raw bytes might" + " lock the event loop. You should probably pass an " + "io.BytesIO object instead", + ResourceWarning, + **kwargs, + ) + + def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: + return self._value.decode(encoding, errors) + + async def write(self, writer: AbstractStreamWriter) -> None: + await writer.write(self._value) + + +class StringPayload(BytesPayload): + def __init__( + self, + value: str, + *args: Any, + encoding: Optional[str] = None, + content_type: Optional[str] = None, + **kwargs: Any, + ) -> None: + + if encoding is None: + if content_type is None: + real_encoding = "utf-8" + content_type = "text/plain; charset=utf-8" + else: + mimetype = parse_mimetype(content_type) + real_encoding = mimetype.parameters.get("charset", "utf-8") + else: + if content_type is None: + content_type = "text/plain; charset=%s" % encoding + real_encoding = encoding + + super().__init__( + value.encode(real_encoding), + encoding=real_encoding, + content_type=content_type, + *args, + **kwargs, + ) + + +class StringIOPayload(StringPayload): + def __init__(self, value: IO[str], *args: Any, **kwargs: Any) -> None: + super().__init__(value.read(), *args, **kwargs) + + +class IOBasePayload(Payload): + _value: io.IOBase + + def __init__( + self, value: IO[Any], disposition: str = "attachment", *args: Any, **kwargs: Any + ) -> None: + if "filename" not in kwargs: + kwargs["filename"] = guess_filename(value) + + super().__init__(value, *args, **kwargs) + + if self._filename is not None and disposition is not None: + if hdrs.CONTENT_DISPOSITION not in self.headers: + self.set_content_disposition(disposition, filename=self._filename) + + async def write(self, writer: AbstractStreamWriter) -> None: + loop = asyncio.get_event_loop() + try: + chunk = await loop.run_in_executor(None, self._value.read, 2**16) + while chunk: + await writer.write(chunk) + chunk = await loop.run_in_executor(None, self._value.read, 2**16) + finally: + await loop.run_in_executor(None, self._value.close) + + def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: + return "".join(r.decode(encoding, errors) for r in self._value.readlines()) + + +class TextIOPayload(IOBasePayload): + _value: io.TextIOBase + + def __init__( + self, + value: TextIO, + *args: Any, + encoding: Optional[str] = None, + content_type: Optional[str] = None, + **kwargs: Any, + ) -> None: + + if encoding is None: + if content_type is None: + encoding = "utf-8" + content_type = "text/plain; charset=utf-8" + else: + mimetype = parse_mimetype(content_type) + encoding = mimetype.parameters.get("charset", "utf-8") + else: + if content_type is None: + content_type = "text/plain; charset=%s" % encoding + + super().__init__( + value, + content_type=content_type, + encoding=encoding, + *args, + **kwargs, + ) + + @property + def size(self) -> Optional[int]: + try: + return os.fstat(self._value.fileno()).st_size - self._value.tell() + except OSError: + return None + + def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: + return self._value.read() + + async def write(self, writer: AbstractStreamWriter) -> None: + loop = asyncio.get_event_loop() + try: + chunk = await loop.run_in_executor(None, self._value.read, 2**16) + while chunk: + data = ( + chunk.encode(encoding=self._encoding) + if self._encoding + else chunk.encode() + ) + await writer.write(data) + chunk = await loop.run_in_executor(None, self._value.read, 2**16) + finally: + await loop.run_in_executor(None, self._value.close) + + +class BytesIOPayload(IOBasePayload): + _value: io.BytesIO + + @property + def size(self) -> int: + position = self._value.tell() + end = self._value.seek(0, os.SEEK_END) + self._value.seek(position) + return end - position + + def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: + return self._value.read().decode(encoding, errors) + + +class BufferedReaderPayload(IOBasePayload): + _value: io.BufferedIOBase + + @property + def size(self) -> Optional[int]: + try: + return os.fstat(self._value.fileno()).st_size - self._value.tell() + except (OSError, AttributeError): + # data.fileno() is not supported, e.g. + # io.BufferedReader(io.BytesIO(b'data')) + # For some file-like objects (e.g. tarfile), the fileno() attribute may + # not exist at all, and will instead raise an AttributeError. + return None + + def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: + return self._value.read().decode(encoding, errors) + + +class JsonPayload(BytesPayload): + def __init__( + self, + value: Any, + encoding: str = "utf-8", + content_type: str = "application/json", + dumps: JSONEncoder = json.dumps, + *args: Any, + **kwargs: Any, + ) -> None: + + super().__init__( + dumps(value).encode(encoding), + content_type=content_type, + encoding=encoding, + *args, + **kwargs, + ) + + +if TYPE_CHECKING: + from typing import AsyncIterable, AsyncIterator + + _AsyncIterator = AsyncIterator[bytes] + _AsyncIterable = AsyncIterable[bytes] +else: + from collections.abc import AsyncIterable, AsyncIterator + + _AsyncIterator = AsyncIterator + _AsyncIterable = AsyncIterable + + +class AsyncIterablePayload(Payload): + + _iter: Optional[_AsyncIterator] = None + _value: _AsyncIterable + + def __init__(self, value: _AsyncIterable, *args: Any, **kwargs: Any) -> None: + if not isinstance(value, AsyncIterable): + raise TypeError( + "value argument must support " + "collections.abc.AsyncIterable interface, " + "got {!r}".format(type(value)) + ) + + if "content_type" not in kwargs: + kwargs["content_type"] = "application/octet-stream" + + super().__init__(value, *args, **kwargs) + + self._iter = value.__aiter__() + + async def write(self, writer: AbstractStreamWriter) -> None: + if self._iter: + try: + # iter is not None check prevents rare cases + # when the case iterable is used twice + while True: + chunk = await self._iter.__anext__() + await writer.write(chunk) + except StopAsyncIteration: + self._iter = None + + def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: + raise TypeError("Unable to decode.") + + +class StreamReaderPayload(AsyncIterablePayload): + def __init__(self, value: StreamReader, *args: Any, **kwargs: Any) -> None: + super().__init__(value.iter_any(), *args, **kwargs) + + +PAYLOAD_REGISTRY = PayloadRegistry() +PAYLOAD_REGISTRY.register(BytesPayload, (bytes, bytearray, memoryview)) +PAYLOAD_REGISTRY.register(StringPayload, str) +PAYLOAD_REGISTRY.register(StringIOPayload, io.StringIO) +PAYLOAD_REGISTRY.register(TextIOPayload, io.TextIOBase) +PAYLOAD_REGISTRY.register(BytesIOPayload, io.BytesIO) +PAYLOAD_REGISTRY.register(BufferedReaderPayload, (io.BufferedReader, io.BufferedRandom)) +PAYLOAD_REGISTRY.register(IOBasePayload, io.IOBase) +PAYLOAD_REGISTRY.register(StreamReaderPayload, StreamReader) +# try_last for giving a chance to more specialized async interables like +# multidict.BodyPartReaderPayload override the default +PAYLOAD_REGISTRY.register(AsyncIterablePayload, AsyncIterable, order=Order.try_last) diff --git a/venv/lib/python3.12/site-packages/aiohttp/payload_streamer.py b/venv/lib/python3.12/site-packages/aiohttp/payload_streamer.py new file mode 100644 index 00000000..831fdc0a --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/payload_streamer.py @@ -0,0 +1,78 @@ +""" +Payload implementation for coroutines as data provider. + +As a simple case, you can upload data from file:: + + @aiohttp.streamer + async def file_sender(writer, file_name=None): + with open(file_name, 'rb') as f: + chunk = f.read(2**16) + while chunk: + await writer.write(chunk) + + chunk = f.read(2**16) + +Then you can use `file_sender` like this: + + async with session.post('http://httpbin.org/post', + data=file_sender(file_name='huge_file')) as resp: + print(await resp.text()) + +..note:: Coroutine must accept `writer` as first argument + +""" + +import types +import warnings +from typing import Any, Awaitable, Callable, Dict, Tuple + +from .abc import AbstractStreamWriter +from .payload import Payload, payload_type + +__all__ = ("streamer",) + + +class _stream_wrapper: + def __init__( + self, + coro: Callable[..., Awaitable[None]], + args: Tuple[Any, ...], + kwargs: Dict[str, Any], + ) -> None: + self.coro = types.coroutine(coro) + self.args = args + self.kwargs = kwargs + + async def __call__(self, writer: AbstractStreamWriter) -> None: + await self.coro(writer, *self.args, **self.kwargs) + + +class streamer: + def __init__(self, coro: Callable[..., Awaitable[None]]) -> None: + warnings.warn( + "@streamer is deprecated, use async generators instead", + DeprecationWarning, + stacklevel=2, + ) + self.coro = coro + + def __call__(self, *args: Any, **kwargs: Any) -> _stream_wrapper: + return _stream_wrapper(self.coro, args, kwargs) + + +@payload_type(_stream_wrapper) +class StreamWrapperPayload(Payload): + async def write(self, writer: AbstractStreamWriter) -> None: + await self._value(writer) + + def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str: + raise TypeError("Unable to decode.") + + +@payload_type(streamer) +class StreamPayload(StreamWrapperPayload): + def __init__(self, value: Any, *args: Any, **kwargs: Any) -> None: + super().__init__(value(), *args, **kwargs) + + async def write(self, writer: AbstractStreamWriter) -> None: + await self._value(writer) diff --git a/venv/lib/python3.12/site-packages/aiohttp/py.typed b/venv/lib/python3.12/site-packages/aiohttp/py.typed new file mode 100644 index 00000000..f5642f79 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/py.typed @@ -0,0 +1 @@ +Marker diff --git a/venv/lib/python3.12/site-packages/aiohttp/pytest_plugin.py b/venv/lib/python3.12/site-packages/aiohttp/pytest_plugin.py new file mode 100644 index 00000000..21d6ea7b --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/pytest_plugin.py @@ -0,0 +1,436 @@ +import asyncio +import contextlib +import inspect +import warnings +from typing import ( + Any, + Awaitable, + Callable, + Dict, + Iterator, + Optional, + Protocol, + Type, + Union, + overload, +) + +import pytest + +from .test_utils import ( + BaseTestServer, + RawTestServer, + TestClient, + TestServer, + loop_context, + setup_test_loop, + teardown_test_loop, + unused_port as _unused_port, +) +from .web import Application, BaseRequest, Request +from .web_protocol import _RequestHandler + +try: + import uvloop +except ImportError: # pragma: no cover + uvloop = None # type: ignore[assignment] + + +class AiohttpClient(Protocol): + @overload + async def __call__( + self, + __param: Application, + *, + server_kwargs: Optional[Dict[str, Any]] = None, + **kwargs: Any, + ) -> TestClient[Request, Application]: ... + @overload + async def __call__( + self, + __param: BaseTestServer, + *, + server_kwargs: Optional[Dict[str, Any]] = None, + **kwargs: Any, + ) -> TestClient[BaseRequest, None]: ... + + +class AiohttpServer(Protocol): + def __call__( + self, app: Application, *, port: Optional[int] = None, **kwargs: Any + ) -> Awaitable[TestServer]: ... + + +class AiohttpRawServer(Protocol): + def __call__( + self, handler: _RequestHandler, *, port: Optional[int] = None, **kwargs: Any + ) -> Awaitable[RawTestServer]: ... + + +def pytest_addoption(parser): # type: ignore[no-untyped-def] + parser.addoption( + "--aiohttp-fast", + action="store_true", + default=False, + help="run tests faster by disabling extra checks", + ) + parser.addoption( + "--aiohttp-loop", + action="store", + default="pyloop", + help="run tests with specific loop: pyloop, uvloop or all", + ) + parser.addoption( + "--aiohttp-enable-loop-debug", + action="store_true", + default=False, + help="enable event loop debug mode", + ) + + +def pytest_fixture_setup(fixturedef): # type: ignore[no-untyped-def] + """Set up pytest fixture. + + Allow fixtures to be coroutines. Run coroutine fixtures in an event loop. + """ + func = fixturedef.func + + if inspect.isasyncgenfunction(func): + # async generator fixture + is_async_gen = True + elif inspect.iscoroutinefunction(func): + # regular async fixture + is_async_gen = False + else: + # not an async fixture, nothing to do + return + + strip_request = False + if "request" not in fixturedef.argnames: + fixturedef.argnames += ("request",) + strip_request = True + + def wrapper(*args, **kwargs): # type: ignore[no-untyped-def] + request = kwargs["request"] + if strip_request: + del kwargs["request"] + + # if neither the fixture nor the test use the 'loop' fixture, + # 'getfixturevalue' will fail because the test is not parameterized + # (this can be removed someday if 'loop' is no longer parameterized) + if "loop" not in request.fixturenames: + raise Exception( + "Asynchronous fixtures must depend on the 'loop' fixture or " + "be used in tests depending from it." + ) + + _loop = request.getfixturevalue("loop") + + if is_async_gen: + # for async generators, we need to advance the generator once, + # then advance it again in a finalizer + gen = func(*args, **kwargs) + + def finalizer(): # type: ignore[no-untyped-def] + try: + return _loop.run_until_complete(gen.__anext__()) + except StopAsyncIteration: + pass + + request.addfinalizer(finalizer) + return _loop.run_until_complete(gen.__anext__()) + else: + return _loop.run_until_complete(func(*args, **kwargs)) + + fixturedef.func = wrapper + + +@pytest.fixture +def fast(request): # type: ignore[no-untyped-def] + """--fast config option""" + return request.config.getoption("--aiohttp-fast") + + +@pytest.fixture +def loop_debug(request): # type: ignore[no-untyped-def] + """--enable-loop-debug config option""" + return request.config.getoption("--aiohttp-enable-loop-debug") + + +@contextlib.contextmanager +def _runtime_warning_context(): # type: ignore[no-untyped-def] + """Context manager which checks for RuntimeWarnings. + + This exists specifically to + avoid "coroutine 'X' was never awaited" warnings being missed. + + If RuntimeWarnings occur in the context a RuntimeError is raised. + """ + with warnings.catch_warnings(record=True) as _warnings: + yield + rw = [ + "{w.filename}:{w.lineno}:{w.message}".format(w=w) + for w in _warnings + if w.category == RuntimeWarning + ] + if rw: + raise RuntimeError( + "{} Runtime Warning{},\n{}".format( + len(rw), "" if len(rw) == 1 else "s", "\n".join(rw) + ) + ) + + +@contextlib.contextmanager +def _passthrough_loop_context(loop, fast=False): # type: ignore[no-untyped-def] + """Passthrough loop context. + + Sets up and tears down a loop unless one is passed in via the loop + argument when it's passed straight through. + """ + if loop: + # loop already exists, pass it straight through + yield loop + else: + # this shadows loop_context's standard behavior + loop = setup_test_loop() + yield loop + teardown_test_loop(loop, fast=fast) + + +def pytest_pycollect_makeitem(collector, name, obj): # type: ignore[no-untyped-def] + """Fix pytest collecting for coroutines.""" + if collector.funcnamefilter(name) and inspect.iscoroutinefunction(obj): + return list(collector._genfunctions(name, obj)) + + +def pytest_pyfunc_call(pyfuncitem): # type: ignore[no-untyped-def] + """Run coroutines in an event loop instead of a normal function call.""" + fast = pyfuncitem.config.getoption("--aiohttp-fast") + if inspect.iscoroutinefunction(pyfuncitem.function): + existing_loop = pyfuncitem.funcargs.get( + "proactor_loop" + ) or pyfuncitem.funcargs.get("loop", None) + with _runtime_warning_context(): + with _passthrough_loop_context(existing_loop, fast=fast) as _loop: + testargs = { + arg: pyfuncitem.funcargs[arg] + for arg in pyfuncitem._fixtureinfo.argnames + } + _loop.run_until_complete(pyfuncitem.obj(**testargs)) + + return True + + +def pytest_generate_tests(metafunc): # type: ignore[no-untyped-def] + if "loop_factory" not in metafunc.fixturenames: + return + + loops = metafunc.config.option.aiohttp_loop + avail_factories: Dict[str, Type[asyncio.AbstractEventLoopPolicy]] + avail_factories = {"pyloop": asyncio.DefaultEventLoopPolicy} + + if uvloop is not None: # pragma: no cover + avail_factories["uvloop"] = uvloop.EventLoopPolicy + + if loops == "all": + loops = "pyloop,uvloop?" + + factories = {} # type: ignore[var-annotated] + for name in loops.split(","): + required = not name.endswith("?") + name = name.strip(" ?") + if name not in avail_factories: # pragma: no cover + if required: + raise ValueError( + "Unknown loop '%s', available loops: %s" + % (name, list(factories.keys())) + ) + else: + continue + factories[name] = avail_factories[name] + metafunc.parametrize( + "loop_factory", list(factories.values()), ids=list(factories.keys()) + ) + + +@pytest.fixture +def loop(loop_factory, fast, loop_debug): # type: ignore[no-untyped-def] + """Return an instance of the event loop.""" + policy = loop_factory() + asyncio.set_event_loop_policy(policy) + with loop_context(fast=fast) as _loop: + if loop_debug: + _loop.set_debug(True) # pragma: no cover + asyncio.set_event_loop(_loop) + yield _loop + + +@pytest.fixture +def proactor_loop(): # type: ignore[no-untyped-def] + policy = asyncio.WindowsProactorEventLoopPolicy() # type: ignore[attr-defined] + asyncio.set_event_loop_policy(policy) + + with loop_context(policy.new_event_loop) as _loop: + asyncio.set_event_loop(_loop) + yield _loop + + +@pytest.fixture +def unused_port(aiohttp_unused_port: Callable[[], int]) -> Callable[[], int]: + warnings.warn( + "Deprecated, use aiohttp_unused_port fixture instead", + DeprecationWarning, + stacklevel=2, + ) + return aiohttp_unused_port + + +@pytest.fixture +def aiohttp_unused_port() -> Callable[[], int]: + """Return a port that is unused on the current host.""" + return _unused_port + + +@pytest.fixture +def aiohttp_server(loop: asyncio.AbstractEventLoop) -> Iterator[AiohttpServer]: + """Factory to create a TestServer instance, given an app. + + aiohttp_server(app, **kwargs) + """ + servers = [] + + async def go( + app: Application, *, port: Optional[int] = None, **kwargs: Any + ) -> TestServer: + server = TestServer(app, port=port) + await server.start_server(loop=loop, **kwargs) + servers.append(server) + return server + + yield go + + async def finalize() -> None: + while servers: + await servers.pop().close() + + loop.run_until_complete(finalize()) + + +@pytest.fixture +def test_server(aiohttp_server): # type: ignore[no-untyped-def] # pragma: no cover + warnings.warn( + "Deprecated, use aiohttp_server fixture instead", + DeprecationWarning, + stacklevel=2, + ) + return aiohttp_server + + +@pytest.fixture +def aiohttp_raw_server(loop: asyncio.AbstractEventLoop) -> Iterator[AiohttpRawServer]: + """Factory to create a RawTestServer instance, given a web handler. + + aiohttp_raw_server(handler, **kwargs) + """ + servers = [] + + async def go( + handler: _RequestHandler, *, port: Optional[int] = None, **kwargs: Any + ) -> RawTestServer: + server = RawTestServer(handler, port=port) + await server.start_server(loop=loop, **kwargs) + servers.append(server) + return server + + yield go + + async def finalize() -> None: + while servers: + await servers.pop().close() + + loop.run_until_complete(finalize()) + + +@pytest.fixture +def raw_test_server( # type: ignore[no-untyped-def] # pragma: no cover + aiohttp_raw_server, +): + warnings.warn( + "Deprecated, use aiohttp_raw_server fixture instead", + DeprecationWarning, + stacklevel=2, + ) + return aiohttp_raw_server + + +@pytest.fixture +def aiohttp_client(loop: asyncio.AbstractEventLoop) -> Iterator[AiohttpClient]: + """Factory to create a TestClient instance. + + aiohttp_client(app, **kwargs) + aiohttp_client(server, **kwargs) + aiohttp_client(raw_server, **kwargs) + """ + clients = [] + + @overload + async def go( + __param: Application, + *, + server_kwargs: Optional[Dict[str, Any]] = None, + **kwargs: Any, + ) -> TestClient[Request, Application]: ... + + @overload + async def go( + __param: BaseTestServer, + *, + server_kwargs: Optional[Dict[str, Any]] = None, + **kwargs: Any, + ) -> TestClient[BaseRequest, None]: ... + + async def go( + __param: Union[Application, BaseTestServer], + *args: Any, + server_kwargs: Optional[Dict[str, Any]] = None, + **kwargs: Any, + ) -> TestClient[Any, Any]: + if isinstance(__param, Callable) and not isinstance( # type: ignore[arg-type] + __param, (Application, BaseTestServer) + ): + __param = __param(loop, *args, **kwargs) + kwargs = {} + else: + assert not args, "args should be empty" + + if isinstance(__param, Application): + server_kwargs = server_kwargs or {} + server = TestServer(__param, loop=loop, **server_kwargs) + client = TestClient(server, loop=loop, **kwargs) + elif isinstance(__param, BaseTestServer): + client = TestClient(__param, loop=loop, **kwargs) + else: + raise ValueError("Unknown argument type: %r" % type(__param)) + + await client.start_server() + clients.append(client) + return client + + yield go + + async def finalize() -> None: + while clients: + await clients.pop().close() + + loop.run_until_complete(finalize()) + + +@pytest.fixture +def test_client(aiohttp_client): # type: ignore[no-untyped-def] # pragma: no cover + warnings.warn( + "Deprecated, use aiohttp_client fixture instead", + DeprecationWarning, + stacklevel=2, + ) + return aiohttp_client diff --git a/venv/lib/python3.12/site-packages/aiohttp/resolver.py b/venv/lib/python3.12/site-packages/aiohttp/resolver.py new file mode 100644 index 00000000..e14179cc --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/resolver.py @@ -0,0 +1,190 @@ +import asyncio +import socket +from typing import Any, Dict, List, Optional, Tuple, Type, Union + +from .abc import AbstractResolver, ResolveResult + +__all__ = ("ThreadedResolver", "AsyncResolver", "DefaultResolver") + + +try: + import aiodns + + aiodns_default = hasattr(aiodns.DNSResolver, "getaddrinfo") +except ImportError: # pragma: no cover + aiodns = None # type: ignore[assignment] + aiodns_default = False + + +_NUMERIC_SOCKET_FLAGS = socket.AI_NUMERICHOST | socket.AI_NUMERICSERV +_NAME_SOCKET_FLAGS = socket.NI_NUMERICHOST | socket.NI_NUMERICSERV +_AI_ADDRCONFIG = socket.AI_ADDRCONFIG +if hasattr(socket, "AI_MASK"): + _AI_ADDRCONFIG &= socket.AI_MASK + + +class ThreadedResolver(AbstractResolver): + """Threaded resolver. + + Uses an Executor for synchronous getaddrinfo() calls. + concurrent.futures.ThreadPoolExecutor is used by default. + """ + + def __init__(self, loop: Optional[asyncio.AbstractEventLoop] = None) -> None: + self._loop = loop or asyncio.get_running_loop() + + async def resolve( + self, host: str, port: int = 0, family: socket.AddressFamily = socket.AF_INET + ) -> List[ResolveResult]: + infos = await self._loop.getaddrinfo( + host, + port, + type=socket.SOCK_STREAM, + family=family, + flags=_AI_ADDRCONFIG, + ) + + hosts: List[ResolveResult] = [] + for family, _, proto, _, address in infos: + if family == socket.AF_INET6: + if len(address) < 3: + # IPv6 is not supported by Python build, + # or IPv6 is not enabled in the host + continue + if address[3]: + # This is essential for link-local IPv6 addresses. + # LL IPv6 is a VERY rare case. Strictly speaking, we should use + # getnameinfo() unconditionally, but performance makes sense. + resolved_host, _port = await self._loop.getnameinfo( + address, _NAME_SOCKET_FLAGS + ) + port = int(_port) + else: + resolved_host, port = address[:2] + else: # IPv4 + assert family == socket.AF_INET + resolved_host, port = address # type: ignore[misc] + hosts.append( + ResolveResult( + hostname=host, + host=resolved_host, + port=port, + family=family, + proto=proto, + flags=_NUMERIC_SOCKET_FLAGS, + ) + ) + + return hosts + + async def close(self) -> None: + pass + + +class AsyncResolver(AbstractResolver): + """Use the `aiodns` package to make asynchronous DNS lookups""" + + def __init__( + self, + loop: Optional[asyncio.AbstractEventLoop] = None, + *args: Any, + **kwargs: Any, + ) -> None: + if aiodns is None: + raise RuntimeError("Resolver requires aiodns library") + + self._resolver = aiodns.DNSResolver(*args, **kwargs) + + if not hasattr(self._resolver, "gethostbyname"): + # aiodns 1.1 is not available, fallback to DNSResolver.query + self.resolve = self._resolve_with_query # type: ignore + + async def resolve( + self, host: str, port: int = 0, family: socket.AddressFamily = socket.AF_INET + ) -> List[ResolveResult]: + try: + resp = await self._resolver.getaddrinfo( + host, + port=port, + type=socket.SOCK_STREAM, + family=family, + flags=_AI_ADDRCONFIG, + ) + except aiodns.error.DNSError as exc: + msg = exc.args[1] if len(exc.args) >= 1 else "DNS lookup failed" + raise OSError(None, msg) from exc + hosts: List[ResolveResult] = [] + for node in resp.nodes: + address: Union[Tuple[bytes, int], Tuple[bytes, int, int, int]] = node.addr + family = node.family + if family == socket.AF_INET6: + if len(address) > 3 and address[3]: + # This is essential for link-local IPv6 addresses. + # LL IPv6 is a VERY rare case. Strictly speaking, we should use + # getnameinfo() unconditionally, but performance makes sense. + result = await self._resolver.getnameinfo( + (address[0].decode("ascii"), *address[1:]), + _NAME_SOCKET_FLAGS, + ) + resolved_host = result.node + else: + resolved_host = address[0].decode("ascii") + port = address[1] + else: # IPv4 + assert family == socket.AF_INET + resolved_host = address[0].decode("ascii") + port = address[1] + hosts.append( + ResolveResult( + hostname=host, + host=resolved_host, + port=port, + family=family, + proto=0, + flags=_NUMERIC_SOCKET_FLAGS, + ) + ) + + if not hosts: + raise OSError(None, "DNS lookup failed") + + return hosts + + async def _resolve_with_query( + self, host: str, port: int = 0, family: int = socket.AF_INET + ) -> List[Dict[str, Any]]: + if family == socket.AF_INET6: + qtype = "AAAA" + else: + qtype = "A" + + try: + resp = await self._resolver.query(host, qtype) + except aiodns.error.DNSError as exc: + msg = exc.args[1] if len(exc.args) >= 1 else "DNS lookup failed" + raise OSError(None, msg) from exc + + hosts = [] + for rr in resp: + hosts.append( + { + "hostname": host, + "host": rr.host, + "port": port, + "family": family, + "proto": 0, + "flags": socket.AI_NUMERICHOST, + } + ) + + if not hosts: + raise OSError(None, "DNS lookup failed") + + return hosts + + async def close(self) -> None: + self._resolver.cancel() + + +_DefaultType = Type[Union[AsyncResolver, ThreadedResolver]] +DefaultResolver: _DefaultType = AsyncResolver if aiodns_default else ThreadedResolver diff --git a/venv/lib/python3.12/site-packages/aiohttp/streams.py b/venv/lib/python3.12/site-packages/aiohttp/streams.py new file mode 100644 index 00000000..7a3f64d1 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/streams.py @@ -0,0 +1,727 @@ +import asyncio +import collections +import warnings +from typing import ( + Awaitable, + Callable, + Deque, + Final, + Generic, + List, + Optional, + Tuple, + TypeVar, +) + +from .base_protocol import BaseProtocol +from .helpers import ( + _EXC_SENTINEL, + BaseTimerContext, + TimerNoop, + set_exception, + set_result, +) +from .log import internal_logger + +__all__ = ( + "EMPTY_PAYLOAD", + "EofStream", + "StreamReader", + "DataQueue", +) + +_T = TypeVar("_T") + + +class EofStream(Exception): + """eof stream indication.""" + + +class AsyncStreamIterator(Generic[_T]): + + __slots__ = ("read_func",) + + def __init__(self, read_func: Callable[[], Awaitable[_T]]) -> None: + self.read_func = read_func + + def __aiter__(self) -> "AsyncStreamIterator[_T]": + return self + + async def __anext__(self) -> _T: + try: + rv = await self.read_func() + except EofStream: + raise StopAsyncIteration + if rv == b"": + raise StopAsyncIteration + return rv + + +class ChunkTupleAsyncStreamIterator: + + __slots__ = ("_stream",) + + def __init__(self, stream: "StreamReader") -> None: + self._stream = stream + + def __aiter__(self) -> "ChunkTupleAsyncStreamIterator": + return self + + async def __anext__(self) -> Tuple[bytes, bool]: + rv = await self._stream.readchunk() + if rv == (b"", False): + raise StopAsyncIteration + return rv + + +class AsyncStreamReaderMixin: + + __slots__ = () + + def __aiter__(self) -> AsyncStreamIterator[bytes]: + return AsyncStreamIterator(self.readline) # type: ignore[attr-defined] + + def iter_chunked(self, n: int) -> AsyncStreamIterator[bytes]: + """Returns an asynchronous iterator that yields chunks of size n.""" + return AsyncStreamIterator(lambda: self.read(n)) # type: ignore[attr-defined] + + def iter_any(self) -> AsyncStreamIterator[bytes]: + """Yield all available data as soon as it is received.""" + return AsyncStreamIterator(self.readany) # type: ignore[attr-defined] + + def iter_chunks(self) -> ChunkTupleAsyncStreamIterator: + """Yield chunks of data as they are received by the server. + + The yielded objects are tuples + of (bytes, bool) as returned by the StreamReader.readchunk method. + """ + return ChunkTupleAsyncStreamIterator(self) # type: ignore[arg-type] + + +class StreamReader(AsyncStreamReaderMixin): + """An enhancement of asyncio.StreamReader. + + Supports asynchronous iteration by line, chunk or as available:: + + async for line in reader: + ... + async for chunk in reader.iter_chunked(1024): + ... + async for slice in reader.iter_any(): + ... + + """ + + __slots__ = ( + "_protocol", + "_low_water", + "_high_water", + "_loop", + "_size", + "_cursor", + "_http_chunk_splits", + "_buffer", + "_buffer_offset", + "_eof", + "_waiter", + "_eof_waiter", + "_exception", + "_timer", + "_eof_callbacks", + "_eof_counter", + "total_bytes", + ) + + def __init__( + self, + protocol: BaseProtocol, + limit: int, + *, + timer: Optional[BaseTimerContext] = None, + loop: Optional[asyncio.AbstractEventLoop] = None, + ) -> None: + self._protocol = protocol + self._low_water = limit + self._high_water = limit * 2 + if loop is None: + loop = asyncio.get_event_loop() + self._loop = loop + self._size = 0 + self._cursor = 0 + self._http_chunk_splits: Optional[List[int]] = None + self._buffer: Deque[bytes] = collections.deque() + self._buffer_offset = 0 + self._eof = False + self._waiter: Optional[asyncio.Future[None]] = None + self._eof_waiter: Optional[asyncio.Future[None]] = None + self._exception: Optional[BaseException] = None + self._timer = TimerNoop() if timer is None else timer + self._eof_callbacks: List[Callable[[], None]] = [] + self._eof_counter = 0 + self.total_bytes = 0 + + def __repr__(self) -> str: + info = [self.__class__.__name__] + if self._size: + info.append("%d bytes" % self._size) + if self._eof: + info.append("eof") + if self._low_water != 2**16: # default limit + info.append("low=%d high=%d" % (self._low_water, self._high_water)) + if self._waiter: + info.append("w=%r" % self._waiter) + if self._exception: + info.append("e=%r" % self._exception) + return "<%s>" % " ".join(info) + + def get_read_buffer_limits(self) -> Tuple[int, int]: + return (self._low_water, self._high_water) + + def exception(self) -> Optional[BaseException]: + return self._exception + + def set_exception( + self, + exc: BaseException, + exc_cause: BaseException = _EXC_SENTINEL, + ) -> None: + self._exception = exc + self._eof_callbacks.clear() + + waiter = self._waiter + if waiter is not None: + self._waiter = None + set_exception(waiter, exc, exc_cause) + + waiter = self._eof_waiter + if waiter is not None: + self._eof_waiter = None + set_exception(waiter, exc, exc_cause) + + def on_eof(self, callback: Callable[[], None]) -> None: + if self._eof: + try: + callback() + except Exception: + internal_logger.exception("Exception in eof callback") + else: + self._eof_callbacks.append(callback) + + def feed_eof(self) -> None: + self._eof = True + + waiter = self._waiter + if waiter is not None: + self._waiter = None + set_result(waiter, None) + + waiter = self._eof_waiter + if waiter is not None: + self._eof_waiter = None + set_result(waiter, None) + + if self._protocol._reading_paused: + self._protocol.resume_reading() + + for cb in self._eof_callbacks: + try: + cb() + except Exception: + internal_logger.exception("Exception in eof callback") + + self._eof_callbacks.clear() + + def is_eof(self) -> bool: + """Return True if 'feed_eof' was called.""" + return self._eof + + def at_eof(self) -> bool: + """Return True if the buffer is empty and 'feed_eof' was called.""" + return self._eof and not self._buffer + + async def wait_eof(self) -> None: + if self._eof: + return + + assert self._eof_waiter is None + self._eof_waiter = self._loop.create_future() + try: + await self._eof_waiter + finally: + self._eof_waiter = None + + def unread_data(self, data: bytes) -> None: + """rollback reading some data from stream, inserting it to buffer head.""" + warnings.warn( + "unread_data() is deprecated " + "and will be removed in future releases (#3260)", + DeprecationWarning, + stacklevel=2, + ) + if not data: + return + + if self._buffer_offset: + self._buffer[0] = self._buffer[0][self._buffer_offset :] + self._buffer_offset = 0 + self._size += len(data) + self._cursor -= len(data) + self._buffer.appendleft(data) + self._eof_counter = 0 + + # TODO: size is ignored, remove the param later + def feed_data(self, data: bytes, size: int = 0) -> None: + assert not self._eof, "feed_data after feed_eof" + + if not data: + return + + data_len = len(data) + self._size += data_len + self._buffer.append(data) + self.total_bytes += data_len + + waiter = self._waiter + if waiter is not None: + self._waiter = None + set_result(waiter, None) + + if self._size > self._high_water and not self._protocol._reading_paused: + self._protocol.pause_reading() + + def begin_http_chunk_receiving(self) -> None: + if self._http_chunk_splits is None: + if self.total_bytes: + raise RuntimeError( + "Called begin_http_chunk_receiving when some data was already fed" + ) + self._http_chunk_splits = [] + + def end_http_chunk_receiving(self) -> None: + if self._http_chunk_splits is None: + raise RuntimeError( + "Called end_chunk_receiving without calling " + "begin_chunk_receiving first" + ) + + # self._http_chunk_splits contains logical byte offsets from start of + # the body transfer. Each offset is the offset of the end of a chunk. + # "Logical" means bytes, accessible for a user. + # If no chunks containing logical data were received, current position + # is difinitely zero. + pos = self._http_chunk_splits[-1] if self._http_chunk_splits else 0 + + if self.total_bytes == pos: + # We should not add empty chunks here. So we check for that. + # Note, when chunked + gzip is used, we can receive a chunk + # of compressed data, but that data may not be enough for gzip FSM + # to yield any uncompressed data. That's why current position may + # not change after receiving a chunk. + return + + self._http_chunk_splits.append(self.total_bytes) + + # wake up readchunk when end of http chunk received + waiter = self._waiter + if waiter is not None: + self._waiter = None + set_result(waiter, None) + + async def _wait(self, func_name: str) -> None: + if not self._protocol.connected: + raise RuntimeError("Connection closed.") + + # StreamReader uses a future to link the protocol feed_data() method + # to a read coroutine. Running two read coroutines at the same time + # would have an unexpected behaviour. It would not possible to know + # which coroutine would get the next data. + if self._waiter is not None: + raise RuntimeError( + "%s() called while another coroutine is " + "already waiting for incoming data" % func_name + ) + + waiter = self._waiter = self._loop.create_future() + try: + with self._timer: + await waiter + finally: + self._waiter = None + + async def readline(self) -> bytes: + return await self.readuntil() + + async def readuntil(self, separator: bytes = b"\n") -> bytes: + seplen = len(separator) + if seplen == 0: + raise ValueError("Separator should be at least one-byte string") + + if self._exception is not None: + raise self._exception + + chunk = b"" + chunk_size = 0 + not_enough = True + + while not_enough: + while self._buffer and not_enough: + offset = self._buffer_offset + ichar = self._buffer[0].find(separator, offset) + 1 + # Read from current offset to found separator or to the end. + data = self._read_nowait_chunk( + ichar - offset + seplen - 1 if ichar else -1 + ) + chunk += data + chunk_size += len(data) + if ichar: + not_enough = False + + if chunk_size > self._high_water: + raise ValueError("Chunk too big") + + if self._eof: + break + + if not_enough: + await self._wait("readuntil") + + return chunk + + async def read(self, n: int = -1) -> bytes: + if self._exception is not None: + raise self._exception + + # migration problem; with DataQueue you have to catch + # EofStream exception, so common way is to run payload.read() inside + # infinite loop. what can cause real infinite loop with StreamReader + # lets keep this code one major release. + if __debug__: + if self._eof and not self._buffer: + self._eof_counter = getattr(self, "_eof_counter", 0) + 1 + if self._eof_counter > 5: + internal_logger.warning( + "Multiple access to StreamReader in eof state, " + "might be infinite loop.", + stack_info=True, + ) + + if not n: + return b"" + + if n < 0: + # This used to just loop creating a new waiter hoping to + # collect everything in self._buffer, but that would + # deadlock if the subprocess sends more than self.limit + # bytes. So just call self.readany() until EOF. + blocks = [] + while True: + block = await self.readany() + if not block: + break + blocks.append(block) + return b"".join(blocks) + + # TODO: should be `if` instead of `while` + # because waiter maybe triggered on chunk end, + # without feeding any data + while not self._buffer and not self._eof: + await self._wait("read") + + return self._read_nowait(n) + + async def readany(self) -> bytes: + if self._exception is not None: + raise self._exception + + # TODO: should be `if` instead of `while` + # because waiter maybe triggered on chunk end, + # without feeding any data + while not self._buffer and not self._eof: + await self._wait("readany") + + return self._read_nowait(-1) + + async def readchunk(self) -> Tuple[bytes, bool]: + """Returns a tuple of (data, end_of_http_chunk). + + When chunked transfer + encoding is used, end_of_http_chunk is a boolean indicating if the end + of the data corresponds to the end of a HTTP chunk , otherwise it is + always False. + """ + while True: + if self._exception is not None: + raise self._exception + + while self._http_chunk_splits: + pos = self._http_chunk_splits.pop(0) + if pos == self._cursor: + return (b"", True) + if pos > self._cursor: + return (self._read_nowait(pos - self._cursor), True) + internal_logger.warning( + "Skipping HTTP chunk end due to data " + "consumption beyond chunk boundary" + ) + + if self._buffer: + return (self._read_nowait_chunk(-1), False) + # return (self._read_nowait(-1), False) + + if self._eof: + # Special case for signifying EOF. + # (b'', True) is not a final return value actually. + return (b"", False) + + await self._wait("readchunk") + + async def readexactly(self, n: int) -> bytes: + if self._exception is not None: + raise self._exception + + blocks: List[bytes] = [] + while n > 0: + block = await self.read(n) + if not block: + partial = b"".join(blocks) + raise asyncio.IncompleteReadError(partial, len(partial) + n) + blocks.append(block) + n -= len(block) + + return b"".join(blocks) + + def read_nowait(self, n: int = -1) -> bytes: + # default was changed to be consistent with .read(-1) + # + # I believe the most users don't know about the method and + # they are not affected. + if self._exception is not None: + raise self._exception + + if self._waiter and not self._waiter.done(): + raise RuntimeError( + "Called while some coroutine is waiting for incoming data." + ) + + return self._read_nowait(n) + + def _read_nowait_chunk(self, n: int) -> bytes: + first_buffer = self._buffer[0] + offset = self._buffer_offset + if n != -1 and len(first_buffer) - offset > n: + data = first_buffer[offset : offset + n] + self._buffer_offset += n + + elif offset: + self._buffer.popleft() + data = first_buffer[offset:] + self._buffer_offset = 0 + + else: + data = self._buffer.popleft() + + data_len = len(data) + self._size -= data_len + self._cursor += data_len + + chunk_splits = self._http_chunk_splits + # Prevent memory leak: drop useless chunk splits + while chunk_splits and chunk_splits[0] < self._cursor: + chunk_splits.pop(0) + + if self._size < self._low_water and self._protocol._reading_paused: + self._protocol.resume_reading() + return data + + def _read_nowait(self, n: int) -> bytes: + """Read not more than n bytes, or whole buffer if n == -1""" + self._timer.assert_timeout() + + chunks = [] + while self._buffer: + chunk = self._read_nowait_chunk(n) + chunks.append(chunk) + if n != -1: + n -= len(chunk) + if n == 0: + break + + return b"".join(chunks) if chunks else b"" + + +class EmptyStreamReader(StreamReader): # lgtm [py/missing-call-to-init] + + __slots__ = ("_read_eof_chunk",) + + def __init__(self) -> None: + self._read_eof_chunk = False + self.total_bytes = 0 + + def __repr__(self) -> str: + return "<%s>" % self.__class__.__name__ + + def exception(self) -> Optional[BaseException]: + return None + + def set_exception( + self, + exc: BaseException, + exc_cause: BaseException = _EXC_SENTINEL, + ) -> None: + pass + + def on_eof(self, callback: Callable[[], None]) -> None: + try: + callback() + except Exception: + internal_logger.exception("Exception in eof callback") + + def feed_eof(self) -> None: + pass + + def is_eof(self) -> bool: + return True + + def at_eof(self) -> bool: + return True + + async def wait_eof(self) -> None: + return + + def feed_data(self, data: bytes, n: int = 0) -> None: + pass + + async def readline(self) -> bytes: + return b"" + + async def read(self, n: int = -1) -> bytes: + return b"" + + # TODO add async def readuntil + + async def readany(self) -> bytes: + return b"" + + async def readchunk(self) -> Tuple[bytes, bool]: + if not self._read_eof_chunk: + self._read_eof_chunk = True + return (b"", False) + + return (b"", True) + + async def readexactly(self, n: int) -> bytes: + raise asyncio.IncompleteReadError(b"", n) + + def read_nowait(self, n: int = -1) -> bytes: + return b"" + + +EMPTY_PAYLOAD: Final[StreamReader] = EmptyStreamReader() + + +class DataQueue(Generic[_T]): + """DataQueue is a general-purpose blocking queue with one reader.""" + + def __init__(self, loop: asyncio.AbstractEventLoop) -> None: + self._loop = loop + self._eof = False + self._waiter: Optional[asyncio.Future[None]] = None + self._exception: Optional[BaseException] = None + self._buffer: Deque[Tuple[_T, int]] = collections.deque() + + def __len__(self) -> int: + return len(self._buffer) + + def is_eof(self) -> bool: + return self._eof + + def at_eof(self) -> bool: + return self._eof and not self._buffer + + def exception(self) -> Optional[BaseException]: + return self._exception + + def set_exception( + self, + exc: BaseException, + exc_cause: BaseException = _EXC_SENTINEL, + ) -> None: + self._eof = True + self._exception = exc + if (waiter := self._waiter) is not None: + self._waiter = None + set_exception(waiter, exc, exc_cause) + + def feed_data(self, data: _T, size: int = 0) -> None: + self._buffer.append((data, size)) + if (waiter := self._waiter) is not None: + self._waiter = None + set_result(waiter, None) + + def feed_eof(self) -> None: + self._eof = True + if (waiter := self._waiter) is not None: + self._waiter = None + set_result(waiter, None) + + async def read(self) -> _T: + if not self._buffer and not self._eof: + assert not self._waiter + self._waiter = self._loop.create_future() + try: + await self._waiter + except (asyncio.CancelledError, asyncio.TimeoutError): + self._waiter = None + raise + if self._buffer: + data, _ = self._buffer.popleft() + return data + if self._exception is not None: + raise self._exception + raise EofStream + + def __aiter__(self) -> AsyncStreamIterator[_T]: + return AsyncStreamIterator(self.read) + + +class FlowControlDataQueue(DataQueue[_T]): + """FlowControlDataQueue resumes and pauses an underlying stream. + + It is a destination for parsed data. + + This class is deprecated and will be removed in version 4.0. + """ + + def __init__( + self, protocol: BaseProtocol, limit: int, *, loop: asyncio.AbstractEventLoop + ) -> None: + super().__init__(loop=loop) + self._size = 0 + self._protocol = protocol + self._limit = limit * 2 + + def feed_data(self, data: _T, size: int = 0) -> None: + super().feed_data(data, size) + self._size += size + + if self._size > self._limit and not self._protocol._reading_paused: + self._protocol.pause_reading() + + async def read(self) -> _T: + if not self._buffer and not self._eof: + assert not self._waiter + self._waiter = self._loop.create_future() + try: + await self._waiter + except (asyncio.CancelledError, asyncio.TimeoutError): + self._waiter = None + raise + if self._buffer: + data, size = self._buffer.popleft() + self._size -= size + if self._size < self._limit and self._protocol._reading_paused: + self._protocol.resume_reading() + return data + if self._exception is not None: + raise self._exception + raise EofStream diff --git a/venv/lib/python3.12/site-packages/aiohttp/tcp_helpers.py b/venv/lib/python3.12/site-packages/aiohttp/tcp_helpers.py new file mode 100644 index 00000000..88b24422 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/tcp_helpers.py @@ -0,0 +1,37 @@ +"""Helper methods to tune a TCP connection""" + +import asyncio +import socket +from contextlib import suppress +from typing import Optional # noqa + +__all__ = ("tcp_keepalive", "tcp_nodelay") + + +if hasattr(socket, "SO_KEEPALIVE"): + + def tcp_keepalive(transport: asyncio.Transport) -> None: + sock = transport.get_extra_info("socket") + if sock is not None: + sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) + +else: + + def tcp_keepalive(transport: asyncio.Transport) -> None: # pragma: no cover + pass + + +def tcp_nodelay(transport: asyncio.Transport, value: bool) -> None: + sock = transport.get_extra_info("socket") + + if sock is None: + return + + if sock.family not in (socket.AF_INET, socket.AF_INET6): + return + + value = bool(value) + + # socket may be closed already, on windows OSError get raised + with suppress(OSError): + sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, value) diff --git a/venv/lib/python3.12/site-packages/aiohttp/test_utils.py b/venv/lib/python3.12/site-packages/aiohttp/test_utils.py new file mode 100644 index 00000000..87c31427 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/test_utils.py @@ -0,0 +1,774 @@ +"""Utilities shared by tests.""" + +import asyncio +import contextlib +import gc +import inspect +import ipaddress +import os +import socket +import sys +import warnings +from abc import ABC, abstractmethod +from types import TracebackType +from typing import ( + TYPE_CHECKING, + Any, + Callable, + Generic, + Iterator, + List, + Optional, + Type, + TypeVar, + cast, + overload, +) +from unittest import IsolatedAsyncioTestCase, mock + +from aiosignal import Signal +from multidict import CIMultiDict, CIMultiDictProxy +from yarl import URL + +import aiohttp +from aiohttp.client import ( + _RequestContextManager, + _RequestOptions, + _WSRequestContextManager, +) + +from . import ClientSession, hdrs +from .abc import AbstractCookieJar +from .client_reqrep import ClientResponse +from .client_ws import ClientWebSocketResponse +from .helpers import sentinel +from .http import HttpVersion, RawRequestMessage +from .streams import EMPTY_PAYLOAD, StreamReader +from .typedefs import StrOrURL +from .web import ( + Application, + AppRunner, + BaseRequest, + BaseRunner, + Request, + Server, + ServerRunner, + SockSite, + UrlMappingMatchInfo, +) +from .web_protocol import _RequestHandler + +if TYPE_CHECKING: + from ssl import SSLContext +else: + SSLContext = None + +if sys.version_info >= (3, 11) and TYPE_CHECKING: + from typing import Unpack + +if sys.version_info >= (3, 11): + from typing import Self +else: + Self = Any + +_ApplicationNone = TypeVar("_ApplicationNone", Application, None) +_Request = TypeVar("_Request", bound=BaseRequest) + +REUSE_ADDRESS = os.name == "posix" and sys.platform != "cygwin" + + +def get_unused_port_socket( + host: str, family: socket.AddressFamily = socket.AF_INET +) -> socket.socket: + return get_port_socket(host, 0, family) + + +def get_port_socket( + host: str, port: int, family: socket.AddressFamily +) -> socket.socket: + s = socket.socket(family, socket.SOCK_STREAM) + if REUSE_ADDRESS: + # Windows has different semantics for SO_REUSEADDR, + # so don't set it. Ref: + # https://docs.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse + s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + s.bind((host, port)) + return s + + +def unused_port() -> int: + """Return a port that is unused on the current host.""" + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.bind(("127.0.0.1", 0)) + return cast(int, s.getsockname()[1]) + + +class BaseTestServer(ABC): + __test__ = False + + def __init__( + self, + *, + scheme: str = "", + loop: Optional[asyncio.AbstractEventLoop] = None, + host: str = "127.0.0.1", + port: Optional[int] = None, + skip_url_asserts: bool = False, + socket_factory: Callable[ + [str, int, socket.AddressFamily], socket.socket + ] = get_port_socket, + **kwargs: Any, + ) -> None: + self._loop = loop + self.runner: Optional[BaseRunner] = None + self._root: Optional[URL] = None + self.host = host + self.port = port + self._closed = False + self.scheme = scheme + self.skip_url_asserts = skip_url_asserts + self.socket_factory = socket_factory + + async def start_server( + self, loop: Optional[asyncio.AbstractEventLoop] = None, **kwargs: Any + ) -> None: + if self.runner: + return + self._loop = loop + self._ssl = kwargs.pop("ssl", None) + self.runner = await self._make_runner(handler_cancellation=True, **kwargs) + await self.runner.setup() + if not self.port: + self.port = 0 + absolute_host = self.host + try: + version = ipaddress.ip_address(self.host).version + except ValueError: + version = 4 + if version == 6: + absolute_host = f"[{self.host}]" + family = socket.AF_INET6 if version == 6 else socket.AF_INET + _sock = self.socket_factory(self.host, self.port, family) + self.host, self.port = _sock.getsockname()[:2] + site = SockSite(self.runner, sock=_sock, ssl_context=self._ssl) + await site.start() + server = site._server + assert server is not None + sockets = server.sockets # type: ignore[attr-defined] + assert sockets is not None + self.port = sockets[0].getsockname()[1] + if not self.scheme: + self.scheme = "https" if self._ssl else "http" + self._root = URL(f"{self.scheme}://{absolute_host}:{self.port}") + + @abstractmethod # pragma: no cover + async def _make_runner(self, **kwargs: Any) -> BaseRunner: + pass + + def make_url(self, path: StrOrURL) -> URL: + assert self._root is not None + url = URL(path) + if not self.skip_url_asserts: + assert not url.absolute + return self._root.join(url) + else: + return URL(str(self._root) + str(path)) + + @property + def started(self) -> bool: + return self.runner is not None + + @property + def closed(self) -> bool: + return self._closed + + @property + def handler(self) -> Server: + # for backward compatibility + # web.Server instance + runner = self.runner + assert runner is not None + assert runner.server is not None + return runner.server + + async def close(self) -> None: + """Close all fixtures created by the test client. + + After that point, the TestClient is no longer usable. + + This is an idempotent function: running close multiple times + will not have any additional effects. + + close is also run when the object is garbage collected, and on + exit when used as a context manager. + + """ + if self.started and not self.closed: + assert self.runner is not None + await self.runner.cleanup() + self._root = None + self.port = None + self._closed = True + + def __enter__(self) -> None: + raise TypeError("Use async with instead") + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_value: Optional[BaseException], + traceback: Optional[TracebackType], + ) -> None: + # __exit__ should exist in pair with __enter__ but never executed + pass # pragma: no cover + + async def __aenter__(self) -> "BaseTestServer": + await self.start_server(loop=self._loop) + return self + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc_value: Optional[BaseException], + traceback: Optional[TracebackType], + ) -> None: + await self.close() + + +class TestServer(BaseTestServer): + def __init__( + self, + app: Application, + *, + scheme: str = "", + host: str = "127.0.0.1", + port: Optional[int] = None, + **kwargs: Any, + ): + self.app = app + super().__init__(scheme=scheme, host=host, port=port, **kwargs) + + async def _make_runner(self, **kwargs: Any) -> BaseRunner: + return AppRunner(self.app, **kwargs) + + +class RawTestServer(BaseTestServer): + def __init__( + self, + handler: _RequestHandler, + *, + scheme: str = "", + host: str = "127.0.0.1", + port: Optional[int] = None, + **kwargs: Any, + ) -> None: + self._handler = handler + super().__init__(scheme=scheme, host=host, port=port, **kwargs) + + async def _make_runner(self, debug: bool = True, **kwargs: Any) -> ServerRunner: + srv = Server(self._handler, loop=self._loop, debug=debug, **kwargs) + return ServerRunner(srv, debug=debug, **kwargs) + + +class TestClient(Generic[_Request, _ApplicationNone]): + """ + A test client implementation. + + To write functional tests for aiohttp based servers. + + """ + + __test__ = False + + @overload + def __init__( + self: "TestClient[Request, Application]", + server: TestServer, + *, + cookie_jar: Optional[AbstractCookieJar] = None, + **kwargs: Any, + ) -> None: ... + @overload + def __init__( + self: "TestClient[_Request, None]", + server: BaseTestServer, + *, + cookie_jar: Optional[AbstractCookieJar] = None, + **kwargs: Any, + ) -> None: ... + def __init__( + self, + server: BaseTestServer, + *, + cookie_jar: Optional[AbstractCookieJar] = None, + loop: Optional[asyncio.AbstractEventLoop] = None, + **kwargs: Any, + ) -> None: + if not isinstance(server, BaseTestServer): + raise TypeError( + "server must be TestServer instance, found type: %r" % type(server) + ) + self._server = server + self._loop = loop + if cookie_jar is None: + cookie_jar = aiohttp.CookieJar(unsafe=True, loop=loop) + self._session = ClientSession(loop=loop, cookie_jar=cookie_jar, **kwargs) + self._session._retry_connection = False + self._closed = False + self._responses: List[ClientResponse] = [] + self._websockets: List[ClientWebSocketResponse] = [] + + async def start_server(self) -> None: + await self._server.start_server(loop=self._loop) + + @property + def host(self) -> str: + return self._server.host + + @property + def port(self) -> Optional[int]: + return self._server.port + + @property + def server(self) -> BaseTestServer: + return self._server + + @property + def app(self) -> _ApplicationNone: + return getattr(self._server, "app", None) # type: ignore[return-value] + + @property + def session(self) -> ClientSession: + """An internal aiohttp.ClientSession. + + Unlike the methods on the TestClient, client session requests + do not automatically include the host in the url queried, and + will require an absolute path to the resource. + + """ + return self._session + + def make_url(self, path: StrOrURL) -> URL: + return self._server.make_url(path) + + async def _request( + self, method: str, path: StrOrURL, **kwargs: Any + ) -> ClientResponse: + resp = await self._session.request(method, self.make_url(path), **kwargs) + # save it to close later + self._responses.append(resp) + return resp + + if sys.version_info >= (3, 11) and TYPE_CHECKING: + + def request( + self, method: str, path: StrOrURL, **kwargs: Unpack[_RequestOptions] + ) -> _RequestContextManager: ... + + def get( + self, + path: StrOrURL, + **kwargs: Unpack[_RequestOptions], + ) -> _RequestContextManager: ... + + def options( + self, + path: StrOrURL, + **kwargs: Unpack[_RequestOptions], + ) -> _RequestContextManager: ... + + def head( + self, + path: StrOrURL, + **kwargs: Unpack[_RequestOptions], + ) -> _RequestContextManager: ... + + def post( + self, + path: StrOrURL, + **kwargs: Unpack[_RequestOptions], + ) -> _RequestContextManager: ... + + def put( + self, + path: StrOrURL, + **kwargs: Unpack[_RequestOptions], + ) -> _RequestContextManager: ... + + def patch( + self, + path: StrOrURL, + **kwargs: Unpack[_RequestOptions], + ) -> _RequestContextManager: ... + + def delete( + self, + path: StrOrURL, + **kwargs: Unpack[_RequestOptions], + ) -> _RequestContextManager: ... + + else: + + def request( + self, method: str, path: StrOrURL, **kwargs: Any + ) -> _RequestContextManager: + """Routes a request to tested http server. + + The interface is identical to aiohttp.ClientSession.request, + except the loop kwarg is overridden by the instance used by the + test server. + + """ + return _RequestContextManager(self._request(method, path, **kwargs)) + + def get(self, path: StrOrURL, **kwargs: Any) -> _RequestContextManager: + """Perform an HTTP GET request.""" + return _RequestContextManager(self._request(hdrs.METH_GET, path, **kwargs)) + + def post(self, path: StrOrURL, **kwargs: Any) -> _RequestContextManager: + """Perform an HTTP POST request.""" + return _RequestContextManager(self._request(hdrs.METH_POST, path, **kwargs)) + + def options(self, path: StrOrURL, **kwargs: Any) -> _RequestContextManager: + """Perform an HTTP OPTIONS request.""" + return _RequestContextManager( + self._request(hdrs.METH_OPTIONS, path, **kwargs) + ) + + def head(self, path: StrOrURL, **kwargs: Any) -> _RequestContextManager: + """Perform an HTTP HEAD request.""" + return _RequestContextManager(self._request(hdrs.METH_HEAD, path, **kwargs)) + + def put(self, path: StrOrURL, **kwargs: Any) -> _RequestContextManager: + """Perform an HTTP PUT request.""" + return _RequestContextManager(self._request(hdrs.METH_PUT, path, **kwargs)) + + def patch(self, path: StrOrURL, **kwargs: Any) -> _RequestContextManager: + """Perform an HTTP PATCH request.""" + return _RequestContextManager( + self._request(hdrs.METH_PATCH, path, **kwargs) + ) + + def delete(self, path: StrOrURL, **kwargs: Any) -> _RequestContextManager: + """Perform an HTTP PATCH request.""" + return _RequestContextManager( + self._request(hdrs.METH_DELETE, path, **kwargs) + ) + + def ws_connect(self, path: StrOrURL, **kwargs: Any) -> _WSRequestContextManager: + """Initiate websocket connection. + + The api corresponds to aiohttp.ClientSession.ws_connect. + + """ + return _WSRequestContextManager(self._ws_connect(path, **kwargs)) + + async def _ws_connect( + self, path: StrOrURL, **kwargs: Any + ) -> ClientWebSocketResponse: + ws = await self._session.ws_connect(self.make_url(path), **kwargs) + self._websockets.append(ws) + return ws + + async def close(self) -> None: + """Close all fixtures created by the test client. + + After that point, the TestClient is no longer usable. + + This is an idempotent function: running close multiple times + will not have any additional effects. + + close is also run on exit when used as a(n) (asynchronous) + context manager. + + """ + if not self._closed: + for resp in self._responses: + resp.close() + for ws in self._websockets: + await ws.close() + await self._session.close() + await self._server.close() + self._closed = True + + def __enter__(self) -> None: + raise TypeError("Use async with instead") + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc: Optional[BaseException], + tb: Optional[TracebackType], + ) -> None: + # __exit__ should exist in pair with __enter__ but never executed + pass # pragma: no cover + + async def __aenter__(self) -> Self: + await self.start_server() + return self + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc: Optional[BaseException], + tb: Optional[TracebackType], + ) -> None: + await self.close() + + +class AioHTTPTestCase(IsolatedAsyncioTestCase): + """A base class to allow for unittest web applications using aiohttp. + + Provides the following: + + * self.client (aiohttp.test_utils.TestClient): an aiohttp test client. + * self.loop (asyncio.BaseEventLoop): the event loop in which the + application and server are running. + * self.app (aiohttp.web.Application): the application returned by + self.get_application() + + Note that the TestClient's methods are asynchronous: you have to + execute function on the test client using asynchronous methods. + """ + + async def get_application(self) -> Application: + """Get application. + + This method should be overridden + to return the aiohttp.web.Application + object to test. + """ + return self.get_app() + + def get_app(self) -> Application: + """Obsolete method used to constructing web application. + + Use .get_application() coroutine instead. + """ + raise RuntimeError("Did you forget to define get_application()?") + + async def asyncSetUp(self) -> None: + self.loop = asyncio.get_running_loop() + return await self.setUpAsync() + + async def setUpAsync(self) -> None: + self.app = await self.get_application() + self.server = await self.get_server(self.app) + self.client = await self.get_client(self.server) + + await self.client.start_server() + + async def asyncTearDown(self) -> None: + return await self.tearDownAsync() + + async def tearDownAsync(self) -> None: + await self.client.close() + + async def get_server(self, app: Application) -> TestServer: + """Return a TestServer instance.""" + return TestServer(app, loop=self.loop) + + async def get_client(self, server: TestServer) -> TestClient[Request, Application]: + """Return a TestClient instance.""" + return TestClient(server, loop=self.loop) + + +def unittest_run_loop(func: Any, *args: Any, **kwargs: Any) -> Any: + """ + A decorator dedicated to use with asynchronous AioHTTPTestCase test methods. + + In 3.8+, this does nothing. + """ + warnings.warn( + "Decorator `@unittest_run_loop` is no longer needed in aiohttp 3.8+", + DeprecationWarning, + stacklevel=2, + ) + return func + + +_LOOP_FACTORY = Callable[[], asyncio.AbstractEventLoop] + + +@contextlib.contextmanager +def loop_context( + loop_factory: _LOOP_FACTORY = asyncio.new_event_loop, fast: bool = False +) -> Iterator[asyncio.AbstractEventLoop]: + """A contextmanager that creates an event_loop, for test purposes. + + Handles the creation and cleanup of a test loop. + """ + loop = setup_test_loop(loop_factory) + yield loop + teardown_test_loop(loop, fast=fast) + + +def setup_test_loop( + loop_factory: _LOOP_FACTORY = asyncio.new_event_loop, +) -> asyncio.AbstractEventLoop: + """Create and return an asyncio.BaseEventLoop instance. + + The caller should also call teardown_test_loop, + once they are done with the loop. + """ + loop = loop_factory() + asyncio.set_event_loop(loop) + return loop + + +def teardown_test_loop(loop: asyncio.AbstractEventLoop, fast: bool = False) -> None: + """Teardown and cleanup an event_loop created by setup_test_loop.""" + closed = loop.is_closed() + if not closed: + loop.call_soon(loop.stop) + loop.run_forever() + loop.close() + + if not fast: + gc.collect() + + asyncio.set_event_loop(None) + + +def _create_app_mock() -> mock.MagicMock: + def get_dict(app: Any, key: str) -> Any: + return app.__app_dict[key] + + def set_dict(app: Any, key: str, value: Any) -> None: + app.__app_dict[key] = value + + app = mock.MagicMock(spec=Application) + app.__app_dict = {} + app.__getitem__ = get_dict + app.__setitem__ = set_dict + + app._debug = False + app.on_response_prepare = Signal(app) + app.on_response_prepare.freeze() + return app + + +def _create_transport(sslcontext: Optional[SSLContext] = None) -> mock.Mock: + transport = mock.Mock() + + def get_extra_info(key: str) -> Optional[SSLContext]: + if key == "sslcontext": + return sslcontext + else: + return None + + transport.get_extra_info.side_effect = get_extra_info + return transport + + +def make_mocked_request( + method: str, + path: str, + headers: Any = None, + *, + match_info: Any = sentinel, + version: HttpVersion = HttpVersion(1, 1), + closing: bool = False, + app: Any = None, + writer: Any = sentinel, + protocol: Any = sentinel, + transport: Any = sentinel, + payload: StreamReader = EMPTY_PAYLOAD, + sslcontext: Optional[SSLContext] = None, + client_max_size: int = 1024**2, + loop: Any = ..., +) -> Request: + """Creates mocked web.Request testing purposes. + + Useful in unit tests, when spinning full web server is overkill or + specific conditions and errors are hard to trigger. + """ + task = mock.Mock() + if loop is ...: + # no loop passed, try to get the current one if + # its is running as we need a real loop to create + # executor jobs to be able to do testing + # with a real executor + try: + loop = asyncio.get_running_loop() + except RuntimeError: + loop = mock.Mock() + loop.create_future.return_value = () + + if version < HttpVersion(1, 1): + closing = True + + if headers: + headers = CIMultiDictProxy(CIMultiDict(headers)) + raw_hdrs = tuple( + (k.encode("utf-8"), v.encode("utf-8")) for k, v in headers.items() + ) + else: + headers = CIMultiDictProxy(CIMultiDict()) + raw_hdrs = () + + chunked = "chunked" in headers.get(hdrs.TRANSFER_ENCODING, "").lower() + + message = RawRequestMessage( + method, + path, + version, + headers, + raw_hdrs, + closing, + None, + False, + chunked, + URL(path), + ) + if app is None: + app = _create_app_mock() + + if transport is sentinel: + transport = _create_transport(sslcontext) + + if protocol is sentinel: + protocol = mock.Mock() + protocol.transport = transport + type(protocol).peername = mock.PropertyMock( + return_value=transport.get_extra_info("peername") + ) + type(protocol).ssl_context = mock.PropertyMock(return_value=sslcontext) + + if writer is sentinel: + writer = mock.Mock() + writer.write_headers = make_mocked_coro(None) + writer.write = make_mocked_coro(None) + writer.write_eof = make_mocked_coro(None) + writer.drain = make_mocked_coro(None) + writer.transport = transport + + protocol.transport = transport + protocol.writer = writer + + req = Request( + message, payload, protocol, writer, task, loop, client_max_size=client_max_size + ) + + match_info = UrlMappingMatchInfo( + {} if match_info is sentinel else match_info, mock.Mock() + ) + match_info.add_app(app) + req._match_info = match_info + + return req + + +def make_mocked_coro( + return_value: Any = sentinel, raise_exception: Any = sentinel +) -> Any: + """Creates a coroutine mock.""" + + async def mock_coro(*args: Any, **kwargs: Any) -> Any: + if raise_exception is not sentinel: + raise raise_exception + if not inspect.isawaitable(return_value): + return return_value + await return_value + + return mock.Mock(wraps=mock_coro) diff --git a/venv/lib/python3.12/site-packages/aiohttp/tracing.py b/venv/lib/python3.12/site-packages/aiohttp/tracing.py new file mode 100644 index 00000000..012ed7bd --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/tracing.py @@ -0,0 +1,470 @@ +from types import SimpleNamespace +from typing import TYPE_CHECKING, Awaitable, Mapping, Optional, Protocol, Type, TypeVar + +import attr +from aiosignal import Signal +from multidict import CIMultiDict +from yarl import URL + +from .client_reqrep import ClientResponse + +if TYPE_CHECKING: + from .client import ClientSession + + _ParamT_contra = TypeVar("_ParamT_contra", contravariant=True) + + class _SignalCallback(Protocol[_ParamT_contra]): + def __call__( + self, + __client_session: ClientSession, + __trace_config_ctx: SimpleNamespace, + __params: _ParamT_contra, + ) -> Awaitable[None]: ... + + +__all__ = ( + "TraceConfig", + "TraceRequestStartParams", + "TraceRequestEndParams", + "TraceRequestExceptionParams", + "TraceConnectionQueuedStartParams", + "TraceConnectionQueuedEndParams", + "TraceConnectionCreateStartParams", + "TraceConnectionCreateEndParams", + "TraceConnectionReuseconnParams", + "TraceDnsResolveHostStartParams", + "TraceDnsResolveHostEndParams", + "TraceDnsCacheHitParams", + "TraceDnsCacheMissParams", + "TraceRequestRedirectParams", + "TraceRequestChunkSentParams", + "TraceResponseChunkReceivedParams", + "TraceRequestHeadersSentParams", +) + + +class TraceConfig: + """First-class used to trace requests launched via ClientSession objects.""" + + def __init__( + self, trace_config_ctx_factory: Type[SimpleNamespace] = SimpleNamespace + ) -> None: + self._on_request_start: Signal[_SignalCallback[TraceRequestStartParams]] = ( + Signal(self) + ) + self._on_request_chunk_sent: Signal[ + _SignalCallback[TraceRequestChunkSentParams] + ] = Signal(self) + self._on_response_chunk_received: Signal[ + _SignalCallback[TraceResponseChunkReceivedParams] + ] = Signal(self) + self._on_request_end: Signal[_SignalCallback[TraceRequestEndParams]] = Signal( + self + ) + self._on_request_exception: Signal[ + _SignalCallback[TraceRequestExceptionParams] + ] = Signal(self) + self._on_request_redirect: Signal[ + _SignalCallback[TraceRequestRedirectParams] + ] = Signal(self) + self._on_connection_queued_start: Signal[ + _SignalCallback[TraceConnectionQueuedStartParams] + ] = Signal(self) + self._on_connection_queued_end: Signal[ + _SignalCallback[TraceConnectionQueuedEndParams] + ] = Signal(self) + self._on_connection_create_start: Signal[ + _SignalCallback[TraceConnectionCreateStartParams] + ] = Signal(self) + self._on_connection_create_end: Signal[ + _SignalCallback[TraceConnectionCreateEndParams] + ] = Signal(self) + self._on_connection_reuseconn: Signal[ + _SignalCallback[TraceConnectionReuseconnParams] + ] = Signal(self) + self._on_dns_resolvehost_start: Signal[ + _SignalCallback[TraceDnsResolveHostStartParams] + ] = Signal(self) + self._on_dns_resolvehost_end: Signal[ + _SignalCallback[TraceDnsResolveHostEndParams] + ] = Signal(self) + self._on_dns_cache_hit: Signal[_SignalCallback[TraceDnsCacheHitParams]] = ( + Signal(self) + ) + self._on_dns_cache_miss: Signal[_SignalCallback[TraceDnsCacheMissParams]] = ( + Signal(self) + ) + self._on_request_headers_sent: Signal[ + _SignalCallback[TraceRequestHeadersSentParams] + ] = Signal(self) + + self._trace_config_ctx_factory = trace_config_ctx_factory + + def trace_config_ctx( + self, trace_request_ctx: Optional[Mapping[str, str]] = None + ) -> SimpleNamespace: + """Return a new trace_config_ctx instance""" + return self._trace_config_ctx_factory(trace_request_ctx=trace_request_ctx) + + def freeze(self) -> None: + self._on_request_start.freeze() + self._on_request_chunk_sent.freeze() + self._on_response_chunk_received.freeze() + self._on_request_end.freeze() + self._on_request_exception.freeze() + self._on_request_redirect.freeze() + self._on_connection_queued_start.freeze() + self._on_connection_queued_end.freeze() + self._on_connection_create_start.freeze() + self._on_connection_create_end.freeze() + self._on_connection_reuseconn.freeze() + self._on_dns_resolvehost_start.freeze() + self._on_dns_resolvehost_end.freeze() + self._on_dns_cache_hit.freeze() + self._on_dns_cache_miss.freeze() + self._on_request_headers_sent.freeze() + + @property + def on_request_start(self) -> "Signal[_SignalCallback[TraceRequestStartParams]]": + return self._on_request_start + + @property + def on_request_chunk_sent( + self, + ) -> "Signal[_SignalCallback[TraceRequestChunkSentParams]]": + return self._on_request_chunk_sent + + @property + def on_response_chunk_received( + self, + ) -> "Signal[_SignalCallback[TraceResponseChunkReceivedParams]]": + return self._on_response_chunk_received + + @property + def on_request_end(self) -> "Signal[_SignalCallback[TraceRequestEndParams]]": + return self._on_request_end + + @property + def on_request_exception( + self, + ) -> "Signal[_SignalCallback[TraceRequestExceptionParams]]": + return self._on_request_exception + + @property + def on_request_redirect( + self, + ) -> "Signal[_SignalCallback[TraceRequestRedirectParams]]": + return self._on_request_redirect + + @property + def on_connection_queued_start( + self, + ) -> "Signal[_SignalCallback[TraceConnectionQueuedStartParams]]": + return self._on_connection_queued_start + + @property + def on_connection_queued_end( + self, + ) -> "Signal[_SignalCallback[TraceConnectionQueuedEndParams]]": + return self._on_connection_queued_end + + @property + def on_connection_create_start( + self, + ) -> "Signal[_SignalCallback[TraceConnectionCreateStartParams]]": + return self._on_connection_create_start + + @property + def on_connection_create_end( + self, + ) -> "Signal[_SignalCallback[TraceConnectionCreateEndParams]]": + return self._on_connection_create_end + + @property + def on_connection_reuseconn( + self, + ) -> "Signal[_SignalCallback[TraceConnectionReuseconnParams]]": + return self._on_connection_reuseconn + + @property + def on_dns_resolvehost_start( + self, + ) -> "Signal[_SignalCallback[TraceDnsResolveHostStartParams]]": + return self._on_dns_resolvehost_start + + @property + def on_dns_resolvehost_end( + self, + ) -> "Signal[_SignalCallback[TraceDnsResolveHostEndParams]]": + return self._on_dns_resolvehost_end + + @property + def on_dns_cache_hit(self) -> "Signal[_SignalCallback[TraceDnsCacheHitParams]]": + return self._on_dns_cache_hit + + @property + def on_dns_cache_miss(self) -> "Signal[_SignalCallback[TraceDnsCacheMissParams]]": + return self._on_dns_cache_miss + + @property + def on_request_headers_sent( + self, + ) -> "Signal[_SignalCallback[TraceRequestHeadersSentParams]]": + return self._on_request_headers_sent + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class TraceRequestStartParams: + """Parameters sent by the `on_request_start` signal""" + + method: str + url: URL + headers: "CIMultiDict[str]" + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class TraceRequestChunkSentParams: + """Parameters sent by the `on_request_chunk_sent` signal""" + + method: str + url: URL + chunk: bytes + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class TraceResponseChunkReceivedParams: + """Parameters sent by the `on_response_chunk_received` signal""" + + method: str + url: URL + chunk: bytes + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class TraceRequestEndParams: + """Parameters sent by the `on_request_end` signal""" + + method: str + url: URL + headers: "CIMultiDict[str]" + response: ClientResponse + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class TraceRequestExceptionParams: + """Parameters sent by the `on_request_exception` signal""" + + method: str + url: URL + headers: "CIMultiDict[str]" + exception: BaseException + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class TraceRequestRedirectParams: + """Parameters sent by the `on_request_redirect` signal""" + + method: str + url: URL + headers: "CIMultiDict[str]" + response: ClientResponse + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class TraceConnectionQueuedStartParams: + """Parameters sent by the `on_connection_queued_start` signal""" + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class TraceConnectionQueuedEndParams: + """Parameters sent by the `on_connection_queued_end` signal""" + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class TraceConnectionCreateStartParams: + """Parameters sent by the `on_connection_create_start` signal""" + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class TraceConnectionCreateEndParams: + """Parameters sent by the `on_connection_create_end` signal""" + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class TraceConnectionReuseconnParams: + """Parameters sent by the `on_connection_reuseconn` signal""" + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class TraceDnsResolveHostStartParams: + """Parameters sent by the `on_dns_resolvehost_start` signal""" + + host: str + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class TraceDnsResolveHostEndParams: + """Parameters sent by the `on_dns_resolvehost_end` signal""" + + host: str + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class TraceDnsCacheHitParams: + """Parameters sent by the `on_dns_cache_hit` signal""" + + host: str + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class TraceDnsCacheMissParams: + """Parameters sent by the `on_dns_cache_miss` signal""" + + host: str + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class TraceRequestHeadersSentParams: + """Parameters sent by the `on_request_headers_sent` signal""" + + method: str + url: URL + headers: "CIMultiDict[str]" + + +class Trace: + """Internal dependency holder class. + + Used to keep together the main dependencies used + at the moment of send a signal. + """ + + def __init__( + self, + session: "ClientSession", + trace_config: TraceConfig, + trace_config_ctx: SimpleNamespace, + ) -> None: + self._trace_config = trace_config + self._trace_config_ctx = trace_config_ctx + self._session = session + + async def send_request_start( + self, method: str, url: URL, headers: "CIMultiDict[str]" + ) -> None: + return await self._trace_config.on_request_start.send( + self._session, + self._trace_config_ctx, + TraceRequestStartParams(method, url, headers), + ) + + async def send_request_chunk_sent( + self, method: str, url: URL, chunk: bytes + ) -> None: + return await self._trace_config.on_request_chunk_sent.send( + self._session, + self._trace_config_ctx, + TraceRequestChunkSentParams(method, url, chunk), + ) + + async def send_response_chunk_received( + self, method: str, url: URL, chunk: bytes + ) -> None: + return await self._trace_config.on_response_chunk_received.send( + self._session, + self._trace_config_ctx, + TraceResponseChunkReceivedParams(method, url, chunk), + ) + + async def send_request_end( + self, + method: str, + url: URL, + headers: "CIMultiDict[str]", + response: ClientResponse, + ) -> None: + return await self._trace_config.on_request_end.send( + self._session, + self._trace_config_ctx, + TraceRequestEndParams(method, url, headers, response), + ) + + async def send_request_exception( + self, + method: str, + url: URL, + headers: "CIMultiDict[str]", + exception: BaseException, + ) -> None: + return await self._trace_config.on_request_exception.send( + self._session, + self._trace_config_ctx, + TraceRequestExceptionParams(method, url, headers, exception), + ) + + async def send_request_redirect( + self, + method: str, + url: URL, + headers: "CIMultiDict[str]", + response: ClientResponse, + ) -> None: + return await self._trace_config._on_request_redirect.send( + self._session, + self._trace_config_ctx, + TraceRequestRedirectParams(method, url, headers, response), + ) + + async def send_connection_queued_start(self) -> None: + return await self._trace_config.on_connection_queued_start.send( + self._session, self._trace_config_ctx, TraceConnectionQueuedStartParams() + ) + + async def send_connection_queued_end(self) -> None: + return await self._trace_config.on_connection_queued_end.send( + self._session, self._trace_config_ctx, TraceConnectionQueuedEndParams() + ) + + async def send_connection_create_start(self) -> None: + return await self._trace_config.on_connection_create_start.send( + self._session, self._trace_config_ctx, TraceConnectionCreateStartParams() + ) + + async def send_connection_create_end(self) -> None: + return await self._trace_config.on_connection_create_end.send( + self._session, self._trace_config_ctx, TraceConnectionCreateEndParams() + ) + + async def send_connection_reuseconn(self) -> None: + return await self._trace_config.on_connection_reuseconn.send( + self._session, self._trace_config_ctx, TraceConnectionReuseconnParams() + ) + + async def send_dns_resolvehost_start(self, host: str) -> None: + return await self._trace_config.on_dns_resolvehost_start.send( + self._session, self._trace_config_ctx, TraceDnsResolveHostStartParams(host) + ) + + async def send_dns_resolvehost_end(self, host: str) -> None: + return await self._trace_config.on_dns_resolvehost_end.send( + self._session, self._trace_config_ctx, TraceDnsResolveHostEndParams(host) + ) + + async def send_dns_cache_hit(self, host: str) -> None: + return await self._trace_config.on_dns_cache_hit.send( + self._session, self._trace_config_ctx, TraceDnsCacheHitParams(host) + ) + + async def send_dns_cache_miss(self, host: str) -> None: + return await self._trace_config.on_dns_cache_miss.send( + self._session, self._trace_config_ctx, TraceDnsCacheMissParams(host) + ) + + async def send_request_headers( + self, method: str, url: URL, headers: "CIMultiDict[str]" + ) -> None: + return await self._trace_config._on_request_headers_sent.send( + self._session, + self._trace_config_ctx, + TraceRequestHeadersSentParams(method, url, headers), + ) diff --git a/venv/lib/python3.12/site-packages/aiohttp/typedefs.py b/venv/lib/python3.12/site-packages/aiohttp/typedefs.py new file mode 100644 index 00000000..cc8c0825 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/typedefs.py @@ -0,0 +1,69 @@ +import json +import os +from typing import ( + TYPE_CHECKING, + Any, + Awaitable, + Callable, + Iterable, + Mapping, + Protocol, + Tuple, + Union, +) + +from multidict import CIMultiDict, CIMultiDictProxy, MultiDict, MultiDictProxy, istr +from yarl import URL, Query as _Query + +Query = _Query + +DEFAULT_JSON_ENCODER = json.dumps +DEFAULT_JSON_DECODER = json.loads + +if TYPE_CHECKING: + _CIMultiDict = CIMultiDict[str] + _CIMultiDictProxy = CIMultiDictProxy[str] + _MultiDict = MultiDict[str] + _MultiDictProxy = MultiDictProxy[str] + from http.cookies import BaseCookie, Morsel + + from .web import Request, StreamResponse +else: + _CIMultiDict = CIMultiDict + _CIMultiDictProxy = CIMultiDictProxy + _MultiDict = MultiDict + _MultiDictProxy = MultiDictProxy + +Byteish = Union[bytes, bytearray, memoryview] +JSONEncoder = Callable[[Any], str] +JSONDecoder = Callable[[str], Any] +LooseHeaders = Union[ + Mapping[str, str], + Mapping[istr, str], + _CIMultiDict, + _CIMultiDictProxy, + Iterable[Tuple[Union[str, istr], str]], +] +RawHeaders = Tuple[Tuple[bytes, bytes], ...] +StrOrURL = Union[str, URL] + +LooseCookiesMappings = Mapping[str, Union[str, "BaseCookie[str]", "Morsel[Any]"]] +LooseCookiesIterables = Iterable[ + Tuple[str, Union[str, "BaseCookie[str]", "Morsel[Any]"]] +] +LooseCookies = Union[ + LooseCookiesMappings, + LooseCookiesIterables, + "BaseCookie[str]", +] + +Handler = Callable[["Request"], Awaitable["StreamResponse"]] + + +class Middleware(Protocol): + def __call__( + self, request: "Request", handler: Handler + ) -> Awaitable["StreamResponse"]: ... + + +PathLike = Union[str, "os.PathLike[str]"] diff --git a/venv/lib/python3.12/site-packages/aiohttp/web.py b/venv/lib/python3.12/site-packages/aiohttp/web.py new file mode 100644 index 00000000..d6ab6f6f --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/web.py @@ -0,0 +1,605 @@ +import asyncio +import logging +import os +import socket +import sys +import warnings +from argparse import ArgumentParser +from collections.abc import Iterable +from contextlib import suppress +from importlib import import_module +from typing import ( + TYPE_CHECKING, + Any, + Awaitable, + Callable, + Iterable as TypingIterable, + List, + Optional, + Set, + Type, + Union, + cast, +) + +from .abc import AbstractAccessLogger +from .helpers import AppKey as AppKey +from .log import access_logger +from .typedefs import PathLike +from .web_app import Application as Application, CleanupError as CleanupError +from .web_exceptions import ( + HTTPAccepted as HTTPAccepted, + HTTPBadGateway as HTTPBadGateway, + HTTPBadRequest as HTTPBadRequest, + HTTPClientError as HTTPClientError, + HTTPConflict as HTTPConflict, + HTTPCreated as HTTPCreated, + HTTPError as HTTPError, + HTTPException as HTTPException, + HTTPExpectationFailed as HTTPExpectationFailed, + HTTPFailedDependency as HTTPFailedDependency, + HTTPForbidden as HTTPForbidden, + HTTPFound as HTTPFound, + HTTPGatewayTimeout as HTTPGatewayTimeout, + HTTPGone as HTTPGone, + HTTPInsufficientStorage as HTTPInsufficientStorage, + HTTPInternalServerError as HTTPInternalServerError, + HTTPLengthRequired as HTTPLengthRequired, + HTTPMethodNotAllowed as HTTPMethodNotAllowed, + HTTPMisdirectedRequest as HTTPMisdirectedRequest, + HTTPMove as HTTPMove, + HTTPMovedPermanently as HTTPMovedPermanently, + HTTPMultipleChoices as HTTPMultipleChoices, + HTTPNetworkAuthenticationRequired as HTTPNetworkAuthenticationRequired, + HTTPNoContent as HTTPNoContent, + HTTPNonAuthoritativeInformation as HTTPNonAuthoritativeInformation, + HTTPNotAcceptable as HTTPNotAcceptable, + HTTPNotExtended as HTTPNotExtended, + HTTPNotFound as HTTPNotFound, + HTTPNotImplemented as HTTPNotImplemented, + HTTPNotModified as HTTPNotModified, + HTTPOk as HTTPOk, + HTTPPartialContent as HTTPPartialContent, + HTTPPaymentRequired as HTTPPaymentRequired, + HTTPPermanentRedirect as HTTPPermanentRedirect, + HTTPPreconditionFailed as HTTPPreconditionFailed, + HTTPPreconditionRequired as HTTPPreconditionRequired, + HTTPProxyAuthenticationRequired as HTTPProxyAuthenticationRequired, + HTTPRedirection as HTTPRedirection, + HTTPRequestEntityTooLarge as HTTPRequestEntityTooLarge, + HTTPRequestHeaderFieldsTooLarge as HTTPRequestHeaderFieldsTooLarge, + HTTPRequestRangeNotSatisfiable as HTTPRequestRangeNotSatisfiable, + HTTPRequestTimeout as HTTPRequestTimeout, + HTTPRequestURITooLong as HTTPRequestURITooLong, + HTTPResetContent as HTTPResetContent, + HTTPSeeOther as HTTPSeeOther, + HTTPServerError as HTTPServerError, + HTTPServiceUnavailable as HTTPServiceUnavailable, + HTTPSuccessful as HTTPSuccessful, + HTTPTemporaryRedirect as HTTPTemporaryRedirect, + HTTPTooManyRequests as HTTPTooManyRequests, + HTTPUnauthorized as HTTPUnauthorized, + HTTPUnavailableForLegalReasons as HTTPUnavailableForLegalReasons, + HTTPUnprocessableEntity as HTTPUnprocessableEntity, + HTTPUnsupportedMediaType as HTTPUnsupportedMediaType, + HTTPUpgradeRequired as HTTPUpgradeRequired, + HTTPUseProxy as HTTPUseProxy, + HTTPVariantAlsoNegotiates as HTTPVariantAlsoNegotiates, + HTTPVersionNotSupported as HTTPVersionNotSupported, + NotAppKeyWarning as NotAppKeyWarning, +) +from .web_fileresponse import FileResponse as FileResponse +from .web_log import AccessLogger +from .web_middlewares import ( + middleware as middleware, + normalize_path_middleware as normalize_path_middleware, +) +from .web_protocol import ( + PayloadAccessError as PayloadAccessError, + RequestHandler as RequestHandler, + RequestPayloadError as RequestPayloadError, +) +from .web_request import ( + BaseRequest as BaseRequest, + FileField as FileField, + Request as Request, +) +from .web_response import ( + ContentCoding as ContentCoding, + Response as Response, + StreamResponse as StreamResponse, + json_response as json_response, +) +from .web_routedef import ( + AbstractRouteDef as AbstractRouteDef, + RouteDef as RouteDef, + RouteTableDef as RouteTableDef, + StaticDef as StaticDef, + delete as delete, + get as get, + head as head, + options as options, + patch as patch, + post as post, + put as put, + route as route, + static as static, + view as view, +) +from .web_runner import ( + AppRunner as AppRunner, + BaseRunner as BaseRunner, + BaseSite as BaseSite, + GracefulExit as GracefulExit, + NamedPipeSite as NamedPipeSite, + ServerRunner as ServerRunner, + SockSite as SockSite, + TCPSite as TCPSite, + UnixSite as UnixSite, +) +from .web_server import Server as Server +from .web_urldispatcher import ( + AbstractResource as AbstractResource, + AbstractRoute as AbstractRoute, + DynamicResource as DynamicResource, + PlainResource as PlainResource, + PrefixedSubAppResource as PrefixedSubAppResource, + Resource as Resource, + ResourceRoute as ResourceRoute, + StaticResource as StaticResource, + UrlDispatcher as UrlDispatcher, + UrlMappingMatchInfo as UrlMappingMatchInfo, + View as View, +) +from .web_ws import ( + WebSocketReady as WebSocketReady, + WebSocketResponse as WebSocketResponse, + WSMsgType as WSMsgType, +) + +__all__ = ( + # web_app + "AppKey", + "Application", + "CleanupError", + # web_exceptions + "NotAppKeyWarning", + "HTTPAccepted", + "HTTPBadGateway", + "HTTPBadRequest", + "HTTPClientError", + "HTTPConflict", + "HTTPCreated", + "HTTPError", + "HTTPException", + "HTTPExpectationFailed", + "HTTPFailedDependency", + "HTTPForbidden", + "HTTPFound", + "HTTPGatewayTimeout", + "HTTPGone", + "HTTPInsufficientStorage", + "HTTPInternalServerError", + "HTTPLengthRequired", + "HTTPMethodNotAllowed", + "HTTPMisdirectedRequest", + "HTTPMove", + "HTTPMovedPermanently", + "HTTPMultipleChoices", + "HTTPNetworkAuthenticationRequired", + "HTTPNoContent", + "HTTPNonAuthoritativeInformation", + "HTTPNotAcceptable", + "HTTPNotExtended", + "HTTPNotFound", + "HTTPNotImplemented", + "HTTPNotModified", + "HTTPOk", + "HTTPPartialContent", + "HTTPPaymentRequired", + "HTTPPermanentRedirect", + "HTTPPreconditionFailed", + "HTTPPreconditionRequired", + "HTTPProxyAuthenticationRequired", + "HTTPRedirection", + "HTTPRequestEntityTooLarge", + "HTTPRequestHeaderFieldsTooLarge", + "HTTPRequestRangeNotSatisfiable", + "HTTPRequestTimeout", + "HTTPRequestURITooLong", + "HTTPResetContent", + "HTTPSeeOther", + "HTTPServerError", + "HTTPServiceUnavailable", + "HTTPSuccessful", + "HTTPTemporaryRedirect", + "HTTPTooManyRequests", + "HTTPUnauthorized", + "HTTPUnavailableForLegalReasons", + "HTTPUnprocessableEntity", + "HTTPUnsupportedMediaType", + "HTTPUpgradeRequired", + "HTTPUseProxy", + "HTTPVariantAlsoNegotiates", + "HTTPVersionNotSupported", + # web_fileresponse + "FileResponse", + # web_middlewares + "middleware", + "normalize_path_middleware", + # web_protocol + "PayloadAccessError", + "RequestHandler", + "RequestPayloadError", + # web_request + "BaseRequest", + "FileField", + "Request", + # web_response + "ContentCoding", + "Response", + "StreamResponse", + "json_response", + # web_routedef + "AbstractRouteDef", + "RouteDef", + "RouteTableDef", + "StaticDef", + "delete", + "get", + "head", + "options", + "patch", + "post", + "put", + "route", + "static", + "view", + # web_runner + "AppRunner", + "BaseRunner", + "BaseSite", + "GracefulExit", + "ServerRunner", + "SockSite", + "TCPSite", + "UnixSite", + "NamedPipeSite", + # web_server + "Server", + # web_urldispatcher + "AbstractResource", + "AbstractRoute", + "DynamicResource", + "PlainResource", + "PrefixedSubAppResource", + "Resource", + "ResourceRoute", + "StaticResource", + "UrlDispatcher", + "UrlMappingMatchInfo", + "View", + # web_ws + "WebSocketReady", + "WebSocketResponse", + "WSMsgType", + # web + "run_app", +) + + +if TYPE_CHECKING: + from ssl import SSLContext +else: + try: + from ssl import SSLContext + except ImportError: # pragma: no cover + SSLContext = object # type: ignore[misc,assignment] + +# Only display warning when using -Wdefault, -We, -X dev or similar. +warnings.filterwarnings("ignore", category=NotAppKeyWarning, append=True) + +HostSequence = TypingIterable[str] + + +async def _run_app( + app: Union[Application, Awaitable[Application]], + *, + host: Optional[Union[str, HostSequence]] = None, + port: Optional[int] = None, + path: Union[PathLike, TypingIterable[PathLike], None] = None, + sock: Optional[Union[socket.socket, TypingIterable[socket.socket]]] = None, + shutdown_timeout: float = 60.0, + keepalive_timeout: float = 75.0, + ssl_context: Optional[SSLContext] = None, + print: Optional[Callable[..., None]] = print, + backlog: int = 128, + access_log_class: Type[AbstractAccessLogger] = AccessLogger, + access_log_format: str = AccessLogger.LOG_FORMAT, + access_log: Optional[logging.Logger] = access_logger, + handle_signals: bool = True, + reuse_address: Optional[bool] = None, + reuse_port: Optional[bool] = None, + handler_cancellation: bool = False, +) -> None: + # An internal function to actually do all dirty job for application running + if asyncio.iscoroutine(app): + app = await app + + app = cast(Application, app) + + runner = AppRunner( + app, + handle_signals=handle_signals, + access_log_class=access_log_class, + access_log_format=access_log_format, + access_log=access_log, + keepalive_timeout=keepalive_timeout, + shutdown_timeout=shutdown_timeout, + handler_cancellation=handler_cancellation, + ) + + await runner.setup() + + sites: List[BaseSite] = [] + + try: + if host is not None: + if isinstance(host, (str, bytes, bytearray, memoryview)): + sites.append( + TCPSite( + runner, + host, + port, + ssl_context=ssl_context, + backlog=backlog, + reuse_address=reuse_address, + reuse_port=reuse_port, + ) + ) + else: + for h in host: + sites.append( + TCPSite( + runner, + h, + port, + ssl_context=ssl_context, + backlog=backlog, + reuse_address=reuse_address, + reuse_port=reuse_port, + ) + ) + elif path is None and sock is None or port is not None: + sites.append( + TCPSite( + runner, + port=port, + ssl_context=ssl_context, + backlog=backlog, + reuse_address=reuse_address, + reuse_port=reuse_port, + ) + ) + + if path is not None: + if isinstance(path, (str, os.PathLike)): + sites.append( + UnixSite( + runner, + path, + ssl_context=ssl_context, + backlog=backlog, + ) + ) + else: + for p in path: + sites.append( + UnixSite( + runner, + p, + ssl_context=ssl_context, + backlog=backlog, + ) + ) + + if sock is not None: + if not isinstance(sock, Iterable): + sites.append( + SockSite( + runner, + sock, + ssl_context=ssl_context, + backlog=backlog, + ) + ) + else: + for s in sock: + sites.append( + SockSite( + runner, + s, + ssl_context=ssl_context, + backlog=backlog, + ) + ) + for site in sites: + await site.start() + + if print: # pragma: no branch + names = sorted(str(s.name) for s in runner.sites) + print( + "======== Running on {} ========\n" + "(Press CTRL+C to quit)".format(", ".join(names)) + ) + + # sleep forever by 1 hour intervals, + while True: + await asyncio.sleep(3600) + finally: + await runner.cleanup() + + +def _cancel_tasks( + to_cancel: Set["asyncio.Task[Any]"], loop: asyncio.AbstractEventLoop +) -> None: + if not to_cancel: + return + + for task in to_cancel: + task.cancel() + + loop.run_until_complete(asyncio.gather(*to_cancel, return_exceptions=True)) + + for task in to_cancel: + if task.cancelled(): + continue + if task.exception() is not None: + loop.call_exception_handler( + { + "message": "unhandled exception during asyncio.run() shutdown", + "exception": task.exception(), + "task": task, + } + ) + + +def run_app( + app: Union[Application, Awaitable[Application]], + *, + host: Optional[Union[str, HostSequence]] = None, + port: Optional[int] = None, + path: Union[PathLike, TypingIterable[PathLike], None] = None, + sock: Optional[Union[socket.socket, TypingIterable[socket.socket]]] = None, + shutdown_timeout: float = 60.0, + keepalive_timeout: float = 75.0, + ssl_context: Optional[SSLContext] = None, + print: Optional[Callable[..., None]] = print, + backlog: int = 128, + access_log_class: Type[AbstractAccessLogger] = AccessLogger, + access_log_format: str = AccessLogger.LOG_FORMAT, + access_log: Optional[logging.Logger] = access_logger, + handle_signals: bool = True, + reuse_address: Optional[bool] = None, + reuse_port: Optional[bool] = None, + handler_cancellation: bool = False, + loop: Optional[asyncio.AbstractEventLoop] = None, +) -> None: + """Run an app locally""" + if loop is None: + loop = asyncio.new_event_loop() + + # Configure if and only if in debugging mode and using the default logger + if loop.get_debug() and access_log and access_log.name == "aiohttp.access": + if access_log.level == logging.NOTSET: + access_log.setLevel(logging.DEBUG) + if not access_log.hasHandlers(): + access_log.addHandler(logging.StreamHandler()) + + main_task = loop.create_task( + _run_app( + app, + host=host, + port=port, + path=path, + sock=sock, + shutdown_timeout=shutdown_timeout, + keepalive_timeout=keepalive_timeout, + ssl_context=ssl_context, + print=print, + backlog=backlog, + access_log_class=access_log_class, + access_log_format=access_log_format, + access_log=access_log, + handle_signals=handle_signals, + reuse_address=reuse_address, + reuse_port=reuse_port, + handler_cancellation=handler_cancellation, + ) + ) + + try: + asyncio.set_event_loop(loop) + loop.run_until_complete(main_task) + except (GracefulExit, KeyboardInterrupt): # pragma: no cover + pass + finally: + try: + main_task.cancel() + with suppress(asyncio.CancelledError): + loop.run_until_complete(main_task) + finally: + _cancel_tasks(asyncio.all_tasks(loop), loop) + loop.run_until_complete(loop.shutdown_asyncgens()) + loop.close() + + +def main(argv: List[str]) -> None: + arg_parser = ArgumentParser( + description="aiohttp.web Application server", prog="aiohttp.web" + ) + arg_parser.add_argument( + "entry_func", + help=( + "Callable returning the `aiohttp.web.Application` instance to " + "run. Should be specified in the 'module:function' syntax." + ), + metavar="entry-func", + ) + arg_parser.add_argument( + "-H", + "--hostname", + help="TCP/IP hostname to serve on (default: localhost)", + default=None, + ) + arg_parser.add_argument( + "-P", + "--port", + help="TCP/IP port to serve on (default: %(default)r)", + type=int, + default=8080, + ) + arg_parser.add_argument( + "-U", + "--path", + help="Unix file system path to serve on. Can be combined with hostname " + "to serve on both Unix and TCP.", + ) + args, extra_argv = arg_parser.parse_known_args(argv) + + # Import logic + mod_str, _, func_str = args.entry_func.partition(":") + if not func_str or not mod_str: + arg_parser.error("'entry-func' not in 'module:function' syntax") + if mod_str.startswith("."): + arg_parser.error("relative module names not supported") + try: + module = import_module(mod_str) + except ImportError as ex: + arg_parser.error(f"unable to import {mod_str}: {ex}") + try: + func = getattr(module, func_str) + except AttributeError: + arg_parser.error(f"module {mod_str!r} has no attribute {func_str!r}") + + # Compatibility logic + if args.path is not None and not hasattr(socket, "AF_UNIX"): + arg_parser.error( + "file system paths not supported by your operating environment" + ) + + logging.basicConfig(level=logging.DEBUG) + + if args.path and args.hostname is None: + host = port = None + else: + host = args.hostname or "localhost" + port = args.port + + app = func(extra_argv) + run_app(app, host=host, port=port, path=args.path) + arg_parser.exit(message="Stopped\n") + + +if __name__ == "__main__": # pragma: no branch + main(sys.argv[1:]) # pragma: no cover diff --git a/venv/lib/python3.12/site-packages/aiohttp/web_app.py b/venv/lib/python3.12/site-packages/aiohttp/web_app.py new file mode 100644 index 00000000..4bdc5403 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/web_app.py @@ -0,0 +1,620 @@ +import asyncio +import logging +import warnings +from functools import lru_cache, partial, update_wrapper +from typing import ( + TYPE_CHECKING, + Any, + AsyncIterator, + Awaitable, + Callable, + Dict, + Iterable, + Iterator, + List, + Mapping, + MutableMapping, + Optional, + Sequence, + Tuple, + Type, + TypeVar, + Union, + cast, + overload, +) + +from aiosignal import Signal +from frozenlist import FrozenList + +from . import hdrs +from .abc import ( + AbstractAccessLogger, + AbstractMatchInfo, + AbstractRouter, + AbstractStreamWriter, +) +from .helpers import DEBUG, AppKey +from .http_parser import RawRequestMessage +from .log import web_logger +from .streams import StreamReader +from .typedefs import Handler, Middleware +from .web_exceptions import NotAppKeyWarning +from .web_log import AccessLogger +from .web_middlewares import _fix_request_current_app +from .web_protocol import RequestHandler +from .web_request import Request +from .web_response import StreamResponse +from .web_routedef import AbstractRouteDef +from .web_server import Server +from .web_urldispatcher import ( + AbstractResource, + AbstractRoute, + Domain, + MaskDomain, + MatchedSubAppResource, + PrefixedSubAppResource, + SystemRoute, + UrlDispatcher, +) + +__all__ = ("Application", "CleanupError") + + +if TYPE_CHECKING: + _AppSignal = Signal[Callable[["Application"], Awaitable[None]]] + _RespPrepareSignal = Signal[Callable[[Request, StreamResponse], Awaitable[None]]] + _Middlewares = FrozenList[Middleware] + _MiddlewaresHandlers = Optional[Sequence[Tuple[Middleware, bool]]] + _Subapps = List["Application"] +else: + # No type checker mode, skip types + _AppSignal = Signal + _RespPrepareSignal = Signal + _Middlewares = FrozenList + _MiddlewaresHandlers = Optional[Sequence] + _Subapps = List + +_T = TypeVar("_T") +_U = TypeVar("_U") +_Resource = TypeVar("_Resource", bound=AbstractResource) + + +def _build_middlewares( + handler: Handler, apps: Tuple["Application", ...] +) -> Callable[[Request], Awaitable[StreamResponse]]: + """Apply middlewares to handler.""" + for app in apps[::-1]: + for m, _ in app._middlewares_handlers: # type: ignore[union-attr] + handler = update_wrapper(partial(m, handler=handler), handler) # type: ignore[misc] + return handler + + +_cached_build_middleware = lru_cache(maxsize=1024)(_build_middlewares) + + +class Application(MutableMapping[Union[str, AppKey[Any]], Any]): + ATTRS = frozenset( + [ + "logger", + "_debug", + "_router", + "_loop", + "_handler_args", + "_middlewares", + "_middlewares_handlers", + "_has_legacy_middlewares", + "_run_middlewares", + "_state", + "_frozen", + "_pre_frozen", + "_subapps", + "_on_response_prepare", + "_on_startup", + "_on_shutdown", + "_on_cleanup", + "_client_max_size", + "_cleanup_ctx", + ] + ) + + def __init__( + self, + *, + logger: logging.Logger = web_logger, + router: Optional[UrlDispatcher] = None, + middlewares: Iterable[Middleware] = (), + handler_args: Optional[Mapping[str, Any]] = None, + client_max_size: int = 1024**2, + loop: Optional[asyncio.AbstractEventLoop] = None, + debug: Any = ..., # mypy doesn't support ellipsis + ) -> None: + if router is None: + router = UrlDispatcher() + else: + warnings.warn( + "router argument is deprecated", DeprecationWarning, stacklevel=2 + ) + assert isinstance(router, AbstractRouter), router + + if loop is not None: + warnings.warn( + "loop argument is deprecated", DeprecationWarning, stacklevel=2 + ) + + if debug is not ...: + warnings.warn( + "debug argument is deprecated", DeprecationWarning, stacklevel=2 + ) + self._debug = debug + self._router: UrlDispatcher = router + self._loop = loop + self._handler_args = handler_args + self.logger = logger + + self._middlewares: _Middlewares = FrozenList(middlewares) + + # initialized on freezing + self._middlewares_handlers: _MiddlewaresHandlers = None + # initialized on freezing + self._run_middlewares: Optional[bool] = None + self._has_legacy_middlewares: bool = True + + self._state: Dict[Union[AppKey[Any], str], object] = {} + self._frozen = False + self._pre_frozen = False + self._subapps: _Subapps = [] + + self._on_response_prepare: _RespPrepareSignal = Signal(self) + self._on_startup: _AppSignal = Signal(self) + self._on_shutdown: _AppSignal = Signal(self) + self._on_cleanup: _AppSignal = Signal(self) + self._cleanup_ctx = CleanupContext() + self._on_startup.append(self._cleanup_ctx._on_startup) + self._on_cleanup.append(self._cleanup_ctx._on_cleanup) + self._client_max_size = client_max_size + + def __init_subclass__(cls: Type["Application"]) -> None: + warnings.warn( + "Inheritance class {} from web.Application " + "is discouraged".format(cls.__name__), + DeprecationWarning, + stacklevel=3, + ) + + if DEBUG: # pragma: no cover + + def __setattr__(self, name: str, val: Any) -> None: + if name not in self.ATTRS: + warnings.warn( + "Setting custom web.Application.{} attribute " + "is discouraged".format(name), + DeprecationWarning, + stacklevel=2, + ) + super().__setattr__(name, val) + + # MutableMapping API + + def __eq__(self, other: object) -> bool: + return self is other + + @overload # type: ignore[override] + def __getitem__(self, key: AppKey[_T]) -> _T: ... + + @overload + def __getitem__(self, key: str) -> Any: ... + + def __getitem__(self, key: Union[str, AppKey[_T]]) -> Any: + return self._state[key] + + def _check_frozen(self) -> None: + if self._frozen: + warnings.warn( + "Changing state of started or joined application is deprecated", + DeprecationWarning, + stacklevel=3, + ) + + @overload # type: ignore[override] + def __setitem__(self, key: AppKey[_T], value: _T) -> None: ... + + @overload + def __setitem__(self, key: str, value: Any) -> None: ... + + def __setitem__(self, key: Union[str, AppKey[_T]], value: Any) -> None: + self._check_frozen() + if not isinstance(key, AppKey): + warnings.warn( + "It is recommended to use web.AppKey instances for keys.\n" + + "https://docs.aiohttp.org/en/stable/web_advanced.html" + + "#application-s-config", + category=NotAppKeyWarning, + stacklevel=2, + ) + self._state[key] = value + + def __delitem__(self, key: Union[str, AppKey[_T]]) -> None: + self._check_frozen() + del self._state[key] + + def __len__(self) -> int: + return len(self._state) + + def __iter__(self) -> Iterator[Union[str, AppKey[Any]]]: + return iter(self._state) + + def __hash__(self) -> int: + return id(self) + + @overload # type: ignore[override] + def get(self, key: AppKey[_T], default: None = ...) -> Optional[_T]: ... + + @overload + def get(self, key: AppKey[_T], default: _U) -> Union[_T, _U]: ... + + @overload + def get(self, key: str, default: Any = ...) -> Any: ... + + def get(self, key: Union[str, AppKey[_T]], default: Any = None) -> Any: + return self._state.get(key, default) + + ######## + @property + def loop(self) -> asyncio.AbstractEventLoop: + # Technically the loop can be None + # but we mask it by explicit type cast + # to provide more convenient type annotation + warnings.warn("loop property is deprecated", DeprecationWarning, stacklevel=2) + return cast(asyncio.AbstractEventLoop, self._loop) + + def _set_loop(self, loop: Optional[asyncio.AbstractEventLoop]) -> None: + if loop is None: + loop = asyncio.get_event_loop() + if self._loop is not None and self._loop is not loop: + raise RuntimeError( + "web.Application instance initialized with different loop" + ) + + self._loop = loop + + # set loop debug + if self._debug is ...: + self._debug = loop.get_debug() + + # set loop to sub applications + for subapp in self._subapps: + subapp._set_loop(loop) + + @property + def pre_frozen(self) -> bool: + return self._pre_frozen + + def pre_freeze(self) -> None: + if self._pre_frozen: + return + + self._pre_frozen = True + self._middlewares.freeze() + self._router.freeze() + self._on_response_prepare.freeze() + self._cleanup_ctx.freeze() + self._on_startup.freeze() + self._on_shutdown.freeze() + self._on_cleanup.freeze() + self._middlewares_handlers = tuple(self._prepare_middleware()) + self._has_legacy_middlewares = any( + not new_style for _, new_style in self._middlewares_handlers + ) + + # If current app and any subapp do not have middlewares avoid run all + # of the code footprint that it implies, which have a middleware + # hardcoded per app that sets up the current_app attribute. If no + # middlewares are configured the handler will receive the proper + # current_app without needing all of this code. + self._run_middlewares = True if self.middlewares else False + + for subapp in self._subapps: + subapp.pre_freeze() + self._run_middlewares = self._run_middlewares or subapp._run_middlewares + + @property + def frozen(self) -> bool: + return self._frozen + + def freeze(self) -> None: + if self._frozen: + return + + self.pre_freeze() + self._frozen = True + for subapp in self._subapps: + subapp.freeze() + + @property + def debug(self) -> bool: + warnings.warn("debug property is deprecated", DeprecationWarning, stacklevel=2) + return self._debug # type: ignore[no-any-return] + + def _reg_subapp_signals(self, subapp: "Application") -> None: + def reg_handler(signame: str) -> None: + subsig = getattr(subapp, signame) + + async def handler(app: "Application") -> None: + await subsig.send(subapp) + + appsig = getattr(self, signame) + appsig.append(handler) + + reg_handler("on_startup") + reg_handler("on_shutdown") + reg_handler("on_cleanup") + + def add_subapp(self, prefix: str, subapp: "Application") -> PrefixedSubAppResource: + if not isinstance(prefix, str): + raise TypeError("Prefix must be str") + prefix = prefix.rstrip("/") + if not prefix: + raise ValueError("Prefix cannot be empty") + factory = partial(PrefixedSubAppResource, prefix, subapp) + return self._add_subapp(factory, subapp) + + def _add_subapp( + self, resource_factory: Callable[[], _Resource], subapp: "Application" + ) -> _Resource: + if self.frozen: + raise RuntimeError("Cannot add sub application to frozen application") + if subapp.frozen: + raise RuntimeError("Cannot add frozen application") + resource = resource_factory() + self.router.register_resource(resource) + self._reg_subapp_signals(subapp) + self._subapps.append(subapp) + subapp.pre_freeze() + if self._loop is not None: + subapp._set_loop(self._loop) + return resource + + def add_domain(self, domain: str, subapp: "Application") -> MatchedSubAppResource: + if not isinstance(domain, str): + raise TypeError("Domain must be str") + elif "*" in domain: + rule: Domain = MaskDomain(domain) + else: + rule = Domain(domain) + factory = partial(MatchedSubAppResource, rule, subapp) + return self._add_subapp(factory, subapp) + + def add_routes(self, routes: Iterable[AbstractRouteDef]) -> List[AbstractRoute]: + return self.router.add_routes(routes) + + @property + def on_response_prepare(self) -> _RespPrepareSignal: + return self._on_response_prepare + + @property + def on_startup(self) -> _AppSignal: + return self._on_startup + + @property + def on_shutdown(self) -> _AppSignal: + return self._on_shutdown + + @property + def on_cleanup(self) -> _AppSignal: + return self._on_cleanup + + @property + def cleanup_ctx(self) -> "CleanupContext": + return self._cleanup_ctx + + @property + def router(self) -> UrlDispatcher: + return self._router + + @property + def middlewares(self) -> _Middlewares: + return self._middlewares + + def _make_handler( + self, + *, + loop: Optional[asyncio.AbstractEventLoop] = None, + access_log_class: Type[AbstractAccessLogger] = AccessLogger, + **kwargs: Any, + ) -> Server: + + if not issubclass(access_log_class, AbstractAccessLogger): + raise TypeError( + "access_log_class must be subclass of " + "aiohttp.abc.AbstractAccessLogger, got {}".format(access_log_class) + ) + + self._set_loop(loop) + self.freeze() + + kwargs["debug"] = self._debug + kwargs["access_log_class"] = access_log_class + if self._handler_args: + for k, v in self._handler_args.items(): + kwargs[k] = v + + return Server( + self._handle, # type: ignore[arg-type] + request_factory=self._make_request, + loop=self._loop, + **kwargs, + ) + + def make_handler( + self, + *, + loop: Optional[asyncio.AbstractEventLoop] = None, + access_log_class: Type[AbstractAccessLogger] = AccessLogger, + **kwargs: Any, + ) -> Server: + + warnings.warn( + "Application.make_handler(...) is deprecated, use AppRunner API instead", + DeprecationWarning, + stacklevel=2, + ) + + return self._make_handler( + loop=loop, access_log_class=access_log_class, **kwargs + ) + + async def startup(self) -> None: + """Causes on_startup signal + + Should be called in the event loop along with the request handler. + """ + await self.on_startup.send(self) + + async def shutdown(self) -> None: + """Causes on_shutdown signal + + Should be called before cleanup() + """ + await self.on_shutdown.send(self) + + async def cleanup(self) -> None: + """Causes on_cleanup signal + + Should be called after shutdown() + """ + if self.on_cleanup.frozen: + await self.on_cleanup.send(self) + else: + # If an exception occurs in startup, ensure cleanup contexts are completed. + await self._cleanup_ctx._on_cleanup(self) + + def _make_request( + self, + message: RawRequestMessage, + payload: StreamReader, + protocol: RequestHandler, + writer: AbstractStreamWriter, + task: "asyncio.Task[None]", + _cls: Type[Request] = Request, + ) -> Request: + if TYPE_CHECKING: + assert self._loop is not None + return _cls( + message, + payload, + protocol, + writer, + task, + self._loop, + client_max_size=self._client_max_size, + ) + + def _prepare_middleware(self) -> Iterator[Tuple[Middleware, bool]]: + for m in reversed(self._middlewares): + if getattr(m, "__middleware_version__", None) == 1: + yield m, True + else: + warnings.warn( + f'old-style middleware "{m!r}" deprecated, see #2252', + DeprecationWarning, + stacklevel=2, + ) + yield m, False + + yield _fix_request_current_app(self), True + + async def _handle(self, request: Request) -> StreamResponse: + loop = asyncio.get_event_loop() + debug = loop.get_debug() + match_info = await self._router.resolve(request) + if debug: # pragma: no cover + if not isinstance(match_info, AbstractMatchInfo): + raise TypeError( + "match_info should be AbstractMatchInfo " + "instance, not {!r}".format(match_info) + ) + match_info.add_app(self) + + match_info.freeze() + + request._match_info = match_info + + if request.headers.get(hdrs.EXPECT): + resp = await match_info.expect_handler(request) + await request.writer.drain() + if resp is not None: + return resp + + handler = match_info.handler + + if self._run_middlewares: + # If its a SystemRoute, don't cache building the middlewares since + # they are constructed for every MatchInfoError as a new handler + # is made each time. + if not self._has_legacy_middlewares and not isinstance( + match_info.route, SystemRoute + ): + handler = _cached_build_middleware(handler, match_info.apps) + else: + for app in match_info.apps[::-1]: + for m, new_style in app._middlewares_handlers: # type: ignore[union-attr] + if new_style: + handler = update_wrapper( + partial(m, handler=handler), handler # type: ignore[misc] + ) + else: + handler = await m(app, handler) # type: ignore[arg-type,assignment] + + return await handler(request) + + def __call__(self) -> "Application": + """gunicorn compatibility""" + return self + + def __repr__(self) -> str: + return f"" + + def __bool__(self) -> bool: + return True + + +class CleanupError(RuntimeError): + @property + def exceptions(self) -> List[BaseException]: + return cast(List[BaseException], self.args[1]) + + +if TYPE_CHECKING: + _CleanupContextBase = FrozenList[Callable[[Application], AsyncIterator[None]]] +else: + _CleanupContextBase = FrozenList + + +class CleanupContext(_CleanupContextBase): + def __init__(self) -> None: + super().__init__() + self._exits: List[AsyncIterator[None]] = [] + + async def _on_startup(self, app: Application) -> None: + for cb in self: + it = cb(app).__aiter__() + await it.__anext__() + self._exits.append(it) + + async def _on_cleanup(self, app: Application) -> None: + errors = [] + for it in reversed(self._exits): + try: + await it.__anext__() + except StopAsyncIteration: + pass + except (Exception, asyncio.CancelledError) as exc: + errors.append(exc) + else: + errors.append(RuntimeError(f"{it!r} has more than one 'yield'")) + if errors: + if len(errors) == 1: + raise errors[0] + else: + raise CleanupError("Multiple errors on cleanup stage", errors) diff --git a/venv/lib/python3.12/site-packages/aiohttp/web_exceptions.py b/venv/lib/python3.12/site-packages/aiohttp/web_exceptions.py new file mode 100644 index 00000000..ee2c1e72 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/web_exceptions.py @@ -0,0 +1,452 @@ +import warnings +from typing import Any, Dict, Iterable, List, Optional, Set # noqa + +from yarl import URL + +from .typedefs import LooseHeaders, StrOrURL +from .web_response import Response + +__all__ = ( + "HTTPException", + "HTTPError", + "HTTPRedirection", + "HTTPSuccessful", + "HTTPOk", + "HTTPCreated", + "HTTPAccepted", + "HTTPNonAuthoritativeInformation", + "HTTPNoContent", + "HTTPResetContent", + "HTTPPartialContent", + "HTTPMove", + "HTTPMultipleChoices", + "HTTPMovedPermanently", + "HTTPFound", + "HTTPSeeOther", + "HTTPNotModified", + "HTTPUseProxy", + "HTTPTemporaryRedirect", + "HTTPPermanentRedirect", + "HTTPClientError", + "HTTPBadRequest", + "HTTPUnauthorized", + "HTTPPaymentRequired", + "HTTPForbidden", + "HTTPNotFound", + "HTTPMethodNotAllowed", + "HTTPNotAcceptable", + "HTTPProxyAuthenticationRequired", + "HTTPRequestTimeout", + "HTTPConflict", + "HTTPGone", + "HTTPLengthRequired", + "HTTPPreconditionFailed", + "HTTPRequestEntityTooLarge", + "HTTPRequestURITooLong", + "HTTPUnsupportedMediaType", + "HTTPRequestRangeNotSatisfiable", + "HTTPExpectationFailed", + "HTTPMisdirectedRequest", + "HTTPUnprocessableEntity", + "HTTPFailedDependency", + "HTTPUpgradeRequired", + "HTTPPreconditionRequired", + "HTTPTooManyRequests", + "HTTPRequestHeaderFieldsTooLarge", + "HTTPUnavailableForLegalReasons", + "HTTPServerError", + "HTTPInternalServerError", + "HTTPNotImplemented", + "HTTPBadGateway", + "HTTPServiceUnavailable", + "HTTPGatewayTimeout", + "HTTPVersionNotSupported", + "HTTPVariantAlsoNegotiates", + "HTTPInsufficientStorage", + "HTTPNotExtended", + "HTTPNetworkAuthenticationRequired", +) + + +class NotAppKeyWarning(UserWarning): + """Warning when not using AppKey in Application.""" + + +############################################################ +# HTTP Exceptions +############################################################ + + +class HTTPException(Response, Exception): + + # You should set in subclasses: + # status = 200 + + status_code = -1 + empty_body = False + + __http_exception__ = True + + def __init__( + self, + *, + headers: Optional[LooseHeaders] = None, + reason: Optional[str] = None, + body: Any = None, + text: Optional[str] = None, + content_type: Optional[str] = None, + ) -> None: + if body is not None: + warnings.warn( + "body argument is deprecated for http web exceptions", + DeprecationWarning, + ) + Response.__init__( + self, + status=self.status_code, + headers=headers, + reason=reason, + body=body, + text=text, + content_type=content_type, + ) + Exception.__init__(self, self.reason) + if self.body is None and not self.empty_body: + self.text = f"{self.status}: {self.reason}" + + def __bool__(self) -> bool: + return True + + +class HTTPError(HTTPException): + """Base class for exceptions with status codes in the 400s and 500s.""" + + +class HTTPRedirection(HTTPException): + """Base class for exceptions with status codes in the 300s.""" + + +class HTTPSuccessful(HTTPException): + """Base class for exceptions with status codes in the 200s.""" + + +class HTTPOk(HTTPSuccessful): + status_code = 200 + + +class HTTPCreated(HTTPSuccessful): + status_code = 201 + + +class HTTPAccepted(HTTPSuccessful): + status_code = 202 + + +class HTTPNonAuthoritativeInformation(HTTPSuccessful): + status_code = 203 + + +class HTTPNoContent(HTTPSuccessful): + status_code = 204 + empty_body = True + + +class HTTPResetContent(HTTPSuccessful): + status_code = 205 + empty_body = True + + +class HTTPPartialContent(HTTPSuccessful): + status_code = 206 + + +############################################################ +# 3xx redirection +############################################################ + + +class HTTPMove(HTTPRedirection): + def __init__( + self, + location: StrOrURL, + *, + headers: Optional[LooseHeaders] = None, + reason: Optional[str] = None, + body: Any = None, + text: Optional[str] = None, + content_type: Optional[str] = None, + ) -> None: + if not location: + raise ValueError("HTTP redirects need a location to redirect to.") + super().__init__( + headers=headers, + reason=reason, + body=body, + text=text, + content_type=content_type, + ) + self.headers["Location"] = str(URL(location)) + self.location = location + + +class HTTPMultipleChoices(HTTPMove): + status_code = 300 + + +class HTTPMovedPermanently(HTTPMove): + status_code = 301 + + +class HTTPFound(HTTPMove): + status_code = 302 + + +# This one is safe after a POST (the redirected location will be +# retrieved with GET): +class HTTPSeeOther(HTTPMove): + status_code = 303 + + +class HTTPNotModified(HTTPRedirection): + # FIXME: this should include a date or etag header + status_code = 304 + empty_body = True + + +class HTTPUseProxy(HTTPMove): + # Not a move, but looks a little like one + status_code = 305 + + +class HTTPTemporaryRedirect(HTTPMove): + status_code = 307 + + +class HTTPPermanentRedirect(HTTPMove): + status_code = 308 + + +############################################################ +# 4xx client error +############################################################ + + +class HTTPClientError(HTTPError): + pass + + +class HTTPBadRequest(HTTPClientError): + status_code = 400 + + +class HTTPUnauthorized(HTTPClientError): + status_code = 401 + + +class HTTPPaymentRequired(HTTPClientError): + status_code = 402 + + +class HTTPForbidden(HTTPClientError): + status_code = 403 + + +class HTTPNotFound(HTTPClientError): + status_code = 404 + + +class HTTPMethodNotAllowed(HTTPClientError): + status_code = 405 + + def __init__( + self, + method: str, + allowed_methods: Iterable[str], + *, + headers: Optional[LooseHeaders] = None, + reason: Optional[str] = None, + body: Any = None, + text: Optional[str] = None, + content_type: Optional[str] = None, + ) -> None: + allow = ",".join(sorted(allowed_methods)) + super().__init__( + headers=headers, + reason=reason, + body=body, + text=text, + content_type=content_type, + ) + self.headers["Allow"] = allow + self.allowed_methods: Set[str] = set(allowed_methods) + self.method = method.upper() + + +class HTTPNotAcceptable(HTTPClientError): + status_code = 406 + + +class HTTPProxyAuthenticationRequired(HTTPClientError): + status_code = 407 + + +class HTTPRequestTimeout(HTTPClientError): + status_code = 408 + + +class HTTPConflict(HTTPClientError): + status_code = 409 + + +class HTTPGone(HTTPClientError): + status_code = 410 + + +class HTTPLengthRequired(HTTPClientError): + status_code = 411 + + +class HTTPPreconditionFailed(HTTPClientError): + status_code = 412 + + +class HTTPRequestEntityTooLarge(HTTPClientError): + status_code = 413 + + def __init__(self, max_size: float, actual_size: float, **kwargs: Any) -> None: + kwargs.setdefault( + "text", + "Maximum request body size {} exceeded, " + "actual body size {}".format(max_size, actual_size), + ) + super().__init__(**kwargs) + + +class HTTPRequestURITooLong(HTTPClientError): + status_code = 414 + + +class HTTPUnsupportedMediaType(HTTPClientError): + status_code = 415 + + +class HTTPRequestRangeNotSatisfiable(HTTPClientError): + status_code = 416 + + +class HTTPExpectationFailed(HTTPClientError): + status_code = 417 + + +class HTTPMisdirectedRequest(HTTPClientError): + status_code = 421 + + +class HTTPUnprocessableEntity(HTTPClientError): + status_code = 422 + + +class HTTPFailedDependency(HTTPClientError): + status_code = 424 + + +class HTTPUpgradeRequired(HTTPClientError): + status_code = 426 + + +class HTTPPreconditionRequired(HTTPClientError): + status_code = 428 + + +class HTTPTooManyRequests(HTTPClientError): + status_code = 429 + + +class HTTPRequestHeaderFieldsTooLarge(HTTPClientError): + status_code = 431 + + +class HTTPUnavailableForLegalReasons(HTTPClientError): + status_code = 451 + + def __init__( + self, + link: Optional[StrOrURL], + *, + headers: Optional[LooseHeaders] = None, + reason: Optional[str] = None, + body: Any = None, + text: Optional[str] = None, + content_type: Optional[str] = None, + ) -> None: + super().__init__( + headers=headers, + reason=reason, + body=body, + text=text, + content_type=content_type, + ) + self._link = None + if link: + self._link = URL(link) + self.headers["Link"] = f'<{str(self._link)}>; rel="blocked-by"' + + @property + def link(self) -> Optional[URL]: + return self._link + + +############################################################ +# 5xx Server Error +############################################################ +# Response status codes beginning with the digit "5" indicate cases in +# which the server is aware that it has erred or is incapable of +# performing the request. Except when responding to a HEAD request, the +# server SHOULD include an entity containing an explanation of the error +# situation, and whether it is a temporary or permanent condition. User +# agents SHOULD display any included entity to the user. These response +# codes are applicable to any request method. + + +class HTTPServerError(HTTPError): + pass + + +class HTTPInternalServerError(HTTPServerError): + status_code = 500 + + +class HTTPNotImplemented(HTTPServerError): + status_code = 501 + + +class HTTPBadGateway(HTTPServerError): + status_code = 502 + + +class HTTPServiceUnavailable(HTTPServerError): + status_code = 503 + + +class HTTPGatewayTimeout(HTTPServerError): + status_code = 504 + + +class HTTPVersionNotSupported(HTTPServerError): + status_code = 505 + + +class HTTPVariantAlsoNegotiates(HTTPServerError): + status_code = 506 + + +class HTTPInsufficientStorage(HTTPServerError): + status_code = 507 + + +class HTTPNotExtended(HTTPServerError): + status_code = 510 + + +class HTTPNetworkAuthenticationRequired(HTTPServerError): + status_code = 511 diff --git a/venv/lib/python3.12/site-packages/aiohttp/web_fileresponse.py b/venv/lib/python3.12/site-packages/aiohttp/web_fileresponse.py new file mode 100644 index 00000000..be9cf87e --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/web_fileresponse.py @@ -0,0 +1,418 @@ +import asyncio +import io +import os +import pathlib +import sys +from contextlib import suppress +from enum import Enum, auto +from mimetypes import MimeTypes +from stat import S_ISREG +from types import MappingProxyType +from typing import ( # noqa + IO, + TYPE_CHECKING, + Any, + Awaitable, + Callable, + Final, + Iterator, + List, + Optional, + Set, + Tuple, + Union, + cast, +) + +from . import hdrs +from .abc import AbstractStreamWriter +from .helpers import ETAG_ANY, ETag, must_be_empty_body +from .typedefs import LooseHeaders, PathLike +from .web_exceptions import ( + HTTPForbidden, + HTTPNotFound, + HTTPNotModified, + HTTPPartialContent, + HTTPPreconditionFailed, + HTTPRequestRangeNotSatisfiable, +) +from .web_response import StreamResponse + +__all__ = ("FileResponse",) + +if TYPE_CHECKING: + from .web_request import BaseRequest + + +_T_OnChunkSent = Optional[Callable[[bytes], Awaitable[None]]] + + +NOSENDFILE: Final[bool] = bool(os.environ.get("AIOHTTP_NOSENDFILE")) + +CONTENT_TYPES: Final[MimeTypes] = MimeTypes() + +# File extension to IANA encodings map that will be checked in the order defined. +ENCODING_EXTENSIONS = MappingProxyType( + {ext: CONTENT_TYPES.encodings_map[ext] for ext in (".br", ".gz")} +) + +FALLBACK_CONTENT_TYPE = "application/octet-stream" + +# Provide additional MIME type/extension pairs to be recognized. +# https://en.wikipedia.org/wiki/List_of_archive_formats#Compression_only +ADDITIONAL_CONTENT_TYPES = MappingProxyType( + { + "application/gzip": ".gz", + "application/x-brotli": ".br", + "application/x-bzip2": ".bz2", + "application/x-compress": ".Z", + "application/x-xz": ".xz", + } +) + + +class _FileResponseResult(Enum): + """The result of the file response.""" + + SEND_FILE = auto() # Ie a regular file to send + NOT_ACCEPTABLE = auto() # Ie a socket, or non-regular file + PRE_CONDITION_FAILED = auto() # Ie If-Match or If-None-Match failed + NOT_MODIFIED = auto() # 304 Not Modified + + +# Add custom pairs and clear the encodings map so guess_type ignores them. +CONTENT_TYPES.encodings_map.clear() +for content_type, extension in ADDITIONAL_CONTENT_TYPES.items(): + CONTENT_TYPES.add_type(content_type, extension) # type: ignore[attr-defined] + + +_CLOSE_FUTURES: Set[asyncio.Future[None]] = set() + + +class FileResponse(StreamResponse): + """A response object can be used to send files.""" + + def __init__( + self, + path: PathLike, + chunk_size: int = 256 * 1024, + status: int = 200, + reason: Optional[str] = None, + headers: Optional[LooseHeaders] = None, + ) -> None: + super().__init__(status=status, reason=reason, headers=headers) + + self._path = pathlib.Path(path) + self._chunk_size = chunk_size + + def _seek_and_read(self, fobj: IO[Any], offset: int, chunk_size: int) -> bytes: + fobj.seek(offset) + return fobj.read(chunk_size) # type: ignore[no-any-return] + + async def _sendfile_fallback( + self, writer: AbstractStreamWriter, fobj: IO[Any], offset: int, count: int + ) -> AbstractStreamWriter: + # To keep memory usage low,fobj is transferred in chunks + # controlled by the constructor's chunk_size argument. + + chunk_size = self._chunk_size + loop = asyncio.get_event_loop() + chunk = await loop.run_in_executor( + None, self._seek_and_read, fobj, offset, chunk_size + ) + while chunk: + await writer.write(chunk) + count = count - chunk_size + if count <= 0: + break + chunk = await loop.run_in_executor(None, fobj.read, min(chunk_size, count)) + + await writer.drain() + return writer + + async def _sendfile( + self, request: "BaseRequest", fobj: IO[Any], offset: int, count: int + ) -> AbstractStreamWriter: + writer = await super().prepare(request) + assert writer is not None + + if NOSENDFILE or self.compression: + return await self._sendfile_fallback(writer, fobj, offset, count) + + loop = request._loop + transport = request.transport + assert transport is not None + + try: + await loop.sendfile(transport, fobj, offset, count) + except NotImplementedError: + return await self._sendfile_fallback(writer, fobj, offset, count) + + await super().write_eof() + return writer + + @staticmethod + def _etag_match(etag_value: str, etags: Tuple[ETag, ...], *, weak: bool) -> bool: + if len(etags) == 1 and etags[0].value == ETAG_ANY: + return True + return any( + etag.value == etag_value for etag in etags if weak or not etag.is_weak + ) + + async def _not_modified( + self, request: "BaseRequest", etag_value: str, last_modified: float + ) -> Optional[AbstractStreamWriter]: + self.set_status(HTTPNotModified.status_code) + self._length_check = False + self.etag = etag_value # type: ignore[assignment] + self.last_modified = last_modified # type: ignore[assignment] + # Delete any Content-Length headers provided by user. HTTP 304 + # should always have empty response body + return await super().prepare(request) + + async def _precondition_failed( + self, request: "BaseRequest" + ) -> Optional[AbstractStreamWriter]: + self.set_status(HTTPPreconditionFailed.status_code) + self.content_length = 0 + return await super().prepare(request) + + def _make_response( + self, request: "BaseRequest", accept_encoding: str + ) -> Tuple[ + _FileResponseResult, Optional[io.BufferedReader], os.stat_result, Optional[str] + ]: + """Return the response result, io object, stat result, and encoding. + + If an uncompressed file is returned, the encoding is set to + :py:data:`None`. + + This method should be called from a thread executor + since it calls os.stat which may block. + """ + file_path, st, file_encoding = self._get_file_path_stat_encoding( + accept_encoding + ) + if not file_path: + return _FileResponseResult.NOT_ACCEPTABLE, None, st, None + + etag_value = f"{st.st_mtime_ns:x}-{st.st_size:x}" + + # https://www.rfc-editor.org/rfc/rfc9110#section-13.1.1-2 + if (ifmatch := request.if_match) is not None and not self._etag_match( + etag_value, ifmatch, weak=False + ): + return _FileResponseResult.PRE_CONDITION_FAILED, None, st, file_encoding + + if ( + (unmodsince := request.if_unmodified_since) is not None + and ifmatch is None + and st.st_mtime > unmodsince.timestamp() + ): + return _FileResponseResult.PRE_CONDITION_FAILED, None, st, file_encoding + + # https://www.rfc-editor.org/rfc/rfc9110#section-13.1.2-2 + if (ifnonematch := request.if_none_match) is not None and self._etag_match( + etag_value, ifnonematch, weak=True + ): + return _FileResponseResult.NOT_MODIFIED, None, st, file_encoding + + if ( + (modsince := request.if_modified_since) is not None + and ifnonematch is None + and st.st_mtime <= modsince.timestamp() + ): + return _FileResponseResult.NOT_MODIFIED, None, st, file_encoding + + fobj = file_path.open("rb") + with suppress(OSError): + # fstat() may not be available on all platforms + # Once we open the file, we want the fstat() to ensure + # the file has not changed between the first stat() + # and the open(). + st = os.stat(fobj.fileno()) + return _FileResponseResult.SEND_FILE, fobj, st, file_encoding + + def _get_file_path_stat_encoding( + self, accept_encoding: str + ) -> Tuple[Optional[pathlib.Path], os.stat_result, Optional[str]]: + file_path = self._path + for file_extension, file_encoding in ENCODING_EXTENSIONS.items(): + if file_encoding not in accept_encoding: + continue + + compressed_path = file_path.with_suffix(file_path.suffix + file_extension) + with suppress(OSError): + # Do not follow symlinks and ignore any non-regular files. + st = compressed_path.lstat() + if S_ISREG(st.st_mode): + return compressed_path, st, file_encoding + + # Fallback to the uncompressed file + st = file_path.stat() + return file_path if S_ISREG(st.st_mode) else None, st, None + + async def prepare(self, request: "BaseRequest") -> Optional[AbstractStreamWriter]: + loop = asyncio.get_running_loop() + # Encoding comparisons should be case-insensitive + # https://www.rfc-editor.org/rfc/rfc9110#section-8.4.1 + accept_encoding = request.headers.get(hdrs.ACCEPT_ENCODING, "").lower() + try: + response_result, fobj, st, file_encoding = await loop.run_in_executor( + None, self._make_response, request, accept_encoding + ) + except PermissionError: + self.set_status(HTTPForbidden.status_code) + return await super().prepare(request) + except OSError: + # Most likely to be FileNotFoundError or OSError for circular + # symlinks in python >= 3.13, so respond with 404. + self.set_status(HTTPNotFound.status_code) + return await super().prepare(request) + + # Forbid special files like sockets, pipes, devices, etc. + if response_result is _FileResponseResult.NOT_ACCEPTABLE: + self.set_status(HTTPForbidden.status_code) + return await super().prepare(request) + + if response_result is _FileResponseResult.PRE_CONDITION_FAILED: + return await self._precondition_failed(request) + + if response_result is _FileResponseResult.NOT_MODIFIED: + etag_value = f"{st.st_mtime_ns:x}-{st.st_size:x}" + last_modified = st.st_mtime + return await self._not_modified(request, etag_value, last_modified) + + assert fobj is not None + try: + return await self._prepare_open_file(request, fobj, st, file_encoding) + finally: + # We do not await here because we do not want to wait + # for the executor to finish before returning the response + # so the connection can begin servicing another request + # as soon as possible. + close_future = loop.run_in_executor(None, fobj.close) + # Hold a strong reference to the future to prevent it from being + # garbage collected before it completes. + _CLOSE_FUTURES.add(close_future) + close_future.add_done_callback(_CLOSE_FUTURES.remove) + + async def _prepare_open_file( + self, + request: "BaseRequest", + fobj: io.BufferedReader, + st: os.stat_result, + file_encoding: Optional[str], + ) -> Optional[AbstractStreamWriter]: + status = self._status + file_size: int = st.st_size + file_mtime: float = st.st_mtime + count: int = file_size + start: Optional[int] = None + + if (ifrange := request.if_range) is None or file_mtime <= ifrange.timestamp(): + # If-Range header check: + # condition = cached date >= last modification date + # return 206 if True else 200. + # if False: + # Range header would not be processed, return 200 + # if True but Range header missing + # return 200 + try: + rng = request.http_range + start = rng.start + end: Optional[int] = rng.stop + except ValueError: + # https://tools.ietf.org/html/rfc7233: + # A server generating a 416 (Range Not Satisfiable) response to + # a byte-range request SHOULD send a Content-Range header field + # with an unsatisfied-range value. + # The complete-length in a 416 response indicates the current + # length of the selected representation. + # + # Will do the same below. Many servers ignore this and do not + # send a Content-Range header with HTTP 416 + self._headers[hdrs.CONTENT_RANGE] = f"bytes */{file_size}" + self.set_status(HTTPRequestRangeNotSatisfiable.status_code) + return await super().prepare(request) + + # If a range request has been made, convert start, end slice + # notation into file pointer offset and count + if start is not None: + if start < 0 and end is None: # return tail of file + start += file_size + if start < 0: + # if Range:bytes=-1000 in request header but file size + # is only 200, there would be trouble without this + start = 0 + count = file_size - start + else: + # rfc7233:If the last-byte-pos value is + # absent, or if the value is greater than or equal to + # the current length of the representation data, + # the byte range is interpreted as the remainder + # of the representation (i.e., the server replaces the + # value of last-byte-pos with a value that is one less than + # the current length of the selected representation). + count = ( + min(end if end is not None else file_size, file_size) - start + ) + + if start >= file_size: + # HTTP 416 should be returned in this case. + # + # According to https://tools.ietf.org/html/rfc7233: + # If a valid byte-range-set includes at least one + # byte-range-spec with a first-byte-pos that is less than + # the current length of the representation, or at least one + # suffix-byte-range-spec with a non-zero suffix-length, + # then the byte-range-set is satisfiable. Otherwise, the + # byte-range-set is unsatisfiable. + self._headers[hdrs.CONTENT_RANGE] = f"bytes */{file_size}" + self.set_status(HTTPRequestRangeNotSatisfiable.status_code) + return await super().prepare(request) + + status = HTTPPartialContent.status_code + # Even though you are sending the whole file, you should still + # return a HTTP 206 for a Range request. + self.set_status(status) + + # If the Content-Type header is not already set, guess it based on the + # extension of the request path. The encoding returned by guess_type + # can be ignored since the map was cleared above. + if hdrs.CONTENT_TYPE not in self._headers: + if sys.version_info >= (3, 13): + guesser = CONTENT_TYPES.guess_file_type + else: + guesser = CONTENT_TYPES.guess_type + self.content_type = guesser(self._path)[0] or FALLBACK_CONTENT_TYPE + + if file_encoding: + self._headers[hdrs.CONTENT_ENCODING] = file_encoding + self._headers[hdrs.VARY] = hdrs.ACCEPT_ENCODING + # Disable compression if we are already sending + # a compressed file since we don't want to double + # compress. + self._compression = False + + self.etag = f"{st.st_mtime_ns:x}-{st.st_size:x}" # type: ignore[assignment] + self.last_modified = file_mtime # type: ignore[assignment] + self.content_length = count + + self._headers[hdrs.ACCEPT_RANGES] = "bytes" + + if status == HTTPPartialContent.status_code: + real_start = start + assert real_start is not None + self._headers[hdrs.CONTENT_RANGE] = "bytes {}-{}/{}".format( + real_start, real_start + count - 1, file_size + ) + + # If we are sending 0 bytes calling sendfile() will throw a ValueError + if count == 0 or must_be_empty_body(request.method, status): + return await super().prepare(request) + + # be aware that start could be None or int=0 here. + offset = start or 0 + + return await self._sendfile(request, fobj, offset, count) diff --git a/venv/lib/python3.12/site-packages/aiohttp/web_log.py b/venv/lib/python3.12/site-packages/aiohttp/web_log.py new file mode 100644 index 00000000..d5ea2bee --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/web_log.py @@ -0,0 +1,216 @@ +import datetime +import functools +import logging +import os +import re +import time as time_mod +from collections import namedtuple +from typing import Any, Callable, Dict, Iterable, List, Tuple # noqa + +from .abc import AbstractAccessLogger +from .web_request import BaseRequest +from .web_response import StreamResponse + +KeyMethod = namedtuple("KeyMethod", "key method") + + +class AccessLogger(AbstractAccessLogger): + """Helper object to log access. + + Usage: + log = logging.getLogger("spam") + log_format = "%a %{User-Agent}i" + access_logger = AccessLogger(log, log_format) + access_logger.log(request, response, time) + + Format: + %% The percent sign + %a Remote IP-address (IP-address of proxy if using reverse proxy) + %t Time when the request was started to process + %P The process ID of the child that serviced the request + %r First line of request + %s Response status code + %b Size of response in bytes, including HTTP headers + %T Time taken to serve the request, in seconds + %Tf Time taken to serve the request, in seconds with floating fraction + in .06f format + %D Time taken to serve the request, in microseconds + %{FOO}i request.headers['FOO'] + %{FOO}o response.headers['FOO'] + %{FOO}e os.environ['FOO'] + + """ + + LOG_FORMAT_MAP = { + "a": "remote_address", + "t": "request_start_time", + "P": "process_id", + "r": "first_request_line", + "s": "response_status", + "b": "response_size", + "T": "request_time", + "Tf": "request_time_frac", + "D": "request_time_micro", + "i": "request_header", + "o": "response_header", + } + + LOG_FORMAT = '%a %t "%r" %s %b "%{Referer}i" "%{User-Agent}i"' + FORMAT_RE = re.compile(r"%(\{([A-Za-z0-9\-_]+)\}([ioe])|[atPrsbOD]|Tf?)") + CLEANUP_RE = re.compile(r"(%[^s])") + _FORMAT_CACHE: Dict[str, Tuple[str, List[KeyMethod]]] = {} + + def __init__(self, logger: logging.Logger, log_format: str = LOG_FORMAT) -> None: + """Initialise the logger. + + logger is a logger object to be used for logging. + log_format is a string with apache compatible log format description. + + """ + super().__init__(logger, log_format=log_format) + + _compiled_format = AccessLogger._FORMAT_CACHE.get(log_format) + if not _compiled_format: + _compiled_format = self.compile_format(log_format) + AccessLogger._FORMAT_CACHE[log_format] = _compiled_format + + self._log_format, self._methods = _compiled_format + + def compile_format(self, log_format: str) -> Tuple[str, List[KeyMethod]]: + """Translate log_format into form usable by modulo formatting + + All known atoms will be replaced with %s + Also methods for formatting of those atoms will be added to + _methods in appropriate order + + For example we have log_format = "%a %t" + This format will be translated to "%s %s" + Also contents of _methods will be + [self._format_a, self._format_t] + These method will be called and results will be passed + to translated string format. + + Each _format_* method receive 'args' which is list of arguments + given to self.log + + Exceptions are _format_e, _format_i and _format_o methods which + also receive key name (by functools.partial) + + """ + # list of (key, method) tuples, we don't use an OrderedDict as users + # can repeat the same key more than once + methods = list() + + for atom in self.FORMAT_RE.findall(log_format): + if atom[1] == "": + format_key1 = self.LOG_FORMAT_MAP[atom[0]] + m = getattr(AccessLogger, "_format_%s" % atom[0]) + key_method = KeyMethod(format_key1, m) + else: + format_key2 = (self.LOG_FORMAT_MAP[atom[2]], atom[1]) + m = getattr(AccessLogger, "_format_%s" % atom[2]) + key_method = KeyMethod(format_key2, functools.partial(m, atom[1])) + + methods.append(key_method) + + log_format = self.FORMAT_RE.sub(r"%s", log_format) + log_format = self.CLEANUP_RE.sub(r"%\1", log_format) + return log_format, methods + + @staticmethod + def _format_i( + key: str, request: BaseRequest, response: StreamResponse, time: float + ) -> str: + if request is None: + return "(no headers)" + + # suboptimal, make istr(key) once + return request.headers.get(key, "-") + + @staticmethod + def _format_o( + key: str, request: BaseRequest, response: StreamResponse, time: float + ) -> str: + # suboptimal, make istr(key) once + return response.headers.get(key, "-") + + @staticmethod + def _format_a(request: BaseRequest, response: StreamResponse, time: float) -> str: + if request is None: + return "-" + ip = request.remote + return ip if ip is not None else "-" + + @staticmethod + def _format_t(request: BaseRequest, response: StreamResponse, time: float) -> str: + tz = datetime.timezone(datetime.timedelta(seconds=-time_mod.timezone)) + now = datetime.datetime.now(tz) + start_time = now - datetime.timedelta(seconds=time) + return start_time.strftime("[%d/%b/%Y:%H:%M:%S %z]") + + @staticmethod + def _format_P(request: BaseRequest, response: StreamResponse, time: float) -> str: + return "<%s>" % os.getpid() + + @staticmethod + def _format_r(request: BaseRequest, response: StreamResponse, time: float) -> str: + if request is None: + return "-" + return "{} {} HTTP/{}.{}".format( + request.method, + request.path_qs, + request.version.major, + request.version.minor, + ) + + @staticmethod + def _format_s(request: BaseRequest, response: StreamResponse, time: float) -> int: + return response.status + + @staticmethod + def _format_b(request: BaseRequest, response: StreamResponse, time: float) -> int: + return response.body_length + + @staticmethod + def _format_T(request: BaseRequest, response: StreamResponse, time: float) -> str: + return str(round(time)) + + @staticmethod + def _format_Tf(request: BaseRequest, response: StreamResponse, time: float) -> str: + return "%06f" % time + + @staticmethod + def _format_D(request: BaseRequest, response: StreamResponse, time: float) -> str: + return str(round(time * 1000000)) + + def _format_line( + self, request: BaseRequest, response: StreamResponse, time: float + ) -> Iterable[Tuple[str, Callable[[BaseRequest, StreamResponse, float], str]]]: + return [(key, method(request, response, time)) for key, method in self._methods] + + @property + def enabled(self) -> bool: + """Check if logger is enabled.""" + # Avoid formatting the log line if it will not be emitted. + return self.logger.isEnabledFor(logging.INFO) + + def log(self, request: BaseRequest, response: StreamResponse, time: float) -> None: + try: + fmt_info = self._format_line(request, response, time) + + values = list() + extra = dict() + for key, value in fmt_info: + values.append(value) + + if key.__class__ is str: + extra[key] = value + else: + k1, k2 = key # type: ignore[misc] + dct = extra.get(k1, {}) # type: ignore[var-annotated,has-type] + dct[k2] = value # type: ignore[index,has-type] + extra[k1] = dct # type: ignore[has-type,assignment] + + self.logger.info(self._log_format % tuple(values), extra=extra) + except Exception: + self.logger.exception("Error in logging") diff --git a/venv/lib/python3.12/site-packages/aiohttp/web_middlewares.py b/venv/lib/python3.12/site-packages/aiohttp/web_middlewares.py new file mode 100644 index 00000000..2f1f5f58 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/web_middlewares.py @@ -0,0 +1,121 @@ +import re +from typing import TYPE_CHECKING, Tuple, Type, TypeVar + +from .typedefs import Handler, Middleware +from .web_exceptions import HTTPMove, HTTPPermanentRedirect +from .web_request import Request +from .web_response import StreamResponse +from .web_urldispatcher import SystemRoute + +__all__ = ( + "middleware", + "normalize_path_middleware", +) + +if TYPE_CHECKING: + from .web_app import Application + +_Func = TypeVar("_Func") + + +async def _check_request_resolves(request: Request, path: str) -> Tuple[bool, Request]: + alt_request = request.clone(rel_url=path) + + match_info = await request.app.router.resolve(alt_request) + alt_request._match_info = match_info + + if match_info.http_exception is None: + return True, alt_request + + return False, request + + +def middleware(f: _Func) -> _Func: + f.__middleware_version__ = 1 # type: ignore[attr-defined] + return f + + +def normalize_path_middleware( + *, + append_slash: bool = True, + remove_slash: bool = False, + merge_slashes: bool = True, + redirect_class: Type[HTTPMove] = HTTPPermanentRedirect, +) -> Middleware: + """Factory for producing a middleware that normalizes the path of a request. + + Normalizing means: + - Add or remove a trailing slash to the path. + - Double slashes are replaced by one. + + The middleware returns as soon as it finds a path that resolves + correctly. The order if both merge and append/remove are enabled is + 1) merge slashes + 2) append/remove slash + 3) both merge slashes and append/remove slash. + If the path resolves with at least one of those conditions, it will + redirect to the new path. + + Only one of `append_slash` and `remove_slash` can be enabled. If both + are `True` the factory will raise an assertion error + + If `append_slash` is `True` the middleware will append a slash when + needed. If a resource is defined with trailing slash and the request + comes without it, it will append it automatically. + + If `remove_slash` is `True`, `append_slash` must be `False`. When enabled + the middleware will remove trailing slashes and redirect if the resource + is defined + + If merge_slashes is True, merge multiple consecutive slashes in the + path into one. + """ + correct_configuration = not (append_slash and remove_slash) + assert correct_configuration, "Cannot both remove and append slash" + + @middleware + async def impl(request: Request, handler: Handler) -> StreamResponse: + if isinstance(request.match_info.route, SystemRoute): + paths_to_check = [] + if "?" in request.raw_path: + path, query = request.raw_path.split("?", 1) + query = "?" + query + else: + query = "" + path = request.raw_path + + if merge_slashes: + paths_to_check.append(re.sub("//+", "/", path)) + if append_slash and not request.path.endswith("/"): + paths_to_check.append(path + "/") + if remove_slash and request.path.endswith("/"): + paths_to_check.append(path[:-1]) + if merge_slashes and append_slash: + paths_to_check.append(re.sub("//+", "/", path + "/")) + if merge_slashes and remove_slash: + merged_slashes = re.sub("//+", "/", path) + paths_to_check.append(merged_slashes[:-1]) + + for path in paths_to_check: + path = re.sub("^//+", "/", path) # SECURITY: GHSA-v6wp-4m6f-gcjg + resolves, request = await _check_request_resolves(request, path) + if resolves: + raise redirect_class(request.raw_path + query) + + return await handler(request) + + return impl + + +def _fix_request_current_app(app: "Application") -> Middleware: + @middleware + async def impl(request: Request, handler: Handler) -> StreamResponse: + match_info = request.match_info + prev = match_info.current_app + match_info.current_app = app + try: + return await handler(request) + finally: + match_info.current_app = prev + + return impl diff --git a/venv/lib/python3.12/site-packages/aiohttp/web_protocol.py b/venv/lib/python3.12/site-packages/aiohttp/web_protocol.py new file mode 100644 index 00000000..e1923aac --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/web_protocol.py @@ -0,0 +1,792 @@ +import asyncio +import asyncio.streams +import sys +import traceback +import warnings +from collections import deque +from contextlib import suppress +from html import escape as html_escape +from http import HTTPStatus +from logging import Logger +from typing import ( + TYPE_CHECKING, + Any, + Awaitable, + Callable, + Deque, + Optional, + Sequence, + Tuple, + Type, + Union, + cast, +) + +import attr +import yarl +from propcache import under_cached_property + +from .abc import AbstractAccessLogger, AbstractStreamWriter +from .base_protocol import BaseProtocol +from .helpers import ceil_timeout +from .http import ( + HttpProcessingError, + HttpRequestParser, + HttpVersion10, + RawRequestMessage, + StreamWriter, +) +from .http_exceptions import BadHttpMethod +from .log import access_logger, server_logger +from .streams import EMPTY_PAYLOAD, StreamReader +from .tcp_helpers import tcp_keepalive +from .web_exceptions import HTTPException, HTTPInternalServerError +from .web_log import AccessLogger +from .web_request import BaseRequest +from .web_response import Response, StreamResponse + +__all__ = ("RequestHandler", "RequestPayloadError", "PayloadAccessError") + +if TYPE_CHECKING: + import ssl + + from .web_server import Server + + +_RequestFactory = Callable[ + [ + RawRequestMessage, + StreamReader, + "RequestHandler", + AbstractStreamWriter, + "asyncio.Task[None]", + ], + BaseRequest, +] + +_RequestHandler = Callable[[BaseRequest], Awaitable[StreamResponse]] + +ERROR = RawRequestMessage( + "UNKNOWN", + "/", + HttpVersion10, + {}, # type: ignore[arg-type] + {}, # type: ignore[arg-type] + True, + None, + False, + False, + yarl.URL("/"), +) + + +class RequestPayloadError(Exception): + """Payload parsing error.""" + + +class PayloadAccessError(Exception): + """Payload was accessed after response was sent.""" + + +_PAYLOAD_ACCESS_ERROR = PayloadAccessError() + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class _ErrInfo: + status: int + exc: BaseException + message: str + + +_MsgType = Tuple[Union[RawRequestMessage, _ErrInfo], StreamReader] + + +class RequestHandler(BaseProtocol): + """HTTP protocol implementation. + + RequestHandler handles incoming HTTP request. It reads request line, + request headers and request payload and calls handle_request() method. + By default it always returns with 404 response. + + RequestHandler handles errors in incoming request, like bad + status line, bad headers or incomplete payload. If any error occurs, + connection gets closed. + + keepalive_timeout -- number of seconds before closing + keep-alive connection + + tcp_keepalive -- TCP keep-alive is on, default is on + + debug -- enable debug mode + + logger -- custom logger object + + access_log_class -- custom class for access_logger + + access_log -- custom logging object + + access_log_format -- access log format string + + loop -- Optional event loop + + max_line_size -- Optional maximum header line size + + max_field_size -- Optional maximum header field size + + max_headers -- Optional maximum header size + + timeout_ceil_threshold -- Optional value to specify + threshold to ceil() timeout + values + + """ + + __slots__ = ( + "_request_count", + "_keepalive", + "_manager", + "_request_handler", + "_request_factory", + "_tcp_keepalive", + "_next_keepalive_close_time", + "_keepalive_handle", + "_keepalive_timeout", + "_lingering_time", + "_messages", + "_message_tail", + "_handler_waiter", + "_waiter", + "_task_handler", + "_upgrade", + "_payload_parser", + "_request_parser", + "_reading_paused", + "logger", + "debug", + "access_log", + "access_logger", + "_close", + "_force_close", + "_current_request", + "_timeout_ceil_threshold", + "_request_in_progress", + "_logging_enabled", + "_cache", + ) + + def __init__( + self, + manager: "Server", + *, + loop: asyncio.AbstractEventLoop, + # Default should be high enough that it's likely longer than a reverse proxy. + keepalive_timeout: float = 3630, + tcp_keepalive: bool = True, + logger: Logger = server_logger, + access_log_class: Type[AbstractAccessLogger] = AccessLogger, + access_log: Logger = access_logger, + access_log_format: str = AccessLogger.LOG_FORMAT, + debug: bool = False, + max_line_size: int = 8190, + max_headers: int = 32768, + max_field_size: int = 8190, + lingering_time: float = 10.0, + read_bufsize: int = 2**16, + auto_decompress: bool = True, + timeout_ceil_threshold: float = 5, + ): + super().__init__(loop) + + # _request_count is the number of requests processed with the same connection. + self._request_count = 0 + self._keepalive = False + self._current_request: Optional[BaseRequest] = None + self._manager: Optional[Server] = manager + self._request_handler: Optional[_RequestHandler] = manager.request_handler + self._request_factory: Optional[_RequestFactory] = manager.request_factory + + self._tcp_keepalive = tcp_keepalive + # placeholder to be replaced on keepalive timeout setup + self._next_keepalive_close_time = 0.0 + self._keepalive_handle: Optional[asyncio.Handle] = None + self._keepalive_timeout = keepalive_timeout + self._lingering_time = float(lingering_time) + + self._messages: Deque[_MsgType] = deque() + self._message_tail = b"" + + self._waiter: Optional[asyncio.Future[None]] = None + self._handler_waiter: Optional[asyncio.Future[None]] = None + self._task_handler: Optional[asyncio.Task[None]] = None + + self._upgrade = False + self._payload_parser: Any = None + self._request_parser: Optional[HttpRequestParser] = HttpRequestParser( + self, + loop, + read_bufsize, + max_line_size=max_line_size, + max_field_size=max_field_size, + max_headers=max_headers, + payload_exception=RequestPayloadError, + auto_decompress=auto_decompress, + ) + + self._timeout_ceil_threshold: float = 5 + try: + self._timeout_ceil_threshold = float(timeout_ceil_threshold) + except (TypeError, ValueError): + pass + + self.logger = logger + self.debug = debug + self.access_log = access_log + if access_log: + self.access_logger: Optional[AbstractAccessLogger] = access_log_class( + access_log, access_log_format + ) + self._logging_enabled = self.access_logger.enabled + else: + self.access_logger = None + self._logging_enabled = False + + self._close = False + self._force_close = False + self._request_in_progress = False + self._cache: dict[str, Any] = {} + + def __repr__(self) -> str: + return "<{} {}>".format( + self.__class__.__name__, + "connected" if self.transport is not None else "disconnected", + ) + + @under_cached_property + def ssl_context(self) -> Optional["ssl.SSLContext"]: + """Return SSLContext if available.""" + return ( + None + if self.transport is None + else self.transport.get_extra_info("sslcontext") + ) + + @under_cached_property + def peername( + self, + ) -> Optional[Union[str, Tuple[str, int, int, int], Tuple[str, int]]]: + """Return peername if available.""" + return ( + None + if self.transport is None + else self.transport.get_extra_info("peername") + ) + + @property + def keepalive_timeout(self) -> float: + return self._keepalive_timeout + + async def shutdown(self, timeout: Optional[float] = 15.0) -> None: + """Do worker process exit preparations. + + We need to clean up everything and stop accepting requests. + It is especially important for keep-alive connections. + """ + self._force_close = True + + if self._keepalive_handle is not None: + self._keepalive_handle.cancel() + + # Wait for graceful handler completion + if self._request_in_progress: + # The future is only created when we are shutting + # down while the handler is still processing a request + # to avoid creating a future for every request. + self._handler_waiter = self._loop.create_future() + try: + async with ceil_timeout(timeout): + await self._handler_waiter + except (asyncio.CancelledError, asyncio.TimeoutError): + self._handler_waiter = None + if ( + sys.version_info >= (3, 11) + and (task := asyncio.current_task()) + and task.cancelling() + ): + raise + # Then cancel handler and wait + try: + async with ceil_timeout(timeout): + if self._current_request is not None: + self._current_request._cancel(asyncio.CancelledError()) + + if self._task_handler is not None and not self._task_handler.done(): + await asyncio.shield(self._task_handler) + except (asyncio.CancelledError, asyncio.TimeoutError): + if ( + sys.version_info >= (3, 11) + and (task := asyncio.current_task()) + and task.cancelling() + ): + raise + + # force-close non-idle handler + if self._task_handler is not None: + self._task_handler.cancel() + + self.force_close() + + def connection_made(self, transport: asyncio.BaseTransport) -> None: + super().connection_made(transport) + + real_transport = cast(asyncio.Transport, transport) + if self._tcp_keepalive: + tcp_keepalive(real_transport) + + assert self._manager is not None + self._manager.connection_made(self, real_transport) + + loop = self._loop + if sys.version_info >= (3, 12): + task = asyncio.Task(self.start(), loop=loop, eager_start=True) + else: + task = loop.create_task(self.start()) + self._task_handler = task + + def connection_lost(self, exc: Optional[BaseException]) -> None: + if self._manager is None: + return + self._manager.connection_lost(self, exc) + + # Grab value before setting _manager to None. + handler_cancellation = self._manager.handler_cancellation + + self.force_close() + super().connection_lost(exc) + self._manager = None + self._request_factory = None + self._request_handler = None + self._request_parser = None + + if self._keepalive_handle is not None: + self._keepalive_handle.cancel() + + if self._current_request is not None: + if exc is None: + exc = ConnectionResetError("Connection lost") + self._current_request._cancel(exc) + + if handler_cancellation and self._task_handler is not None: + self._task_handler.cancel() + + self._task_handler = None + + if self._payload_parser is not None: + self._payload_parser.feed_eof() + self._payload_parser = None + + def set_parser(self, parser: Any) -> None: + # Actual type is WebReader + assert self._payload_parser is None + + self._payload_parser = parser + + if self._message_tail: + self._payload_parser.feed_data(self._message_tail) + self._message_tail = b"" + + def eof_received(self) -> None: + pass + + def data_received(self, data: bytes) -> None: + if self._force_close or self._close: + return + # parse http messages + messages: Sequence[_MsgType] + if self._payload_parser is None and not self._upgrade: + assert self._request_parser is not None + try: + messages, upgraded, tail = self._request_parser.feed_data(data) + except HttpProcessingError as exc: + messages = [ + (_ErrInfo(status=400, exc=exc, message=exc.message), EMPTY_PAYLOAD) + ] + upgraded = False + tail = b"" + + for msg, payload in messages or (): + self._request_count += 1 + self._messages.append((msg, payload)) + + waiter = self._waiter + if messages and waiter is not None and not waiter.done(): + # don't set result twice + waiter.set_result(None) + + self._upgrade = upgraded + if upgraded and tail: + self._message_tail = tail + + # no parser, just store + elif self._payload_parser is None and self._upgrade and data: + self._message_tail += data + + # feed payload + elif data: + eof, tail = self._payload_parser.feed_data(data) + if eof: + self.close() + + def keep_alive(self, val: bool) -> None: + """Set keep-alive connection mode. + + :param bool val: new state. + """ + self._keepalive = val + if self._keepalive_handle: + self._keepalive_handle.cancel() + self._keepalive_handle = None + + def close(self) -> None: + """Close connection. + + Stop accepting new pipelining messages and close + connection when handlers done processing messages. + """ + self._close = True + if self._waiter: + self._waiter.cancel() + + def force_close(self) -> None: + """Forcefully close connection.""" + self._force_close = True + if self._waiter: + self._waiter.cancel() + if self.transport is not None: + self.transport.close() + self.transport = None + + def log_access( + self, request: BaseRequest, response: StreamResponse, time: Optional[float] + ) -> None: + if self.access_logger is not None and self.access_logger.enabled: + if TYPE_CHECKING: + assert time is not None + self.access_logger.log(request, response, self._loop.time() - time) + + def log_debug(self, *args: Any, **kw: Any) -> None: + if self.debug: + self.logger.debug(*args, **kw) + + def log_exception(self, *args: Any, **kw: Any) -> None: + self.logger.exception(*args, **kw) + + def _process_keepalive(self) -> None: + self._keepalive_handle = None + if self._force_close or not self._keepalive: + return + + loop = self._loop + now = loop.time() + close_time = self._next_keepalive_close_time + if now < close_time: + # Keep alive close check fired too early, reschedule + self._keepalive_handle = loop.call_at(close_time, self._process_keepalive) + return + + # handler in idle state + if self._waiter and not self._waiter.done(): + self.force_close() + + async def _handle_request( + self, + request: BaseRequest, + start_time: Optional[float], + request_handler: Callable[[BaseRequest], Awaitable[StreamResponse]], + ) -> Tuple[StreamResponse, bool]: + self._request_in_progress = True + try: + try: + self._current_request = request + resp = await request_handler(request) + finally: + self._current_request = None + except HTTPException as exc: + resp = exc + resp, reset = await self.finish_response(request, resp, start_time) + except asyncio.CancelledError: + raise + except asyncio.TimeoutError as exc: + self.log_debug("Request handler timed out.", exc_info=exc) + resp = self.handle_error(request, 504) + resp, reset = await self.finish_response(request, resp, start_time) + except Exception as exc: + resp = self.handle_error(request, 500, exc) + resp, reset = await self.finish_response(request, resp, start_time) + else: + # Deprecation warning (See #2415) + if getattr(resp, "__http_exception__", False): + warnings.warn( + "returning HTTPException object is deprecated " + "(#2415) and will be removed, " + "please raise the exception instead", + DeprecationWarning, + ) + + resp, reset = await self.finish_response(request, resp, start_time) + finally: + self._request_in_progress = False + if self._handler_waiter is not None: + self._handler_waiter.set_result(None) + + return resp, reset + + async def start(self) -> None: + """Process incoming request. + + It reads request line, request headers and request payload, then + calls handle_request() method. Subclass has to override + handle_request(). start() handles various exceptions in request + or response handling. Connection is being closed always unless + keep_alive(True) specified. + """ + loop = self._loop + manager = self._manager + assert manager is not None + keepalive_timeout = self._keepalive_timeout + resp = None + assert self._request_factory is not None + assert self._request_handler is not None + + while not self._force_close: + if not self._messages: + try: + # wait for next request + self._waiter = loop.create_future() + await self._waiter + finally: + self._waiter = None + + message, payload = self._messages.popleft() + + # time is only fetched if logging is enabled as otherwise + # its thrown away and never used. + start = loop.time() if self._logging_enabled else None + + manager.requests_count += 1 + writer = StreamWriter(self, loop) + if isinstance(message, _ErrInfo): + # make request_factory work + request_handler = self._make_error_handler(message) + message = ERROR + else: + request_handler = self._request_handler + + # Important don't hold a reference to the current task + # as on traceback it will prevent the task from being + # collected and will cause a memory leak. + request = self._request_factory( + message, + payload, + self, + writer, + self._task_handler or asyncio.current_task(loop), # type: ignore[arg-type] + ) + try: + # a new task is used for copy context vars (#3406) + coro = self._handle_request(request, start, request_handler) + if sys.version_info >= (3, 12): + task = asyncio.Task(coro, loop=loop, eager_start=True) + else: + task = loop.create_task(coro) + try: + resp, reset = await task + except ConnectionError: + self.log_debug("Ignored premature client disconnection") + break + + # Drop the processed task from asyncio.Task.all_tasks() early + del task + if reset: + self.log_debug("Ignored premature client disconnection 2") + break + + # notify server about keep-alive + self._keepalive = bool(resp.keep_alive) + + # check payload + if not payload.is_eof(): + lingering_time = self._lingering_time + if not self._force_close and lingering_time: + self.log_debug( + "Start lingering close timer for %s sec.", lingering_time + ) + + now = loop.time() + end_t = now + lingering_time + + try: + while not payload.is_eof() and now < end_t: + async with ceil_timeout(end_t - now): + # read and ignore + await payload.readany() + now = loop.time() + except (asyncio.CancelledError, asyncio.TimeoutError): + if ( + sys.version_info >= (3, 11) + and (t := asyncio.current_task()) + and t.cancelling() + ): + raise + + # if payload still uncompleted + if not payload.is_eof() and not self._force_close: + self.log_debug("Uncompleted request.") + self.close() + + payload.set_exception(_PAYLOAD_ACCESS_ERROR) + + except asyncio.CancelledError: + self.log_debug("Ignored premature client disconnection") + self.force_close() + raise + except Exception as exc: + self.log_exception("Unhandled exception", exc_info=exc) + self.force_close() + except BaseException: + self.force_close() + raise + finally: + request._task = None # type: ignore[assignment] # Break reference cycle in case of exception + if self.transport is None and resp is not None: + self.log_debug("Ignored premature client disconnection.") + + if self._keepalive and not self._close and not self._force_close: + # start keep-alive timer + close_time = loop.time() + keepalive_timeout + self._next_keepalive_close_time = close_time + if self._keepalive_handle is None: + self._keepalive_handle = loop.call_at( + close_time, self._process_keepalive + ) + else: + break + + # remove handler, close transport if no handlers left + if not self._force_close: + self._task_handler = None + if self.transport is not None: + self.transport.close() + + async def finish_response( + self, request: BaseRequest, resp: StreamResponse, start_time: Optional[float] + ) -> Tuple[StreamResponse, bool]: + """Prepare the response and write_eof, then log access. + + This has to + be called within the context of any exception so the access logger + can get exception information. Returns True if the client disconnects + prematurely. + """ + request._finish() + if self._request_parser is not None: + self._request_parser.set_upgraded(False) + self._upgrade = False + if self._message_tail: + self._request_parser.feed_data(self._message_tail) + self._message_tail = b"" + try: + prepare_meth = resp.prepare + except AttributeError: + if resp is None: + self.log_exception("Missing return statement on request handler") + else: + self.log_exception( + "Web-handler should return a response instance, " + "got {!r}".format(resp) + ) + exc = HTTPInternalServerError() + resp = Response( + status=exc.status, reason=exc.reason, text=exc.text, headers=exc.headers + ) + prepare_meth = resp.prepare + try: + await prepare_meth(request) + await resp.write_eof() + except ConnectionError: + self.log_access(request, resp, start_time) + return resp, True + + self.log_access(request, resp, start_time) + return resp, False + + def handle_error( + self, + request: BaseRequest, + status: int = 500, + exc: Optional[BaseException] = None, + message: Optional[str] = None, + ) -> StreamResponse: + """Handle errors. + + Returns HTTP response with specific status code. Logs additional + information. It always closes current connection. + """ + if self._request_count == 1 and isinstance(exc, BadHttpMethod): + # BadHttpMethod is common when a client sends non-HTTP + # or encrypted traffic to an HTTP port. This is expected + # to happen when connected to the public internet so we log + # it at the debug level as to not fill logs with noise. + self.logger.debug( + "Error handling request from %s", request.remote, exc_info=exc + ) + else: + self.log_exception( + "Error handling request from %s", request.remote, exc_info=exc + ) + + # some data already got sent, connection is broken + if request.writer.output_size > 0: + raise ConnectionError( + "Response is sent already, cannot send another response " + "with the error message" + ) + + ct = "text/plain" + if status == HTTPStatus.INTERNAL_SERVER_ERROR: + title = "{0.value} {0.phrase}".format(HTTPStatus.INTERNAL_SERVER_ERROR) + msg = HTTPStatus.INTERNAL_SERVER_ERROR.description + tb = None + if self.debug: + with suppress(Exception): + tb = traceback.format_exc() + + if "text/html" in request.headers.get("Accept", ""): + if tb: + tb = html_escape(tb) + msg = f"

    Traceback:

    \n
    {tb}
    " + message = ( + "" + "{title}" + "\n

    {title}

    " + "\n{msg}\n\n" + ).format(title=title, msg=msg) + ct = "text/html" + else: + if tb: + msg = tb + message = title + "\n\n" + msg + + resp = Response(status=status, text=message, content_type=ct) + resp.force_close() + + return resp + + def _make_error_handler( + self, err_info: _ErrInfo + ) -> Callable[[BaseRequest], Awaitable[StreamResponse]]: + async def handler(request: BaseRequest) -> StreamResponse: + return self.handle_error( + request, err_info.status, err_info.exc, err_info.message + ) + + return handler diff --git a/venv/lib/python3.12/site-packages/aiohttp/web_request.py b/venv/lib/python3.12/site-packages/aiohttp/web_request.py new file mode 100644 index 00000000..6bf5a9de --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/web_request.py @@ -0,0 +1,914 @@ +import asyncio +import datetime +import io +import re +import socket +import string +import tempfile +import types +import warnings +from http.cookies import SimpleCookie +from types import MappingProxyType +from typing import ( + TYPE_CHECKING, + Any, + Dict, + Final, + Iterator, + Mapping, + MutableMapping, + Optional, + Pattern, + Tuple, + Union, + cast, +) +from urllib.parse import parse_qsl + +import attr +from multidict import ( + CIMultiDict, + CIMultiDictProxy, + MultiDict, + MultiDictProxy, + MultiMapping, +) +from yarl import URL + +from . import hdrs +from .abc import AbstractStreamWriter +from .helpers import ( + _SENTINEL, + DEBUG, + ETAG_ANY, + LIST_QUOTED_ETAG_RE, + ChainMapProxy, + ETag, + HeadersMixin, + parse_http_date, + reify, + sentinel, + set_exception, +) +from .http_parser import RawRequestMessage +from .http_writer import HttpVersion +from .multipart import BodyPartReader, MultipartReader +from .streams import EmptyStreamReader, StreamReader +from .typedefs import ( + DEFAULT_JSON_DECODER, + JSONDecoder, + LooseHeaders, + RawHeaders, + StrOrURL, +) +from .web_exceptions import HTTPRequestEntityTooLarge +from .web_response import StreamResponse + +__all__ = ("BaseRequest", "FileField", "Request") + + +if TYPE_CHECKING: + from .web_app import Application + from .web_protocol import RequestHandler + from .web_urldispatcher import UrlMappingMatchInfo + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class FileField: + name: str + filename: str + file: io.BufferedReader + content_type: str + headers: CIMultiDictProxy[str] + + +_TCHAR: Final[str] = string.digits + string.ascii_letters + r"!#$%&'*+.^_`|~-" +# '-' at the end to prevent interpretation as range in a char class + +_TOKEN: Final[str] = rf"[{_TCHAR}]+" + +_QDTEXT: Final[str] = r"[{}]".format( + r"".join(chr(c) for c in (0x09, 0x20, 0x21) + tuple(range(0x23, 0x7F))) +) +# qdtext includes 0x5C to escape 0x5D ('\]') +# qdtext excludes obs-text (because obsoleted, and encoding not specified) + +_QUOTED_PAIR: Final[str] = r"\\[\t !-~]" + +_QUOTED_STRING: Final[str] = r'"(?:{quoted_pair}|{qdtext})*"'.format( + qdtext=_QDTEXT, quoted_pair=_QUOTED_PAIR +) + +_FORWARDED_PAIR: Final[str] = ( + r"({token})=({token}|{quoted_string})(:\d{{1,4}})?".format( + token=_TOKEN, quoted_string=_QUOTED_STRING + ) +) + +_QUOTED_PAIR_REPLACE_RE: Final[Pattern[str]] = re.compile(r"\\([\t !-~])") +# same pattern as _QUOTED_PAIR but contains a capture group + +_FORWARDED_PAIR_RE: Final[Pattern[str]] = re.compile(_FORWARDED_PAIR) + +############################################################ +# HTTP Request +############################################################ + + +class BaseRequest(MutableMapping[str, Any], HeadersMixin): + + POST_METHODS = { + hdrs.METH_PATCH, + hdrs.METH_POST, + hdrs.METH_PUT, + hdrs.METH_TRACE, + hdrs.METH_DELETE, + } + + ATTRS = HeadersMixin.ATTRS | frozenset( + [ + "_message", + "_protocol", + "_payload_writer", + "_payload", + "_headers", + "_method", + "_version", + "_rel_url", + "_post", + "_read_bytes", + "_state", + "_cache", + "_task", + "_client_max_size", + "_loop", + "_transport_sslcontext", + "_transport_peername", + ] + ) + _post: Optional[MultiDictProxy[Union[str, bytes, FileField]]] = None + _read_bytes: Optional[bytes] = None + + def __init__( + self, + message: RawRequestMessage, + payload: StreamReader, + protocol: "RequestHandler", + payload_writer: AbstractStreamWriter, + task: "asyncio.Task[None]", + loop: asyncio.AbstractEventLoop, + *, + client_max_size: int = 1024**2, + state: Optional[Dict[str, Any]] = None, + scheme: Optional[str] = None, + host: Optional[str] = None, + remote: Optional[str] = None, + ) -> None: + self._message = message + self._protocol = protocol + self._payload_writer = payload_writer + + self._payload = payload + self._headers: CIMultiDictProxy[str] = message.headers + self._method = message.method + self._version = message.version + self._cache: Dict[str, Any] = {} + url = message.url + if url.absolute: + if scheme is not None: + url = url.with_scheme(scheme) + if host is not None: + url = url.with_host(host) + # absolute URL is given, + # override auto-calculating url, host, and scheme + # all other properties should be good + self._cache["url"] = url + self._cache["host"] = url.host + self._cache["scheme"] = url.scheme + self._rel_url = url.relative() + else: + self._rel_url = url + if scheme is not None: + self._cache["scheme"] = scheme + if host is not None: + self._cache["host"] = host + + self._state = {} if state is None else state + self._task = task + self._client_max_size = client_max_size + self._loop = loop + + self._transport_sslcontext = protocol.ssl_context + self._transport_peername = protocol.peername + + if remote is not None: + self._cache["remote"] = remote + + def clone( + self, + *, + method: Union[str, _SENTINEL] = sentinel, + rel_url: Union[StrOrURL, _SENTINEL] = sentinel, + headers: Union[LooseHeaders, _SENTINEL] = sentinel, + scheme: Union[str, _SENTINEL] = sentinel, + host: Union[str, _SENTINEL] = sentinel, + remote: Union[str, _SENTINEL] = sentinel, + client_max_size: Union[int, _SENTINEL] = sentinel, + ) -> "BaseRequest": + """Clone itself with replacement some attributes. + + Creates and returns a new instance of Request object. If no parameters + are given, an exact copy is returned. If a parameter is not passed, it + will reuse the one from the current request object. + """ + if self._read_bytes: + raise RuntimeError("Cannot clone request after reading its content") + + dct: Dict[str, Any] = {} + if method is not sentinel: + dct["method"] = method + if rel_url is not sentinel: + new_url: URL = URL(rel_url) + dct["url"] = new_url + dct["path"] = str(new_url) + if headers is not sentinel: + # a copy semantic + dct["headers"] = CIMultiDictProxy(CIMultiDict(headers)) + dct["raw_headers"] = tuple( + (k.encode("utf-8"), v.encode("utf-8")) + for k, v in dct["headers"].items() + ) + + message = self._message._replace(**dct) + + kwargs = {} + if scheme is not sentinel: + kwargs["scheme"] = scheme + if host is not sentinel: + kwargs["host"] = host + if remote is not sentinel: + kwargs["remote"] = remote + if client_max_size is sentinel: + client_max_size = self._client_max_size + + return self.__class__( + message, + self._payload, + self._protocol, + self._payload_writer, + self._task, + self._loop, + client_max_size=client_max_size, + state=self._state.copy(), + **kwargs, + ) + + @property + def task(self) -> "asyncio.Task[None]": + return self._task + + @property + def protocol(self) -> "RequestHandler": + return self._protocol + + @property + def transport(self) -> Optional[asyncio.Transport]: + if self._protocol is None: + return None + return self._protocol.transport + + @property + def writer(self) -> AbstractStreamWriter: + return self._payload_writer + + @property + def client_max_size(self) -> int: + return self._client_max_size + + @reify + def message(self) -> RawRequestMessage: + warnings.warn("Request.message is deprecated", DeprecationWarning, stacklevel=3) + return self._message + + @reify + def rel_url(self) -> URL: + return self._rel_url + + @reify + def loop(self) -> asyncio.AbstractEventLoop: + warnings.warn( + "request.loop property is deprecated", DeprecationWarning, stacklevel=2 + ) + return self._loop + + # MutableMapping API + + def __getitem__(self, key: str) -> Any: + return self._state[key] + + def __setitem__(self, key: str, value: Any) -> None: + self._state[key] = value + + def __delitem__(self, key: str) -> None: + del self._state[key] + + def __len__(self) -> int: + return len(self._state) + + def __iter__(self) -> Iterator[str]: + return iter(self._state) + + ######## + + @reify + def secure(self) -> bool: + """A bool indicating if the request is handled with SSL.""" + return self.scheme == "https" + + @reify + def forwarded(self) -> Tuple[Mapping[str, str], ...]: + """A tuple containing all parsed Forwarded header(s). + + Makes an effort to parse Forwarded headers as specified by RFC 7239: + + - It adds one (immutable) dictionary per Forwarded 'field-value', ie + per proxy. The element corresponds to the data in the Forwarded + field-value added by the first proxy encountered by the client. Each + subsequent item corresponds to those added by later proxies. + - It checks that every value has valid syntax in general as specified + in section 4: either a 'token' or a 'quoted-string'. + - It un-escapes found escape sequences. + - It does NOT validate 'by' and 'for' contents as specified in section + 6. + - It does NOT validate 'host' contents (Host ABNF). + - It does NOT validate 'proto' contents for valid URI scheme names. + + Returns a tuple containing one or more immutable dicts + """ + elems = [] + for field_value in self._message.headers.getall(hdrs.FORWARDED, ()): + length = len(field_value) + pos = 0 + need_separator = False + elem: Dict[str, str] = {} + elems.append(types.MappingProxyType(elem)) + while 0 <= pos < length: + match = _FORWARDED_PAIR_RE.match(field_value, pos) + if match is not None: # got a valid forwarded-pair + if need_separator: + # bad syntax here, skip to next comma + pos = field_value.find(",", pos) + else: + name, value, port = match.groups() + if value[0] == '"': + # quoted string: remove quotes and unescape + value = _QUOTED_PAIR_REPLACE_RE.sub(r"\1", value[1:-1]) + if port: + value += port + elem[name.lower()] = value + pos += len(match.group(0)) + need_separator = True + elif field_value[pos] == ",": # next forwarded-element + need_separator = False + elem = {} + elems.append(types.MappingProxyType(elem)) + pos += 1 + elif field_value[pos] == ";": # next forwarded-pair + need_separator = False + pos += 1 + elif field_value[pos] in " \t": + # Allow whitespace even between forwarded-pairs, though + # RFC 7239 doesn't. This simplifies code and is in line + # with Postel's law. + pos += 1 + else: + # bad syntax here, skip to next comma + pos = field_value.find(",", pos) + return tuple(elems) + + @reify + def scheme(self) -> str: + """A string representing the scheme of the request. + + Hostname is resolved in this order: + + - overridden value by .clone(scheme=new_scheme) call. + - type of connection to peer: HTTPS if socket is SSL, HTTP otherwise. + + 'http' or 'https'. + """ + if self._transport_sslcontext: + return "https" + else: + return "http" + + @reify + def method(self) -> str: + """Read only property for getting HTTP method. + + The value is upper-cased str like 'GET', 'POST', 'PUT' etc. + """ + return self._method + + @reify + def version(self) -> HttpVersion: + """Read only property for getting HTTP version of request. + + Returns aiohttp.protocol.HttpVersion instance. + """ + return self._version + + @reify + def host(self) -> str: + """Hostname of the request. + + Hostname is resolved in this order: + + - overridden value by .clone(host=new_host) call. + - HOST HTTP header + - socket.getfqdn() value + + For example, 'example.com' or 'localhost:8080'. + + For historical reasons, the port number may be included. + """ + host = self._message.headers.get(hdrs.HOST) + if host is not None: + return host + return socket.getfqdn() + + @reify + def remote(self) -> Optional[str]: + """Remote IP of client initiated HTTP request. + + The IP is resolved in this order: + + - overridden value by .clone(remote=new_remote) call. + - peername of opened socket + """ + if self._transport_peername is None: + return None + if isinstance(self._transport_peername, (list, tuple)): + return str(self._transport_peername[0]) + return str(self._transport_peername) + + @reify + def url(self) -> URL: + """The full URL of the request.""" + # authority is used here because it may include the port number + # and we want yarl to parse it correctly + return URL.build(scheme=self.scheme, authority=self.host).join(self._rel_url) + + @reify + def path(self) -> str: + """The URL including *PATH INFO* without the host or scheme. + + E.g., ``/app/blog`` + """ + return self._rel_url.path + + @reify + def path_qs(self) -> str: + """The URL including PATH_INFO and the query string. + + E.g, /app/blog?id=10 + """ + return str(self._rel_url) + + @reify + def raw_path(self) -> str: + """The URL including raw *PATH INFO* without the host or scheme. + + Warning, the path is unquoted and may contains non valid URL characters + + E.g., ``/my%2Fpath%7Cwith%21some%25strange%24characters`` + """ + return self._message.path + + @reify + def query(self) -> "MultiMapping[str]": + """A multidict with all the variables in the query string.""" + return self._rel_url.query + + @reify + def query_string(self) -> str: + """The query string in the URL. + + E.g., id=10 + """ + return self._rel_url.query_string + + @reify + def headers(self) -> CIMultiDictProxy[str]: + """A case-insensitive multidict proxy with all headers.""" + return self._headers + + @reify + def raw_headers(self) -> RawHeaders: + """A sequence of pairs for all headers.""" + return self._message.raw_headers + + @reify + def if_modified_since(self) -> Optional[datetime.datetime]: + """The value of If-Modified-Since HTTP header, or None. + + This header is represented as a `datetime` object. + """ + return parse_http_date(self.headers.get(hdrs.IF_MODIFIED_SINCE)) + + @reify + def if_unmodified_since(self) -> Optional[datetime.datetime]: + """The value of If-Unmodified-Since HTTP header, or None. + + This header is represented as a `datetime` object. + """ + return parse_http_date(self.headers.get(hdrs.IF_UNMODIFIED_SINCE)) + + @staticmethod + def _etag_values(etag_header: str) -> Iterator[ETag]: + """Extract `ETag` objects from raw header.""" + if etag_header == ETAG_ANY: + yield ETag( + is_weak=False, + value=ETAG_ANY, + ) + else: + for match in LIST_QUOTED_ETAG_RE.finditer(etag_header): + is_weak, value, garbage = match.group(2, 3, 4) + # Any symbol captured by 4th group means + # that the following sequence is invalid. + if garbage: + break + + yield ETag( + is_weak=bool(is_weak), + value=value, + ) + + @classmethod + def _if_match_or_none_impl( + cls, header_value: Optional[str] + ) -> Optional[Tuple[ETag, ...]]: + if not header_value: + return None + + return tuple(cls._etag_values(header_value)) + + @reify + def if_match(self) -> Optional[Tuple[ETag, ...]]: + """The value of If-Match HTTP header, or None. + + This header is represented as a `tuple` of `ETag` objects. + """ + return self._if_match_or_none_impl(self.headers.get(hdrs.IF_MATCH)) + + @reify + def if_none_match(self) -> Optional[Tuple[ETag, ...]]: + """The value of If-None-Match HTTP header, or None. + + This header is represented as a `tuple` of `ETag` objects. + """ + return self._if_match_or_none_impl(self.headers.get(hdrs.IF_NONE_MATCH)) + + @reify + def if_range(self) -> Optional[datetime.datetime]: + """The value of If-Range HTTP header, or None. + + This header is represented as a `datetime` object. + """ + return parse_http_date(self.headers.get(hdrs.IF_RANGE)) + + @reify + def keep_alive(self) -> bool: + """Is keepalive enabled by client?""" + return not self._message.should_close + + @reify + def cookies(self) -> Mapping[str, str]: + """Return request cookies. + + A read-only dictionary-like object. + """ + raw = self.headers.get(hdrs.COOKIE, "") + parsed = SimpleCookie(raw) + return MappingProxyType({key: val.value for key, val in parsed.items()}) + + @reify + def http_range(self) -> slice: + """The content of Range HTTP header. + + Return a slice instance. + + """ + rng = self._headers.get(hdrs.RANGE) + start, end = None, None + if rng is not None: + try: + pattern = r"^bytes=(\d*)-(\d*)$" + start, end = re.findall(pattern, rng)[0] + except IndexError: # pattern was not found in header + raise ValueError("range not in acceptable format") + + end = int(end) if end else None + start = int(start) if start else None + + if start is None and end is not None: + # end with no start is to return tail of content + start = -end + end = None + + if start is not None and end is not None: + # end is inclusive in range header, exclusive for slice + end += 1 + + if start >= end: + raise ValueError("start cannot be after end") + + if start is end is None: # No valid range supplied + raise ValueError("No start or end of range specified") + + return slice(start, end, 1) + + @reify + def content(self) -> StreamReader: + """Return raw payload stream.""" + return self._payload + + @property + def has_body(self) -> bool: + """Return True if request's HTTP BODY can be read, False otherwise.""" + warnings.warn( + "Deprecated, use .can_read_body #2005", DeprecationWarning, stacklevel=2 + ) + return not self._payload.at_eof() + + @property + def can_read_body(self) -> bool: + """Return True if request's HTTP BODY can be read, False otherwise.""" + return not self._payload.at_eof() + + @reify + def body_exists(self) -> bool: + """Return True if request has HTTP BODY, False otherwise.""" + return type(self._payload) is not EmptyStreamReader + + async def release(self) -> None: + """Release request. + + Eat unread part of HTTP BODY if present. + """ + while not self._payload.at_eof(): + await self._payload.readany() + + async def read(self) -> bytes: + """Read request body if present. + + Returns bytes object with full request content. + """ + if self._read_bytes is None: + body = bytearray() + while True: + chunk = await self._payload.readany() + body.extend(chunk) + if self._client_max_size: + body_size = len(body) + if body_size >= self._client_max_size: + raise HTTPRequestEntityTooLarge( + max_size=self._client_max_size, actual_size=body_size + ) + if not chunk: + break + self._read_bytes = bytes(body) + return self._read_bytes + + async def text(self) -> str: + """Return BODY as text using encoding from .charset.""" + bytes_body = await self.read() + encoding = self.charset or "utf-8" + return bytes_body.decode(encoding) + + async def json(self, *, loads: JSONDecoder = DEFAULT_JSON_DECODER) -> Any: + """Return BODY as JSON.""" + body = await self.text() + return loads(body) + + async def multipart(self) -> MultipartReader: + """Return async iterator to process BODY as multipart.""" + return MultipartReader(self._headers, self._payload) + + async def post(self) -> "MultiDictProxy[Union[str, bytes, FileField]]": + """Return POST parameters.""" + if self._post is not None: + return self._post + if self._method not in self.POST_METHODS: + self._post = MultiDictProxy(MultiDict()) + return self._post + + content_type = self.content_type + if content_type not in ( + "", + "application/x-www-form-urlencoded", + "multipart/form-data", + ): + self._post = MultiDictProxy(MultiDict()) + return self._post + + out: MultiDict[Union[str, bytes, FileField]] = MultiDict() + + if content_type == "multipart/form-data": + multipart = await self.multipart() + max_size = self._client_max_size + + field = await multipart.next() + while field is not None: + size = 0 + field_ct = field.headers.get(hdrs.CONTENT_TYPE) + + if isinstance(field, BodyPartReader): + assert field.name is not None + + # Note that according to RFC 7578, the Content-Type header + # is optional, even for files, so we can't assume it's + # present. + # https://tools.ietf.org/html/rfc7578#section-4.4 + if field.filename: + # store file in temp file + tmp = await self._loop.run_in_executor( + None, tempfile.TemporaryFile + ) + chunk = await field.read_chunk(size=2**16) + while chunk: + chunk = field.decode(chunk) + await self._loop.run_in_executor(None, tmp.write, chunk) + size += len(chunk) + if 0 < max_size < size: + await self._loop.run_in_executor(None, tmp.close) + raise HTTPRequestEntityTooLarge( + max_size=max_size, actual_size=size + ) + chunk = await field.read_chunk(size=2**16) + await self._loop.run_in_executor(None, tmp.seek, 0) + + if field_ct is None: + field_ct = "application/octet-stream" + + ff = FileField( + field.name, + field.filename, + cast(io.BufferedReader, tmp), + field_ct, + field.headers, + ) + out.add(field.name, ff) + else: + # deal with ordinary data + value = await field.read(decode=True) + if field_ct is None or field_ct.startswith("text/"): + charset = field.get_charset(default="utf-8") + out.add(field.name, value.decode(charset)) + else: + out.add(field.name, value) + size += len(value) + if 0 < max_size < size: + raise HTTPRequestEntityTooLarge( + max_size=max_size, actual_size=size + ) + else: + raise ValueError( + "To decode nested multipart you need to use custom reader", + ) + + field = await multipart.next() + else: + data = await self.read() + if data: + charset = self.charset or "utf-8" + out.extend( + parse_qsl( + data.rstrip().decode(charset), + keep_blank_values=True, + encoding=charset, + ) + ) + + self._post = MultiDictProxy(out) + return self._post + + def get_extra_info(self, name: str, default: Any = None) -> Any: + """Extra info from protocol transport""" + protocol = self._protocol + if protocol is None: + return default + + transport = protocol.transport + if transport is None: + return default + + return transport.get_extra_info(name, default) + + def __repr__(self) -> str: + ascii_encodable_path = self.path.encode("ascii", "backslashreplace").decode( + "ascii" + ) + return "<{} {} {} >".format( + self.__class__.__name__, self._method, ascii_encodable_path + ) + + def __eq__(self, other: object) -> bool: + return id(self) == id(other) + + def __bool__(self) -> bool: + return True + + async def _prepare_hook(self, response: StreamResponse) -> None: + return + + def _cancel(self, exc: BaseException) -> None: + set_exception(self._payload, exc) + + def _finish(self) -> None: + if self._post is None or self.content_type != "multipart/form-data": + return + + # NOTE: Release file descriptors for the + # NOTE: `tempfile.Temporaryfile`-created `_io.BufferedRandom` + # NOTE: instances of files sent within multipart request body + # NOTE: via HTTP POST request. + for file_name, file_field_object in self._post.items(): + if isinstance(file_field_object, FileField): + file_field_object.file.close() + + +class Request(BaseRequest): + + ATTRS = BaseRequest.ATTRS | frozenset(["_match_info"]) + + _match_info: Optional["UrlMappingMatchInfo"] = None + + if DEBUG: + + def __setattr__(self, name: str, val: Any) -> None: + if name not in self.ATTRS: + warnings.warn( + "Setting custom {}.{} attribute " + "is discouraged".format(self.__class__.__name__, name), + DeprecationWarning, + stacklevel=2, + ) + super().__setattr__(name, val) + + def clone( + self, + *, + method: Union[str, _SENTINEL] = sentinel, + rel_url: Union[StrOrURL, _SENTINEL] = sentinel, + headers: Union[LooseHeaders, _SENTINEL] = sentinel, + scheme: Union[str, _SENTINEL] = sentinel, + host: Union[str, _SENTINEL] = sentinel, + remote: Union[str, _SENTINEL] = sentinel, + client_max_size: Union[int, _SENTINEL] = sentinel, + ) -> "Request": + ret = super().clone( + method=method, + rel_url=rel_url, + headers=headers, + scheme=scheme, + host=host, + remote=remote, + client_max_size=client_max_size, + ) + new_ret = cast(Request, ret) + new_ret._match_info = self._match_info + return new_ret + + @reify + def match_info(self) -> "UrlMappingMatchInfo": + """Result of route resolving.""" + match_info = self._match_info + assert match_info is not None + return match_info + + @property + def app(self) -> "Application": + """Application instance.""" + match_info = self._match_info + assert match_info is not None + return match_info.current_app + + @property + def config_dict(self) -> ChainMapProxy: + match_info = self._match_info + assert match_info is not None + lst = match_info.apps + app = self.app + idx = lst.index(app) + sublist = list(reversed(lst[: idx + 1])) + return ChainMapProxy(sublist) + + async def _prepare_hook(self, response: StreamResponse) -> None: + match_info = self._match_info + if match_info is None: + return + for app in match_info._apps: + if on_response_prepare := app.on_response_prepare: + await on_response_prepare.send(self, response) diff --git a/venv/lib/python3.12/site-packages/aiohttp/web_response.py b/venv/lib/python3.12/site-packages/aiohttp/web_response.py new file mode 100644 index 00000000..367ac6e8 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/web_response.py @@ -0,0 +1,838 @@ +import asyncio +import collections.abc +import datetime +import enum +import json +import math +import time +import warnings +import zlib +from concurrent.futures import Executor +from http import HTTPStatus +from http.cookies import SimpleCookie +from typing import ( + TYPE_CHECKING, + Any, + Dict, + Iterator, + MutableMapping, + Optional, + Union, + cast, +) + +from multidict import CIMultiDict, istr + +from . import hdrs, payload +from .abc import AbstractStreamWriter +from .compression_utils import ZLibCompressor +from .helpers import ( + ETAG_ANY, + QUOTED_ETAG_RE, + ETag, + HeadersMixin, + must_be_empty_body, + parse_http_date, + rfc822_formatted_time, + sentinel, + should_remove_content_length, + validate_etag_value, +) +from .http import SERVER_SOFTWARE, HttpVersion10, HttpVersion11 +from .payload import Payload +from .typedefs import JSONEncoder, LooseHeaders + +REASON_PHRASES = {http_status.value: http_status.phrase for http_status in HTTPStatus} +LARGE_BODY_SIZE = 1024**2 + +__all__ = ("ContentCoding", "StreamResponse", "Response", "json_response") + + +if TYPE_CHECKING: + from .web_request import BaseRequest + + BaseClass = MutableMapping[str, Any] +else: + BaseClass = collections.abc.MutableMapping + + +# TODO(py311): Convert to StrEnum for wider use +class ContentCoding(enum.Enum): + # The content codings that we have support for. + # + # Additional registered codings are listed at: + # https://www.iana.org/assignments/http-parameters/http-parameters.xhtml#content-coding + deflate = "deflate" + gzip = "gzip" + identity = "identity" + + +CONTENT_CODINGS = {coding.value: coding for coding in ContentCoding} + +############################################################ +# HTTP Response classes +############################################################ + + +class StreamResponse(BaseClass, HeadersMixin): + + _body: Union[None, bytes, bytearray, Payload] + _length_check = True + _body = None + _keep_alive: Optional[bool] = None + _chunked: bool = False + _compression: bool = False + _compression_strategy: int = zlib.Z_DEFAULT_STRATEGY + _compression_force: Optional[ContentCoding] = None + _req: Optional["BaseRequest"] = None + _payload_writer: Optional[AbstractStreamWriter] = None + _eof_sent: bool = False + _must_be_empty_body: Optional[bool] = None + _body_length = 0 + _cookies: Optional[SimpleCookie] = None + + def __init__( + self, + *, + status: int = 200, + reason: Optional[str] = None, + headers: Optional[LooseHeaders] = None, + _real_headers: Optional[CIMultiDict[str]] = None, + ) -> None: + """Initialize a new stream response object. + + _real_headers is an internal parameter used to pass a pre-populated + headers object. It is used by the `Response` class to avoid copying + the headers when creating a new response object. It is not intended + to be used by external code. + """ + self._state: Dict[str, Any] = {} + + if _real_headers is not None: + self._headers = _real_headers + elif headers is not None: + self._headers: CIMultiDict[str] = CIMultiDict(headers) + else: + self._headers = CIMultiDict() + + self._set_status(status, reason) + + @property + def prepared(self) -> bool: + return self._eof_sent or self._payload_writer is not None + + @property + def task(self) -> "Optional[asyncio.Task[None]]": + if self._req: + return self._req.task + else: + return None + + @property + def status(self) -> int: + return self._status + + @property + def chunked(self) -> bool: + return self._chunked + + @property + def compression(self) -> bool: + return self._compression + + @property + def reason(self) -> str: + return self._reason + + def set_status( + self, + status: int, + reason: Optional[str] = None, + ) -> None: + assert ( + not self.prepared + ), "Cannot change the response status code after the headers have been sent" + self._set_status(status, reason) + + def _set_status(self, status: int, reason: Optional[str]) -> None: + self._status = int(status) + if reason is None: + reason = REASON_PHRASES.get(self._status, "") + elif "\n" in reason: + raise ValueError("Reason cannot contain \\n") + self._reason = reason + + @property + def keep_alive(self) -> Optional[bool]: + return self._keep_alive + + def force_close(self) -> None: + self._keep_alive = False + + @property + def body_length(self) -> int: + return self._body_length + + @property + def output_length(self) -> int: + warnings.warn("output_length is deprecated", DeprecationWarning) + assert self._payload_writer + return self._payload_writer.buffer_size + + def enable_chunked_encoding(self, chunk_size: Optional[int] = None) -> None: + """Enables automatic chunked transfer encoding.""" + if hdrs.CONTENT_LENGTH in self._headers: + raise RuntimeError( + "You can't enable chunked encoding when a content length is set" + ) + if chunk_size is not None: + warnings.warn("Chunk size is deprecated #1615", DeprecationWarning) + self._chunked = True + + def enable_compression( + self, + force: Optional[Union[bool, ContentCoding]] = None, + strategy: int = zlib.Z_DEFAULT_STRATEGY, + ) -> None: + """Enables response compression encoding.""" + # Backwards compatibility for when force was a bool <0.17. + if isinstance(force, bool): + force = ContentCoding.deflate if force else ContentCoding.identity + warnings.warn( + "Using boolean for force is deprecated #3318", DeprecationWarning + ) + elif force is not None: + assert isinstance( + force, ContentCoding + ), "force should one of None, bool or ContentEncoding" + + self._compression = True + self._compression_force = force + self._compression_strategy = strategy + + @property + def headers(self) -> "CIMultiDict[str]": + return self._headers + + @property + def cookies(self) -> SimpleCookie: + if self._cookies is None: + self._cookies = SimpleCookie() + return self._cookies + + def set_cookie( + self, + name: str, + value: str, + *, + expires: Optional[str] = None, + domain: Optional[str] = None, + max_age: Optional[Union[int, str]] = None, + path: str = "/", + secure: Optional[bool] = None, + httponly: Optional[bool] = None, + version: Optional[str] = None, + samesite: Optional[str] = None, + ) -> None: + """Set or update response cookie. + + Sets new cookie or updates existent with new value. + Also updates only those params which are not None. + """ + if self._cookies is None: + self._cookies = SimpleCookie() + + self._cookies[name] = value + c = self._cookies[name] + + if expires is not None: + c["expires"] = expires + elif c.get("expires") == "Thu, 01 Jan 1970 00:00:00 GMT": + del c["expires"] + + if domain is not None: + c["domain"] = domain + + if max_age is not None: + c["max-age"] = str(max_age) + elif "max-age" in c: + del c["max-age"] + + c["path"] = path + + if secure is not None: + c["secure"] = secure + if httponly is not None: + c["httponly"] = httponly + if version is not None: + c["version"] = version + if samesite is not None: + c["samesite"] = samesite + + def del_cookie( + self, + name: str, + *, + domain: Optional[str] = None, + path: str = "/", + secure: Optional[bool] = None, + httponly: Optional[bool] = None, + samesite: Optional[str] = None, + ) -> None: + """Delete cookie. + + Creates new empty expired cookie. + """ + # TODO: do we need domain/path here? + if self._cookies is not None: + self._cookies.pop(name, None) + self.set_cookie( + name, + "", + max_age=0, + expires="Thu, 01 Jan 1970 00:00:00 GMT", + domain=domain, + path=path, + secure=secure, + httponly=httponly, + samesite=samesite, + ) + + @property + def content_length(self) -> Optional[int]: + # Just a placeholder for adding setter + return super().content_length + + @content_length.setter + def content_length(self, value: Optional[int]) -> None: + if value is not None: + value = int(value) + if self._chunked: + raise RuntimeError( + "You can't set content length when chunked encoding is enable" + ) + self._headers[hdrs.CONTENT_LENGTH] = str(value) + else: + self._headers.pop(hdrs.CONTENT_LENGTH, None) + + @property + def content_type(self) -> str: + # Just a placeholder for adding setter + return super().content_type + + @content_type.setter + def content_type(self, value: str) -> None: + self.content_type # read header values if needed + self._content_type = str(value) + self._generate_content_type_header() + + @property + def charset(self) -> Optional[str]: + # Just a placeholder for adding setter + return super().charset + + @charset.setter + def charset(self, value: Optional[str]) -> None: + ctype = self.content_type # read header values if needed + if ctype == "application/octet-stream": + raise RuntimeError( + "Setting charset for application/octet-stream " + "doesn't make sense, setup content_type first" + ) + assert self._content_dict is not None + if value is None: + self._content_dict.pop("charset", None) + else: + self._content_dict["charset"] = str(value).lower() + self._generate_content_type_header() + + @property + def last_modified(self) -> Optional[datetime.datetime]: + """The value of Last-Modified HTTP header, or None. + + This header is represented as a `datetime` object. + """ + return parse_http_date(self._headers.get(hdrs.LAST_MODIFIED)) + + @last_modified.setter + def last_modified( + self, value: Optional[Union[int, float, datetime.datetime, str]] + ) -> None: + if value is None: + self._headers.pop(hdrs.LAST_MODIFIED, None) + elif isinstance(value, (int, float)): + self._headers[hdrs.LAST_MODIFIED] = time.strftime( + "%a, %d %b %Y %H:%M:%S GMT", time.gmtime(math.ceil(value)) + ) + elif isinstance(value, datetime.datetime): + self._headers[hdrs.LAST_MODIFIED] = time.strftime( + "%a, %d %b %Y %H:%M:%S GMT", value.utctimetuple() + ) + elif isinstance(value, str): + self._headers[hdrs.LAST_MODIFIED] = value + + @property + def etag(self) -> Optional[ETag]: + quoted_value = self._headers.get(hdrs.ETAG) + if not quoted_value: + return None + elif quoted_value == ETAG_ANY: + return ETag(value=ETAG_ANY) + match = QUOTED_ETAG_RE.fullmatch(quoted_value) + if not match: + return None + is_weak, value = match.group(1, 2) + return ETag( + is_weak=bool(is_weak), + value=value, + ) + + @etag.setter + def etag(self, value: Optional[Union[ETag, str]]) -> None: + if value is None: + self._headers.pop(hdrs.ETAG, None) + elif (isinstance(value, str) and value == ETAG_ANY) or ( + isinstance(value, ETag) and value.value == ETAG_ANY + ): + self._headers[hdrs.ETAG] = ETAG_ANY + elif isinstance(value, str): + validate_etag_value(value) + self._headers[hdrs.ETAG] = f'"{value}"' + elif isinstance(value, ETag) and isinstance(value.value, str): + validate_etag_value(value.value) + hdr_value = f'W/"{value.value}"' if value.is_weak else f'"{value.value}"' + self._headers[hdrs.ETAG] = hdr_value + else: + raise ValueError( + f"Unsupported etag type: {type(value)}. " + f"etag must be str, ETag or None" + ) + + def _generate_content_type_header( + self, CONTENT_TYPE: istr = hdrs.CONTENT_TYPE + ) -> None: + assert self._content_dict is not None + assert self._content_type is not None + params = "; ".join(f"{k}={v}" for k, v in self._content_dict.items()) + if params: + ctype = self._content_type + "; " + params + else: + ctype = self._content_type + self._headers[CONTENT_TYPE] = ctype + + async def _do_start_compression(self, coding: ContentCoding) -> None: + if coding is ContentCoding.identity: + return + assert self._payload_writer is not None + self._headers[hdrs.CONTENT_ENCODING] = coding.value + self._payload_writer.enable_compression( + coding.value, self._compression_strategy + ) + # Compressed payload may have different content length, + # remove the header + self._headers.popall(hdrs.CONTENT_LENGTH, None) + + async def _start_compression(self, request: "BaseRequest") -> None: + if self._compression_force: + await self._do_start_compression(self._compression_force) + return + # Encoding comparisons should be case-insensitive + # https://www.rfc-editor.org/rfc/rfc9110#section-8.4.1 + accept_encoding = request.headers.get(hdrs.ACCEPT_ENCODING, "").lower() + for value, coding in CONTENT_CODINGS.items(): + if value in accept_encoding: + await self._do_start_compression(coding) + return + + async def prepare(self, request: "BaseRequest") -> Optional[AbstractStreamWriter]: + if self._eof_sent: + return None + if self._payload_writer is not None: + return self._payload_writer + self._must_be_empty_body = must_be_empty_body(request.method, self.status) + return await self._start(request) + + async def _start(self, request: "BaseRequest") -> AbstractStreamWriter: + self._req = request + writer = self._payload_writer = request._payload_writer + + await self._prepare_headers() + await request._prepare_hook(self) + await self._write_headers() + + return writer + + async def _prepare_headers(self) -> None: + request = self._req + assert request is not None + writer = self._payload_writer + assert writer is not None + keep_alive = self._keep_alive + if keep_alive is None: + keep_alive = request.keep_alive + self._keep_alive = keep_alive + + version = request.version + + headers = self._headers + if self._cookies: + for cookie in self._cookies.values(): + value = cookie.output(header="")[1:] + headers.add(hdrs.SET_COOKIE, value) + + if self._compression: + await self._start_compression(request) + + if self._chunked: + if version != HttpVersion11: + raise RuntimeError( + "Using chunked encoding is forbidden " + "for HTTP/{0.major}.{0.minor}".format(request.version) + ) + if not self._must_be_empty_body: + writer.enable_chunking() + headers[hdrs.TRANSFER_ENCODING] = "chunked" + elif self._length_check: # Disabled for WebSockets + writer.length = self.content_length + if writer.length is None: + if version >= HttpVersion11: + if not self._must_be_empty_body: + writer.enable_chunking() + headers[hdrs.TRANSFER_ENCODING] = "chunked" + elif not self._must_be_empty_body: + keep_alive = False + + # HTTP 1.1: https://tools.ietf.org/html/rfc7230#section-3.3.2 + # HTTP 1.0: https://tools.ietf.org/html/rfc1945#section-10.4 + if self._must_be_empty_body: + if hdrs.CONTENT_LENGTH in headers and should_remove_content_length( + request.method, self.status + ): + del headers[hdrs.CONTENT_LENGTH] + # https://datatracker.ietf.org/doc/html/rfc9112#section-6.1-10 + # https://datatracker.ietf.org/doc/html/rfc9112#section-6.1-13 + if hdrs.TRANSFER_ENCODING in headers: + del headers[hdrs.TRANSFER_ENCODING] + elif (writer.length if self._length_check else self.content_length) != 0: + # https://www.rfc-editor.org/rfc/rfc9110#section-8.3-5 + headers.setdefault(hdrs.CONTENT_TYPE, "application/octet-stream") + headers.setdefault(hdrs.DATE, rfc822_formatted_time()) + headers.setdefault(hdrs.SERVER, SERVER_SOFTWARE) + + # connection header + if hdrs.CONNECTION not in headers: + if keep_alive: + if version == HttpVersion10: + headers[hdrs.CONNECTION] = "keep-alive" + elif version == HttpVersion11: + headers[hdrs.CONNECTION] = "close" + + async def _write_headers(self) -> None: + request = self._req + assert request is not None + writer = self._payload_writer + assert writer is not None + # status line + version = request.version + status_line = f"HTTP/{version[0]}.{version[1]} {self._status} {self._reason}" + await writer.write_headers(status_line, self._headers) + + async def write(self, data: Union[bytes, bytearray, memoryview]) -> None: + assert isinstance( + data, (bytes, bytearray, memoryview) + ), "data argument must be byte-ish (%r)" % type(data) + + if self._eof_sent: + raise RuntimeError("Cannot call write() after write_eof()") + if self._payload_writer is None: + raise RuntimeError("Cannot call write() before prepare()") + + await self._payload_writer.write(data) + + async def drain(self) -> None: + assert not self._eof_sent, "EOF has already been sent" + assert self._payload_writer is not None, "Response has not been started" + warnings.warn( + "drain method is deprecated, use await resp.write()", + DeprecationWarning, + stacklevel=2, + ) + await self._payload_writer.drain() + + async def write_eof(self, data: bytes = b"") -> None: + assert isinstance( + data, (bytes, bytearray, memoryview) + ), "data argument must be byte-ish (%r)" % type(data) + + if self._eof_sent: + return + + assert self._payload_writer is not None, "Response has not been started" + + await self._payload_writer.write_eof(data) + self._eof_sent = True + self._req = None + self._body_length = self._payload_writer.output_size + self._payload_writer = None + + def __repr__(self) -> str: + if self._eof_sent: + info = "eof" + elif self.prepared: + assert self._req is not None + info = f"{self._req.method} {self._req.path} " + else: + info = "not prepared" + return f"<{self.__class__.__name__} {self.reason} {info}>" + + def __getitem__(self, key: str) -> Any: + return self._state[key] + + def __setitem__(self, key: str, value: Any) -> None: + self._state[key] = value + + def __delitem__(self, key: str) -> None: + del self._state[key] + + def __len__(self) -> int: + return len(self._state) + + def __iter__(self) -> Iterator[str]: + return iter(self._state) + + def __hash__(self) -> int: + return hash(id(self)) + + def __eq__(self, other: object) -> bool: + return self is other + + +class Response(StreamResponse): + + _compressed_body: Optional[bytes] = None + + def __init__( + self, + *, + body: Any = None, + status: int = 200, + reason: Optional[str] = None, + text: Optional[str] = None, + headers: Optional[LooseHeaders] = None, + content_type: Optional[str] = None, + charset: Optional[str] = None, + zlib_executor_size: Optional[int] = None, + zlib_executor: Optional[Executor] = None, + ) -> None: + if body is not None and text is not None: + raise ValueError("body and text are not allowed together") + + if headers is None: + real_headers: CIMultiDict[str] = CIMultiDict() + else: + real_headers = CIMultiDict(headers) + + if content_type is not None and "charset" in content_type: + raise ValueError("charset must not be in content_type argument") + + if text is not None: + if hdrs.CONTENT_TYPE in real_headers: + if content_type or charset: + raise ValueError( + "passing both Content-Type header and " + "content_type or charset params " + "is forbidden" + ) + else: + # fast path for filling headers + if not isinstance(text, str): + raise TypeError("text argument must be str (%r)" % type(text)) + if content_type is None: + content_type = "text/plain" + if charset is None: + charset = "utf-8" + real_headers[hdrs.CONTENT_TYPE] = content_type + "; charset=" + charset + body = text.encode(charset) + text = None + elif hdrs.CONTENT_TYPE in real_headers: + if content_type is not None or charset is not None: + raise ValueError( + "passing both Content-Type header and " + "content_type or charset params " + "is forbidden" + ) + elif content_type is not None: + if charset is not None: + content_type += "; charset=" + charset + real_headers[hdrs.CONTENT_TYPE] = content_type + + super().__init__(status=status, reason=reason, _real_headers=real_headers) + + if text is not None: + self.text = text + else: + self.body = body + + self._zlib_executor_size = zlib_executor_size + self._zlib_executor = zlib_executor + + @property + def body(self) -> Optional[Union[bytes, Payload]]: + return self._body + + @body.setter + def body(self, body: Any) -> None: + if body is None: + self._body = None + elif isinstance(body, (bytes, bytearray)): + self._body = body + else: + try: + self._body = body = payload.PAYLOAD_REGISTRY.get(body) + except payload.LookupError: + raise ValueError("Unsupported body type %r" % type(body)) + + headers = self._headers + + # set content-type + if hdrs.CONTENT_TYPE not in headers: + headers[hdrs.CONTENT_TYPE] = body.content_type + + # copy payload headers + if body.headers: + for key, value in body.headers.items(): + if key not in headers: + headers[key] = value + + self._compressed_body = None + + @property + def text(self) -> Optional[str]: + if self._body is None: + return None + return self._body.decode(self.charset or "utf-8") + + @text.setter + def text(self, text: str) -> None: + assert text is None or isinstance( + text, str + ), "text argument must be str (%r)" % type(text) + + if self.content_type == "application/octet-stream": + self.content_type = "text/plain" + if self.charset is None: + self.charset = "utf-8" + + self._body = text.encode(self.charset) + self._compressed_body = None + + @property + def content_length(self) -> Optional[int]: + if self._chunked: + return None + + if hdrs.CONTENT_LENGTH in self._headers: + return int(self._headers[hdrs.CONTENT_LENGTH]) + + if self._compressed_body is not None: + # Return length of the compressed body + return len(self._compressed_body) + elif isinstance(self._body, Payload): + # A payload without content length, or a compressed payload + return None + elif self._body is not None: + return len(self._body) + else: + return 0 + + @content_length.setter + def content_length(self, value: Optional[int]) -> None: + raise RuntimeError("Content length is set automatically") + + async def write_eof(self, data: bytes = b"") -> None: + if self._eof_sent: + return + if self._compressed_body is None: + body: Optional[Union[bytes, Payload]] = self._body + else: + body = self._compressed_body + assert not data, f"data arg is not supported, got {data!r}" + assert self._req is not None + assert self._payload_writer is not None + if body is None or self._must_be_empty_body: + await super().write_eof() + elif isinstance(self._body, Payload): + await self._body.write(self._payload_writer) + await super().write_eof() + else: + await super().write_eof(cast(bytes, body)) + + async def _start(self, request: "BaseRequest") -> AbstractStreamWriter: + if hdrs.CONTENT_LENGTH in self._headers: + if should_remove_content_length(request.method, self.status): + del self._headers[hdrs.CONTENT_LENGTH] + elif not self._chunked: + if isinstance(self._body, Payload): + if self._body.size is not None: + self._headers[hdrs.CONTENT_LENGTH] = str(self._body.size) + else: + body_len = len(self._body) if self._body else "0" + # https://www.rfc-editor.org/rfc/rfc9110.html#section-8.6-7 + if body_len != "0" or ( + self.status != 304 and request.method not in hdrs.METH_HEAD_ALL + ): + self._headers[hdrs.CONTENT_LENGTH] = str(body_len) + + return await super()._start(request) + + async def _do_start_compression(self, coding: ContentCoding) -> None: + if self._chunked or isinstance(self._body, Payload): + return await super()._do_start_compression(coding) + if coding is ContentCoding.identity: + return + # Instead of using _payload_writer.enable_compression, + # compress the whole body + compressor = ZLibCompressor( + encoding=coding.value, + max_sync_chunk_size=self._zlib_executor_size, + executor=self._zlib_executor, + ) + assert self._body is not None + if self._zlib_executor_size is None and len(self._body) > LARGE_BODY_SIZE: + warnings.warn( + "Synchronous compression of large response bodies " + f"({len(self._body)} bytes) might block the async event loop. " + "Consider providing a custom value to zlib_executor_size/" + "zlib_executor response properties or disabling compression on it." + ) + self._compressed_body = ( + await compressor.compress(self._body) + compressor.flush() + ) + self._headers[hdrs.CONTENT_ENCODING] = coding.value + self._headers[hdrs.CONTENT_LENGTH] = str(len(self._compressed_body)) + + +def json_response( + data: Any = sentinel, + *, + text: Optional[str] = None, + body: Optional[bytes] = None, + status: int = 200, + reason: Optional[str] = None, + headers: Optional[LooseHeaders] = None, + content_type: str = "application/json", + dumps: JSONEncoder = json.dumps, +) -> Response: + if data is not sentinel: + if text or body: + raise ValueError("only one of data, text, or body should be specified") + else: + text = dumps(data) + return Response( + text=text, + body=body, + status=status, + reason=reason, + headers=headers, + content_type=content_type, + ) diff --git a/venv/lib/python3.12/site-packages/aiohttp/web_routedef.py b/venv/lib/python3.12/site-packages/aiohttp/web_routedef.py new file mode 100644 index 00000000..f51b6cd0 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/web_routedef.py @@ -0,0 +1,214 @@ +import abc +import os # noqa +from typing import ( + TYPE_CHECKING, + Any, + Callable, + Dict, + Iterator, + List, + Optional, + Sequence, + Type, + Union, + overload, +) + +import attr + +from . import hdrs +from .abc import AbstractView +from .typedefs import Handler, PathLike + +if TYPE_CHECKING: + from .web_request import Request + from .web_response import StreamResponse + from .web_urldispatcher import AbstractRoute, UrlDispatcher +else: + Request = StreamResponse = UrlDispatcher = AbstractRoute = None + + +__all__ = ( + "AbstractRouteDef", + "RouteDef", + "StaticDef", + "RouteTableDef", + "head", + "options", + "get", + "post", + "patch", + "put", + "delete", + "route", + "view", + "static", +) + + +class AbstractRouteDef(abc.ABC): + @abc.abstractmethod + def register(self, router: UrlDispatcher) -> List[AbstractRoute]: + pass # pragma: no cover + + +_HandlerType = Union[Type[AbstractView], Handler] + + +@attr.s(auto_attribs=True, frozen=True, repr=False, slots=True) +class RouteDef(AbstractRouteDef): + method: str + path: str + handler: _HandlerType + kwargs: Dict[str, Any] + + def __repr__(self) -> str: + info = [] + for name, value in sorted(self.kwargs.items()): + info.append(f", {name}={value!r}") + return " {handler.__name__!r}{info}>".format( + method=self.method, path=self.path, handler=self.handler, info="".join(info) + ) + + def register(self, router: UrlDispatcher) -> List[AbstractRoute]: + if self.method in hdrs.METH_ALL: + reg = getattr(router, "add_" + self.method.lower()) + return [reg(self.path, self.handler, **self.kwargs)] + else: + return [ + router.add_route(self.method, self.path, self.handler, **self.kwargs) + ] + + +@attr.s(auto_attribs=True, frozen=True, repr=False, slots=True) +class StaticDef(AbstractRouteDef): + prefix: str + path: PathLike + kwargs: Dict[str, Any] + + def __repr__(self) -> str: + info = [] + for name, value in sorted(self.kwargs.items()): + info.append(f", {name}={value!r}") + return " {path}{info}>".format( + prefix=self.prefix, path=self.path, info="".join(info) + ) + + def register(self, router: UrlDispatcher) -> List[AbstractRoute]: + resource = router.add_static(self.prefix, self.path, **self.kwargs) + routes = resource.get_info().get("routes", {}) + return list(routes.values()) + + +def route(method: str, path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef: + return RouteDef(method, path, handler, kwargs) + + +def head(path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef: + return route(hdrs.METH_HEAD, path, handler, **kwargs) + + +def options(path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef: + return route(hdrs.METH_OPTIONS, path, handler, **kwargs) + + +def get( + path: str, + handler: _HandlerType, + *, + name: Optional[str] = None, + allow_head: bool = True, + **kwargs: Any, +) -> RouteDef: + return route( + hdrs.METH_GET, path, handler, name=name, allow_head=allow_head, **kwargs + ) + + +def post(path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef: + return route(hdrs.METH_POST, path, handler, **kwargs) + + +def put(path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef: + return route(hdrs.METH_PUT, path, handler, **kwargs) + + +def patch(path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef: + return route(hdrs.METH_PATCH, path, handler, **kwargs) + + +def delete(path: str, handler: _HandlerType, **kwargs: Any) -> RouteDef: + return route(hdrs.METH_DELETE, path, handler, **kwargs) + + +def view(path: str, handler: Type[AbstractView], **kwargs: Any) -> RouteDef: + return route(hdrs.METH_ANY, path, handler, **kwargs) + + +def static(prefix: str, path: PathLike, **kwargs: Any) -> StaticDef: + return StaticDef(prefix, path, kwargs) + + +_Deco = Callable[[_HandlerType], _HandlerType] + + +class RouteTableDef(Sequence[AbstractRouteDef]): + """Route definition table""" + + def __init__(self) -> None: + self._items: List[AbstractRouteDef] = [] + + def __repr__(self) -> str: + return f"" + + @overload + def __getitem__(self, index: int) -> AbstractRouteDef: ... + + @overload + def __getitem__(self, index: slice) -> List[AbstractRouteDef]: ... + + def __getitem__(self, index): # type: ignore[no-untyped-def] + return self._items[index] + + def __iter__(self) -> Iterator[AbstractRouteDef]: + return iter(self._items) + + def __len__(self) -> int: + return len(self._items) + + def __contains__(self, item: object) -> bool: + return item in self._items + + def route(self, method: str, path: str, **kwargs: Any) -> _Deco: + def inner(handler: _HandlerType) -> _HandlerType: + self._items.append(RouteDef(method, path, handler, kwargs)) + return handler + + return inner + + def head(self, path: str, **kwargs: Any) -> _Deco: + return self.route(hdrs.METH_HEAD, path, **kwargs) + + def get(self, path: str, **kwargs: Any) -> _Deco: + return self.route(hdrs.METH_GET, path, **kwargs) + + def post(self, path: str, **kwargs: Any) -> _Deco: + return self.route(hdrs.METH_POST, path, **kwargs) + + def put(self, path: str, **kwargs: Any) -> _Deco: + return self.route(hdrs.METH_PUT, path, **kwargs) + + def patch(self, path: str, **kwargs: Any) -> _Deco: + return self.route(hdrs.METH_PATCH, path, **kwargs) + + def delete(self, path: str, **kwargs: Any) -> _Deco: + return self.route(hdrs.METH_DELETE, path, **kwargs) + + def options(self, path: str, **kwargs: Any) -> _Deco: + return self.route(hdrs.METH_OPTIONS, path, **kwargs) + + def view(self, path: str, **kwargs: Any) -> _Deco: + return self.route(hdrs.METH_ANY, path, **kwargs) + + def static(self, prefix: str, path: PathLike, **kwargs: Any) -> None: + self._items.append(StaticDef(prefix, path, kwargs)) diff --git a/venv/lib/python3.12/site-packages/aiohttp/web_runner.py b/venv/lib/python3.12/site-packages/aiohttp/web_runner.py new file mode 100644 index 00000000..bcfec727 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/web_runner.py @@ -0,0 +1,399 @@ +import asyncio +import signal +import socket +import warnings +from abc import ABC, abstractmethod +from typing import TYPE_CHECKING, Any, List, Optional, Set + +from yarl import URL + +from .typedefs import PathLike +from .web_app import Application +from .web_server import Server + +if TYPE_CHECKING: + from ssl import SSLContext +else: + try: + from ssl import SSLContext + except ImportError: # pragma: no cover + SSLContext = object # type: ignore[misc,assignment] + +__all__ = ( + "BaseSite", + "TCPSite", + "UnixSite", + "NamedPipeSite", + "SockSite", + "BaseRunner", + "AppRunner", + "ServerRunner", + "GracefulExit", +) + + +class GracefulExit(SystemExit): + code = 1 + + +def _raise_graceful_exit() -> None: + raise GracefulExit() + + +class BaseSite(ABC): + __slots__ = ("_runner", "_ssl_context", "_backlog", "_server") + + def __init__( + self, + runner: "BaseRunner", + *, + shutdown_timeout: float = 60.0, + ssl_context: Optional[SSLContext] = None, + backlog: int = 128, + ) -> None: + if runner.server is None: + raise RuntimeError("Call runner.setup() before making a site") + if shutdown_timeout != 60.0: + msg = "shutdown_timeout should be set on BaseRunner" + warnings.warn(msg, DeprecationWarning, stacklevel=2) + runner._shutdown_timeout = shutdown_timeout + self._runner = runner + self._ssl_context = ssl_context + self._backlog = backlog + self._server: Optional[asyncio.AbstractServer] = None + + @property + @abstractmethod + def name(self) -> str: + pass # pragma: no cover + + @abstractmethod + async def start(self) -> None: + self._runner._reg_site(self) + + async def stop(self) -> None: + self._runner._check_site(self) + if self._server is not None: # Maybe not started yet + self._server.close() + + self._runner._unreg_site(self) + + +class TCPSite(BaseSite): + __slots__ = ("_host", "_port", "_reuse_address", "_reuse_port") + + def __init__( + self, + runner: "BaseRunner", + host: Optional[str] = None, + port: Optional[int] = None, + *, + shutdown_timeout: float = 60.0, + ssl_context: Optional[SSLContext] = None, + backlog: int = 128, + reuse_address: Optional[bool] = None, + reuse_port: Optional[bool] = None, + ) -> None: + super().__init__( + runner, + shutdown_timeout=shutdown_timeout, + ssl_context=ssl_context, + backlog=backlog, + ) + self._host = host + if port is None: + port = 8443 if self._ssl_context else 8080 + self._port = port + self._reuse_address = reuse_address + self._reuse_port = reuse_port + + @property + def name(self) -> str: + scheme = "https" if self._ssl_context else "http" + host = "0.0.0.0" if not self._host else self._host + return str(URL.build(scheme=scheme, host=host, port=self._port)) + + async def start(self) -> None: + await super().start() + loop = asyncio.get_event_loop() + server = self._runner.server + assert server is not None + self._server = await loop.create_server( + server, + self._host, + self._port, + ssl=self._ssl_context, + backlog=self._backlog, + reuse_address=self._reuse_address, + reuse_port=self._reuse_port, + ) + + +class UnixSite(BaseSite): + __slots__ = ("_path",) + + def __init__( + self, + runner: "BaseRunner", + path: PathLike, + *, + shutdown_timeout: float = 60.0, + ssl_context: Optional[SSLContext] = None, + backlog: int = 128, + ) -> None: + super().__init__( + runner, + shutdown_timeout=shutdown_timeout, + ssl_context=ssl_context, + backlog=backlog, + ) + self._path = path + + @property + def name(self) -> str: + scheme = "https" if self._ssl_context else "http" + return f"{scheme}://unix:{self._path}:" + + async def start(self) -> None: + await super().start() + loop = asyncio.get_event_loop() + server = self._runner.server + assert server is not None + self._server = await loop.create_unix_server( + server, + self._path, + ssl=self._ssl_context, + backlog=self._backlog, + ) + + +class NamedPipeSite(BaseSite): + __slots__ = ("_path",) + + def __init__( + self, runner: "BaseRunner", path: str, *, shutdown_timeout: float = 60.0 + ) -> None: + loop = asyncio.get_event_loop() + if not isinstance( + loop, asyncio.ProactorEventLoop # type: ignore[attr-defined] + ): + raise RuntimeError( + "Named Pipes only available in proactor loop under windows" + ) + super().__init__(runner, shutdown_timeout=shutdown_timeout) + self._path = path + + @property + def name(self) -> str: + return self._path + + async def start(self) -> None: + await super().start() + loop = asyncio.get_event_loop() + server = self._runner.server + assert server is not None + _server = await loop.start_serving_pipe( # type: ignore[attr-defined] + server, self._path + ) + self._server = _server[0] + + +class SockSite(BaseSite): + __slots__ = ("_sock", "_name") + + def __init__( + self, + runner: "BaseRunner", + sock: socket.socket, + *, + shutdown_timeout: float = 60.0, + ssl_context: Optional[SSLContext] = None, + backlog: int = 128, + ) -> None: + super().__init__( + runner, + shutdown_timeout=shutdown_timeout, + ssl_context=ssl_context, + backlog=backlog, + ) + self._sock = sock + scheme = "https" if self._ssl_context else "http" + if hasattr(socket, "AF_UNIX") and sock.family == socket.AF_UNIX: + name = f"{scheme}://unix:{sock.getsockname()}:" + else: + host, port = sock.getsockname()[:2] + name = str(URL.build(scheme=scheme, host=host, port=port)) + self._name = name + + @property + def name(self) -> str: + return self._name + + async def start(self) -> None: + await super().start() + loop = asyncio.get_event_loop() + server = self._runner.server + assert server is not None + self._server = await loop.create_server( + server, sock=self._sock, ssl=self._ssl_context, backlog=self._backlog + ) + + +class BaseRunner(ABC): + __slots__ = ("_handle_signals", "_kwargs", "_server", "_sites", "_shutdown_timeout") + + def __init__( + self, + *, + handle_signals: bool = False, + shutdown_timeout: float = 60.0, + **kwargs: Any, + ) -> None: + self._handle_signals = handle_signals + self._kwargs = kwargs + self._server: Optional[Server] = None + self._sites: List[BaseSite] = [] + self._shutdown_timeout = shutdown_timeout + + @property + def server(self) -> Optional[Server]: + return self._server + + @property + def addresses(self) -> List[Any]: + ret: List[Any] = [] + for site in self._sites: + server = site._server + if server is not None: + sockets = server.sockets # type: ignore[attr-defined] + if sockets is not None: + for sock in sockets: + ret.append(sock.getsockname()) + return ret + + @property + def sites(self) -> Set[BaseSite]: + return set(self._sites) + + async def setup(self) -> None: + loop = asyncio.get_event_loop() + + if self._handle_signals: + try: + loop.add_signal_handler(signal.SIGINT, _raise_graceful_exit) + loop.add_signal_handler(signal.SIGTERM, _raise_graceful_exit) + except NotImplementedError: # pragma: no cover + # add_signal_handler is not implemented on Windows + pass + + self._server = await self._make_server() + + @abstractmethod + async def shutdown(self) -> None: + """Call any shutdown hooks to help server close gracefully.""" + + async def cleanup(self) -> None: + # The loop over sites is intentional, an exception on gather() + # leaves self._sites in unpredictable state. + # The loop guaranties that a site is either deleted on success or + # still present on failure + for site in list(self._sites): + await site.stop() + + if self._server: # If setup succeeded + # Yield to event loop to ensure incoming requests prior to stopping the sites + # have all started to be handled before we proceed to close idle connections. + await asyncio.sleep(0) + self._server.pre_shutdown() + await self.shutdown() + await self._server.shutdown(self._shutdown_timeout) + await self._cleanup_server() + + self._server = None + if self._handle_signals: + loop = asyncio.get_running_loop() + try: + loop.remove_signal_handler(signal.SIGINT) + loop.remove_signal_handler(signal.SIGTERM) + except NotImplementedError: # pragma: no cover + # remove_signal_handler is not implemented on Windows + pass + + @abstractmethod + async def _make_server(self) -> Server: + pass # pragma: no cover + + @abstractmethod + async def _cleanup_server(self) -> None: + pass # pragma: no cover + + def _reg_site(self, site: BaseSite) -> None: + if site in self._sites: + raise RuntimeError(f"Site {site} is already registered in runner {self}") + self._sites.append(site) + + def _check_site(self, site: BaseSite) -> None: + if site not in self._sites: + raise RuntimeError(f"Site {site} is not registered in runner {self}") + + def _unreg_site(self, site: BaseSite) -> None: + if site not in self._sites: + raise RuntimeError(f"Site {site} is not registered in runner {self}") + self._sites.remove(site) + + +class ServerRunner(BaseRunner): + """Low-level web server runner""" + + __slots__ = ("_web_server",) + + def __init__( + self, web_server: Server, *, handle_signals: bool = False, **kwargs: Any + ) -> None: + super().__init__(handle_signals=handle_signals, **kwargs) + self._web_server = web_server + + async def shutdown(self) -> None: + pass + + async def _make_server(self) -> Server: + return self._web_server + + async def _cleanup_server(self) -> None: + pass + + +class AppRunner(BaseRunner): + """Web Application runner""" + + __slots__ = ("_app",) + + def __init__( + self, app: Application, *, handle_signals: bool = False, **kwargs: Any + ) -> None: + super().__init__(handle_signals=handle_signals, **kwargs) + if not isinstance(app, Application): + raise TypeError( + "The first argument should be web.Application " + "instance, got {!r}".format(app) + ) + self._app = app + + @property + def app(self) -> Application: + return self._app + + async def shutdown(self) -> None: + await self._app.shutdown() + + async def _make_server(self) -> Server: + loop = asyncio.get_event_loop() + self._app._set_loop(loop) + self._app.on_startup.freeze() + await self._app.startup() + self._app.freeze() + + return self._app._make_handler(loop=loop, **self._kwargs) + + async def _cleanup_server(self) -> None: + await self._app.cleanup() diff --git a/venv/lib/python3.12/site-packages/aiohttp/web_server.py b/venv/lib/python3.12/site-packages/aiohttp/web_server.py new file mode 100644 index 00000000..328aca1e --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/web_server.py @@ -0,0 +1,84 @@ +"""Low level HTTP server.""" + +import asyncio +from typing import Any, Awaitable, Callable, Dict, List, Optional # noqa + +from .abc import AbstractStreamWriter +from .http_parser import RawRequestMessage +from .streams import StreamReader +from .web_protocol import RequestHandler, _RequestFactory, _RequestHandler +from .web_request import BaseRequest + +__all__ = ("Server",) + + +class Server: + def __init__( + self, + handler: _RequestHandler, + *, + request_factory: Optional[_RequestFactory] = None, + handler_cancellation: bool = False, + loop: Optional[asyncio.AbstractEventLoop] = None, + **kwargs: Any, + ) -> None: + self._loop = loop or asyncio.get_running_loop() + self._connections: Dict[RequestHandler, asyncio.Transport] = {} + self._kwargs = kwargs + # requests_count is the number of requests being processed by the server + # for the lifetime of the server. + self.requests_count = 0 + self.request_handler = handler + self.request_factory = request_factory or self._make_request + self.handler_cancellation = handler_cancellation + + @property + def connections(self) -> List[RequestHandler]: + return list(self._connections.keys()) + + def connection_made( + self, handler: RequestHandler, transport: asyncio.Transport + ) -> None: + self._connections[handler] = transport + + def connection_lost( + self, handler: RequestHandler, exc: Optional[BaseException] = None + ) -> None: + if handler in self._connections: + if handler._task_handler: + handler._task_handler.add_done_callback( + lambda f: self._connections.pop(handler, None) + ) + else: + del self._connections[handler] + + def _make_request( + self, + message: RawRequestMessage, + payload: StreamReader, + protocol: RequestHandler, + writer: AbstractStreamWriter, + task: "asyncio.Task[None]", + ) -> BaseRequest: + return BaseRequest(message, payload, protocol, writer, task, self._loop) + + def pre_shutdown(self) -> None: + for conn in self._connections: + conn.close() + + async def shutdown(self, timeout: Optional[float] = None) -> None: + coros = (conn.shutdown(timeout) for conn in self._connections) + await asyncio.gather(*coros) + self._connections.clear() + + def __call__(self) -> RequestHandler: + try: + return RequestHandler(self, loop=self._loop, **self._kwargs) + except TypeError: + # Failsafe creation: remove all custom handler_args + kwargs = { + k: v + for k, v in self._kwargs.items() + if k in ["debug", "access_log_class"] + } + return RequestHandler(self, loop=self._loop, **kwargs) diff --git a/venv/lib/python3.12/site-packages/aiohttp/web_urldispatcher.py b/venv/lib/python3.12/site-packages/aiohttp/web_urldispatcher.py new file mode 100644 index 00000000..28ae2518 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/web_urldispatcher.py @@ -0,0 +1,1303 @@ +import abc +import asyncio +import base64 +import functools +import hashlib +import html +import inspect +import keyword +import os +import re +import sys +import warnings +from functools import wraps +from pathlib import Path +from types import MappingProxyType +from typing import ( + TYPE_CHECKING, + Any, + Awaitable, + Callable, + Container, + Dict, + Final, + Generator, + Iterable, + Iterator, + List, + Mapping, + NoReturn, + Optional, + Pattern, + Set, + Sized, + Tuple, + Type, + TypedDict, + Union, + cast, +) + +from yarl import URL, __version__ as yarl_version + +from . import hdrs +from .abc import AbstractMatchInfo, AbstractRouter, AbstractView +from .helpers import DEBUG +from .http import HttpVersion11 +from .typedefs import Handler, PathLike +from .web_exceptions import ( + HTTPException, + HTTPExpectationFailed, + HTTPForbidden, + HTTPMethodNotAllowed, + HTTPNotFound, +) +from .web_fileresponse import FileResponse +from .web_request import Request +from .web_response import Response, StreamResponse +from .web_routedef import AbstractRouteDef + +__all__ = ( + "UrlDispatcher", + "UrlMappingMatchInfo", + "AbstractResource", + "Resource", + "PlainResource", + "DynamicResource", + "AbstractRoute", + "ResourceRoute", + "StaticResource", + "View", +) + + +if TYPE_CHECKING: + from .web_app import Application + + BaseDict = Dict[str, str] +else: + BaseDict = dict + +CIRCULAR_SYMLINK_ERROR = ( + (OSError,) + if sys.version_info < (3, 10) and sys.platform.startswith("win32") + else (RuntimeError,) if sys.version_info < (3, 13) else () +) + +YARL_VERSION: Final[Tuple[int, ...]] = tuple(map(int, yarl_version.split(".")[:2])) + +HTTP_METHOD_RE: Final[Pattern[str]] = re.compile( + r"^[0-9A-Za-z!#\$%&'\*\+\-\.\^_`\|~]+$" +) +ROUTE_RE: Final[Pattern[str]] = re.compile( + r"(\{[_a-zA-Z][^{}]*(?:\{[^{}]*\}[^{}]*)*\})" +) +PATH_SEP: Final[str] = re.escape("/") + + +_ExpectHandler = Callable[[Request], Awaitable[Optional[StreamResponse]]] +_Resolve = Tuple[Optional["UrlMappingMatchInfo"], Set[str]] + +html_escape = functools.partial(html.escape, quote=True) + + +class _InfoDict(TypedDict, total=False): + path: str + + formatter: str + pattern: Pattern[str] + + directory: Path + prefix: str + routes: Mapping[str, "AbstractRoute"] + + app: "Application" + + domain: str + + rule: "AbstractRuleMatching" + + http_exception: HTTPException + + +class AbstractResource(Sized, Iterable["AbstractRoute"]): + def __init__(self, *, name: Optional[str] = None) -> None: + self._name = name + + @property + def name(self) -> Optional[str]: + return self._name + + @property + @abc.abstractmethod + def canonical(self) -> str: + """Exposes the resource's canonical path. + + For example '/foo/bar/{name}' + + """ + + @abc.abstractmethod # pragma: no branch + def url_for(self, **kwargs: str) -> URL: + """Construct url for resource with additional params.""" + + @abc.abstractmethod # pragma: no branch + async def resolve(self, request: Request) -> _Resolve: + """Resolve resource. + + Return (UrlMappingMatchInfo, allowed_methods) pair. + """ + + @abc.abstractmethod + def add_prefix(self, prefix: str) -> None: + """Add a prefix to processed URLs. + + Required for subapplications support. + """ + + @abc.abstractmethod + def get_info(self) -> _InfoDict: + """Return a dict with additional info useful for introspection""" + + def freeze(self) -> None: + pass + + @abc.abstractmethod + def raw_match(self, path: str) -> bool: + """Perform a raw match against path""" + + +class AbstractRoute(abc.ABC): + def __init__( + self, + method: str, + handler: Union[Handler, Type[AbstractView]], + *, + expect_handler: Optional[_ExpectHandler] = None, + resource: Optional[AbstractResource] = None, + ) -> None: + + if expect_handler is None: + expect_handler = _default_expect_handler + + assert inspect.iscoroutinefunction(expect_handler) or ( + sys.version_info < (3, 14) and asyncio.iscoroutinefunction(expect_handler) + ), f"Coroutine is expected, got {expect_handler!r}" + + method = method.upper() + if not HTTP_METHOD_RE.match(method): + raise ValueError(f"{method} is not allowed HTTP method") + + assert callable(handler), handler + if inspect.iscoroutinefunction(handler) or ( + sys.version_info < (3, 14) and asyncio.iscoroutinefunction(handler) + ): + pass + elif inspect.isgeneratorfunction(handler): + warnings.warn( + "Bare generators are deprecated, use @coroutine wrapper", + DeprecationWarning, + ) + elif isinstance(handler, type) and issubclass(handler, AbstractView): + pass + else: + warnings.warn( + "Bare functions are deprecated, use async ones", DeprecationWarning + ) + + @wraps(handler) + async def handler_wrapper(request: Request) -> StreamResponse: + result = old_handler(request) # type: ignore[call-arg] + if asyncio.iscoroutine(result): + result = await result + assert isinstance(result, StreamResponse) + return result + + old_handler = handler + handler = handler_wrapper + + self._method = method + self._handler = handler + self._expect_handler = expect_handler + self._resource = resource + + @property + def method(self) -> str: + return self._method + + @property + def handler(self) -> Handler: + return self._handler + + @property + @abc.abstractmethod + def name(self) -> Optional[str]: + """Optional route's name, always equals to resource's name.""" + + @property + def resource(self) -> Optional[AbstractResource]: + return self._resource + + @abc.abstractmethod + def get_info(self) -> _InfoDict: + """Return a dict with additional info useful for introspection""" + + @abc.abstractmethod # pragma: no branch + def url_for(self, *args: str, **kwargs: str) -> URL: + """Construct url for route with additional params.""" + + async def handle_expect_header(self, request: Request) -> Optional[StreamResponse]: + return await self._expect_handler(request) + + +class UrlMappingMatchInfo(BaseDict, AbstractMatchInfo): + + __slots__ = ("_route", "_apps", "_current_app", "_frozen") + + def __init__(self, match_dict: Dict[str, str], route: AbstractRoute) -> None: + super().__init__(match_dict) + self._route = route + self._apps: List[Application] = [] + self._current_app: Optional[Application] = None + self._frozen = False + + @property + def handler(self) -> Handler: + return self._route.handler + + @property + def route(self) -> AbstractRoute: + return self._route + + @property + def expect_handler(self) -> _ExpectHandler: + return self._route.handle_expect_header + + @property + def http_exception(self) -> Optional[HTTPException]: + return None + + def get_info(self) -> _InfoDict: # type: ignore[override] + return self._route.get_info() + + @property + def apps(self) -> Tuple["Application", ...]: + return tuple(self._apps) + + def add_app(self, app: "Application") -> None: + if self._frozen: + raise RuntimeError("Cannot change apps stack after .freeze() call") + if self._current_app is None: + self._current_app = app + self._apps.insert(0, app) + + @property + def current_app(self) -> "Application": + app = self._current_app + assert app is not None + return app + + @current_app.setter + def current_app(self, app: "Application") -> None: + if DEBUG: # pragma: no cover + if app not in self._apps: + raise RuntimeError( + "Expected one of the following apps {!r}, got {!r}".format( + self._apps, app + ) + ) + self._current_app = app + + def freeze(self) -> None: + self._frozen = True + + def __repr__(self) -> str: + return f"" + + +class MatchInfoError(UrlMappingMatchInfo): + + __slots__ = ("_exception",) + + def __init__(self, http_exception: HTTPException) -> None: + self._exception = http_exception + super().__init__({}, SystemRoute(self._exception)) + + @property + def http_exception(self) -> HTTPException: + return self._exception + + def __repr__(self) -> str: + return "".format( + self._exception.status, self._exception.reason + ) + + +async def _default_expect_handler(request: Request) -> None: + """Default handler for Expect header. + + Just send "100 Continue" to client. + raise HTTPExpectationFailed if value of header is not "100-continue" + """ + expect = request.headers.get(hdrs.EXPECT, "") + if request.version == HttpVersion11: + if expect.lower() == "100-continue": + await request.writer.write(b"HTTP/1.1 100 Continue\r\n\r\n") + # Reset output_size as we haven't started the main body yet. + request.writer.output_size = 0 + else: + raise HTTPExpectationFailed(text="Unknown Expect: %s" % expect) + + +class Resource(AbstractResource): + def __init__(self, *, name: Optional[str] = None) -> None: + super().__init__(name=name) + self._routes: Dict[str, ResourceRoute] = {} + self._any_route: Optional[ResourceRoute] = None + self._allowed_methods: Set[str] = set() + + def add_route( + self, + method: str, + handler: Union[Type[AbstractView], Handler], + *, + expect_handler: Optional[_ExpectHandler] = None, + ) -> "ResourceRoute": + if route := self._routes.get(method, self._any_route): + raise RuntimeError( + "Added route will never be executed, " + f"method {route.method} is already " + "registered" + ) + + route_obj = ResourceRoute(method, handler, self, expect_handler=expect_handler) + self.register_route(route_obj) + return route_obj + + def register_route(self, route: "ResourceRoute") -> None: + assert isinstance( + route, ResourceRoute + ), f"Instance of Route class is required, got {route!r}" + if route.method == hdrs.METH_ANY: + self._any_route = route + self._allowed_methods.add(route.method) + self._routes[route.method] = route + + async def resolve(self, request: Request) -> _Resolve: + if (match_dict := self._match(request.rel_url.path_safe)) is None: + return None, set() + if route := self._routes.get(request.method, self._any_route): + return UrlMappingMatchInfo(match_dict, route), self._allowed_methods + return None, self._allowed_methods + + @abc.abstractmethod + def _match(self, path: str) -> Optional[Dict[str, str]]: + pass # pragma: no cover + + def __len__(self) -> int: + return len(self._routes) + + def __iter__(self) -> Iterator["ResourceRoute"]: + return iter(self._routes.values()) + + # TODO: implement all abstract methods + + +class PlainResource(Resource): + def __init__(self, path: str, *, name: Optional[str] = None) -> None: + super().__init__(name=name) + assert not path or path.startswith("/") + self._path = path + + @property + def canonical(self) -> str: + return self._path + + def freeze(self) -> None: + if not self._path: + self._path = "/" + + def add_prefix(self, prefix: str) -> None: + assert prefix.startswith("/") + assert not prefix.endswith("/") + assert len(prefix) > 1 + self._path = prefix + self._path + + def _match(self, path: str) -> Optional[Dict[str, str]]: + # string comparison is about 10 times faster than regexp matching + if self._path == path: + return {} + return None + + def raw_match(self, path: str) -> bool: + return self._path == path + + def get_info(self) -> _InfoDict: + return {"path": self._path} + + def url_for(self) -> URL: # type: ignore[override] + return URL.build(path=self._path, encoded=True) + + def __repr__(self) -> str: + name = "'" + self.name + "' " if self.name is not None else "" + return f"" + + +class DynamicResource(Resource): + + DYN = re.compile(r"\{(?P[_a-zA-Z][_a-zA-Z0-9]*)\}") + DYN_WITH_RE = re.compile(r"\{(?P[_a-zA-Z][_a-zA-Z0-9]*):(?P.+)\}") + GOOD = r"[^{}/]+" + + def __init__(self, path: str, *, name: Optional[str] = None) -> None: + super().__init__(name=name) + self._orig_path = path + pattern = "" + formatter = "" + for part in ROUTE_RE.split(path): + match = self.DYN.fullmatch(part) + if match: + pattern += "(?P<{}>{})".format(match.group("var"), self.GOOD) + formatter += "{" + match.group("var") + "}" + continue + + match = self.DYN_WITH_RE.fullmatch(part) + if match: + pattern += "(?P<{var}>{re})".format(**match.groupdict()) + formatter += "{" + match.group("var") + "}" + continue + + if "{" in part or "}" in part: + raise ValueError(f"Invalid path '{path}'['{part}']") + + part = _requote_path(part) + formatter += part + pattern += re.escape(part) + + try: + compiled = re.compile(pattern) + except re.error as exc: + raise ValueError(f"Bad pattern '{pattern}': {exc}") from None + assert compiled.pattern.startswith(PATH_SEP) + assert formatter.startswith("/") + self._pattern = compiled + self._formatter = formatter + + @property + def canonical(self) -> str: + return self._formatter + + def add_prefix(self, prefix: str) -> None: + assert prefix.startswith("/") + assert not prefix.endswith("/") + assert len(prefix) > 1 + self._pattern = re.compile(re.escape(prefix) + self._pattern.pattern) + self._formatter = prefix + self._formatter + + def _match(self, path: str) -> Optional[Dict[str, str]]: + match = self._pattern.fullmatch(path) + if match is None: + return None + return { + key: _unquote_path_safe(value) for key, value in match.groupdict().items() + } + + def raw_match(self, path: str) -> bool: + return self._orig_path == path + + def get_info(self) -> _InfoDict: + return {"formatter": self._formatter, "pattern": self._pattern} + + def url_for(self, **parts: str) -> URL: + url = self._formatter.format_map({k: _quote_path(v) for k, v in parts.items()}) + return URL.build(path=url, encoded=True) + + def __repr__(self) -> str: + name = "'" + self.name + "' " if self.name is not None else "" + return "".format( + name=name, formatter=self._formatter + ) + + +class PrefixResource(AbstractResource): + def __init__(self, prefix: str, *, name: Optional[str] = None) -> None: + assert not prefix or prefix.startswith("/"), prefix + assert prefix in ("", "/") or not prefix.endswith("/"), prefix + super().__init__(name=name) + self._prefix = _requote_path(prefix) + self._prefix2 = self._prefix + "/" + + @property + def canonical(self) -> str: + return self._prefix + + def add_prefix(self, prefix: str) -> None: + assert prefix.startswith("/") + assert not prefix.endswith("/") + assert len(prefix) > 1 + self._prefix = prefix + self._prefix + self._prefix2 = self._prefix + "/" + + def raw_match(self, prefix: str) -> bool: + return False + + # TODO: impl missing abstract methods + + +class StaticResource(PrefixResource): + VERSION_KEY = "v" + + def __init__( + self, + prefix: str, + directory: PathLike, + *, + name: Optional[str] = None, + expect_handler: Optional[_ExpectHandler] = None, + chunk_size: int = 256 * 1024, + show_index: bool = False, + follow_symlinks: bool = False, + append_version: bool = False, + ) -> None: + super().__init__(prefix, name=name) + try: + directory = Path(directory).expanduser().resolve(strict=True) + except FileNotFoundError as error: + raise ValueError(f"'{directory}' does not exist") from error + if not directory.is_dir(): + raise ValueError(f"'{directory}' is not a directory") + self._directory = directory + self._show_index = show_index + self._chunk_size = chunk_size + self._follow_symlinks = follow_symlinks + self._expect_handler = expect_handler + self._append_version = append_version + + self._routes = { + "GET": ResourceRoute( + "GET", self._handle, self, expect_handler=expect_handler + ), + "HEAD": ResourceRoute( + "HEAD", self._handle, self, expect_handler=expect_handler + ), + } + self._allowed_methods = set(self._routes) + + def url_for( # type: ignore[override] + self, + *, + filename: PathLike, + append_version: Optional[bool] = None, + ) -> URL: + if append_version is None: + append_version = self._append_version + filename = str(filename).lstrip("/") + + url = URL.build(path=self._prefix, encoded=True) + # filename is not encoded + if YARL_VERSION < (1, 6): + url = url / filename.replace("%", "%25") + else: + url = url / filename + + if append_version: + unresolved_path = self._directory.joinpath(filename) + try: + if self._follow_symlinks: + normalized_path = Path(os.path.normpath(unresolved_path)) + normalized_path.relative_to(self._directory) + filepath = normalized_path.resolve() + else: + filepath = unresolved_path.resolve() + filepath.relative_to(self._directory) + except (ValueError, FileNotFoundError): + # ValueError for case when path point to symlink + # with follow_symlinks is False + return url # relatively safe + if filepath.is_file(): + # TODO cache file content + # with file watcher for cache invalidation + with filepath.open("rb") as f: + file_bytes = f.read() + h = self._get_file_hash(file_bytes) + url = url.with_query({self.VERSION_KEY: h}) + return url + return url + + @staticmethod + def _get_file_hash(byte_array: bytes) -> str: + m = hashlib.sha256() # todo sha256 can be configurable param + m.update(byte_array) + b64 = base64.urlsafe_b64encode(m.digest()) + return b64.decode("ascii") + + def get_info(self) -> _InfoDict: + return { + "directory": self._directory, + "prefix": self._prefix, + "routes": self._routes, + } + + def set_options_route(self, handler: Handler) -> None: + if "OPTIONS" in self._routes: + raise RuntimeError("OPTIONS route was set already") + self._routes["OPTIONS"] = ResourceRoute( + "OPTIONS", handler, self, expect_handler=self._expect_handler + ) + self._allowed_methods.add("OPTIONS") + + async def resolve(self, request: Request) -> _Resolve: + path = request.rel_url.path_safe + method = request.method + if not path.startswith(self._prefix2) and path != self._prefix: + return None, set() + + allowed_methods = self._allowed_methods + if method not in allowed_methods: + return None, allowed_methods + + match_dict = {"filename": _unquote_path_safe(path[len(self._prefix) + 1 :])} + return (UrlMappingMatchInfo(match_dict, self._routes[method]), allowed_methods) + + def __len__(self) -> int: + return len(self._routes) + + def __iter__(self) -> Iterator[AbstractRoute]: + return iter(self._routes.values()) + + async def _handle(self, request: Request) -> StreamResponse: + rel_url = request.match_info["filename"] + filename = Path(rel_url) + if filename.anchor: + # rel_url is an absolute name like + # /static/\\machine_name\c$ or /static/D:\path + # where the static dir is totally different + raise HTTPForbidden() + + unresolved_path = self._directory.joinpath(filename) + loop = asyncio.get_running_loop() + return await loop.run_in_executor( + None, self._resolve_path_to_response, unresolved_path + ) + + def _resolve_path_to_response(self, unresolved_path: Path) -> StreamResponse: + """Take the unresolved path and query the file system to form a response.""" + # Check for access outside the root directory. For follow symlinks, URI + # cannot traverse out, but symlinks can. Otherwise, no access outside + # root is permitted. + try: + if self._follow_symlinks: + normalized_path = Path(os.path.normpath(unresolved_path)) + normalized_path.relative_to(self._directory) + file_path = normalized_path.resolve() + else: + file_path = unresolved_path.resolve() + file_path.relative_to(self._directory) + except (ValueError, *CIRCULAR_SYMLINK_ERROR) as error: + # ValueError is raised for the relative check. Circular symlinks + # raise here on resolving for python < 3.13. + raise HTTPNotFound() from error + + # if path is a directory, return the contents if permitted. Note the + # directory check will raise if a segment is not readable. + try: + if file_path.is_dir(): + if self._show_index: + return Response( + text=self._directory_as_html(file_path), + content_type="text/html", + ) + else: + raise HTTPForbidden() + except PermissionError as error: + raise HTTPForbidden() from error + + # Return the file response, which handles all other checks. + return FileResponse(file_path, chunk_size=self._chunk_size) + + def _directory_as_html(self, dir_path: Path) -> str: + """returns directory's index as html.""" + assert dir_path.is_dir() + + relative_path_to_dir = dir_path.relative_to(self._directory).as_posix() + index_of = f"Index of /{html_escape(relative_path_to_dir)}" + h1 = f"

    {index_of}

    " + + index_list = [] + dir_index = dir_path.iterdir() + for _file in sorted(dir_index): + # show file url as relative to static path + rel_path = _file.relative_to(self._directory).as_posix() + quoted_file_url = _quote_path(f"{self._prefix}/{rel_path}") + + # if file is a directory, add '/' to the end of the name + if _file.is_dir(): + file_name = f"{_file.name}/" + else: + file_name = _file.name + + index_list.append( + f'
  1. {html_escape(file_name)}
  2. ' + ) + ul = "
      \n{}\n
    ".format("\n".join(index_list)) + body = f"\n{h1}\n{ul}\n" + + head_str = f"\n{index_of}\n" + html = f"\n{head_str}\n{body}\n" + + return html + + def __repr__(self) -> str: + name = "'" + self.name + "'" if self.name is not None else "" + return " {directory!r}>".format( + name=name, path=self._prefix, directory=self._directory + ) + + +class PrefixedSubAppResource(PrefixResource): + def __init__(self, prefix: str, app: "Application") -> None: + super().__init__(prefix) + self._app = app + self._add_prefix_to_resources(prefix) + + def add_prefix(self, prefix: str) -> None: + super().add_prefix(prefix) + self._add_prefix_to_resources(prefix) + + def _add_prefix_to_resources(self, prefix: str) -> None: + router = self._app.router + for resource in router.resources(): + # Since the canonical path of a resource is about + # to change, we need to unindex it and then reindex + router.unindex_resource(resource) + resource.add_prefix(prefix) + router.index_resource(resource) + + def url_for(self, *args: str, **kwargs: str) -> URL: + raise RuntimeError(".url_for() is not supported by sub-application root") + + def get_info(self) -> _InfoDict: + return {"app": self._app, "prefix": self._prefix} + + async def resolve(self, request: Request) -> _Resolve: + match_info = await self._app.router.resolve(request) + match_info.add_app(self._app) + if isinstance(match_info.http_exception, HTTPMethodNotAllowed): + methods = match_info.http_exception.allowed_methods + else: + methods = set() + return match_info, methods + + def __len__(self) -> int: + return len(self._app.router.routes()) + + def __iter__(self) -> Iterator[AbstractRoute]: + return iter(self._app.router.routes()) + + def __repr__(self) -> str: + return " {app!r}>".format( + prefix=self._prefix, app=self._app + ) + + +class AbstractRuleMatching(abc.ABC): + @abc.abstractmethod # pragma: no branch + async def match(self, request: Request) -> bool: + """Return bool if the request satisfies the criteria""" + + @abc.abstractmethod # pragma: no branch + def get_info(self) -> _InfoDict: + """Return a dict with additional info useful for introspection""" + + @property + @abc.abstractmethod # pragma: no branch + def canonical(self) -> str: + """Return a str""" + + +class Domain(AbstractRuleMatching): + re_part = re.compile(r"(?!-)[a-z\d-]{1,63}(? None: + super().__init__() + self._domain = self.validation(domain) + + @property + def canonical(self) -> str: + return self._domain + + def validation(self, domain: str) -> str: + if not isinstance(domain, str): + raise TypeError("Domain must be str") + domain = domain.rstrip(".").lower() + if not domain: + raise ValueError("Domain cannot be empty") + elif "://" in domain: + raise ValueError("Scheme not supported") + url = URL("http://" + domain) + assert url.raw_host is not None + if not all(self.re_part.fullmatch(x) for x in url.raw_host.split(".")): + raise ValueError("Domain not valid") + if url.port == 80: + return url.raw_host + return f"{url.raw_host}:{url.port}" + + async def match(self, request: Request) -> bool: + host = request.headers.get(hdrs.HOST) + if not host: + return False + return self.match_domain(host) + + def match_domain(self, host: str) -> bool: + return host.lower() == self._domain + + def get_info(self) -> _InfoDict: + return {"domain": self._domain} + + +class MaskDomain(Domain): + re_part = re.compile(r"(?!-)[a-z\d\*-]{1,63}(? None: + super().__init__(domain) + mask = self._domain.replace(".", r"\.").replace("*", ".*") + self._mask = re.compile(mask) + + @property + def canonical(self) -> str: + return self._mask.pattern + + def match_domain(self, host: str) -> bool: + return self._mask.fullmatch(host) is not None + + +class MatchedSubAppResource(PrefixedSubAppResource): + def __init__(self, rule: AbstractRuleMatching, app: "Application") -> None: + AbstractResource.__init__(self) + self._prefix = "" + self._app = app + self._rule = rule + + @property + def canonical(self) -> str: + return self._rule.canonical + + def get_info(self) -> _InfoDict: + return {"app": self._app, "rule": self._rule} + + async def resolve(self, request: Request) -> _Resolve: + if not await self._rule.match(request): + return None, set() + match_info = await self._app.router.resolve(request) + match_info.add_app(self._app) + if isinstance(match_info.http_exception, HTTPMethodNotAllowed): + methods = match_info.http_exception.allowed_methods + else: + methods = set() + return match_info, methods + + def __repr__(self) -> str: + return f" {self._app!r}>" + + +class ResourceRoute(AbstractRoute): + """A route with resource""" + + def __init__( + self, + method: str, + handler: Union[Handler, Type[AbstractView]], + resource: AbstractResource, + *, + expect_handler: Optional[_ExpectHandler] = None, + ) -> None: + super().__init__( + method, handler, expect_handler=expect_handler, resource=resource + ) + + def __repr__(self) -> str: + return " {handler!r}".format( + method=self.method, resource=self._resource, handler=self.handler + ) + + @property + def name(self) -> Optional[str]: + if self._resource is None: + return None + return self._resource.name + + def url_for(self, *args: str, **kwargs: str) -> URL: + """Construct url for route with additional params.""" + assert self._resource is not None + return self._resource.url_for(*args, **kwargs) + + def get_info(self) -> _InfoDict: + assert self._resource is not None + return self._resource.get_info() + + +class SystemRoute(AbstractRoute): + def __init__(self, http_exception: HTTPException) -> None: + super().__init__(hdrs.METH_ANY, self._handle) + self._http_exception = http_exception + + def url_for(self, *args: str, **kwargs: str) -> URL: + raise RuntimeError(".url_for() is not allowed for SystemRoute") + + @property + def name(self) -> Optional[str]: + return None + + def get_info(self) -> _InfoDict: + return {"http_exception": self._http_exception} + + async def _handle(self, request: Request) -> StreamResponse: + raise self._http_exception + + @property + def status(self) -> int: + return self._http_exception.status + + @property + def reason(self) -> str: + return self._http_exception.reason + + def __repr__(self) -> str: + return "".format(self=self) + + +class View(AbstractView): + async def _iter(self) -> StreamResponse: + if self.request.method not in hdrs.METH_ALL: + self._raise_allowed_methods() + method: Optional[Callable[[], Awaitable[StreamResponse]]] + method = getattr(self, self.request.method.lower(), None) + if method is None: + self._raise_allowed_methods() + ret = await method() + assert isinstance(ret, StreamResponse) + return ret + + def __await__(self) -> Generator[Any, None, StreamResponse]: + return self._iter().__await__() + + def _raise_allowed_methods(self) -> NoReturn: + allowed_methods = {m for m in hdrs.METH_ALL if hasattr(self, m.lower())} + raise HTTPMethodNotAllowed(self.request.method, allowed_methods) + + +class ResourcesView(Sized, Iterable[AbstractResource], Container[AbstractResource]): + def __init__(self, resources: List[AbstractResource]) -> None: + self._resources = resources + + def __len__(self) -> int: + return len(self._resources) + + def __iter__(self) -> Iterator[AbstractResource]: + yield from self._resources + + def __contains__(self, resource: object) -> bool: + return resource in self._resources + + +class RoutesView(Sized, Iterable[AbstractRoute], Container[AbstractRoute]): + def __init__(self, resources: List[AbstractResource]): + self._routes: List[AbstractRoute] = [] + for resource in resources: + for route in resource: + self._routes.append(route) + + def __len__(self) -> int: + return len(self._routes) + + def __iter__(self) -> Iterator[AbstractRoute]: + yield from self._routes + + def __contains__(self, route: object) -> bool: + return route in self._routes + + +class UrlDispatcher(AbstractRouter, Mapping[str, AbstractResource]): + + NAME_SPLIT_RE = re.compile(r"[.:-]") + + def __init__(self) -> None: + super().__init__() + self._resources: List[AbstractResource] = [] + self._named_resources: Dict[str, AbstractResource] = {} + self._resource_index: dict[str, list[AbstractResource]] = {} + self._matched_sub_app_resources: List[MatchedSubAppResource] = [] + + async def resolve(self, request: Request) -> UrlMappingMatchInfo: + resource_index = self._resource_index + allowed_methods: Set[str] = set() + + # Walk the url parts looking for candidates. We walk the url backwards + # to ensure the most explicit match is found first. If there are multiple + # candidates for a given url part because there are multiple resources + # registered for the same canonical path, we resolve them in a linear + # fashion to ensure registration order is respected. + url_part = request.rel_url.path_safe + while url_part: + for candidate in resource_index.get(url_part, ()): + match_dict, allowed = await candidate.resolve(request) + if match_dict is not None: + return match_dict + else: + allowed_methods |= allowed + if url_part == "/": + break + url_part = url_part.rpartition("/")[0] or "/" + + # + # We didn't find any candidates, so we'll try the matched sub-app + # resources which we have to walk in a linear fashion because they + # have regex/wildcard match rules and we cannot index them. + # + # For most cases we do not expect there to be many of these since + # currently they are only added by `add_domain` + # + for resource in self._matched_sub_app_resources: + match_dict, allowed = await resource.resolve(request) + if match_dict is not None: + return match_dict + else: + allowed_methods |= allowed + + if allowed_methods: + return MatchInfoError(HTTPMethodNotAllowed(request.method, allowed_methods)) + + return MatchInfoError(HTTPNotFound()) + + def __iter__(self) -> Iterator[str]: + return iter(self._named_resources) + + def __len__(self) -> int: + return len(self._named_resources) + + def __contains__(self, resource: object) -> bool: + return resource in self._named_resources + + def __getitem__(self, name: str) -> AbstractResource: + return self._named_resources[name] + + def resources(self) -> ResourcesView: + return ResourcesView(self._resources) + + def routes(self) -> RoutesView: + return RoutesView(self._resources) + + def named_resources(self) -> Mapping[str, AbstractResource]: + return MappingProxyType(self._named_resources) + + def register_resource(self, resource: AbstractResource) -> None: + assert isinstance( + resource, AbstractResource + ), f"Instance of AbstractResource class is required, got {resource!r}" + if self.frozen: + raise RuntimeError("Cannot register a resource into frozen router.") + + name = resource.name + + if name is not None: + parts = self.NAME_SPLIT_RE.split(name) + for part in parts: + if keyword.iskeyword(part): + raise ValueError( + f"Incorrect route name {name!r}, " + "python keywords cannot be used " + "for route name" + ) + if not part.isidentifier(): + raise ValueError( + "Incorrect route name {!r}, " + "the name should be a sequence of " + "python identifiers separated " + "by dash, dot or column".format(name) + ) + if name in self._named_resources: + raise ValueError( + "Duplicate {!r}, " + "already handled by {!r}".format(name, self._named_resources[name]) + ) + self._named_resources[name] = resource + self._resources.append(resource) + + if isinstance(resource, MatchedSubAppResource): + # We cannot index match sub-app resources because they have match rules + self._matched_sub_app_resources.append(resource) + else: + self.index_resource(resource) + + def _get_resource_index_key(self, resource: AbstractResource) -> str: + """Return a key to index the resource in the resource index.""" + if "{" in (index_key := resource.canonical): + # strip at the first { to allow for variables, and than + # rpartition at / to allow for variable parts in the path + # For example if the canonical path is `/core/locations{tail:.*}` + # the index key will be `/core` since index is based on the + # url parts split by `/` + index_key = index_key.partition("{")[0].rpartition("/")[0] + return index_key.rstrip("/") or "/" + + def index_resource(self, resource: AbstractResource) -> None: + """Add a resource to the resource index.""" + resource_key = self._get_resource_index_key(resource) + # There may be multiple resources for a canonical path + # so we keep them in a list to ensure that registration + # order is respected. + self._resource_index.setdefault(resource_key, []).append(resource) + + def unindex_resource(self, resource: AbstractResource) -> None: + """Remove a resource from the resource index.""" + resource_key = self._get_resource_index_key(resource) + self._resource_index[resource_key].remove(resource) + + def add_resource(self, path: str, *, name: Optional[str] = None) -> Resource: + if path and not path.startswith("/"): + raise ValueError("path should be started with / or be empty") + # Reuse last added resource if path and name are the same + if self._resources: + resource = self._resources[-1] + if resource.name == name and resource.raw_match(path): + return cast(Resource, resource) + if not ("{" in path or "}" in path or ROUTE_RE.search(path)): + resource = PlainResource(path, name=name) + self.register_resource(resource) + return resource + resource = DynamicResource(path, name=name) + self.register_resource(resource) + return resource + + def add_route( + self, + method: str, + path: str, + handler: Union[Handler, Type[AbstractView]], + *, + name: Optional[str] = None, + expect_handler: Optional[_ExpectHandler] = None, + ) -> AbstractRoute: + resource = self.add_resource(path, name=name) + return resource.add_route(method, handler, expect_handler=expect_handler) + + def add_static( + self, + prefix: str, + path: PathLike, + *, + name: Optional[str] = None, + expect_handler: Optional[_ExpectHandler] = None, + chunk_size: int = 256 * 1024, + show_index: bool = False, + follow_symlinks: bool = False, + append_version: bool = False, + ) -> AbstractResource: + """Add static files view. + + prefix - url prefix + path - folder with files + + """ + assert prefix.startswith("/") + if prefix.endswith("/"): + prefix = prefix[:-1] + resource = StaticResource( + prefix, + path, + name=name, + expect_handler=expect_handler, + chunk_size=chunk_size, + show_index=show_index, + follow_symlinks=follow_symlinks, + append_version=append_version, + ) + self.register_resource(resource) + return resource + + def add_head(self, path: str, handler: Handler, **kwargs: Any) -> AbstractRoute: + """Shortcut for add_route with method HEAD.""" + return self.add_route(hdrs.METH_HEAD, path, handler, **kwargs) + + def add_options(self, path: str, handler: Handler, **kwargs: Any) -> AbstractRoute: + """Shortcut for add_route with method OPTIONS.""" + return self.add_route(hdrs.METH_OPTIONS, path, handler, **kwargs) + + def add_get( + self, + path: str, + handler: Handler, + *, + name: Optional[str] = None, + allow_head: bool = True, + **kwargs: Any, + ) -> AbstractRoute: + """Shortcut for add_route with method GET. + + If allow_head is true, another + route is added allowing head requests to the same endpoint. + """ + resource = self.add_resource(path, name=name) + if allow_head: + resource.add_route(hdrs.METH_HEAD, handler, **kwargs) + return resource.add_route(hdrs.METH_GET, handler, **kwargs) + + def add_post(self, path: str, handler: Handler, **kwargs: Any) -> AbstractRoute: + """Shortcut for add_route with method POST.""" + return self.add_route(hdrs.METH_POST, path, handler, **kwargs) + + def add_put(self, path: str, handler: Handler, **kwargs: Any) -> AbstractRoute: + """Shortcut for add_route with method PUT.""" + return self.add_route(hdrs.METH_PUT, path, handler, **kwargs) + + def add_patch(self, path: str, handler: Handler, **kwargs: Any) -> AbstractRoute: + """Shortcut for add_route with method PATCH.""" + return self.add_route(hdrs.METH_PATCH, path, handler, **kwargs) + + def add_delete(self, path: str, handler: Handler, **kwargs: Any) -> AbstractRoute: + """Shortcut for add_route with method DELETE.""" + return self.add_route(hdrs.METH_DELETE, path, handler, **kwargs) + + def add_view( + self, path: str, handler: Type[AbstractView], **kwargs: Any + ) -> AbstractRoute: + """Shortcut for add_route with ANY methods for a class-based view.""" + return self.add_route(hdrs.METH_ANY, path, handler, **kwargs) + + def freeze(self) -> None: + super().freeze() + for resource in self._resources: + resource.freeze() + + def add_routes(self, routes: Iterable[AbstractRouteDef]) -> List[AbstractRoute]: + """Append routes to route table. + + Parameter should be a sequence of RouteDef objects. + + Returns a list of registered AbstractRoute instances. + """ + registered_routes = [] + for route_def in routes: + registered_routes.extend(route_def.register(self)) + return registered_routes + + +def _quote_path(value: str) -> str: + if YARL_VERSION < (1, 6): + value = value.replace("%", "%25") + return URL.build(path=value, encoded=False).raw_path + + +def _unquote_path_safe(value: str) -> str: + if "%" not in value: + return value + return value.replace("%2F", "/").replace("%25", "%") + + +def _requote_path(value: str) -> str: + # Quote non-ascii characters and other characters which must be quoted, + # but preserve existing %-sequences. + result = _quote_path(value) + if "%" in value: + result = result.replace("%25", "%") + return result diff --git a/venv/lib/python3.12/site-packages/aiohttp/web_ws.py b/venv/lib/python3.12/site-packages/aiohttp/web_ws.py new file mode 100644 index 00000000..439b8049 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/web_ws.py @@ -0,0 +1,627 @@ +import asyncio +import base64 +import binascii +import hashlib +import json +import sys +from typing import Any, Final, Iterable, Optional, Tuple, Union, cast + +import attr +from multidict import CIMultiDict + +from . import hdrs +from ._websocket.reader import WebSocketDataQueue +from ._websocket.writer import DEFAULT_LIMIT +from .abc import AbstractStreamWriter +from .client_exceptions import WSMessageTypeError +from .helpers import calculate_timeout_when, set_exception, set_result +from .http import ( + WS_CLOSED_MESSAGE, + WS_CLOSING_MESSAGE, + WS_KEY, + WebSocketError, + WebSocketReader, + WebSocketWriter, + WSCloseCode, + WSMessage, + WSMsgType as WSMsgType, + ws_ext_gen, + ws_ext_parse, +) +from .http_websocket import _INTERNAL_RECEIVE_TYPES +from .log import ws_logger +from .streams import EofStream +from .typedefs import JSONDecoder, JSONEncoder +from .web_exceptions import HTTPBadRequest, HTTPException +from .web_request import BaseRequest +from .web_response import StreamResponse + +if sys.version_info >= (3, 11): + import asyncio as async_timeout +else: + import async_timeout + +__all__ = ( + "WebSocketResponse", + "WebSocketReady", + "WSMsgType", +) + +THRESHOLD_CONNLOST_ACCESS: Final[int] = 5 + + +@attr.s(auto_attribs=True, frozen=True, slots=True) +class WebSocketReady: + ok: bool + protocol: Optional[str] + + def __bool__(self) -> bool: + return self.ok + + +class WebSocketResponse(StreamResponse): + + _length_check: bool = False + _ws_protocol: Optional[str] = None + _writer: Optional[WebSocketWriter] = None + _reader: Optional[WebSocketDataQueue] = None + _closed: bool = False + _closing: bool = False + _conn_lost: int = 0 + _close_code: Optional[int] = None + _loop: Optional[asyncio.AbstractEventLoop] = None + _waiting: bool = False + _close_wait: Optional[asyncio.Future[None]] = None + _exception: Optional[BaseException] = None + _heartbeat_when: float = 0.0 + _heartbeat_cb: Optional[asyncio.TimerHandle] = None + _pong_response_cb: Optional[asyncio.TimerHandle] = None + _ping_task: Optional[asyncio.Task[None]] = None + + def __init__( + self, + *, + timeout: float = 10.0, + receive_timeout: Optional[float] = None, + autoclose: bool = True, + autoping: bool = True, + heartbeat: Optional[float] = None, + protocols: Iterable[str] = (), + compress: bool = True, + max_msg_size: int = 4 * 1024 * 1024, + writer_limit: int = DEFAULT_LIMIT, + ) -> None: + super().__init__(status=101) + self._protocols = protocols + self._timeout = timeout + self._receive_timeout = receive_timeout + self._autoclose = autoclose + self._autoping = autoping + self._heartbeat = heartbeat + if heartbeat is not None: + self._pong_heartbeat = heartbeat / 2.0 + self._compress: Union[bool, int] = compress + self._max_msg_size = max_msg_size + self._writer_limit = writer_limit + + def _cancel_heartbeat(self) -> None: + self._cancel_pong_response_cb() + if self._heartbeat_cb is not None: + self._heartbeat_cb.cancel() + self._heartbeat_cb = None + if self._ping_task is not None: + self._ping_task.cancel() + self._ping_task = None + + def _cancel_pong_response_cb(self) -> None: + if self._pong_response_cb is not None: + self._pong_response_cb.cancel() + self._pong_response_cb = None + + def _reset_heartbeat(self) -> None: + if self._heartbeat is None: + return + self._cancel_pong_response_cb() + req = self._req + timeout_ceil_threshold = ( + req._protocol._timeout_ceil_threshold if req is not None else 5 + ) + loop = self._loop + assert loop is not None + now = loop.time() + when = calculate_timeout_when(now, self._heartbeat, timeout_ceil_threshold) + self._heartbeat_when = when + if self._heartbeat_cb is None: + # We do not cancel the previous heartbeat_cb here because + # it generates a significant amount of TimerHandle churn + # which causes asyncio to rebuild the heap frequently. + # Instead _send_heartbeat() will reschedule the next + # heartbeat if it fires too early. + self._heartbeat_cb = loop.call_at(when, self._send_heartbeat) + + def _send_heartbeat(self) -> None: + self._heartbeat_cb = None + loop = self._loop + assert loop is not None and self._writer is not None + now = loop.time() + if now < self._heartbeat_when: + # Heartbeat fired too early, reschedule + self._heartbeat_cb = loop.call_at( + self._heartbeat_when, self._send_heartbeat + ) + return + + req = self._req + timeout_ceil_threshold = ( + req._protocol._timeout_ceil_threshold if req is not None else 5 + ) + when = calculate_timeout_when(now, self._pong_heartbeat, timeout_ceil_threshold) + self._cancel_pong_response_cb() + self._pong_response_cb = loop.call_at(when, self._pong_not_received) + + coro = self._writer.send_frame(b"", WSMsgType.PING) + if sys.version_info >= (3, 12): + # Optimization for Python 3.12, try to send the ping + # immediately to avoid having to schedule + # the task on the event loop. + ping_task = asyncio.Task(coro, loop=loop, eager_start=True) + else: + ping_task = loop.create_task(coro) + + if not ping_task.done(): + self._ping_task = ping_task + ping_task.add_done_callback(self._ping_task_done) + else: + self._ping_task_done(ping_task) + + def _ping_task_done(self, task: "asyncio.Task[None]") -> None: + """Callback for when the ping task completes.""" + if not task.cancelled() and (exc := task.exception()): + self._handle_ping_pong_exception(exc) + self._ping_task = None + + def _pong_not_received(self) -> None: + if self._req is not None and self._req.transport is not None: + self._handle_ping_pong_exception( + asyncio.TimeoutError( + f"No PONG received after {self._pong_heartbeat} seconds" + ) + ) + + def _handle_ping_pong_exception(self, exc: BaseException) -> None: + """Handle exceptions raised during ping/pong processing.""" + if self._closed: + return + self._set_closed() + self._set_code_close_transport(WSCloseCode.ABNORMAL_CLOSURE) + self._exception = exc + if self._waiting and not self._closing and self._reader is not None: + self._reader.feed_data(WSMessage(WSMsgType.ERROR, exc, None), 0) + + def _set_closed(self) -> None: + """Set the connection to closed. + + Cancel any heartbeat timers and set the closed flag. + """ + self._closed = True + self._cancel_heartbeat() + + async def prepare(self, request: BaseRequest) -> AbstractStreamWriter: + # make pre-check to don't hide it by do_handshake() exceptions + if self._payload_writer is not None: + return self._payload_writer + + protocol, writer = self._pre_start(request) + payload_writer = await super().prepare(request) + assert payload_writer is not None + self._post_start(request, protocol, writer) + await payload_writer.drain() + return payload_writer + + def _handshake( + self, request: BaseRequest + ) -> Tuple["CIMultiDict[str]", Optional[str], int, bool]: + headers = request.headers + if "websocket" != headers.get(hdrs.UPGRADE, "").lower().strip(): + raise HTTPBadRequest( + text=( + "No WebSocket UPGRADE hdr: {}\n Can " + '"Upgrade" only to "WebSocket".' + ).format(headers.get(hdrs.UPGRADE)) + ) + + if "upgrade" not in headers.get(hdrs.CONNECTION, "").lower(): + raise HTTPBadRequest( + text="No CONNECTION upgrade hdr: {}".format( + headers.get(hdrs.CONNECTION) + ) + ) + + # find common sub-protocol between client and server + protocol: Optional[str] = None + if hdrs.SEC_WEBSOCKET_PROTOCOL in headers: + req_protocols = [ + str(proto.strip()) + for proto in headers[hdrs.SEC_WEBSOCKET_PROTOCOL].split(",") + ] + + for proto in req_protocols: + if proto in self._protocols: + protocol = proto + break + else: + # No overlap found: Return no protocol as per spec + ws_logger.warning( + "%s: Client protocols %r don’t overlap server-known ones %r", + request.remote, + req_protocols, + self._protocols, + ) + + # check supported version + version = headers.get(hdrs.SEC_WEBSOCKET_VERSION, "") + if version not in ("13", "8", "7"): + raise HTTPBadRequest(text=f"Unsupported version: {version}") + + # check client handshake for validity + key = headers.get(hdrs.SEC_WEBSOCKET_KEY) + try: + if not key or len(base64.b64decode(key)) != 16: + raise HTTPBadRequest(text=f"Handshake error: {key!r}") + except binascii.Error: + raise HTTPBadRequest(text=f"Handshake error: {key!r}") from None + + accept_val = base64.b64encode( + hashlib.sha1(key.encode() + WS_KEY).digest() + ).decode() + response_headers = CIMultiDict( + { + hdrs.UPGRADE: "websocket", + hdrs.CONNECTION: "upgrade", + hdrs.SEC_WEBSOCKET_ACCEPT: accept_val, + } + ) + + notakeover = False + compress = 0 + if self._compress: + extensions = headers.get(hdrs.SEC_WEBSOCKET_EXTENSIONS) + # Server side always get return with no exception. + # If something happened, just drop compress extension + compress, notakeover = ws_ext_parse(extensions, isserver=True) + if compress: + enabledext = ws_ext_gen( + compress=compress, isserver=True, server_notakeover=notakeover + ) + response_headers[hdrs.SEC_WEBSOCKET_EXTENSIONS] = enabledext + + if protocol: + response_headers[hdrs.SEC_WEBSOCKET_PROTOCOL] = protocol + return ( + response_headers, + protocol, + compress, + notakeover, + ) + + def _pre_start(self, request: BaseRequest) -> Tuple[Optional[str], WebSocketWriter]: + self._loop = request._loop + + headers, protocol, compress, notakeover = self._handshake(request) + + self.set_status(101) + self.headers.update(headers) + self.force_close() + self._compress = compress + transport = request._protocol.transport + assert transport is not None + writer = WebSocketWriter( + request._protocol, + transport, + compress=compress, + notakeover=notakeover, + limit=self._writer_limit, + ) + + return protocol, writer + + def _post_start( + self, request: BaseRequest, protocol: Optional[str], writer: WebSocketWriter + ) -> None: + self._ws_protocol = protocol + self._writer = writer + + self._reset_heartbeat() + + loop = self._loop + assert loop is not None + self._reader = WebSocketDataQueue(request._protocol, 2**16, loop=loop) + request.protocol.set_parser( + WebSocketReader( + self._reader, self._max_msg_size, compress=bool(self._compress) + ) + ) + # disable HTTP keepalive for WebSocket + request.protocol.keep_alive(False) + + def can_prepare(self, request: BaseRequest) -> WebSocketReady: + if self._writer is not None: + raise RuntimeError("Already started") + try: + _, protocol, _, _ = self._handshake(request) + except HTTPException: + return WebSocketReady(False, None) + else: + return WebSocketReady(True, protocol) + + @property + def closed(self) -> bool: + return self._closed + + @property + def close_code(self) -> Optional[int]: + return self._close_code + + @property + def ws_protocol(self) -> Optional[str]: + return self._ws_protocol + + @property + def compress(self) -> Union[int, bool]: + return self._compress + + def get_extra_info(self, name: str, default: Any = None) -> Any: + """Get optional transport information. + + If no value associated with ``name`` is found, ``default`` is returned. + """ + writer = self._writer + if writer is None: + return default + transport = writer.transport + if transport is None: + return default + return transport.get_extra_info(name, default) + + def exception(self) -> Optional[BaseException]: + return self._exception + + async def ping(self, message: bytes = b"") -> None: + if self._writer is None: + raise RuntimeError("Call .prepare() first") + await self._writer.send_frame(message, WSMsgType.PING) + + async def pong(self, message: bytes = b"") -> None: + # unsolicited pong + if self._writer is None: + raise RuntimeError("Call .prepare() first") + await self._writer.send_frame(message, WSMsgType.PONG) + + async def send_frame( + self, message: bytes, opcode: WSMsgType, compress: Optional[int] = None + ) -> None: + """Send a frame over the websocket.""" + if self._writer is None: + raise RuntimeError("Call .prepare() first") + await self._writer.send_frame(message, opcode, compress) + + async def send_str(self, data: str, compress: Optional[int] = None) -> None: + if self._writer is None: + raise RuntimeError("Call .prepare() first") + if not isinstance(data, str): + raise TypeError("data argument must be str (%r)" % type(data)) + await self._writer.send_frame( + data.encode("utf-8"), WSMsgType.TEXT, compress=compress + ) + + async def send_bytes(self, data: bytes, compress: Optional[int] = None) -> None: + if self._writer is None: + raise RuntimeError("Call .prepare() first") + if not isinstance(data, (bytes, bytearray, memoryview)): + raise TypeError("data argument must be byte-ish (%r)" % type(data)) + await self._writer.send_frame(data, WSMsgType.BINARY, compress=compress) + + async def send_json( + self, + data: Any, + compress: Optional[int] = None, + *, + dumps: JSONEncoder = json.dumps, + ) -> None: + await self.send_str(dumps(data), compress=compress) + + async def write_eof(self) -> None: # type: ignore[override] + if self._eof_sent: + return + if self._payload_writer is None: + raise RuntimeError("Response has not been started") + + await self.close() + self._eof_sent = True + + async def close( + self, *, code: int = WSCloseCode.OK, message: bytes = b"", drain: bool = True + ) -> bool: + """Close websocket connection.""" + if self._writer is None: + raise RuntimeError("Call .prepare() first") + + if self._closed: + return False + self._set_closed() + + try: + await self._writer.close(code, message) + writer = self._payload_writer + assert writer is not None + if drain: + await writer.drain() + except (asyncio.CancelledError, asyncio.TimeoutError): + self._set_code_close_transport(WSCloseCode.ABNORMAL_CLOSURE) + raise + except Exception as exc: + self._exception = exc + self._set_code_close_transport(WSCloseCode.ABNORMAL_CLOSURE) + return True + + reader = self._reader + assert reader is not None + # we need to break `receive()` cycle before we can call + # `reader.read()` as `close()` may be called from different task + if self._waiting: + assert self._loop is not None + assert self._close_wait is None + self._close_wait = self._loop.create_future() + reader.feed_data(WS_CLOSING_MESSAGE, 0) + await self._close_wait + + if self._closing: + self._close_transport() + return True + + try: + async with async_timeout.timeout(self._timeout): + while True: + msg = await reader.read() + if msg.type is WSMsgType.CLOSE: + self._set_code_close_transport(msg.data) + return True + except asyncio.CancelledError: + self._set_code_close_transport(WSCloseCode.ABNORMAL_CLOSURE) + raise + except Exception as exc: + self._exception = exc + self._set_code_close_transport(WSCloseCode.ABNORMAL_CLOSURE) + return True + + def _set_closing(self, code: WSCloseCode) -> None: + """Set the close code and mark the connection as closing.""" + self._closing = True + self._close_code = code + self._cancel_heartbeat() + + def _set_code_close_transport(self, code: WSCloseCode) -> None: + """Set the close code and close the transport.""" + self._close_code = code + self._close_transport() + + def _close_transport(self) -> None: + """Close the transport.""" + if self._req is not None and self._req.transport is not None: + self._req.transport.close() + + async def receive(self, timeout: Optional[float] = None) -> WSMessage: + if self._reader is None: + raise RuntimeError("Call .prepare() first") + + receive_timeout = timeout or self._receive_timeout + while True: + if self._waiting: + raise RuntimeError("Concurrent call to receive() is not allowed") + + if self._closed: + self._conn_lost += 1 + if self._conn_lost >= THRESHOLD_CONNLOST_ACCESS: + raise RuntimeError("WebSocket connection is closed.") + return WS_CLOSED_MESSAGE + elif self._closing: + return WS_CLOSING_MESSAGE + + try: + self._waiting = True + try: + if receive_timeout: + # Entering the context manager and creating + # Timeout() object can take almost 50% of the + # run time in this loop so we avoid it if + # there is no read timeout. + async with async_timeout.timeout(receive_timeout): + msg = await self._reader.read() + else: + msg = await self._reader.read() + self._reset_heartbeat() + finally: + self._waiting = False + if self._close_wait: + set_result(self._close_wait, None) + except asyncio.TimeoutError: + raise + except EofStream: + self._close_code = WSCloseCode.OK + await self.close() + return WSMessage(WSMsgType.CLOSED, None, None) + except WebSocketError as exc: + self._close_code = exc.code + await self.close(code=exc.code) + return WSMessage(WSMsgType.ERROR, exc, None) + except Exception as exc: + self._exception = exc + self._set_closing(WSCloseCode.ABNORMAL_CLOSURE) + await self.close() + return WSMessage(WSMsgType.ERROR, exc, None) + + if msg.type not in _INTERNAL_RECEIVE_TYPES: + # If its not a close/closing/ping/pong message + # we can return it immediately + return msg + + if msg.type is WSMsgType.CLOSE: + self._set_closing(msg.data) + # Could be closed while awaiting reader. + if not self._closed and self._autoclose: + # The client is likely going to close the + # connection out from under us so we do not + # want to drain any pending writes as it will + # likely result writing to a broken pipe. + await self.close(drain=False) + elif msg.type is WSMsgType.CLOSING: + self._set_closing(WSCloseCode.OK) + elif msg.type is WSMsgType.PING and self._autoping: + await self.pong(msg.data) + continue + elif msg.type is WSMsgType.PONG and self._autoping: + continue + + return msg + + async def receive_str(self, *, timeout: Optional[float] = None) -> str: + msg = await self.receive(timeout) + if msg.type is not WSMsgType.TEXT: + raise WSMessageTypeError( + f"Received message {msg.type}:{msg.data!r} is not WSMsgType.TEXT" + ) + return cast(str, msg.data) + + async def receive_bytes(self, *, timeout: Optional[float] = None) -> bytes: + msg = await self.receive(timeout) + if msg.type is not WSMsgType.BINARY: + raise WSMessageTypeError( + f"Received message {msg.type}:{msg.data!r} is not WSMsgType.BINARY" + ) + return cast(bytes, msg.data) + + async def receive_json( + self, *, loads: JSONDecoder = json.loads, timeout: Optional[float] = None + ) -> Any: + data = await self.receive_str(timeout=timeout) + return loads(data) + + async def write(self, data: bytes) -> None: + raise RuntimeError("Cannot call .write() for websocket") + + def __aiter__(self) -> "WebSocketResponse": + return self + + async def __anext__(self) -> WSMessage: + msg = await self.receive() + if msg.type in (WSMsgType.CLOSE, WSMsgType.CLOSING, WSMsgType.CLOSED): + raise StopAsyncIteration + return msg + + def _cancel(self, exc: BaseException) -> None: + # web_protocol calls this from connection_lost + # or when the server is shutting down. + self._closing = True + self._cancel_heartbeat() + if self._reader is not None: + set_exception(self._reader, exc) diff --git a/venv/lib/python3.12/site-packages/aiohttp/worker.py b/venv/lib/python3.12/site-packages/aiohttp/worker.py new file mode 100644 index 00000000..f7281bfd --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiohttp/worker.py @@ -0,0 +1,255 @@ +"""Async gunicorn worker for aiohttp.web""" + +import asyncio +import inspect +import os +import re +import signal +import sys +from types import FrameType +from typing import TYPE_CHECKING, Any, Optional + +from gunicorn.config import AccessLogFormat as GunicornAccessLogFormat +from gunicorn.workers import base + +from aiohttp import web + +from .helpers import set_result +from .web_app import Application +from .web_log import AccessLogger + +if TYPE_CHECKING: + import ssl + + SSLContext = ssl.SSLContext +else: + try: + import ssl + + SSLContext = ssl.SSLContext + except ImportError: # pragma: no cover + ssl = None # type: ignore[assignment] + SSLContext = object # type: ignore[misc,assignment] + + +__all__ = ("GunicornWebWorker", "GunicornUVLoopWebWorker") + + +class GunicornWebWorker(base.Worker): # type: ignore[misc,no-any-unimported] + + DEFAULT_AIOHTTP_LOG_FORMAT = AccessLogger.LOG_FORMAT + DEFAULT_GUNICORN_LOG_FORMAT = GunicornAccessLogFormat.default + + def __init__(self, *args: Any, **kw: Any) -> None: # pragma: no cover + super().__init__(*args, **kw) + + self._task: Optional[asyncio.Task[None]] = None + self.exit_code = 0 + self._notify_waiter: Optional[asyncio.Future[bool]] = None + + def init_process(self) -> None: + # create new event_loop after fork + asyncio.get_event_loop().close() + + self.loop = asyncio.new_event_loop() + asyncio.set_event_loop(self.loop) + + super().init_process() + + def run(self) -> None: + self._task = self.loop.create_task(self._run()) + + try: # ignore all finalization problems + self.loop.run_until_complete(self._task) + except Exception: + self.log.exception("Exception in gunicorn worker") + self.loop.run_until_complete(self.loop.shutdown_asyncgens()) + self.loop.close() + + sys.exit(self.exit_code) + + async def _run(self) -> None: + runner = None + if isinstance(self.wsgi, Application): + app = self.wsgi + elif inspect.iscoroutinefunction(self.wsgi) or ( + sys.version_info < (3, 14) and asyncio.iscoroutinefunction(self.wsgi) + ): + wsgi = await self.wsgi() + if isinstance(wsgi, web.AppRunner): + runner = wsgi + app = runner.app + else: + app = wsgi + else: + raise RuntimeError( + "wsgi app should be either Application or " + "async function returning Application, got {}".format(self.wsgi) + ) + + if runner is None: + access_log = self.log.access_log if self.cfg.accesslog else None + runner = web.AppRunner( + app, + logger=self.log, + keepalive_timeout=self.cfg.keepalive, + access_log=access_log, + access_log_format=self._get_valid_log_format( + self.cfg.access_log_format + ), + shutdown_timeout=self.cfg.graceful_timeout / 100 * 95, + ) + await runner.setup() + + ctx = self._create_ssl_context(self.cfg) if self.cfg.is_ssl else None + + runner = runner + assert runner is not None + server = runner.server + assert server is not None + for sock in self.sockets: + site = web.SockSite( + runner, + sock, + ssl_context=ctx, + ) + await site.start() + + # If our parent changed then we shut down. + pid = os.getpid() + try: + while self.alive: # type: ignore[has-type] + self.notify() + + cnt = server.requests_count + if self.max_requests and cnt > self.max_requests: + self.alive = False + self.log.info("Max requests, shutting down: %s", self) + + elif pid == os.getpid() and self.ppid != os.getppid(): + self.alive = False + self.log.info("Parent changed, shutting down: %s", self) + else: + await self._wait_next_notify() + except BaseException: + pass + + await runner.cleanup() + + def _wait_next_notify(self) -> "asyncio.Future[bool]": + self._notify_waiter_done() + + loop = self.loop + assert loop is not None + self._notify_waiter = waiter = loop.create_future() + self.loop.call_later(1.0, self._notify_waiter_done, waiter) + + return waiter + + def _notify_waiter_done( + self, waiter: Optional["asyncio.Future[bool]"] = None + ) -> None: + if waiter is None: + waiter = self._notify_waiter + if waiter is not None: + set_result(waiter, True) + + if waiter is self._notify_waiter: + self._notify_waiter = None + + def init_signals(self) -> None: + # Set up signals through the event loop API. + + self.loop.add_signal_handler( + signal.SIGQUIT, self.handle_quit, signal.SIGQUIT, None + ) + + self.loop.add_signal_handler( + signal.SIGTERM, self.handle_exit, signal.SIGTERM, None + ) + + self.loop.add_signal_handler( + signal.SIGINT, self.handle_quit, signal.SIGINT, None + ) + + self.loop.add_signal_handler( + signal.SIGWINCH, self.handle_winch, signal.SIGWINCH, None + ) + + self.loop.add_signal_handler( + signal.SIGUSR1, self.handle_usr1, signal.SIGUSR1, None + ) + + self.loop.add_signal_handler( + signal.SIGABRT, self.handle_abort, signal.SIGABRT, None + ) + + # Don't let SIGTERM and SIGUSR1 disturb active requests + # by interrupting system calls + signal.siginterrupt(signal.SIGTERM, False) + signal.siginterrupt(signal.SIGUSR1, False) + # Reset signals so Gunicorn doesn't swallow subprocess return codes + # See: https://github.com/aio-libs/aiohttp/issues/6130 + + def handle_quit(self, sig: int, frame: Optional[FrameType]) -> None: + self.alive = False + + # worker_int callback + self.cfg.worker_int(self) + + # wakeup closing process + self._notify_waiter_done() + + def handle_abort(self, sig: int, frame: Optional[FrameType]) -> None: + self.alive = False + self.exit_code = 1 + self.cfg.worker_abort(self) + sys.exit(1) + + @staticmethod + def _create_ssl_context(cfg: Any) -> "SSLContext": + """Creates SSLContext instance for usage in asyncio.create_server. + + See ssl.SSLSocket.__init__ for more details. + """ + if ssl is None: # pragma: no cover + raise RuntimeError("SSL is not supported.") + + ctx = ssl.SSLContext(cfg.ssl_version) + ctx.load_cert_chain(cfg.certfile, cfg.keyfile) + ctx.verify_mode = cfg.cert_reqs + if cfg.ca_certs: + ctx.load_verify_locations(cfg.ca_certs) + if cfg.ciphers: + ctx.set_ciphers(cfg.ciphers) + return ctx + + def _get_valid_log_format(self, source_format: str) -> str: + if source_format == self.DEFAULT_GUNICORN_LOG_FORMAT: + return self.DEFAULT_AIOHTTP_LOG_FORMAT + elif re.search(r"%\([^\)]+\)", source_format): + raise ValueError( + "Gunicorn's style options in form of `%(name)s` are not " + "supported for the log formatting. Please use aiohttp's " + "format specification to configure access log formatting: " + "http://docs.aiohttp.org/en/stable/logging.html" + "#format-specification" + ) + else: + return source_format + + +class GunicornUVLoopWebWorker(GunicornWebWorker): + def init_process(self) -> None: + import uvloop + + # Close any existing event loop before setting a + # new policy. + asyncio.get_event_loop().close() + + # Setup uvloop policy, so that every + # asyncio.get_event_loop() will create an instance + # of uvloop event loop. + asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) + + super().init_process() diff --git a/venv/lib/python3.12/site-packages/aiosignal-1.3.2.dist-info/INSTALLER b/venv/lib/python3.12/site-packages/aiosignal-1.3.2.dist-info/INSTALLER new file mode 100644 index 00000000..a1b589e3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiosignal-1.3.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.12/site-packages/aiosignal-1.3.2.dist-info/LICENSE b/venv/lib/python3.12/site-packages/aiosignal-1.3.2.dist-info/LICENSE new file mode 100644 index 00000000..7082a2d5 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiosignal-1.3.2.dist-info/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2013-2019 Nikolay Kim and Andrew Svetlov + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/venv/lib/python3.12/site-packages/aiosignal-1.3.2.dist-info/METADATA b/venv/lib/python3.12/site-packages/aiosignal-1.3.2.dist-info/METADATA new file mode 100644 index 00000000..6839bf9c --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiosignal-1.3.2.dist-info/METADATA @@ -0,0 +1,123 @@ +Metadata-Version: 2.1 +Name: aiosignal +Version: 1.3.2 +Summary: aiosignal: a list of registered asynchronous callbacks +Home-page: https://github.com/aio-libs/aiosignal +Maintainer: aiohttp team +Maintainer-email: team@aiohttp.org +License: Apache 2.0 +Project-URL: Chat: Gitter, https://gitter.im/aio-libs/Lobby +Project-URL: CI: GitHub Actions, https://github.com/aio-libs/aiosignal/actions +Project-URL: Coverage: codecov, https://codecov.io/github/aio-libs/aiosignal +Project-URL: Docs: RTD, https://docs.aiosignal.org +Project-URL: GitHub: issues, https://github.com/aio-libs/aiosignal/issues +Project-URL: GitHub: repo, https://github.com/aio-libs/aiosignal +Classifier: License :: OSI Approved :: Apache Software License +Classifier: Intended Audience :: Developers +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Development Status :: 5 - Production/Stable +Classifier: Operating System :: POSIX +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Operating System :: Microsoft :: Windows +Classifier: Framework :: AsyncIO +Requires-Python: >=3.9 +Description-Content-Type: text/x-rst +License-File: LICENSE +Requires-Dist: frozenlist>=1.1.0 + +========= +aiosignal +========= + +.. image:: https://github.com/aio-libs/aiosignal/workflows/CI/badge.svg + :target: https://github.com/aio-libs/aiosignal/actions?query=workflow%3ACI + :alt: GitHub status for master branch + +.. image:: https://codecov.io/gh/aio-libs/aiosignal/branch/master/graph/badge.svg + :target: https://codecov.io/gh/aio-libs/aiosignal + :alt: codecov.io status for master branch + +.. image:: https://badge.fury.io/py/aiosignal.svg + :target: https://pypi.org/project/aiosignal + :alt: Latest PyPI package version + +.. image:: https://readthedocs.org/projects/aiosignal/badge/?version=latest + :target: https://aiosignal.readthedocs.io/ + :alt: Latest Read The Docs + +.. image:: https://img.shields.io/discourse/topics?server=https%3A%2F%2Faio-libs.discourse.group%2F + :target: https://aio-libs.discourse.group/ + :alt: Discourse group for io-libs + +.. image:: https://badges.gitter.im/Join%20Chat.svg + :target: https://gitter.im/aio-libs/Lobby + :alt: Chat on Gitter + +Introduction +============ + +A project to manage callbacks in `asyncio` projects. + +``Signal`` is a list of registered asynchronous callbacks. + +The signal's life-cycle has two stages: after creation its content +could be filled by using standard list operations: ``sig.append()`` +etc. + +After you call ``sig.freeze()`` the signal is *frozen*: adding, removing +and dropping callbacks is forbidden. + +The only available operation is calling the previously registered +callbacks by using ``await sig.send(data)``. + +For concrete usage examples see the `Signals + +section of the `Web Server Advanced +` chapter of the `aiohttp +documentation`_. + + +Installation +------------ + +:: + + $ pip install aiosignal + +The library requires Python 3.8 or newer. + + +Documentation +============= + +https://aiosignal.readthedocs.io/ + +Communication channels +====================== + +*gitter chat* https://gitter.im/aio-libs/Lobby + +Requirements +============ + +- Python >= 3.8 +- frozenlist >= 1.0.0 + +License +======= + +``aiosignal`` is offered under the Apache 2 license. + +Source code +=========== + +The project is hosted on GitHub_ + +Please file an issue in the `bug tracker +`_ if you have found a bug +or have some suggestions to improve the library. + +.. _GitHub: https://github.com/aio-libs/aiosignal +.. _aiohttp documentation: https://docs.aiohttp.org/ diff --git a/venv/lib/python3.12/site-packages/aiosignal-1.3.2.dist-info/RECORD b/venv/lib/python3.12/site-packages/aiosignal-1.3.2.dist-info/RECORD new file mode 100644 index 00000000..d0905865 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiosignal-1.3.2.dist-info/RECORD @@ -0,0 +1,10 @@ +aiosignal-1.3.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +aiosignal-1.3.2.dist-info/LICENSE,sha256=b9UkPpLdf5jsacesN3co50kFcJ_1J6W_mNbQJjwE9bY,11332 +aiosignal-1.3.2.dist-info/METADATA,sha256=TeI_xgZ191qgx37rviEnpMWC0QnYsg_j9EGVivNqqjc,3753 +aiosignal-1.3.2.dist-info/RECORD,, +aiosignal-1.3.2.dist-info/WHEEL,sha256=pxeNX5JdtCe58PUSYP9upmc7jdRPgvT0Gm9kb1SHlVw,109 +aiosignal-1.3.2.dist-info/top_level.txt,sha256=z45aNOKGDdrI1roqZY3BGXQ22kJFPHBmVdwtLYLtXC0,10 +aiosignal/__init__.py,sha256=1oIrRl6kNpqFh32e7HfMFbMV_35v8sqJJFfnuKgmtEU,867 +aiosignal/__init__.pyi,sha256=xeCddYSS8fZAkz8S4HuKSR2IDe3N7RW_LKcXDPPA1Xk,311 +aiosignal/__pycache__/__init__.cpython-312.pyc,, +aiosignal/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/venv/lib/python3.12/site-packages/aiosignal-1.3.2.dist-info/WHEEL b/venv/lib/python3.12/site-packages/aiosignal-1.3.2.dist-info/WHEEL new file mode 100644 index 00000000..104f3874 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiosignal-1.3.2.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: setuptools (75.6.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/lib/python3.12/site-packages/aiosignal-1.3.2.dist-info/top_level.txt b/venv/lib/python3.12/site-packages/aiosignal-1.3.2.dist-info/top_level.txt new file mode 100644 index 00000000..ac6df3af --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiosignal-1.3.2.dist-info/top_level.txt @@ -0,0 +1 @@ +aiosignal diff --git a/venv/lib/python3.12/site-packages/aiosignal/__init__.py b/venv/lib/python3.12/site-packages/aiosignal/__init__.py new file mode 100644 index 00000000..4ad02789 --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiosignal/__init__.py @@ -0,0 +1,36 @@ +from frozenlist import FrozenList + +__version__ = "1.3.2" + +__all__ = ("Signal",) + + +class Signal(FrozenList): + """Coroutine-based signal implementation. + + To connect a callback to a signal, use any list method. + + Signals are fired using the send() coroutine, which takes named + arguments. + """ + + __slots__ = ("_owner",) + + def __init__(self, owner): + super().__init__() + self._owner = owner + + def __repr__(self): + return "".format( + self._owner, self.frozen, list(self) + ) + + async def send(self, *args, **kwargs): + """ + Sends data to all registered receivers. + """ + if not self.frozen: + raise RuntimeError("Cannot send non-frozen signal.") + + for receiver in self: + await receiver(*args, **kwargs) # type: ignore diff --git a/venv/lib/python3.12/site-packages/aiosignal/__init__.pyi b/venv/lib/python3.12/site-packages/aiosignal/__init__.pyi new file mode 100644 index 00000000..d4e3416d --- /dev/null +++ b/venv/lib/python3.12/site-packages/aiosignal/__init__.pyi @@ -0,0 +1,12 @@ +from typing import Any, Generic, TypeVar + +from frozenlist import FrozenList + +__all__ = ("Signal",) + +_T = TypeVar("_T") + +class Signal(FrozenList[_T], Generic[_T]): + def __init__(self, owner: Any) -> None: ... + def __repr__(self) -> str: ... + async def send(self, *args: Any, **kwargs: Any) -> None: ... diff --git a/venv/lib/python3.12/site-packages/aiosignal/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/aiosignal/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f342848f1f4fb28de6ef2b7bedeadff73856a59a GIT binary patch literal 1702 zcmZ8h-A^1<6u)<7XLneZLRZjQu-+OUn6T{1hf$kaNvQP$L!#)*CT23sT$X{^nf2aT zkY!0oB?_j zr&iKN=5JvdILcmQL4*45xIAoVBgL`eC`_hj+=_2`w%F4aB{5o~V0;GoC@NzIK^|OI zAzx|}&0$B~(94?0SWY_{=*%Yi7?<@KWTaUN92-AR1}vzDu1|+&ElwT6Wh&xUYaXpq zKeR$O@Qc|j0eL?lcHsNe4v9r<%kyR}dy#|zjAFL}sdGv!e}#B(08*vleBdO`@fkR= z7$tKqgH(0y`V|t+Q^Kk53>pwTsii=c=UscAgw`VE#J8%{kp)<+QWr(>q8tin%wXB4 z%x=RWP!Yh2uk`|`FYzu4;UCME(nQ;EQG3Z4qb6=5^VE9Ui19A9>nqk)SO?V5=#F77wilj&N!|zQ;X1mjcWq@3^mD)I=MSIk-%M?HwqOC- zSm;DD@R!)lf&nDP3y-cQo0@3h6tQFqelRO2^_YYrqLe1uOJcRD4>VM!8_!*iYbFxa zS69~xWKK4LG*>UOwJSy{O3wwXYK8J5U?4X{DM2#>Gtrb>1ShNuw754$Ys@qs!6Tk{ zO6(j2wT=$E$L@4rI_SQ1nCsb@+M2rA`%VAX{kNRk0!k?kZXfw#5PJn=kX}LxGewr zX?$_vB6D~HE`;luydyQQQh*Am5gaRfeq8ptlWbx17?UuVWKhE)1acRq>XLrd8P?$5~(Dc zCgic?Ln)Om7A}B#xPk5|X-z-wL1zcn-+GWzw1NA&s%8Jp>RLfkMmkIzT9l1(7EEP= z4pFCRimQQV70QD8;2njc1d`vQ*i~@&M86y#=?Z%uhJxHO^|6XE{sUb+I@7n_d6ey2 R&pb#E;KFA49|S+?{~xj>sM7!d literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/aiosignal/py.typed b/venv/lib/python3.12/site-packages/aiosignal/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/venv/lib/python3.12/site-packages/attr/__init__.py b/venv/lib/python3.12/site-packages/attr/__init__.py new file mode 100644 index 00000000..5c6e0650 --- /dev/null +++ b/venv/lib/python3.12/site-packages/attr/__init__.py @@ -0,0 +1,104 @@ +# SPDX-License-Identifier: MIT + +""" +Classes Without Boilerplate +""" + +from functools import partial +from typing import Callable, Literal, Protocol + +from . import converters, exceptions, filters, setters, validators +from ._cmp import cmp_using +from ._config import get_run_validators, set_run_validators +from ._funcs import asdict, assoc, astuple, has, resolve_types +from ._make import ( + NOTHING, + Attribute, + Converter, + Factory, + _Nothing, + attrib, + attrs, + evolve, + fields, + fields_dict, + make_class, + validate, +) +from ._next_gen import define, field, frozen, mutable +from ._version_info import VersionInfo + + +s = attributes = attrs +ib = attr = attrib +dataclass = partial(attrs, auto_attribs=True) # happy Easter ;) + + +class AttrsInstance(Protocol): + pass + + +NothingType = Literal[_Nothing.NOTHING] + +__all__ = [ + "NOTHING", + "Attribute", + "AttrsInstance", + "Converter", + "Factory", + "NothingType", + "asdict", + "assoc", + "astuple", + "attr", + "attrib", + "attributes", + "attrs", + "cmp_using", + "converters", + "define", + "evolve", + "exceptions", + "field", + "fields", + "fields_dict", + "filters", + "frozen", + "get_run_validators", + "has", + "ib", + "make_class", + "mutable", + "resolve_types", + "s", + "set_run_validators", + "setters", + "validate", + "validators", +] + + +def _make_getattr(mod_name: str) -> Callable: + """ + Create a metadata proxy for packaging information that uses *mod_name* in + its warnings and errors. + """ + + def __getattr__(name: str) -> str: + if name not in ("__version__", "__version_info__"): + msg = f"module {mod_name} has no attribute {name}" + raise AttributeError(msg) + + from importlib.metadata import metadata + + meta = metadata("attrs") + + if name == "__version_info__": + return VersionInfo._from_version_string(meta["version"]) + + return meta["version"] + + return __getattr__ + + +__getattr__ = _make_getattr(__name__) diff --git a/venv/lib/python3.12/site-packages/attr/__init__.pyi b/venv/lib/python3.12/site-packages/attr/__init__.pyi new file mode 100644 index 00000000..133e5010 --- /dev/null +++ b/venv/lib/python3.12/site-packages/attr/__init__.pyi @@ -0,0 +1,389 @@ +import enum +import sys + +from typing import ( + Any, + Callable, + Generic, + Literal, + Mapping, + Protocol, + Sequence, + TypeVar, + overload, +) + +# `import X as X` is required to make these public +from . import converters as converters +from . import exceptions as exceptions +from . import filters as filters +from . import setters as setters +from . import validators as validators +from ._cmp import cmp_using as cmp_using +from ._typing_compat import AttrsInstance_ +from ._version_info import VersionInfo +from attrs import ( + define as define, + field as field, + mutable as mutable, + frozen as frozen, + _EqOrderType, + _ValidatorType, + _ConverterType, + _ReprArgType, + _OnSetAttrType, + _OnSetAttrArgType, + _FieldTransformer, + _ValidatorArgType, +) + +if sys.version_info >= (3, 10): + from typing import TypeGuard, TypeAlias +else: + from typing_extensions import TypeGuard, TypeAlias + +if sys.version_info >= (3, 11): + from typing import dataclass_transform +else: + from typing_extensions import dataclass_transform + +__version__: str +__version_info__: VersionInfo +__title__: str +__description__: str +__url__: str +__uri__: str +__author__: str +__email__: str +__license__: str +__copyright__: str + +_T = TypeVar("_T") +_C = TypeVar("_C", bound=type) + +_FilterType = Callable[["Attribute[_T]", _T], bool] + +# We subclass this here to keep the protocol's qualified name clean. +class AttrsInstance(AttrsInstance_, Protocol): + pass + +_A = TypeVar("_A", bound=type[AttrsInstance]) + +class _Nothing(enum.Enum): + NOTHING = enum.auto() + +NOTHING = _Nothing.NOTHING +NothingType: TypeAlias = Literal[_Nothing.NOTHING] + +# NOTE: Factory lies about its return type to make this possible: +# `x: List[int] # = Factory(list)` +# Work around mypy issue #4554 in the common case by using an overload. + +@overload +def Factory(factory: Callable[[], _T]) -> _T: ... +@overload +def Factory( + factory: Callable[[Any], _T], + takes_self: Literal[True], +) -> _T: ... +@overload +def Factory( + factory: Callable[[], _T], + takes_self: Literal[False], +) -> _T: ... + +In = TypeVar("In") +Out = TypeVar("Out") + +class Converter(Generic[In, Out]): + @overload + def __init__(self, converter: Callable[[In], Out]) -> None: ... + @overload + def __init__( + self, + converter: Callable[[In, AttrsInstance, Attribute], Out], + *, + takes_self: Literal[True], + takes_field: Literal[True], + ) -> None: ... + @overload + def __init__( + self, + converter: Callable[[In, Attribute], Out], + *, + takes_field: Literal[True], + ) -> None: ... + @overload + def __init__( + self, + converter: Callable[[In, AttrsInstance], Out], + *, + takes_self: Literal[True], + ) -> None: ... + +class Attribute(Generic[_T]): + name: str + default: _T | None + validator: _ValidatorType[_T] | None + repr: _ReprArgType + cmp: _EqOrderType + eq: _EqOrderType + order: _EqOrderType + hash: bool | None + init: bool + converter: Converter | None + metadata: dict[Any, Any] + type: type[_T] | None + kw_only: bool + on_setattr: _OnSetAttrType + alias: str | None + + def evolve(self, **changes: Any) -> "Attribute[Any]": ... + +# NOTE: We had several choices for the annotation to use for type arg: +# 1) Type[_T] +# - Pros: Handles simple cases correctly +# - Cons: Might produce less informative errors in the case of conflicting +# TypeVars e.g. `attr.ib(default='bad', type=int)` +# 2) Callable[..., _T] +# - Pros: Better error messages than #1 for conflicting TypeVars +# - Cons: Terrible error messages for validator checks. +# e.g. attr.ib(type=int, validator=validate_str) +# -> error: Cannot infer function type argument +# 3) type (and do all of the work in the mypy plugin) +# - Pros: Simple here, and we could customize the plugin with our own errors. +# - Cons: Would need to write mypy plugin code to handle all the cases. +# We chose option #1. + +# `attr` lies about its return type to make the following possible: +# attr() -> Any +# attr(8) -> int +# attr(validator=) -> Whatever the callable expects. +# This makes this type of assignments possible: +# x: int = attr(8) +# +# This form catches explicit None or no default but with no other arguments +# returns Any. +@overload +def attrib( + default: None = ..., + validator: None = ..., + repr: _ReprArgType = ..., + cmp: _EqOrderType | None = ..., + hash: bool | None = ..., + init: bool = ..., + metadata: Mapping[Any, Any] | None = ..., + type: None = ..., + converter: None = ..., + factory: None = ..., + kw_only: bool = ..., + eq: _EqOrderType | None = ..., + order: _EqOrderType | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + alias: str | None = ..., +) -> Any: ... + +# This form catches an explicit None or no default and infers the type from the +# other arguments. +@overload +def attrib( + default: None = ..., + validator: _ValidatorArgType[_T] | None = ..., + repr: _ReprArgType = ..., + cmp: _EqOrderType | None = ..., + hash: bool | None = ..., + init: bool = ..., + metadata: Mapping[Any, Any] | None = ..., + type: type[_T] | None = ..., + converter: _ConverterType + | list[_ConverterType] + | tuple[_ConverterType] + | None = ..., + factory: Callable[[], _T] | None = ..., + kw_only: bool = ..., + eq: _EqOrderType | None = ..., + order: _EqOrderType | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + alias: str | None = ..., +) -> _T: ... + +# This form catches an explicit default argument. +@overload +def attrib( + default: _T, + validator: _ValidatorArgType[_T] | None = ..., + repr: _ReprArgType = ..., + cmp: _EqOrderType | None = ..., + hash: bool | None = ..., + init: bool = ..., + metadata: Mapping[Any, Any] | None = ..., + type: type[_T] | None = ..., + converter: _ConverterType + | list[_ConverterType] + | tuple[_ConverterType] + | None = ..., + factory: Callable[[], _T] | None = ..., + kw_only: bool = ..., + eq: _EqOrderType | None = ..., + order: _EqOrderType | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + alias: str | None = ..., +) -> _T: ... + +# This form covers type=non-Type: e.g. forward references (str), Any +@overload +def attrib( + default: _T | None = ..., + validator: _ValidatorArgType[_T] | None = ..., + repr: _ReprArgType = ..., + cmp: _EqOrderType | None = ..., + hash: bool | None = ..., + init: bool = ..., + metadata: Mapping[Any, Any] | None = ..., + type: object = ..., + converter: _ConverterType + | list[_ConverterType] + | tuple[_ConverterType] + | None = ..., + factory: Callable[[], _T] | None = ..., + kw_only: bool = ..., + eq: _EqOrderType | None = ..., + order: _EqOrderType | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + alias: str | None = ..., +) -> Any: ... +@overload +@dataclass_transform(order_default=True, field_specifiers=(attrib, field)) +def attrs( + maybe_cls: _C, + these: dict[str, Any] | None = ..., + repr_ns: str | None = ..., + repr: bool = ..., + cmp: _EqOrderType | None = ..., + hash: bool | None = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: _EqOrderType | None = ..., + order: _EqOrderType | None = ..., + auto_detect: bool = ..., + collect_by_mro: bool = ..., + getstate_setstate: bool | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + field_transformer: _FieldTransformer | None = ..., + match_args: bool = ..., + unsafe_hash: bool | None = ..., +) -> _C: ... +@overload +@dataclass_transform(order_default=True, field_specifiers=(attrib, field)) +def attrs( + maybe_cls: None = ..., + these: dict[str, Any] | None = ..., + repr_ns: str | None = ..., + repr: bool = ..., + cmp: _EqOrderType | None = ..., + hash: bool | None = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: _EqOrderType | None = ..., + order: _EqOrderType | None = ..., + auto_detect: bool = ..., + collect_by_mro: bool = ..., + getstate_setstate: bool | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + field_transformer: _FieldTransformer | None = ..., + match_args: bool = ..., + unsafe_hash: bool | None = ..., +) -> Callable[[_C], _C]: ... +def fields(cls: type[AttrsInstance]) -> Any: ... +def fields_dict(cls: type[AttrsInstance]) -> dict[str, Attribute[Any]]: ... +def validate(inst: AttrsInstance) -> None: ... +def resolve_types( + cls: _A, + globalns: dict[str, Any] | None = ..., + localns: dict[str, Any] | None = ..., + attribs: list[Attribute[Any]] | None = ..., + include_extras: bool = ..., +) -> _A: ... + +# TODO: add support for returning a proper attrs class from the mypy plugin +# we use Any instead of _CountingAttr so that e.g. `make_class('Foo', +# [attr.ib()])` is valid +def make_class( + name: str, + attrs: list[str] | tuple[str, ...] | dict[str, Any], + bases: tuple[type, ...] = ..., + class_body: dict[str, Any] | None = ..., + repr_ns: str | None = ..., + repr: bool = ..., + cmp: _EqOrderType | None = ..., + hash: bool | None = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: _EqOrderType | None = ..., + order: _EqOrderType | None = ..., + collect_by_mro: bool = ..., + on_setattr: _OnSetAttrArgType | None = ..., + field_transformer: _FieldTransformer | None = ..., +) -> type: ... + +# _funcs -- + +# TODO: add support for returning TypedDict from the mypy plugin +# FIXME: asdict/astuple do not honor their factory args. Waiting on one of +# these: +# https://github.com/python/mypy/issues/4236 +# https://github.com/python/typing/issues/253 +# XXX: remember to fix attrs.asdict/astuple too! +def asdict( + inst: AttrsInstance, + recurse: bool = ..., + filter: _FilterType[Any] | None = ..., + dict_factory: type[Mapping[Any, Any]] = ..., + retain_collection_types: bool = ..., + value_serializer: Callable[[type, Attribute[Any], Any], Any] | None = ..., + tuple_keys: bool | None = ..., +) -> dict[str, Any]: ... + +# TODO: add support for returning NamedTuple from the mypy plugin +def astuple( + inst: AttrsInstance, + recurse: bool = ..., + filter: _FilterType[Any] | None = ..., + tuple_factory: type[Sequence[Any]] = ..., + retain_collection_types: bool = ..., +) -> tuple[Any, ...]: ... +def has(cls: type) -> TypeGuard[type[AttrsInstance]]: ... +def assoc(inst: _T, **changes: Any) -> _T: ... +def evolve(inst: _T, **changes: Any) -> _T: ... + +# _config -- + +def set_run_validators(run: bool) -> None: ... +def get_run_validators() -> bool: ... + +# aliases -- + +s = attributes = attrs +ib = attr = attrib +dataclass = attrs # Technically, partial(attrs, auto_attribs=True) ;) diff --git a/venv/lib/python3.12/site-packages/attr/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/attr/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..743440fcdd49aca2e0604467df74ad4d73983d9e GIT binary patch literal 2651 zcmZWr-ESMm5#Ku=dHfV*QkHD%>nvHe=|p5~MRDK+0%AFh90W=OxlOSz*As6kU3`1T z?j03NkWscUQ0Jk5QJ}DZq(D&gp@mx@eM|p_zR*>JxQhf%Q4~eqlqx}rJauMIlu~yg z&Cbq#&Cbm4cl>jylqb;s^z-rcT$Yf3;Go~q2g?2rG(zqZmr&wruI_7Gr@DrE%1?2F z8az$YJVP^JGu*Uq@+{5r9L@1O&GP~+@FFd$xr|@p19U*?reEfRbdVpT$J99MS9q0H z`4AoA$LVoCOo#ah9Z_>R{{%ltPx4dr6d$Fde2k9qaXQW?=mejnliZ>fKTS{bDLTcc z=`=q>&!~NQe}XZbmLj-RLJd5zYTz2INqPtm6|!X|HN^l3WFCZMm=hEAByCf(xi zOAqwq_4FB?yh7Z8JH#!s%!AZ{^&(5N@wYDZLv_@j1eIP|Bktg@H9F@WW6!!3X0!~q zddHyiaQ-}d?g7LT8@;?aR6D*ko?rBxC}NTIrWdb=o!Gh>dOj0v--%iNb6i=|q}g^v z>^XidC9{i;?>nnLljdt)%!K31>~}>Nht1Ic9M7($Wxg2(8%)4#B=hW6leJ?n3?gZ^ zJYN~jh{eh5hU0s#6Ne&#YjREAwmXp*tkrZ`S!1y+I)Qz(L{?zm6E?Um<3z64jAa@g z5;mpjL~*AL4yM+fNR|YPLVttV@n)MvwW2haU%#<*efbrcdnt~Ex7vxB%q{jEmgaYy zCb+XHv-WZruY)gezFG+9Lm$Zu+rR^5rsXl;jbtI|ZRJCrJ2#o##F)zLf#Zpl{=(mFmlKmoB?h{6+ z2Kdl7HHcaX9~E5>qSy(VY#9?~+kwNGZOgoE^U&@1s26SfM;*scW`0NZ@$7FpjqgR^ zM8gSO!QS3#uCt)AGW%*L@Iuj8X$uI3^+pFufr-ZAigj`RQllAxTn*!Bc1?tx_VbMm z7Hl+pZ?)0hgnA0*>K89HA}EyEw$r@ntT8wpJZ#vu7kII4*V~)oJlw6s3@8yI{|ijffUEG!j9_s` z1kHZ(V3rv0kD%Uv8pO|#=Cl~Jq`CT$-ZJiz7Es=u;%#kPTOl=LtDU!?EeZxWwH%AH z*Z~|lR$GL(Hmz1DtR&!=GY?8ia0fwX#p_ONbrA3u`o3L&1?n^}j;yyG5x}0vf+Db( z5P;0Onv@0>i1+3CMI21@|;3cRv z#U?Lf&}7Bq?NG#kg!iFf_^U}0!H*7*ObFEGQgdO^kKq$!! z@I1s)AhrZ@iO8V&0P70j3epOw3ZsS%pB=>qa4LMcTHacMbp*7`*myzo1hpt0NRXda zkNFls9deVvnpE_Yl#Jq-BW6(yV&NS*J7BkBNNA9dk)j~QIY=oC-!h60l!karTA#iIHq`(lEF1%c^6xJG{f zv6s>`?Td`A8DC|IHu0F$ACmgN$kmU?)lbRjWAegdvhWdE_*yS%`q!i{_LVk9wC8ro z{HNsXUWQagdStk(bzgl{tn^5wt9NhwtysPH@^6j57H7M;FEg5!ySMZufo?BL%ER~8 yKOR2&5dH?vbqoJCrVD!4+t)X7I4 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/attr/__pycache__/_compat.cpython-312.pyc b/venv/lib/python3.12/site-packages/attr/__pycache__/_compat.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f9ed0e0ca05555d945ad3feaf58e643aeb61be31 GIT binary patch literal 3541 zcmcIm&2QVt6(3Sxlq~DRQlup7B;4l1p&MJVle$T}STsnsiHoh_t(yW?+a+jnBvYYC z?U0HsL&3U5fF=uU9RmfNLkswrB9}dE5B(c@vEYMTW(x#pfg(T;NqlILQ{N0lNj7Yw zmky}MH+*kKGw=Q0$6p2qV+h8dzdW`01h~J`i9doJX7?F~&<4_w#u=#Sy}2UC=6sQ7 z??5pCZ{7%2L&Z=vTnuwmFJMHfLQ&ulk1$sm@;C0ipLbX-c<&-Y#Te!*xt`SLG)@bh zL|XXXFF+@Lq)vqC3?8W?FrCDaI#H&RJW?mdbW%s^3^1KEPLnjV(@=2;4^=MsH|xEN zSu>!;AEIKGN4JqS_z-D{=e#E`9s~OYDwlfNKIhx7nAei9_IQJnQm?3RM&jMbkCj?Y zH_NUthd--hQ^gYJ4$8N&iHWY>Fm%OsgR_m<#w+?i68|ayuUApV6M^y+8xrsF1ATnF zk00#g6TqtgmhPYsqPy;X56A{;qDoiPV=7c*-_ST6`PZL=Gpt;SiJfs9JECHmmZLbj zW!hrNBI2lO*rVfJ6*no%eJZjH)(~V_(^W^7-9Q;TV2J>%vFTyOcTVB1jfq`QOpV~B z6?GAtg}JdG)lJxF+4L2pjLHf^0j=^b$;b&8_ie3vS zm04>(Znl$WTFEn8;>1^z+sUadVQLrTNTtLdzSVajj=<6w(Ex?uxRp}}*?8O+ ze;btTt3bfvd>}gfP5yK{f3cOn`0V(0e)7?+FYo;4o7BnQPj4kJyhU7ecqjkfqg%hd z^Ev?hJDY~$uTP#rf5=S*{=`iM4i3M6f!1N+XLAkC>4xATAxizTZ&V`tKETw^N4|F+ za7~U}YjPS-?O5r0q_@&x^@q+Y^eX#Cg=Um}qt21!Q9I5d$bx~Dy9{U!i~=QN^Xel33>Gl6@=Mpdk=K7G%>J4$xJHK2wag4gwa8&6R@%U zDG)D*WY?CzSl-Fx|B*iSMB7+gUu@^3R!(Z?F1K=*w{w%*=_`-Ie;r6aDLwsUU2o?` zTe;D%N7|D&Ta!22lhZADa??AR6Hnh?zuwM_v@#=G@sXFw4577p58$YAD3o@e0XYnC zuo!D8;Tz&3PSNCas2%Fg-00A$@&|rG)&KGxfQrQh*U1+C9 zTdDm%OijPcO+)zaz)<>RvaSzR$Yk_gmL zONGx-S+)%*ezHv7hXasNO2&cw5iwA(YmwvhD@E;(&lIa$r$sbi93Qnua}8BzP3D?Da#U zYACiXUcB*h+abS{{F=t{gRion*qHSjx-&i_1*jR=DlkI`{(@T0B6?Xjq2u6O9vTc< zr8@N>MV;K)Nv1oI>mV$`&!!n-6}^l^f7AR`^LGzgk#jrA^xA{R54MEioq;4Xi*&+6 zlTb4h2YQ|=6w!w5Mx8~16^*ueN!2n8C||TI8dnxnLL-q-Gq_0szjsLcqimOY%k6F%_p`XTuk1k~g< zZIGZsa@=khamg15p4bbN`X?Iu8xmiKk#J#kxg9y*ik#n$j69oaMJ85*JBf5Vak`Z_ z{giBSTZwONmRgBRs{=d9A+P`1$+MeFt>pM>{Qvp+O&A4JFM`Kk=FheBS6lD| qvu}l9=)3<;oaeG{5Rli497>&e)L8rc@#ot~aW%dh4st1Gl>Y*x(KNOI literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/attr/__pycache__/_config.cpython-312.pyc b/venv/lib/python3.12/site-packages/attr/__pycache__/_config.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..21e4de5daebcac33bb2f3b5af15489dadc6be93d GIT binary patch literal 1147 zcmd5*Pfrs;6rb%DsHOY~CJ+J5Ll4*lb_K*3Vmx3xsEJ047cT8|XJ|KWXPTMWk~Wy2 z@nB+1yy3wwVE6=n1}_{un2iS#zW}iw3@6_#6pSA9=u7rDZ{NK6&70r6`8YI`CukpD zpReC@3HfS&dX_nMy3^?F5Js3&%d8WYp$>Cjko649BD(FqVt+DL^Nre!%azd6=8>%lesNodYhBoV^0q;=c!}*Fg3L;XZJY&xwA#6+s+i- z&W}8xmAHY;IyZH$Kq?T@z-d`P6$h-;16XYX;~O-N%p72H`(!Gg(s&+DHx&=4;cR6E z78krF?+V;O@-T{0+A31Xn;mq{+f_d*{aesFcJjcgi3`PqjaSLf;PBr z(tvyLSaUdvd#Ck!Rz((ST8%inT&$e%g+d!nnU@ASXJ_$Dv(SjO0j#PjW#rv2W|MrV zZ6Xx`PqH?eoLOr(`E8}7N=AOWvSKE2ktT5)x~8q}0EfoMvXu6zV2W>cf;ty|Y5s03 zLaF>xQ-z`i4`ZqfSN^RMEG#ejfkv!KqvvZ%#?9+~i;I>Yg;l@VHgzeMyoE(yhlbDN zxu4J)M|M=hF9%X=gf*|(R<ipu45`O#gZ>#U5YT!*RySV& literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/attr/__pycache__/_funcs.cpython-312.pyc b/venv/lib/python3.12/site-packages/attr/__pycache__/_funcs.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e626f800ad0449b3f7fbc54ba630f322995d9d94 GIT binary patch literal 13670 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/attr/__pycache__/converters.cpython-312.pyc b/venv/lib/python3.12/site-packages/attr/__pycache__/converters.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ad508e8f6dfa5b7a6377fed6c30a49fb0f3b9270 GIT binary patch literal 4665 zcmbVPO>7&-72Y3`yQKac$*C*Za;J)1nXE-xvJ4A~?Nkx0Gyy8Lm0GmAkSp#|T6wuk z%r2!+rC=p6P^m^y2XSEmNr9jz8}22iw6`1!^g>n!EH8vsKwF@>xseMLIrY8SACih) z2VH=}`F-!ryf@$X=1(0R2@bwL{IY-f!x`J3_vZ$?>Nz`BES z*tg9+@Fi>rRbfR6`Wycb{OX2S6)ADhHukMBKLsuCzbf`ZrOL0gxAtR86))qMumWB^ z`h_|o)yNBVME-}42F809hnFHJBxTK_H;ZPC;zR8CBiL)2 z#g{utm+T4FhnowRkh4yuq?=3WDcGK}XlTjCB%FwP8k5;Mz)s+PfE^Yk5Wd5n`D9fw z${Ji0rX!suaC2-7YE{+Li3u`tDLs-t&j$0M7r+%5k3H}^JPpOK`MX?|+vF>pz-^0F z@JUr@c<4SqbDx9zBZ4Y7qMNqkMhm)TsBSzo(T;!^uzT~1wakxfFd?IuD%IB3^UIo< znHzqqZ0Z)x%#|o?n*5-w;PuW-&5@CdqnW%7<)Y=-!%NgEm&P-znz@=W^ut=jY}mg(81$tt8&+O1?5pXZr!nhWV7lE0 z#eX)ry{_)9pY5GE`MBrQ&fG_X_oBN!=~{dG5JtHcT)?wr=Z6bh&X2E#H++txoiI%C z0wx7|4C}baMzkQC^f-3B48>P7bQqW7^rMEpf3?>BP5L#IhC19B)toXl=aYh)aFpws zowYTi;I?^n=DVcqCUhH}shD|<#&9kA&^^ASIoX0vZ6{k&s8Y;AplWW+3s+a3^&!*k z%4VCcOE&9v;X+R_Ta%2ky|VqeB7n8aJFY+-8$&M#u|mB4BdSp>aA)=hP{8({p62B4 z+sO}q`cNABcSMY5o_31yfu{+s?HfCl-9&P8>OgLLB$K*KcIAQ1$;XnsKQ{5n?8md8 zPS(e!YjWQsIaQZa_b%4uk%M^qqxh+M{M2sz^ycf2rTG4(E1%r>_{OKSe(9~o)bYAJ z_IK$eU+aF?*K57s{(a<+gAcoAYx3+tTYoLm&ki{s!af*_hlas$_)jR1Ab=L2=6z-G zeU;zrQ27m^2?T`)J_WqXx6I~o_B$P_@VwbD+SZ_wDj&%C1?PlB0us?C_Jy=Wwz-v% zNPH>6MqUvhFQB10j_7 zixracsW?Rd%n<9SW&<-bc~*g>3LbT*o(ZD<+E&2)F~XqF3k)U!kbQ&%;4CRNKxdkK zAN~=5fCqxmCsu)}#el>whtOiD{p2A>V6|N?l`H@(^&DBY)-*s^W^*prxLdiLPe3rg zMO+FPCD;av_jmRp{D(vJi2+mr2{KIp`>+$ZlN#nmz-g8poE)0jy6qM#8b{#q#19qS z)|z+;+3y;q7M&n(!ttj}O$V>gRI1fep^^0F|CV}h)yyy@-oAmlfa|Gd;;!qfEcu|g|tmzgGLKtEkbPg&W2fZUy zxjAl|U-7STaIx_}$oYI$f^=H)cW~e1CRg&+HS?3(d&GtYajuUZ8EUZXk%7h<0}N>< z+Z%f)`feu1BlS(8s4NS$|<>QetlL$!g6d!5&g zjMb#R{qEkKq22C*EeUCD=)+47rC0Xax*xUm|GBMyulw58)P6UlIqzp6dw3d&#LqlA z#kHTQMFyXCMB*o(w0n&&yCbB$RWP&pMO1y(i|AODTM1u3u)zONqB; zuiUX8N+3!7B_2qLTIZ{E>D9fio;|EzsY_S(x{e>Tr|w<2H&jcEZcgnd zj^CcUm8nH~Jv`}frEFHU^4Toy2iefdTg8&%csY4ATZAm0L5`QHGqAyY4wpfq0Lxe! z%}|7yicbzEn!(E#^5vqXmJRJH{SFKup4yk7cp~yV|F4+9M-F9<@B9as{3|!M%Z+^= ii?#`y(&xug{OKnPJl8*XZ~l-Q=g%Cj@@M!yCiuU1dAPj* literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/attr/__pycache__/exceptions.cpython-312.pyc b/venv/lib/python3.12/site-packages/attr/__pycache__/exceptions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..443ac56a841723460778fa1fc392f83548f2a455 GIT binary patch literal 3618 zcmbVO-ES0C6u+}y-EKc=O9e{x0)e{4?$RPs5e-cdg@-DZlDL4=>CWADWOin`_fE?; zHR(f*O@ss=OnKxH!e7AO;0q=^kcm$kAAB)riy=ID&Yjt>+G5Hid*;mVo_qKH&ey#^ zwY8-PJdbYo&pm1)6JkbJh#6zC zhtXh8F0Rlxpa~YQq6vjI0h+8sn-tm%Xo@APw#^D{0kpLaO)0bu(00~RwQW^s2cVsG zXq!TJ0oqlEwkxz7&>q%NU7@qQJKg&SZa%H~Er#Q`(vX(x2>48n+lCOA4W19k1u|r+ ztsjB!HNr?vGf6Ho1zyTU%}5TsF{|a`W|Sq&*lDmS$I}VFe7oPd@7*Ep&PO>A}PIb}yfOoO<&~>{VjKzaW)#>;cngYl z6p93Hm3LLd8=$OXfL6%gkytz#*x>Mvi1q|T8*^~+S|d{oLZxtCmug-1PVjDIv58qP zVkq81r3ZzgjnIxL^&uHiWi;W+bFSx@K@8o1nL`JWlo+H1&&gwI(Y))~CKgq}f(kWM zYY17(IYX+F_8{Y_A+AHaD7bvvN`ztHOJ- zR<&EE@_wX_;w1d4MH;UZDUR&O6?>2IMw+1I=6yjt(lzB?iu^oYC8d{bc6&D>GUZEs8VntIKGFcEokp=jtf9 z97T;+hAd}R(P^*Pj~cx z3itrBMDZyq{U}tkLa2dm1ORxn^|wKOx9O-^B?ZlltR!lZ-zQClOjIw(V~ge;NUaCR+eOOb~a{`f`o>Pkxy_`0e=eq6Bu_rwIV3ku_D9B9^cRROv#a8{jyW?tQDV+bI>`e0Xty8OjfV zFW!L<@I-ZNiF{r4g|bxQVK_cX_+bFj5kCqyG({q<@j-wDT2QrdA8ukWs_Tn;w%EKH z`3h$sN!WTv*PVCQMt>On{+q|i{c5M_rY)}%=ntL&;kSh@%QM^7b=bjCTn~3}CUD&$ zG(~X{2k>U`Vg)W*(8e~}qw&6fQd+z}$a*xINbkaXWx>M=gm_`7{RH$E$We|l@!K0) zS8$J0_Zd9m{nTa5R26o0G^#_yZ~ek^q*V-Y)mT-lIRI0*Iz81k8}AY?lc$6G?MM6s z*dZrT2JtMaY1;Dy(GLAi`Zf}++Q6O627%Ycn{h39_vi+J*G4DmAJp`FgEjr`sZdXV d&D9M8uZ=FSzt>uagRby)t^ZE>If0jQ)4z!7X=(rf literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/attr/__pycache__/filters.cpython-312.pyc b/venv/lib/python3.12/site-packages/attr/__pycache__/filters.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..87f48e15fc3d91aec0207a4fd4d37c7458f08184 GIT binary patch literal 3032 zcmds2L2nyH6rR~#JGPsUhB}ad+D=>4V$-hMR6tb~r@`g|s1-yAsZcqa-LbRnde@p6 zCry-A5vr7=Dk=w{IrbVAB(6yO11>G060$f{;sUo21EM+c-g<4P1yO-o4ve%uo-+tZKmm<)<{BY-#-b2U_*l9N{a+>?WxlSB%hB(yGJX+PxXp}hmWpYM$46ue1 z0~?!-XL{zwQiY&e4Sa8w)g>?2Jyv!-#f4<$K(Gl*DIrZuI?ZsSP1#lg|xYkFX=6V;h>=w&ibisWV#c{7^X5}`db0zm!M9%X%; zWQ@6Dia~putGe(dvsjoi3(9PwEP^@iORgp)_HECSl0ygpM93iwX@<-1Llc8!k0P2^ z!Ms5zAetvkFH9b#1rPnDXSBDKUOFq|U=qf#x(HbdNy1rDF zZ}WzsW@~&^YiQ=-hHiUO;(Eq5Rqh=LRmnkyg3rv^Q{2yuA9}s+yMf4!*M#d=*jsf= zKW~{&dcBCv&w~H5K?r%_Ac@=_-DxX4&Vh3WwbR zdoFqaW^Hyed7{F7exWAvbGu5i=DDggGi53BgcsPBC-Y`!z8}(*!(e_Szb}w)21Zx* zefG>3g|E_gGWn19-5wad*G$0d2ZOumO3!ZkI4@P;lgnrV2tpdVR6-=di!M_1f-m~O zJPgrxT(kvIK0>tPPUaOvl)opQfRO(Ri9izlJ0t@SASp&jhVNtwh@{v;f*kJf0y+kk zS|Tf1cx#PqTb_VO!#IkOJO*Zg{E{NcC!x$Y(%%k@t|dmlPYl2nVK2Xy$cMcm_KItX z;(CwK8($|zEZ&5*#75I@h!P9e#BCR~MSaoODjM^oEfeoUf~tb?E= zF4B1l)Yq&<$UCHOL2yfPW<|Qj6o6u(-dUa(%t)3+m{~IwMvsY#JRW+e95})T%4;U+6sKAXf0T6?zi_+-$ZnlcLm6}M^!t_jKqze;T)0Cgprzvwk!=w_%Pdi; zSGljEluVONgY>w8Z%_laTcwoXJutRP$1) zVc-D>4R&k9FiJ{PcE%PK7FusT5tXkrH{32{NA%iL_@k90 zU_kNi_6}S-y?lB_-s;`ELA1WT-}Mh&yR>}i#^9~~{Tn(A-0dG)dF@vJ9(eu9lo*6% zt2AU$CMNJk1Vgh64dx|wgNd>_dGcf{tDfj+u@@$BizYgoK)+pN__-U!wV}*yV{oCc zH26{MHzO8Htv^9}(+j7=<7^1+G+@so;n~XH^2`a~r<%?Bfy%QFbNy1kV+=!e8R1RvVhHvX&w}|Am7>xBmD)w>P^mpN zhU;Di^G~U?Jq16Kh)-eC*+Y8wjE?R9xhveK$oTvs)-Q#)j0t5jsh(tE8>y*-;;~F)7O%S?sBc7n~ji-ia Ly7>~A@U%Yw$JO1< literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/attr/__pycache__/setters.cpython-312.pyc b/venv/lib/python3.12/site-packages/attr/__pycache__/setters.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f8cce413e8705e0092ee989829a837c02a93d829 GIT binary patch literal 1952 zcma)7|4ST46rb7M+uJ+8oEoF1RGp?KvXa}2mO=<3q_$E@F-fIAL}<5rw{za=-R?27 zch=)9wghTu3qmRSqdzwI7xZuFFG>Q53jsshANrfo7D|5Vo4GsDq!b^_+u51fH}AdA z=e_;4qa%qxe)(ara92m@H}TREr8zmCfypLv(L8dos}ylbnOCrwt3|b>&1*2%?xXpb z8w0JoI_S6?2W=>bCU%-;=94RinW$Y!P6wq@;1^d&g;SRlf?$c0e85QH+nk0@7&0sQ zCx)*~9L4Qi;OD)ChdAn;VL^@hw_xAPRzms#V*$%Gjmw8{I1b~u2h_LV@;b_67vDEl zaUIVgQ>o>X1mu&7Pn=?rjKOswWqgb{zDpPlE6gWhfwrbqr&ysR$jh~&!$WY9T1jcc zvPcy^^#b2Zp$E>Q3{kRrUK$4b@ff7|%XLrXCrd&qK%0(MT8R@v>3Er^~kVFH%@F(i@RP@n%F^ zTq;5(YcIphryM-ZK#Yto*K!5wXXer$ReUdCnYl9a`~`Bi;xNcWW_pf{zdMo1anRWy z9Uhsauz692fs4S+pY3S)V|D|a+$hz z*(=l98$w%?#USSt`IL2fPhiEbf%<0+J?-dQR}T6Hj}T5+>ofb^{aeQN)t@gv>P|m+ z?@)!sLmhSXtS64)JYohYQ(>KA-UW&a0(?PO3LcRru4KY`o7fWjaKm4ndaUQL3$+jI zYW=Jm7SCWMSSL_87B)9g2)ZHPU=!Cqmf+rD6w(m_XGjAK;35eFlBJ{+xL)3)?s+)E zG_Y){5w;`6wj3kL@r=4GH zRWhu%#KjfFl)5qp)LRs;ydtY=UFC8g2&zhgDlLLyps*~b&rix}tdWYbQBHuBp6i6N zpvl+?PsfOtCtgSj4nJ=h&6p|^0YxdBReVABhG8BhPUfb@5^#ixDBgsWV{19@yF z(r6y0>`hp|3WHC9lBqOOPvS#+@uBT2d-2hysexT%;K1m7VhrpV18cYT+u9pz&$ZZE zVME_aJk~BBwDs<4z5kQ`MKBIkj>Yp;5ou*3tv0#}tuquIOA4e}+i60@p>@K$vLhG? zGKU)P0*Dq20G)tAt$p=hFhJjg1_eb;(&@9Q7Yl)Z2AZ?|Pnu(tSBl}em@IsTUY(e3 zU1@4j;^h7)W|y2L%7)-nl=OJ3mzlBGkju$KTo75n*TgU0G{xSA^&2pn@EvxdMCt^p zxbcTE@_Xvi)>~Wm9;Zh4FZ6EQ`*Cu&efW8*Yva<^huir_sr0UqJ_X;b*#gf+%OUi2&V(PbgUA|`?2$f1dXQbDxiE^&-nMVwk$p(=K^E>yV-os6rAVik z2?hj!JOc{)7sfAi1#5pB2=_fh*N*fQ9yl7&@$gYk3ST@L>BbjdSP;~A#@8`v@LxE4 B*V6z1 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/attr/__pycache__/validators.cpython-312.pyc b/venv/lib/python3.12/site-packages/attr/__pycache__/validators.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9d7b93bdbda47759689f33a3759c423617470bae GIT binary patch literal 26262 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 Py%xQ#t`%1)grNTy&9q(P literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/attr/_cmp.py b/venv/lib/python3.12/site-packages/attr/_cmp.py new file mode 100644 index 00000000..09bab491 --- /dev/null +++ b/venv/lib/python3.12/site-packages/attr/_cmp.py @@ -0,0 +1,160 @@ +# SPDX-License-Identifier: MIT + + +import functools +import types + +from ._make import __ne__ + + +_operation_names = {"eq": "==", "lt": "<", "le": "<=", "gt": ">", "ge": ">="} + + +def cmp_using( + eq=None, + lt=None, + le=None, + gt=None, + ge=None, + require_same_type=True, + class_name="Comparable", +): + """ + Create a class that can be passed into `attrs.field`'s ``eq``, ``order``, + and ``cmp`` arguments to customize field comparison. + + The resulting class will have a full set of ordering methods if at least + one of ``{lt, le, gt, ge}`` and ``eq`` are provided. + + Args: + eq (typing.Callable | None): + Callable used to evaluate equality of two objects. + + lt (typing.Callable | None): + Callable used to evaluate whether one object is less than another + object. + + le (typing.Callable | None): + Callable used to evaluate whether one object is less than or equal + to another object. + + gt (typing.Callable | None): + Callable used to evaluate whether one object is greater than + another object. + + ge (typing.Callable | None): + Callable used to evaluate whether one object is greater than or + equal to another object. + + require_same_type (bool): + When `True`, equality and ordering methods will return + `NotImplemented` if objects are not of the same type. + + class_name (str | None): Name of class. Defaults to "Comparable". + + See `comparison` for more details. + + .. versionadded:: 21.1.0 + """ + + body = { + "__slots__": ["value"], + "__init__": _make_init(), + "_requirements": [], + "_is_comparable_to": _is_comparable_to, + } + + # Add operations. + num_order_functions = 0 + has_eq_function = False + + if eq is not None: + has_eq_function = True + body["__eq__"] = _make_operator("eq", eq) + body["__ne__"] = __ne__ + + if lt is not None: + num_order_functions += 1 + body["__lt__"] = _make_operator("lt", lt) + + if le is not None: + num_order_functions += 1 + body["__le__"] = _make_operator("le", le) + + if gt is not None: + num_order_functions += 1 + body["__gt__"] = _make_operator("gt", gt) + + if ge is not None: + num_order_functions += 1 + body["__ge__"] = _make_operator("ge", ge) + + type_ = types.new_class( + class_name, (object,), {}, lambda ns: ns.update(body) + ) + + # Add same type requirement. + if require_same_type: + type_._requirements.append(_check_same_type) + + # Add total ordering if at least one operation was defined. + if 0 < num_order_functions < 4: + if not has_eq_function: + # functools.total_ordering requires __eq__ to be defined, + # so raise early error here to keep a nice stack. + msg = "eq must be define is order to complete ordering from lt, le, gt, ge." + raise ValueError(msg) + type_ = functools.total_ordering(type_) + + return type_ + + +def _make_init(): + """ + Create __init__ method. + """ + + def __init__(self, value): + """ + Initialize object with *value*. + """ + self.value = value + + return __init__ + + +def _make_operator(name, func): + """ + Create operator method. + """ + + def method(self, other): + if not self._is_comparable_to(other): + return NotImplemented + + result = func(self.value, other.value) + if result is NotImplemented: + return NotImplemented + + return result + + method.__name__ = f"__{name}__" + method.__doc__ = ( + f"Return a {_operation_names[name]} b. Computed by attrs." + ) + + return method + + +def _is_comparable_to(self, other): + """ + Check whether `other` is comparable to `self`. + """ + return all(func(self, other) for func in self._requirements) + + +def _check_same_type(self, other): + """ + Return True if *self* and *other* are of the same type, False otherwise. + """ + return other.value.__class__ is self.value.__class__ diff --git a/venv/lib/python3.12/site-packages/attr/_cmp.pyi b/venv/lib/python3.12/site-packages/attr/_cmp.pyi new file mode 100644 index 00000000..cc7893b0 --- /dev/null +++ b/venv/lib/python3.12/site-packages/attr/_cmp.pyi @@ -0,0 +1,13 @@ +from typing import Any, Callable + +_CompareWithType = Callable[[Any, Any], bool] + +def cmp_using( + eq: _CompareWithType | None = ..., + lt: _CompareWithType | None = ..., + le: _CompareWithType | None = ..., + gt: _CompareWithType | None = ..., + ge: _CompareWithType | None = ..., + require_same_type: bool = ..., + class_name: str = ..., +) -> type: ... diff --git a/venv/lib/python3.12/site-packages/attr/_compat.py b/venv/lib/python3.12/site-packages/attr/_compat.py new file mode 100644 index 00000000..22fcd783 --- /dev/null +++ b/venv/lib/python3.12/site-packages/attr/_compat.py @@ -0,0 +1,94 @@ +# SPDX-License-Identifier: MIT + +import inspect +import platform +import sys +import threading + +from collections.abc import Mapping, Sequence # noqa: F401 +from typing import _GenericAlias + + +PYPY = platform.python_implementation() == "PyPy" +PY_3_9_PLUS = sys.version_info[:2] >= (3, 9) +PY_3_10_PLUS = sys.version_info[:2] >= (3, 10) +PY_3_11_PLUS = sys.version_info[:2] >= (3, 11) +PY_3_12_PLUS = sys.version_info[:2] >= (3, 12) +PY_3_13_PLUS = sys.version_info[:2] >= (3, 13) +PY_3_14_PLUS = sys.version_info[:2] >= (3, 14) + + +if PY_3_14_PLUS: # pragma: no cover + import annotationlib + + _get_annotations = annotationlib.get_annotations + +else: + + def _get_annotations(cls): + """ + Get annotations for *cls*. + """ + return cls.__dict__.get("__annotations__", {}) + + +class _AnnotationExtractor: + """ + Extract type annotations from a callable, returning None whenever there + is none. + """ + + __slots__ = ["sig"] + + def __init__(self, callable): + try: + self.sig = inspect.signature(callable) + except (ValueError, TypeError): # inspect failed + self.sig = None + + def get_first_param_type(self): + """ + Return the type annotation of the first argument if it's not empty. + """ + if not self.sig: + return None + + params = list(self.sig.parameters.values()) + if params and params[0].annotation is not inspect.Parameter.empty: + return params[0].annotation + + return None + + def get_return_type(self): + """ + Return the return type if it's not empty. + """ + if ( + self.sig + and self.sig.return_annotation is not inspect.Signature.empty + ): + return self.sig.return_annotation + + return None + + +# Thread-local global to track attrs instances which are already being repr'd. +# This is needed because there is no other (thread-safe) way to pass info +# about the instances that are already being repr'd through the call stack +# in order to ensure we don't perform infinite recursion. +# +# For instance, if an instance contains a dict which contains that instance, +# we need to know that we're already repr'ing the outside instance from within +# the dict's repr() call. +# +# This lives here rather than in _make.py so that the functions in _make.py +# don't have a direct reference to the thread-local in their globals dict. +# If they have such a reference, it breaks cloudpickle. +repr_context = threading.local() + + +def get_generic_base(cl): + """If this is a generic class (A[str]), return the generic base for it.""" + if cl.__class__ is _GenericAlias: + return cl.__origin__ + return None diff --git a/venv/lib/python3.12/site-packages/attr/_config.py b/venv/lib/python3.12/site-packages/attr/_config.py new file mode 100644 index 00000000..4b257726 --- /dev/null +++ b/venv/lib/python3.12/site-packages/attr/_config.py @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: MIT + +__all__ = ["get_run_validators", "set_run_validators"] + +_run_validators = True + + +def set_run_validators(run): + """ + Set whether or not validators are run. By default, they are run. + + .. deprecated:: 21.3.0 It will not be removed, but it also will not be + moved to new ``attrs`` namespace. Use `attrs.validators.set_disabled()` + instead. + """ + if not isinstance(run, bool): + msg = "'run' must be bool." + raise TypeError(msg) + global _run_validators + _run_validators = run + + +def get_run_validators(): + """ + Return whether or not validators are run. + + .. deprecated:: 21.3.0 It will not be removed, but it also will not be + moved to new ``attrs`` namespace. Use `attrs.validators.get_disabled()` + instead. + """ + return _run_validators diff --git a/venv/lib/python3.12/site-packages/attr/_funcs.py b/venv/lib/python3.12/site-packages/attr/_funcs.py new file mode 100644 index 00000000..c39fb8aa --- /dev/null +++ b/venv/lib/python3.12/site-packages/attr/_funcs.py @@ -0,0 +1,468 @@ +# SPDX-License-Identifier: MIT + + +import copy + +from ._compat import PY_3_9_PLUS, get_generic_base +from ._make import _OBJ_SETATTR, NOTHING, fields +from .exceptions import AttrsAttributeNotFoundError + + +def asdict( + inst, + recurse=True, + filter=None, + dict_factory=dict, + retain_collection_types=False, + value_serializer=None, +): + """ + Return the *attrs* attribute values of *inst* as a dict. + + Optionally recurse into other *attrs*-decorated classes. + + Args: + inst: Instance of an *attrs*-decorated class. + + recurse (bool): Recurse into classes that are also *attrs*-decorated. + + filter (~typing.Callable): + A callable whose return code determines whether an attribute or + element is included (`True`) or dropped (`False`). Is called with + the `attrs.Attribute` as the first argument and the value as the + second argument. + + dict_factory (~typing.Callable): + A callable to produce dictionaries from. For example, to produce + ordered dictionaries instead of normal Python dictionaries, pass in + ``collections.OrderedDict``. + + retain_collection_types (bool): + Do not convert to `list` when encountering an attribute whose type + is `tuple` or `set`. Only meaningful if *recurse* is `True`. + + value_serializer (typing.Callable | None): + A hook that is called for every attribute or dict key/value. It + receives the current instance, field and value and must return the + (updated) value. The hook is run *after* the optional *filter* has + been applied. + + Returns: + Return type of *dict_factory*. + + Raises: + attrs.exceptions.NotAnAttrsClassError: + If *cls* is not an *attrs* class. + + .. versionadded:: 16.0.0 *dict_factory* + .. versionadded:: 16.1.0 *retain_collection_types* + .. versionadded:: 20.3.0 *value_serializer* + .. versionadded:: 21.3.0 + If a dict has a collection for a key, it is serialized as a tuple. + """ + attrs = fields(inst.__class__) + rv = dict_factory() + for a in attrs: + v = getattr(inst, a.name) + if filter is not None and not filter(a, v): + continue + + if value_serializer is not None: + v = value_serializer(inst, a, v) + + if recurse is True: + if has(v.__class__): + rv[a.name] = asdict( + v, + recurse=True, + filter=filter, + dict_factory=dict_factory, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ) + elif isinstance(v, (tuple, list, set, frozenset)): + cf = v.__class__ if retain_collection_types is True else list + items = [ + _asdict_anything( + i, + is_key=False, + filter=filter, + dict_factory=dict_factory, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ) + for i in v + ] + try: + rv[a.name] = cf(items) + except TypeError: + if not issubclass(cf, tuple): + raise + # Workaround for TypeError: cf.__new__() missing 1 required + # positional argument (which appears, for a namedturle) + rv[a.name] = cf(*items) + elif isinstance(v, dict): + df = dict_factory + rv[a.name] = df( + ( + _asdict_anything( + kk, + is_key=True, + filter=filter, + dict_factory=df, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ), + _asdict_anything( + vv, + is_key=False, + filter=filter, + dict_factory=df, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ), + ) + for kk, vv in v.items() + ) + else: + rv[a.name] = v + else: + rv[a.name] = v + return rv + + +def _asdict_anything( + val, + is_key, + filter, + dict_factory, + retain_collection_types, + value_serializer, +): + """ + ``asdict`` only works on attrs instances, this works on anything. + """ + if getattr(val.__class__, "__attrs_attrs__", None) is not None: + # Attrs class. + rv = asdict( + val, + recurse=True, + filter=filter, + dict_factory=dict_factory, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ) + elif isinstance(val, (tuple, list, set, frozenset)): + if retain_collection_types is True: + cf = val.__class__ + elif is_key: + cf = tuple + else: + cf = list + + rv = cf( + [ + _asdict_anything( + i, + is_key=False, + filter=filter, + dict_factory=dict_factory, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ) + for i in val + ] + ) + elif isinstance(val, dict): + df = dict_factory + rv = df( + ( + _asdict_anything( + kk, + is_key=True, + filter=filter, + dict_factory=df, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ), + _asdict_anything( + vv, + is_key=False, + filter=filter, + dict_factory=df, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ), + ) + for kk, vv in val.items() + ) + else: + rv = val + if value_serializer is not None: + rv = value_serializer(None, None, rv) + + return rv + + +def astuple( + inst, + recurse=True, + filter=None, + tuple_factory=tuple, + retain_collection_types=False, +): + """ + Return the *attrs* attribute values of *inst* as a tuple. + + Optionally recurse into other *attrs*-decorated classes. + + Args: + inst: Instance of an *attrs*-decorated class. + + recurse (bool): + Recurse into classes that are also *attrs*-decorated. + + filter (~typing.Callable): + A callable whose return code determines whether an attribute or + element is included (`True`) or dropped (`False`). Is called with + the `attrs.Attribute` as the first argument and the value as the + second argument. + + tuple_factory (~typing.Callable): + A callable to produce tuples from. For example, to produce lists + instead of tuples. + + retain_collection_types (bool): + Do not convert to `list` or `dict` when encountering an attribute + which type is `tuple`, `dict` or `set`. Only meaningful if + *recurse* is `True`. + + Returns: + Return type of *tuple_factory* + + Raises: + attrs.exceptions.NotAnAttrsClassError: + If *cls* is not an *attrs* class. + + .. versionadded:: 16.2.0 + """ + attrs = fields(inst.__class__) + rv = [] + retain = retain_collection_types # Very long. :/ + for a in attrs: + v = getattr(inst, a.name) + if filter is not None and not filter(a, v): + continue + if recurse is True: + if has(v.__class__): + rv.append( + astuple( + v, + recurse=True, + filter=filter, + tuple_factory=tuple_factory, + retain_collection_types=retain, + ) + ) + elif isinstance(v, (tuple, list, set, frozenset)): + cf = v.__class__ if retain is True else list + items = [ + ( + astuple( + j, + recurse=True, + filter=filter, + tuple_factory=tuple_factory, + retain_collection_types=retain, + ) + if has(j.__class__) + else j + ) + for j in v + ] + try: + rv.append(cf(items)) + except TypeError: + if not issubclass(cf, tuple): + raise + # Workaround for TypeError: cf.__new__() missing 1 required + # positional argument (which appears, for a namedturle) + rv.append(cf(*items)) + elif isinstance(v, dict): + df = v.__class__ if retain is True else dict + rv.append( + df( + ( + ( + astuple( + kk, + tuple_factory=tuple_factory, + retain_collection_types=retain, + ) + if has(kk.__class__) + else kk + ), + ( + astuple( + vv, + tuple_factory=tuple_factory, + retain_collection_types=retain, + ) + if has(vv.__class__) + else vv + ), + ) + for kk, vv in v.items() + ) + ) + else: + rv.append(v) + else: + rv.append(v) + + return rv if tuple_factory is list else tuple_factory(rv) + + +def has(cls): + """ + Check whether *cls* is a class with *attrs* attributes. + + Args: + cls (type): Class to introspect. + + Raises: + TypeError: If *cls* is not a class. + + Returns: + bool: + """ + attrs = getattr(cls, "__attrs_attrs__", None) + if attrs is not None: + return True + + # No attrs, maybe it's a specialized generic (A[str])? + generic_base = get_generic_base(cls) + if generic_base is not None: + generic_attrs = getattr(generic_base, "__attrs_attrs__", None) + if generic_attrs is not None: + # Stick it on here for speed next time. + cls.__attrs_attrs__ = generic_attrs + return generic_attrs is not None + return False + + +def assoc(inst, **changes): + """ + Copy *inst* and apply *changes*. + + This is different from `evolve` that applies the changes to the arguments + that create the new instance. + + `evolve`'s behavior is preferable, but there are `edge cases`_ where it + doesn't work. Therefore `assoc` is deprecated, but will not be removed. + + .. _`edge cases`: https://github.com/python-attrs/attrs/issues/251 + + Args: + inst: Instance of a class with *attrs* attributes. + + changes: Keyword changes in the new copy. + + Returns: + A copy of inst with *changes* incorporated. + + Raises: + attrs.exceptions.AttrsAttributeNotFoundError: + If *attr_name* couldn't be found on *cls*. + + attrs.exceptions.NotAnAttrsClassError: + If *cls* is not an *attrs* class. + + .. deprecated:: 17.1.0 + Use `attrs.evolve` instead if you can. This function will not be + removed du to the slightly different approach compared to + `attrs.evolve`, though. + """ + new = copy.copy(inst) + attrs = fields(inst.__class__) + for k, v in changes.items(): + a = getattr(attrs, k, NOTHING) + if a is NOTHING: + msg = f"{k} is not an attrs attribute on {new.__class__}." + raise AttrsAttributeNotFoundError(msg) + _OBJ_SETATTR(new, k, v) + return new + + +def resolve_types( + cls, globalns=None, localns=None, attribs=None, include_extras=True +): + """ + Resolve any strings and forward annotations in type annotations. + + This is only required if you need concrete types in :class:`Attribute`'s + *type* field. In other words, you don't need to resolve your types if you + only use them for static type checking. + + With no arguments, names will be looked up in the module in which the class + was created. If this is not what you want, for example, if the name only + exists inside a method, you may pass *globalns* or *localns* to specify + other dictionaries in which to look up these names. See the docs of + `typing.get_type_hints` for more details. + + Args: + cls (type): Class to resolve. + + globalns (dict | None): Dictionary containing global variables. + + localns (dict | None): Dictionary containing local variables. + + attribs (list | None): + List of attribs for the given class. This is necessary when calling + from inside a ``field_transformer`` since *cls* is not an *attrs* + class yet. + + include_extras (bool): + Resolve more accurately, if possible. Pass ``include_extras`` to + ``typing.get_hints``, if supported by the typing module. On + supported Python versions (3.9+), this resolves the types more + accurately. + + Raises: + TypeError: If *cls* is not a class. + + attrs.exceptions.NotAnAttrsClassError: + If *cls* is not an *attrs* class and you didn't pass any attribs. + + NameError: If types cannot be resolved because of missing variables. + + Returns: + *cls* so you can use this function also as a class decorator. Please + note that you have to apply it **after** `attrs.define`. That means the + decorator has to come in the line **before** `attrs.define`. + + .. versionadded:: 20.1.0 + .. versionadded:: 21.1.0 *attribs* + .. versionadded:: 23.1.0 *include_extras* + """ + # Since calling get_type_hints is expensive we cache whether we've + # done it already. + if getattr(cls, "__attrs_types_resolved__", None) != cls: + import typing + + kwargs = {"globalns": globalns, "localns": localns} + + if PY_3_9_PLUS: + kwargs["include_extras"] = include_extras + + hints = typing.get_type_hints(cls, **kwargs) + for field in fields(cls) if attribs is None else attribs: + if field.name in hints: + # Since fields have been frozen we must work around it. + _OBJ_SETATTR(field, "type", hints[field.name]) + # We store the class we resolved so that subclasses know they haven't + # been resolved. + cls.__attrs_types_resolved__ = cls + + # Return the class so you can use it as a decorator too. + return cls diff --git a/venv/lib/python3.12/site-packages/attr/_make.py b/venv/lib/python3.12/site-packages/attr/_make.py new file mode 100644 index 00000000..e84d9792 --- /dev/null +++ b/venv/lib/python3.12/site-packages/attr/_make.py @@ -0,0 +1,3123 @@ +# SPDX-License-Identifier: MIT + +from __future__ import annotations + +import abc +import contextlib +import copy +import enum +import inspect +import itertools +import linecache +import sys +import types +import unicodedata + +from collections.abc import Callable, Mapping +from functools import cached_property +from typing import Any, NamedTuple, TypeVar + +# We need to import _compat itself in addition to the _compat members to avoid +# having the thread-local in the globals here. +from . import _compat, _config, setters +from ._compat import ( + PY_3_10_PLUS, + PY_3_11_PLUS, + PY_3_13_PLUS, + _AnnotationExtractor, + _get_annotations, + get_generic_base, +) +from .exceptions import ( + DefaultAlreadySetError, + FrozenInstanceError, + NotAnAttrsClassError, + UnannotatedAttributeError, +) + + +# This is used at least twice, so cache it here. +_OBJ_SETATTR = object.__setattr__ +_INIT_FACTORY_PAT = "__attr_factory_%s" +_CLASSVAR_PREFIXES = ( + "typing.ClassVar", + "t.ClassVar", + "ClassVar", + "typing_extensions.ClassVar", +) +# we don't use a double-underscore prefix because that triggers +# name mangling when trying to create a slot for the field +# (when slots=True) +_HASH_CACHE_FIELD = "_attrs_cached_hash" + +_EMPTY_METADATA_SINGLETON = types.MappingProxyType({}) + +# Unique object for unequivocal getattr() defaults. +_SENTINEL = object() + +_DEFAULT_ON_SETATTR = setters.pipe(setters.convert, setters.validate) + + +class _Nothing(enum.Enum): + """ + Sentinel to indicate the lack of a value when `None` is ambiguous. + + If extending attrs, you can use ``typing.Literal[NOTHING]`` to show + that a value may be ``NOTHING``. + + .. versionchanged:: 21.1.0 ``bool(NOTHING)`` is now False. + .. versionchanged:: 22.2.0 ``NOTHING`` is now an ``enum.Enum`` variant. + """ + + NOTHING = enum.auto() + + def __repr__(self): + return "NOTHING" + + def __bool__(self): + return False + + +NOTHING = _Nothing.NOTHING +""" +Sentinel to indicate the lack of a value when `None` is ambiguous. + +When using in 3rd party code, use `attrs.NothingType` for type annotations. +""" + + +class _CacheHashWrapper(int): + """ + An integer subclass that pickles / copies as None + + This is used for non-slots classes with ``cache_hash=True``, to avoid + serializing a potentially (even likely) invalid hash value. Since `None` + is the default value for uncalculated hashes, whenever this is copied, + the copy's value for the hash should automatically reset. + + See GH #613 for more details. + """ + + def __reduce__(self, _none_constructor=type(None), _args=()): # noqa: B008 + return _none_constructor, _args + + +def attrib( + default=NOTHING, + validator=None, + repr=True, + cmp=None, + hash=None, + init=True, + metadata=None, + type=None, + converter=None, + factory=None, + kw_only=False, + eq=None, + order=None, + on_setattr=None, + alias=None, +): + """ + Create a new field / attribute on a class. + + Identical to `attrs.field`, except it's not keyword-only. + + Consider using `attrs.field` in new code (``attr.ib`` will *never* go away, + though). + + .. warning:: + + Does **nothing** unless the class is also decorated with + `attr.s` (or similar)! + + + .. versionadded:: 15.2.0 *convert* + .. versionadded:: 16.3.0 *metadata* + .. versionchanged:: 17.1.0 *validator* can be a ``list`` now. + .. versionchanged:: 17.1.0 + *hash* is `None` and therefore mirrors *eq* by default. + .. versionadded:: 17.3.0 *type* + .. deprecated:: 17.4.0 *convert* + .. versionadded:: 17.4.0 + *converter* as a replacement for the deprecated *convert* to achieve + consistency with other noun-based arguments. + .. versionadded:: 18.1.0 + ``factory=f`` is syntactic sugar for ``default=attr.Factory(f)``. + .. versionadded:: 18.2.0 *kw_only* + .. versionchanged:: 19.2.0 *convert* keyword argument removed. + .. versionchanged:: 19.2.0 *repr* also accepts a custom callable. + .. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01. + .. versionadded:: 19.2.0 *eq* and *order* + .. versionadded:: 20.1.0 *on_setattr* + .. versionchanged:: 20.3.0 *kw_only* backported to Python 2 + .. versionchanged:: 21.1.0 + *eq*, *order*, and *cmp* also accept a custom callable + .. versionchanged:: 21.1.0 *cmp* undeprecated + .. versionadded:: 22.2.0 *alias* + """ + eq, eq_key, order, order_key = _determine_attrib_eq_order( + cmp, eq, order, True + ) + + if hash is not None and hash is not True and hash is not False: + msg = "Invalid value for hash. Must be True, False, or None." + raise TypeError(msg) + + if factory is not None: + if default is not NOTHING: + msg = ( + "The `default` and `factory` arguments are mutually exclusive." + ) + raise ValueError(msg) + if not callable(factory): + msg = "The `factory` argument must be a callable." + raise ValueError(msg) + default = Factory(factory) + + if metadata is None: + metadata = {} + + # Apply syntactic sugar by auto-wrapping. + if isinstance(on_setattr, (list, tuple)): + on_setattr = setters.pipe(*on_setattr) + + if validator and isinstance(validator, (list, tuple)): + validator = and_(*validator) + + if converter and isinstance(converter, (list, tuple)): + converter = pipe(*converter) + + return _CountingAttr( + default=default, + validator=validator, + repr=repr, + cmp=None, + hash=hash, + init=init, + converter=converter, + metadata=metadata, + type=type, + kw_only=kw_only, + eq=eq, + eq_key=eq_key, + order=order, + order_key=order_key, + on_setattr=on_setattr, + alias=alias, + ) + + +def _compile_and_eval( + script: str, + globs: dict[str, Any] | None, + locs: Mapping[str, object] | None = None, + filename: str = "", +) -> None: + """ + Evaluate the script with the given global (globs) and local (locs) + variables. + """ + bytecode = compile(script, filename, "exec") + eval(bytecode, globs, locs) + + +def _linecache_and_compile( + script: str, + filename: str, + globs: dict[str, Any] | None, + locals: Mapping[str, object] | None = None, +) -> dict[str, Any]: + """ + Cache the script with _linecache_, compile it and return the _locals_. + """ + + locs = {} if locals is None else locals + + # In order of debuggers like PDB being able to step through the code, + # we add a fake linecache entry. + count = 1 + base_filename = filename + while True: + linecache_tuple = ( + len(script), + None, + script.splitlines(True), + filename, + ) + old_val = linecache.cache.setdefault(filename, linecache_tuple) + if old_val == linecache_tuple: + break + + filename = f"{base_filename[:-1]}-{count}>" + count += 1 + + _compile_and_eval(script, globs, locs, filename) + + return locs + + +def _make_attr_tuple_class(cls_name: str, attr_names: list[str]) -> type: + """ + Create a tuple subclass to hold `Attribute`s for an `attrs` class. + + The subclass is a bare tuple with properties for names. + + class MyClassAttributes(tuple): + __slots__ = () + x = property(itemgetter(0)) + """ + attr_class_name = f"{cls_name}Attributes" + body = {} + for i, attr_name in enumerate(attr_names): + + def getter(self, i=i): + return self[i] + + body[attr_name] = property(getter) + return type(attr_class_name, (tuple,), body) + + +# Tuple class for extracted attributes from a class definition. +# `base_attrs` is a subset of `attrs`. +class _Attributes(NamedTuple): + attrs: type + base_attrs: list[Attribute] + base_attrs_map: dict[str, type] + + +def _is_class_var(annot): + """ + Check whether *annot* is a typing.ClassVar. + + The string comparison hack is used to avoid evaluating all string + annotations which would put attrs-based classes at a performance + disadvantage compared to plain old classes. + """ + annot = str(annot) + + # Annotation can be quoted. + if annot.startswith(("'", '"')) and annot.endswith(("'", '"')): + annot = annot[1:-1] + + return annot.startswith(_CLASSVAR_PREFIXES) + + +def _has_own_attribute(cls, attrib_name): + """ + Check whether *cls* defines *attrib_name* (and doesn't just inherit it). + """ + return attrib_name in cls.__dict__ + + +def _collect_base_attrs( + cls, taken_attr_names +) -> tuple[list[Attribute], dict[str, type]]: + """ + Collect attr.ibs from base classes of *cls*, except *taken_attr_names*. + """ + base_attrs = [] + base_attr_map = {} # A dictionary of base attrs to their classes. + + # Traverse the MRO and collect attributes. + for base_cls in reversed(cls.__mro__[1:-1]): + for a in getattr(base_cls, "__attrs_attrs__", []): + if a.inherited or a.name in taken_attr_names: + continue + + a = a.evolve(inherited=True) # noqa: PLW2901 + base_attrs.append(a) + base_attr_map[a.name] = base_cls + + # For each name, only keep the freshest definition i.e. the furthest at the + # back. base_attr_map is fine because it gets overwritten with every new + # instance. + filtered = [] + seen = set() + for a in reversed(base_attrs): + if a.name in seen: + continue + filtered.insert(0, a) + seen.add(a.name) + + return filtered, base_attr_map + + +def _collect_base_attrs_broken(cls, taken_attr_names): + """ + Collect attr.ibs from base classes of *cls*, except *taken_attr_names*. + + N.B. *taken_attr_names* will be mutated. + + Adhere to the old incorrect behavior. + + Notably it collects from the front and considers inherited attributes which + leads to the buggy behavior reported in #428. + """ + base_attrs = [] + base_attr_map = {} # A dictionary of base attrs to their classes. + + # Traverse the MRO and collect attributes. + for base_cls in cls.__mro__[1:-1]: + for a in getattr(base_cls, "__attrs_attrs__", []): + if a.name in taken_attr_names: + continue + + a = a.evolve(inherited=True) # noqa: PLW2901 + taken_attr_names.add(a.name) + base_attrs.append(a) + base_attr_map[a.name] = base_cls + + return base_attrs, base_attr_map + + +def _transform_attrs( + cls, these, auto_attribs, kw_only, collect_by_mro, field_transformer +) -> _Attributes: + """ + Transform all `_CountingAttr`s on a class into `Attribute`s. + + If *these* is passed, use that and don't look for them on the class. + + If *collect_by_mro* is True, collect them in the correct MRO order, + otherwise use the old -- incorrect -- order. See #428. + + Return an `_Attributes`. + """ + cd = cls.__dict__ + anns = _get_annotations(cls) + + if these is not None: + ca_list = list(these.items()) + elif auto_attribs is True: + ca_names = { + name + for name, attr in cd.items() + if attr.__class__ is _CountingAttr + } + ca_list = [] + annot_names = set() + for attr_name, type in anns.items(): + if _is_class_var(type): + continue + annot_names.add(attr_name) + a = cd.get(attr_name, NOTHING) + + if a.__class__ is not _CountingAttr: + a = attrib(a) + ca_list.append((attr_name, a)) + + unannotated = ca_names - annot_names + if unannotated: + raise UnannotatedAttributeError( + "The following `attr.ib`s lack a type annotation: " + + ", ".join( + sorted(unannotated, key=lambda n: cd.get(n).counter) + ) + + "." + ) + else: + ca_list = sorted( + ( + (name, attr) + for name, attr in cd.items() + if attr.__class__ is _CountingAttr + ), + key=lambda e: e[1].counter, + ) + + fca = Attribute.from_counting_attr + own_attrs = [ + fca(attr_name, ca, anns.get(attr_name)) for attr_name, ca in ca_list + ] + + if collect_by_mro: + base_attrs, base_attr_map = _collect_base_attrs( + cls, {a.name for a in own_attrs} + ) + else: + base_attrs, base_attr_map = _collect_base_attrs_broken( + cls, {a.name for a in own_attrs} + ) + + if kw_only: + own_attrs = [a.evolve(kw_only=True) for a in own_attrs] + base_attrs = [a.evolve(kw_only=True) for a in base_attrs] + + attrs = base_attrs + own_attrs + + if field_transformer is not None: + attrs = tuple(field_transformer(cls, attrs)) + + # Check attr order after executing the field_transformer. + # Mandatory vs non-mandatory attr order only matters when they are part of + # the __init__ signature and when they aren't kw_only (which are moved to + # the end and can be mandatory or non-mandatory in any order, as they will + # be specified as keyword args anyway). Check the order of those attrs: + had_default = False + for a in (a for a in attrs if a.init is not False and a.kw_only is False): + if had_default is True and a.default is NOTHING: + msg = f"No mandatory attributes allowed after an attribute with a default value or factory. Attribute in question: {a!r}" + raise ValueError(msg) + + if had_default is False and a.default is not NOTHING: + had_default = True + + # Resolve default field alias after executing field_transformer. + # This allows field_transformer to differentiate between explicit vs + # default aliases and supply their own defaults. + for a in attrs: + if not a.alias: + # Evolve is very slow, so we hold our nose and do it dirty. + _OBJ_SETATTR.__get__(a)("alias", _default_init_alias_for(a.name)) + + # Create AttrsClass *after* applying the field_transformer since it may + # add or remove attributes! + attr_names = [a.name for a in attrs] + AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names) + + return _Attributes(AttrsClass(attrs), base_attrs, base_attr_map) + + +def _make_cached_property_getattr(cached_properties, original_getattr, cls): + lines = [ + # Wrapped to get `__class__` into closure cell for super() + # (It will be replaced with the newly constructed class after construction). + "def wrapper(_cls):", + " __class__ = _cls", + " def __getattr__(self, item, cached_properties=cached_properties, original_getattr=original_getattr, _cached_setattr_get=_cached_setattr_get):", + " func = cached_properties.get(item)", + " if func is not None:", + " result = func(self)", + " _setter = _cached_setattr_get(self)", + " _setter(item, result)", + " return result", + ] + if original_getattr is not None: + lines.append( + " return original_getattr(self, item)", + ) + else: + lines.extend( + [ + " try:", + " return super().__getattribute__(item)", + " except AttributeError:", + " if not hasattr(super(), '__getattr__'):", + " raise", + " return super().__getattr__(item)", + " original_error = f\"'{self.__class__.__name__}' object has no attribute '{item}'\"", + " raise AttributeError(original_error)", + ] + ) + + lines.extend( + [ + " return __getattr__", + "__getattr__ = wrapper(_cls)", + ] + ) + + unique_filename = _generate_unique_filename(cls, "getattr") + + glob = { + "cached_properties": cached_properties, + "_cached_setattr_get": _OBJ_SETATTR.__get__, + "original_getattr": original_getattr, + } + + return _linecache_and_compile( + "\n".join(lines), unique_filename, glob, locals={"_cls": cls} + )["__getattr__"] + + +def _frozen_setattrs(self, name, value): + """ + Attached to frozen classes as __setattr__. + """ + if isinstance(self, BaseException) and name in ( + "__cause__", + "__context__", + "__traceback__", + "__suppress_context__", + "__notes__", + ): + BaseException.__setattr__(self, name, value) + return + + raise FrozenInstanceError + + +def _frozen_delattrs(self, name): + """ + Attached to frozen classes as __delattr__. + """ + if isinstance(self, BaseException) and name in ("__notes__",): + BaseException.__delattr__(self, name) + return + + raise FrozenInstanceError + + +def evolve(*args, **changes): + """ + Create a new instance, based on the first positional argument with + *changes* applied. + + .. tip:: + + On Python 3.13 and later, you can also use `copy.replace` instead. + + Args: + + inst: + Instance of a class with *attrs* attributes. *inst* must be passed + as a positional argument. + + changes: + Keyword changes in the new copy. + + Returns: + A copy of inst with *changes* incorporated. + + Raises: + TypeError: + If *attr_name* couldn't be found in the class ``__init__``. + + attrs.exceptions.NotAnAttrsClassError: + If *cls* is not an *attrs* class. + + .. versionadded:: 17.1.0 + .. deprecated:: 23.1.0 + It is now deprecated to pass the instance using the keyword argument + *inst*. It will raise a warning until at least April 2024, after which + it will become an error. Always pass the instance as a positional + argument. + .. versionchanged:: 24.1.0 + *inst* can't be passed as a keyword argument anymore. + """ + try: + (inst,) = args + except ValueError: + msg = ( + f"evolve() takes 1 positional argument, but {len(args)} were given" + ) + raise TypeError(msg) from None + + cls = inst.__class__ + attrs = fields(cls) + for a in attrs: + if not a.init: + continue + attr_name = a.name # To deal with private attributes. + init_name = a.alias + if init_name not in changes: + changes[init_name] = getattr(inst, attr_name) + + return cls(**changes) + + +class _ClassBuilder: + """ + Iteratively build *one* class. + """ + + __slots__ = ( + "_add_method_dunders", + "_attr_names", + "_attrs", + "_base_attr_map", + "_base_names", + "_cache_hash", + "_cls", + "_cls_dict", + "_delete_attribs", + "_frozen", + "_has_custom_setattr", + "_has_post_init", + "_has_pre_init", + "_is_exc", + "_on_setattr", + "_pre_init_has_args", + "_repr_added", + "_script_snippets", + "_slots", + "_weakref_slot", + "_wrote_own_setattr", + ) + + def __init__( + self, + cls: type, + these, + slots, + frozen, + weakref_slot, + getstate_setstate, + auto_attribs, + kw_only, + cache_hash, + is_exc, + collect_by_mro, + on_setattr, + has_custom_setattr, + field_transformer, + ): + attrs, base_attrs, base_map = _transform_attrs( + cls, + these, + auto_attribs, + kw_only, + collect_by_mro, + field_transformer, + ) + + self._cls = cls + self._cls_dict = dict(cls.__dict__) if slots else {} + self._attrs = attrs + self._base_names = {a.name for a in base_attrs} + self._base_attr_map = base_map + self._attr_names = tuple(a.name for a in attrs) + self._slots = slots + self._frozen = frozen + self._weakref_slot = weakref_slot + self._cache_hash = cache_hash + self._has_pre_init = bool(getattr(cls, "__attrs_pre_init__", False)) + self._pre_init_has_args = False + if self._has_pre_init: + # Check if the pre init method has more arguments than just `self` + # We want to pass arguments if pre init expects arguments + pre_init_func = cls.__attrs_pre_init__ + pre_init_signature = inspect.signature(pre_init_func) + self._pre_init_has_args = len(pre_init_signature.parameters) > 1 + self._has_post_init = bool(getattr(cls, "__attrs_post_init__", False)) + self._delete_attribs = not bool(these) + self._is_exc = is_exc + self._on_setattr = on_setattr + + self._has_custom_setattr = has_custom_setattr + self._wrote_own_setattr = False + + self._cls_dict["__attrs_attrs__"] = self._attrs + + if frozen: + self._cls_dict["__setattr__"] = _frozen_setattrs + self._cls_dict["__delattr__"] = _frozen_delattrs + + self._wrote_own_setattr = True + elif on_setattr in ( + _DEFAULT_ON_SETATTR, + setters.validate, + setters.convert, + ): + has_validator = has_converter = False + for a in attrs: + if a.validator is not None: + has_validator = True + if a.converter is not None: + has_converter = True + + if has_validator and has_converter: + break + if ( + ( + on_setattr == _DEFAULT_ON_SETATTR + and not (has_validator or has_converter) + ) + or (on_setattr == setters.validate and not has_validator) + or (on_setattr == setters.convert and not has_converter) + ): + # If class-level on_setattr is set to convert + validate, but + # there's no field to convert or validate, pretend like there's + # no on_setattr. + self._on_setattr = None + + if getstate_setstate: + ( + self._cls_dict["__getstate__"], + self._cls_dict["__setstate__"], + ) = self._make_getstate_setstate() + + # tuples of script, globs, hook + self._script_snippets: list[ + tuple[str, dict, Callable[[dict, dict], Any]] + ] = [] + self._repr_added = False + + # We want to only do this check once; in 99.9% of cases these + # exist. + if not hasattr(self._cls, "__module__") or not hasattr( + self._cls, "__qualname__" + ): + self._add_method_dunders = self._add_method_dunders_safe + else: + self._add_method_dunders = self._add_method_dunders_unsafe + + def __repr__(self): + return f"<_ClassBuilder(cls={self._cls.__name__})>" + + def _eval_snippets(self) -> None: + """ + Evaluate any registered snippets in one go. + """ + script = "\n".join([snippet[0] for snippet in self._script_snippets]) + globs = {} + for _, snippet_globs, _ in self._script_snippets: + globs.update(snippet_globs) + + locs = _linecache_and_compile( + script, + _generate_unique_filename(self._cls, "methods"), + globs, + ) + + for _, _, hook in self._script_snippets: + hook(self._cls_dict, locs) + + def build_class(self): + """ + Finalize class based on the accumulated configuration. + + Builder cannot be used after calling this method. + """ + self._eval_snippets() + if self._slots is True: + cls = self._create_slots_class() + else: + cls = self._patch_original_class() + if PY_3_10_PLUS: + cls = abc.update_abstractmethods(cls) + + # The method gets only called if it's not inherited from a base class. + # _has_own_attribute does NOT work properly for classmethods. + if ( + getattr(cls, "__attrs_init_subclass__", None) + and "__attrs_init_subclass__" not in cls.__dict__ + ): + cls.__attrs_init_subclass__() + + return cls + + def _patch_original_class(self): + """ + Apply accumulated methods and return the class. + """ + cls = self._cls + base_names = self._base_names + + # Clean class of attribute definitions (`attr.ib()`s). + if self._delete_attribs: + for name in self._attr_names: + if ( + name not in base_names + and getattr(cls, name, _SENTINEL) is not _SENTINEL + ): + # An AttributeError can happen if a base class defines a + # class variable and we want to set an attribute with the + # same name by using only a type annotation. + with contextlib.suppress(AttributeError): + delattr(cls, name) + + # Attach our dunder methods. + for name, value in self._cls_dict.items(): + setattr(cls, name, value) + + # If we've inherited an attrs __setattr__ and don't write our own, + # reset it to object's. + if not self._wrote_own_setattr and getattr( + cls, "__attrs_own_setattr__", False + ): + cls.__attrs_own_setattr__ = False + + if not self._has_custom_setattr: + cls.__setattr__ = _OBJ_SETATTR + + return cls + + def _create_slots_class(self): + """ + Build and return a new class with a `__slots__` attribute. + """ + cd = { + k: v + for k, v in self._cls_dict.items() + if k not in (*tuple(self._attr_names), "__dict__", "__weakref__") + } + + # If our class doesn't have its own implementation of __setattr__ + # (either from the user or by us), check the bases, if one of them has + # an attrs-made __setattr__, that needs to be reset. We don't walk the + # MRO because we only care about our immediate base classes. + # XXX: This can be confused by subclassing a slotted attrs class with + # XXX: a non-attrs class and subclass the resulting class with an attrs + # XXX: class. See `test_slotted_confused` for details. For now that's + # XXX: OK with us. + if not self._wrote_own_setattr: + cd["__attrs_own_setattr__"] = False + + if not self._has_custom_setattr: + for base_cls in self._cls.__bases__: + if base_cls.__dict__.get("__attrs_own_setattr__", False): + cd["__setattr__"] = _OBJ_SETATTR + break + + # Traverse the MRO to collect existing slots + # and check for an existing __weakref__. + existing_slots = {} + weakref_inherited = False + for base_cls in self._cls.__mro__[1:-1]: + if base_cls.__dict__.get("__weakref__", None) is not None: + weakref_inherited = True + existing_slots.update( + { + name: getattr(base_cls, name) + for name in getattr(base_cls, "__slots__", []) + } + ) + + base_names = set(self._base_names) + + names = self._attr_names + if ( + self._weakref_slot + and "__weakref__" not in getattr(self._cls, "__slots__", ()) + and "__weakref__" not in names + and not weakref_inherited + ): + names += ("__weakref__",) + + cached_properties = { + name: cached_prop.func + for name, cached_prop in cd.items() + if isinstance(cached_prop, cached_property) + } + + # Collect methods with a `__class__` reference that are shadowed in the new class. + # To know to update them. + additional_closure_functions_to_update = [] + if cached_properties: + class_annotations = _get_annotations(self._cls) + for name, func in cached_properties.items(): + # Add cached properties to names for slotting. + names += (name,) + # Clear out function from class to avoid clashing. + del cd[name] + additional_closure_functions_to_update.append(func) + annotation = inspect.signature(func).return_annotation + if annotation is not inspect.Parameter.empty: + class_annotations[name] = annotation + + original_getattr = cd.get("__getattr__") + if original_getattr is not None: + additional_closure_functions_to_update.append(original_getattr) + + cd["__getattr__"] = _make_cached_property_getattr( + cached_properties, original_getattr, self._cls + ) + + # We only add the names of attributes that aren't inherited. + # Setting __slots__ to inherited attributes wastes memory. + slot_names = [name for name in names if name not in base_names] + + # There are slots for attributes from current class + # that are defined in parent classes. + # As their descriptors may be overridden by a child class, + # we collect them here and update the class dict + reused_slots = { + slot: slot_descriptor + for slot, slot_descriptor in existing_slots.items() + if slot in slot_names + } + slot_names = [name for name in slot_names if name not in reused_slots] + cd.update(reused_slots) + if self._cache_hash: + slot_names.append(_HASH_CACHE_FIELD) + + cd["__slots__"] = tuple(slot_names) + + cd["__qualname__"] = self._cls.__qualname__ + + # Create new class based on old class and our methods. + cls = type(self._cls)(self._cls.__name__, self._cls.__bases__, cd) + + # The following is a fix for + # . + # If a method mentions `__class__` or uses the no-arg super(), the + # compiler will bake a reference to the class in the method itself + # as `method.__closure__`. Since we replace the class with a + # clone, we rewrite these references so it keeps working. + for item in itertools.chain( + cls.__dict__.values(), additional_closure_functions_to_update + ): + if isinstance(item, (classmethod, staticmethod)): + # Class- and staticmethods hide their functions inside. + # These might need to be rewritten as well. + closure_cells = getattr(item.__func__, "__closure__", None) + elif isinstance(item, property): + # Workaround for property `super()` shortcut (PY3-only). + # There is no universal way for other descriptors. + closure_cells = getattr(item.fget, "__closure__", None) + else: + closure_cells = getattr(item, "__closure__", None) + + if not closure_cells: # Catch None or the empty list. + continue + for cell in closure_cells: + try: + match = cell.cell_contents is self._cls + except ValueError: # noqa: PERF203 + # ValueError: Cell is empty + pass + else: + if match: + cell.cell_contents = cls + return cls + + def add_repr(self, ns): + script, globs = _make_repr_script(self._attrs, ns) + + def _attach_repr(cls_dict, globs): + cls_dict["__repr__"] = self._add_method_dunders(globs["__repr__"]) + + self._script_snippets.append((script, globs, _attach_repr)) + self._repr_added = True + return self + + def add_str(self): + if not self._repr_added: + msg = "__str__ can only be generated if a __repr__ exists." + raise ValueError(msg) + + def __str__(self): + return self.__repr__() + + self._cls_dict["__str__"] = self._add_method_dunders(__str__) + return self + + def _make_getstate_setstate(self): + """ + Create custom __setstate__ and __getstate__ methods. + """ + # __weakref__ is not writable. + state_attr_names = tuple( + an for an in self._attr_names if an != "__weakref__" + ) + + def slots_getstate(self): + """ + Automatically created by attrs. + """ + return {name: getattr(self, name) for name in state_attr_names} + + hash_caching_enabled = self._cache_hash + + def slots_setstate(self, state): + """ + Automatically created by attrs. + """ + __bound_setattr = _OBJ_SETATTR.__get__(self) + if isinstance(state, tuple): + # Backward compatibility with attrs instances pickled with + # attrs versions before v22.2.0 which stored tuples. + for name, value in zip(state_attr_names, state): + __bound_setattr(name, value) + else: + for name in state_attr_names: + if name in state: + __bound_setattr(name, state[name]) + + # The hash code cache is not included when the object is + # serialized, but it still needs to be initialized to None to + # indicate that the first call to __hash__ should be a cache + # miss. + if hash_caching_enabled: + __bound_setattr(_HASH_CACHE_FIELD, None) + + return slots_getstate, slots_setstate + + def make_unhashable(self): + self._cls_dict["__hash__"] = None + return self + + def add_hash(self): + script, globs = _make_hash_script( + self._cls, + self._attrs, + frozen=self._frozen, + cache_hash=self._cache_hash, + ) + + def attach_hash(cls_dict: dict, locs: dict) -> None: + cls_dict["__hash__"] = self._add_method_dunders(locs["__hash__"]) + + self._script_snippets.append((script, globs, attach_hash)) + + return self + + def add_init(self): + script, globs, annotations = _make_init_script( + self._cls, + self._attrs, + self._has_pre_init, + self._pre_init_has_args, + self._has_post_init, + self._frozen, + self._slots, + self._cache_hash, + self._base_attr_map, + self._is_exc, + self._on_setattr, + attrs_init=False, + ) + + def _attach_init(cls_dict, globs): + init = globs["__init__"] + init.__annotations__ = annotations + cls_dict["__init__"] = self._add_method_dunders(init) + + self._script_snippets.append((script, globs, _attach_init)) + + return self + + def add_replace(self): + self._cls_dict["__replace__"] = self._add_method_dunders( + lambda self, **changes: evolve(self, **changes) + ) + return self + + def add_match_args(self): + self._cls_dict["__match_args__"] = tuple( + field.name + for field in self._attrs + if field.init and not field.kw_only + ) + + def add_attrs_init(self): + script, globs, annotations = _make_init_script( + self._cls, + self._attrs, + self._has_pre_init, + self._pre_init_has_args, + self._has_post_init, + self._frozen, + self._slots, + self._cache_hash, + self._base_attr_map, + self._is_exc, + self._on_setattr, + attrs_init=True, + ) + + def _attach_attrs_init(cls_dict, globs): + init = globs["__attrs_init__"] + init.__annotations__ = annotations + cls_dict["__attrs_init__"] = self._add_method_dunders(init) + + self._script_snippets.append((script, globs, _attach_attrs_init)) + + return self + + def add_eq(self): + cd = self._cls_dict + + script, globs = _make_eq_script(self._attrs) + + def _attach_eq(cls_dict, globs): + cls_dict["__eq__"] = self._add_method_dunders(globs["__eq__"]) + + self._script_snippets.append((script, globs, _attach_eq)) + + cd["__ne__"] = __ne__ + + return self + + def add_order(self): + cd = self._cls_dict + + cd["__lt__"], cd["__le__"], cd["__gt__"], cd["__ge__"] = ( + self._add_method_dunders(meth) + for meth in _make_order(self._cls, self._attrs) + ) + + return self + + def add_setattr(self): + sa_attrs = {} + for a in self._attrs: + on_setattr = a.on_setattr or self._on_setattr + if on_setattr and on_setattr is not setters.NO_OP: + sa_attrs[a.name] = a, on_setattr + + if not sa_attrs: + return self + + if self._has_custom_setattr: + # We need to write a __setattr__ but there already is one! + msg = "Can't combine custom __setattr__ with on_setattr hooks." + raise ValueError(msg) + + # docstring comes from _add_method_dunders + def __setattr__(self, name, val): + try: + a, hook = sa_attrs[name] + except KeyError: + nval = val + else: + nval = hook(self, a, val) + + _OBJ_SETATTR(self, name, nval) + + self._cls_dict["__attrs_own_setattr__"] = True + self._cls_dict["__setattr__"] = self._add_method_dunders(__setattr__) + self._wrote_own_setattr = True + + return self + + def _add_method_dunders_unsafe(self, method: Callable) -> Callable: + """ + Add __module__ and __qualname__ to a *method*. + """ + method.__module__ = self._cls.__module__ + + method.__qualname__ = f"{self._cls.__qualname__}.{method.__name__}" + + method.__doc__ = ( + f"Method generated by attrs for class {self._cls.__qualname__}." + ) + + return method + + def _add_method_dunders_safe(self, method: Callable) -> Callable: + """ + Add __module__ and __qualname__ to a *method* if possible. + """ + with contextlib.suppress(AttributeError): + method.__module__ = self._cls.__module__ + + with contextlib.suppress(AttributeError): + method.__qualname__ = f"{self._cls.__qualname__}.{method.__name__}" + + with contextlib.suppress(AttributeError): + method.__doc__ = f"Method generated by attrs for class {self._cls.__qualname__}." + + return method + + +def _determine_attrs_eq_order(cmp, eq, order, default_eq): + """ + Validate the combination of *cmp*, *eq*, and *order*. Derive the effective + values of eq and order. If *eq* is None, set it to *default_eq*. + """ + if cmp is not None and any((eq is not None, order is not None)): + msg = "Don't mix `cmp` with `eq' and `order`." + raise ValueError(msg) + + # cmp takes precedence due to bw-compatibility. + if cmp is not None: + return cmp, cmp + + # If left None, equality is set to the specified default and ordering + # mirrors equality. + if eq is None: + eq = default_eq + + if order is None: + order = eq + + if eq is False and order is True: + msg = "`order` can only be True if `eq` is True too." + raise ValueError(msg) + + return eq, order + + +def _determine_attrib_eq_order(cmp, eq, order, default_eq): + """ + Validate the combination of *cmp*, *eq*, and *order*. Derive the effective + values of eq and order. If *eq* is None, set it to *default_eq*. + """ + if cmp is not None and any((eq is not None, order is not None)): + msg = "Don't mix `cmp` with `eq' and `order`." + raise ValueError(msg) + + def decide_callable_or_boolean(value): + """ + Decide whether a key function is used. + """ + if callable(value): + value, key = True, value + else: + key = None + return value, key + + # cmp takes precedence due to bw-compatibility. + if cmp is not None: + cmp, cmp_key = decide_callable_or_boolean(cmp) + return cmp, cmp_key, cmp, cmp_key + + # If left None, equality is set to the specified default and ordering + # mirrors equality. + if eq is None: + eq, eq_key = default_eq, None + else: + eq, eq_key = decide_callable_or_boolean(eq) + + if order is None: + order, order_key = eq, eq_key + else: + order, order_key = decide_callable_or_boolean(order) + + if eq is False and order is True: + msg = "`order` can only be True if `eq` is True too." + raise ValueError(msg) + + return eq, eq_key, order, order_key + + +def _determine_whether_to_implement( + cls, flag, auto_detect, dunders, default=True +): + """ + Check whether we should implement a set of methods for *cls*. + + *flag* is the argument passed into @attr.s like 'init', *auto_detect* the + same as passed into @attr.s and *dunders* is a tuple of attribute names + whose presence signal that the user has implemented it themselves. + + Return *default* if no reason for either for or against is found. + """ + if flag is True or flag is False: + return flag + + if flag is None and auto_detect is False: + return default + + # Logically, flag is None and auto_detect is True here. + for dunder in dunders: + if _has_own_attribute(cls, dunder): + return False + + return default + + +def attrs( + maybe_cls=None, + these=None, + repr_ns=None, + repr=None, + cmp=None, + hash=None, + init=None, + slots=False, + frozen=False, + weakref_slot=True, + str=False, + auto_attribs=False, + kw_only=False, + cache_hash=False, + auto_exc=False, + eq=None, + order=None, + auto_detect=False, + collect_by_mro=False, + getstate_setstate=None, + on_setattr=None, + field_transformer=None, + match_args=True, + unsafe_hash=None, +): + r""" + A class decorator that adds :term:`dunder methods` according to the + specified attributes using `attr.ib` or the *these* argument. + + Consider using `attrs.define` / `attrs.frozen` in new code (``attr.s`` will + *never* go away, though). + + Args: + repr_ns (str): + When using nested classes, there was no way in Python 2 to + automatically detect that. This argument allows to set a custom + name for a more meaningful ``repr`` output. This argument is + pointless in Python 3 and is therefore deprecated. + + .. caution:: + Refer to `attrs.define` for the rest of the parameters, but note that they + can have different defaults. + + Notably, leaving *on_setattr* as `None` will **not** add any hooks. + + .. versionadded:: 16.0.0 *slots* + .. versionadded:: 16.1.0 *frozen* + .. versionadded:: 16.3.0 *str* + .. versionadded:: 16.3.0 Support for ``__attrs_post_init__``. + .. versionchanged:: 17.1.0 + *hash* supports `None` as value which is also the default now. + .. versionadded:: 17.3.0 *auto_attribs* + .. versionchanged:: 18.1.0 + If *these* is passed, no attributes are deleted from the class body. + .. versionchanged:: 18.1.0 If *these* is ordered, the order is retained. + .. versionadded:: 18.2.0 *weakref_slot* + .. deprecated:: 18.2.0 + ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now raise a + `DeprecationWarning` if the classes compared are subclasses of + each other. ``__eq`` and ``__ne__`` never tried to compared subclasses + to each other. + .. versionchanged:: 19.2.0 + ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now do not consider + subclasses comparable anymore. + .. versionadded:: 18.2.0 *kw_only* + .. versionadded:: 18.2.0 *cache_hash* + .. versionadded:: 19.1.0 *auto_exc* + .. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01. + .. versionadded:: 19.2.0 *eq* and *order* + .. versionadded:: 20.1.0 *auto_detect* + .. versionadded:: 20.1.0 *collect_by_mro* + .. versionadded:: 20.1.0 *getstate_setstate* + .. versionadded:: 20.1.0 *on_setattr* + .. versionadded:: 20.3.0 *field_transformer* + .. versionchanged:: 21.1.0 + ``init=False`` injects ``__attrs_init__`` + .. versionchanged:: 21.1.0 Support for ``__attrs_pre_init__`` + .. versionchanged:: 21.1.0 *cmp* undeprecated + .. versionadded:: 21.3.0 *match_args* + .. versionadded:: 22.2.0 + *unsafe_hash* as an alias for *hash* (for :pep:`681` compliance). + .. deprecated:: 24.1.0 *repr_ns* + .. versionchanged:: 24.1.0 + Instances are not compared as tuples of attributes anymore, but using a + big ``and`` condition. This is faster and has more correct behavior for + uncomparable values like `math.nan`. + .. versionadded:: 24.1.0 + If a class has an *inherited* classmethod called + ``__attrs_init_subclass__``, it is executed after the class is created. + .. deprecated:: 24.1.0 *hash* is deprecated in favor of *unsafe_hash*. + """ + if repr_ns is not None: + import warnings + + warnings.warn( + DeprecationWarning( + "The `repr_ns` argument is deprecated and will be removed in or after August 2025." + ), + stacklevel=2, + ) + + eq_, order_ = _determine_attrs_eq_order(cmp, eq, order, None) + + # unsafe_hash takes precedence due to PEP 681. + if unsafe_hash is not None: + hash = unsafe_hash + + if isinstance(on_setattr, (list, tuple)): + on_setattr = setters.pipe(*on_setattr) + + def wrap(cls): + is_frozen = frozen or _has_frozen_base_class(cls) + is_exc = auto_exc is True and issubclass(cls, BaseException) + has_own_setattr = auto_detect and _has_own_attribute( + cls, "__setattr__" + ) + + if has_own_setattr and is_frozen: + msg = "Can't freeze a class with a custom __setattr__." + raise ValueError(msg) + + builder = _ClassBuilder( + cls, + these, + slots, + is_frozen, + weakref_slot, + _determine_whether_to_implement( + cls, + getstate_setstate, + auto_detect, + ("__getstate__", "__setstate__"), + default=slots, + ), + auto_attribs, + kw_only, + cache_hash, + is_exc, + collect_by_mro, + on_setattr, + has_own_setattr, + field_transformer, + ) + + if _determine_whether_to_implement( + cls, repr, auto_detect, ("__repr__",) + ): + builder.add_repr(repr_ns) + + if str is True: + builder.add_str() + + eq = _determine_whether_to_implement( + cls, eq_, auto_detect, ("__eq__", "__ne__") + ) + if not is_exc and eq is True: + builder.add_eq() + if not is_exc and _determine_whether_to_implement( + cls, order_, auto_detect, ("__lt__", "__le__", "__gt__", "__ge__") + ): + builder.add_order() + + if not frozen: + builder.add_setattr() + + nonlocal hash + if ( + hash is None + and auto_detect is True + and _has_own_attribute(cls, "__hash__") + ): + hash = False + + if hash is not True and hash is not False and hash is not None: + # Can't use `hash in` because 1 == True for example. + msg = "Invalid value for hash. Must be True, False, or None." + raise TypeError(msg) + + if hash is False or (hash is None and eq is False) or is_exc: + # Don't do anything. Should fall back to __object__'s __hash__ + # which is by id. + if cache_hash: + msg = "Invalid value for cache_hash. To use hash caching, hashing must be either explicitly or implicitly enabled." + raise TypeError(msg) + elif hash is True or ( + hash is None and eq is True and is_frozen is True + ): + # Build a __hash__ if told so, or if it's safe. + builder.add_hash() + else: + # Raise TypeError on attempts to hash. + if cache_hash: + msg = "Invalid value for cache_hash. To use hash caching, hashing must be either explicitly or implicitly enabled." + raise TypeError(msg) + builder.make_unhashable() + + if _determine_whether_to_implement( + cls, init, auto_detect, ("__init__",) + ): + builder.add_init() + else: + builder.add_attrs_init() + if cache_hash: + msg = "Invalid value for cache_hash. To use hash caching, init must be True." + raise TypeError(msg) + + if PY_3_13_PLUS and not _has_own_attribute(cls, "__replace__"): + builder.add_replace() + + if ( + PY_3_10_PLUS + and match_args + and not _has_own_attribute(cls, "__match_args__") + ): + builder.add_match_args() + + return builder.build_class() + + # maybe_cls's type depends on the usage of the decorator. It's a class + # if it's used as `@attrs` but `None` if used as `@attrs()`. + if maybe_cls is None: + return wrap + + return wrap(maybe_cls) + + +_attrs = attrs +""" +Internal alias so we can use it in functions that take an argument called +*attrs*. +""" + + +def _has_frozen_base_class(cls): + """ + Check whether *cls* has a frozen ancestor by looking at its + __setattr__. + """ + return cls.__setattr__ is _frozen_setattrs + + +def _generate_unique_filename(cls: type, func_name: str) -> str: + """ + Create a "filename" suitable for a function being generated. + """ + return ( + f"" + ) + + +def _make_hash_script( + cls: type, attrs: list[Attribute], frozen: bool, cache_hash: bool +) -> tuple[str, dict]: + attrs = tuple( + a for a in attrs if a.hash is True or (a.hash is None and a.eq is True) + ) + + tab = " " + + type_hash = hash(_generate_unique_filename(cls, "hash")) + # If eq is custom generated, we need to include the functions in globs + globs = {} + + hash_def = "def __hash__(self" + hash_func = "hash((" + closing_braces = "))" + if not cache_hash: + hash_def += "):" + else: + hash_def += ", *" + + hash_def += ", _cache_wrapper=__import__('attr._make')._make._CacheHashWrapper):" + hash_func = "_cache_wrapper(" + hash_func + closing_braces += ")" + + method_lines = [hash_def] + + def append_hash_computation_lines(prefix, indent): + """ + Generate the code for actually computing the hash code. + Below this will either be returned directly or used to compute + a value which is then cached, depending on the value of cache_hash + """ + + method_lines.extend( + [ + indent + prefix + hash_func, + indent + f" {type_hash},", + ] + ) + + for a in attrs: + if a.eq_key: + cmp_name = f"_{a.name}_key" + globs[cmp_name] = a.eq_key + method_lines.append( + indent + f" {cmp_name}(self.{a.name})," + ) + else: + method_lines.append(indent + f" self.{a.name},") + + method_lines.append(indent + " " + closing_braces) + + if cache_hash: + method_lines.append(tab + f"if self.{_HASH_CACHE_FIELD} is None:") + if frozen: + append_hash_computation_lines( + f"object.__setattr__(self, '{_HASH_CACHE_FIELD}', ", tab * 2 + ) + method_lines.append(tab * 2 + ")") # close __setattr__ + else: + append_hash_computation_lines( + f"self.{_HASH_CACHE_FIELD} = ", tab * 2 + ) + method_lines.append(tab + f"return self.{_HASH_CACHE_FIELD}") + else: + append_hash_computation_lines("return ", tab) + + script = "\n".join(method_lines) + return script, globs + + +def _add_hash(cls: type, attrs: list[Attribute]): + """ + Add a hash method to *cls*. + """ + script, globs = _make_hash_script( + cls, attrs, frozen=False, cache_hash=False + ) + _compile_and_eval( + script, globs, filename=_generate_unique_filename(cls, "__hash__") + ) + cls.__hash__ = globs["__hash__"] + return cls + + +def __ne__(self, other): + """ + Check equality and either forward a NotImplemented or + return the result negated. + """ + result = self.__eq__(other) + if result is NotImplemented: + return NotImplemented + + return not result + + +def _make_eq_script(attrs: list) -> tuple[str, dict]: + """ + Create __eq__ method for *cls* with *attrs*. + """ + attrs = [a for a in attrs if a.eq] + + lines = [ + "def __eq__(self, other):", + " if other.__class__ is not self.__class__:", + " return NotImplemented", + ] + + globs = {} + if attrs: + lines.append(" return (") + for a in attrs: + if a.eq_key: + cmp_name = f"_{a.name}_key" + # Add the key function to the global namespace + # of the evaluated function. + globs[cmp_name] = a.eq_key + lines.append( + f" {cmp_name}(self.{a.name}) == {cmp_name}(other.{a.name})" + ) + else: + lines.append(f" self.{a.name} == other.{a.name}") + if a is not attrs[-1]: + lines[-1] = f"{lines[-1]} and" + lines.append(" )") + else: + lines.append(" return True") + + script = "\n".join(lines) + + return script, globs + + +def _make_order(cls, attrs): + """ + Create ordering methods for *cls* with *attrs*. + """ + attrs = [a for a in attrs if a.order] + + def attrs_to_tuple(obj): + """ + Save us some typing. + """ + return tuple( + key(value) if key else value + for value, key in ( + (getattr(obj, a.name), a.order_key) for a in attrs + ) + ) + + def __lt__(self, other): + """ + Automatically created by attrs. + """ + if other.__class__ is self.__class__: + return attrs_to_tuple(self) < attrs_to_tuple(other) + + return NotImplemented + + def __le__(self, other): + """ + Automatically created by attrs. + """ + if other.__class__ is self.__class__: + return attrs_to_tuple(self) <= attrs_to_tuple(other) + + return NotImplemented + + def __gt__(self, other): + """ + Automatically created by attrs. + """ + if other.__class__ is self.__class__: + return attrs_to_tuple(self) > attrs_to_tuple(other) + + return NotImplemented + + def __ge__(self, other): + """ + Automatically created by attrs. + """ + if other.__class__ is self.__class__: + return attrs_to_tuple(self) >= attrs_to_tuple(other) + + return NotImplemented + + return __lt__, __le__, __gt__, __ge__ + + +def _add_eq(cls, attrs=None): + """ + Add equality methods to *cls* with *attrs*. + """ + if attrs is None: + attrs = cls.__attrs_attrs__ + + script, globs = _make_eq_script(attrs) + _compile_and_eval( + script, globs, filename=_generate_unique_filename(cls, "__eq__") + ) + cls.__eq__ = globs["__eq__"] + cls.__ne__ = __ne__ + + return cls + + +def _make_repr_script(attrs, ns) -> tuple[str, dict]: + """ + Create the source and globs for a __repr__ and return it. + """ + # Figure out which attributes to include, and which function to use to + # format them. The a.repr value can be either bool or a custom + # callable. + attr_names_with_reprs = tuple( + (a.name, (repr if a.repr is True else a.repr), a.init) + for a in attrs + if a.repr is not False + ) + globs = { + name + "_repr": r for name, r, _ in attr_names_with_reprs if r != repr + } + globs["_compat"] = _compat + globs["AttributeError"] = AttributeError + globs["NOTHING"] = NOTHING + attribute_fragments = [] + for name, r, i in attr_names_with_reprs: + accessor = ( + "self." + name if i else 'getattr(self, "' + name + '", NOTHING)' + ) + fragment = ( + "%s={%s!r}" % (name, accessor) + if r == repr + else "%s={%s_repr(%s)}" % (name, name, accessor) + ) + attribute_fragments.append(fragment) + repr_fragment = ", ".join(attribute_fragments) + + if ns is None: + cls_name_fragment = '{self.__class__.__qualname__.rsplit(">.", 1)[-1]}' + else: + cls_name_fragment = ns + ".{self.__class__.__name__}" + + lines = [ + "def __repr__(self):", + " try:", + " already_repring = _compat.repr_context.already_repring", + " except AttributeError:", + " already_repring = {id(self),}", + " _compat.repr_context.already_repring = already_repring", + " else:", + " if id(self) in already_repring:", + " return '...'", + " else:", + " already_repring.add(id(self))", + " try:", + f" return f'{cls_name_fragment}({repr_fragment})'", + " finally:", + " already_repring.remove(id(self))", + ] + + return "\n".join(lines), globs + + +def _add_repr(cls, ns=None, attrs=None): + """ + Add a repr method to *cls*. + """ + if attrs is None: + attrs = cls.__attrs_attrs__ + + script, globs = _make_repr_script(attrs, ns) + _compile_and_eval( + script, globs, filename=_generate_unique_filename(cls, "__repr__") + ) + cls.__repr__ = globs["__repr__"] + return cls + + +def fields(cls): + """ + Return the tuple of *attrs* attributes for a class. + + The tuple also allows accessing the fields by their names (see below for + examples). + + Args: + cls (type): Class to introspect. + + Raises: + TypeError: If *cls* is not a class. + + attrs.exceptions.NotAnAttrsClassError: + If *cls* is not an *attrs* class. + + Returns: + tuple (with name accessors) of `attrs.Attribute` + + .. versionchanged:: 16.2.0 Returned tuple allows accessing the fields + by name. + .. versionchanged:: 23.1.0 Add support for generic classes. + """ + generic_base = get_generic_base(cls) + + if generic_base is None and not isinstance(cls, type): + msg = "Passed object must be a class." + raise TypeError(msg) + + attrs = getattr(cls, "__attrs_attrs__", None) + + if attrs is None: + if generic_base is not None: + attrs = getattr(generic_base, "__attrs_attrs__", None) + if attrs is not None: + # Even though this is global state, stick it on here to speed + # it up. We rely on `cls` being cached for this to be + # efficient. + cls.__attrs_attrs__ = attrs + return attrs + msg = f"{cls!r} is not an attrs-decorated class." + raise NotAnAttrsClassError(msg) + + return attrs + + +def fields_dict(cls): + """ + Return an ordered dictionary of *attrs* attributes for a class, whose keys + are the attribute names. + + Args: + cls (type): Class to introspect. + + Raises: + TypeError: If *cls* is not a class. + + attrs.exceptions.NotAnAttrsClassError: + If *cls* is not an *attrs* class. + + Returns: + dict[str, attrs.Attribute]: Dict of attribute name to definition + + .. versionadded:: 18.1.0 + """ + if not isinstance(cls, type): + msg = "Passed object must be a class." + raise TypeError(msg) + attrs = getattr(cls, "__attrs_attrs__", None) + if attrs is None: + msg = f"{cls!r} is not an attrs-decorated class." + raise NotAnAttrsClassError(msg) + return {a.name: a for a in attrs} + + +def validate(inst): + """ + Validate all attributes on *inst* that have a validator. + + Leaves all exceptions through. + + Args: + inst: Instance of a class with *attrs* attributes. + """ + if _config._run_validators is False: + return + + for a in fields(inst.__class__): + v = a.validator + if v is not None: + v(inst, a, getattr(inst, a.name)) + + +def _is_slot_attr(a_name, base_attr_map): + """ + Check if the attribute name comes from a slot class. + """ + cls = base_attr_map.get(a_name) + return cls and "__slots__" in cls.__dict__ + + +def _make_init_script( + cls, + attrs, + pre_init, + pre_init_has_args, + post_init, + frozen, + slots, + cache_hash, + base_attr_map, + is_exc, + cls_on_setattr, + attrs_init, +) -> tuple[str, dict, dict]: + has_cls_on_setattr = ( + cls_on_setattr is not None and cls_on_setattr is not setters.NO_OP + ) + + if frozen and has_cls_on_setattr: + msg = "Frozen classes can't use on_setattr." + raise ValueError(msg) + + needs_cached_setattr = cache_hash or frozen + filtered_attrs = [] + attr_dict = {} + for a in attrs: + if not a.init and a.default is NOTHING: + continue + + filtered_attrs.append(a) + attr_dict[a.name] = a + + if a.on_setattr is not None: + if frozen is True: + msg = "Frozen classes can't use on_setattr." + raise ValueError(msg) + + needs_cached_setattr = True + elif has_cls_on_setattr and a.on_setattr is not setters.NO_OP: + needs_cached_setattr = True + + script, globs, annotations = _attrs_to_init_script( + filtered_attrs, + frozen, + slots, + pre_init, + pre_init_has_args, + post_init, + cache_hash, + base_attr_map, + is_exc, + needs_cached_setattr, + has_cls_on_setattr, + "__attrs_init__" if attrs_init else "__init__", + ) + if cls.__module__ in sys.modules: + # This makes typing.get_type_hints(CLS.__init__) resolve string types. + globs.update(sys.modules[cls.__module__].__dict__) + + globs.update({"NOTHING": NOTHING, "attr_dict": attr_dict}) + + if needs_cached_setattr: + # Save the lookup overhead in __init__ if we need to circumvent + # setattr hooks. + globs["_cached_setattr_get"] = _OBJ_SETATTR.__get__ + + return script, globs, annotations + + +def _setattr(attr_name: str, value_var: str, has_on_setattr: bool) -> str: + """ + Use the cached object.setattr to set *attr_name* to *value_var*. + """ + return f"_setattr('{attr_name}', {value_var})" + + +def _setattr_with_converter( + attr_name: str, value_var: str, has_on_setattr: bool, converter: Converter +) -> str: + """ + Use the cached object.setattr to set *attr_name* to *value_var*, but run + its converter first. + """ + return f"_setattr('{attr_name}', {converter._fmt_converter_call(attr_name, value_var)})" + + +def _assign(attr_name: str, value: str, has_on_setattr: bool) -> str: + """ + Unless *attr_name* has an on_setattr hook, use normal assignment. Otherwise + relegate to _setattr. + """ + if has_on_setattr: + return _setattr(attr_name, value, True) + + return f"self.{attr_name} = {value}" + + +def _assign_with_converter( + attr_name: str, value_var: str, has_on_setattr: bool, converter: Converter +) -> str: + """ + Unless *attr_name* has an on_setattr hook, use normal assignment after + conversion. Otherwise relegate to _setattr_with_converter. + """ + if has_on_setattr: + return _setattr_with_converter(attr_name, value_var, True, converter) + + return f"self.{attr_name} = {converter._fmt_converter_call(attr_name, value_var)}" + + +def _determine_setters( + frozen: bool, slots: bool, base_attr_map: dict[str, type] +): + """ + Determine the correct setter functions based on whether a class is frozen + and/or slotted. + """ + if frozen is True: + if slots is True: + return (), _setattr, _setattr_with_converter + + # Dict frozen classes assign directly to __dict__. + # But only if the attribute doesn't come from an ancestor slot + # class. + # Note _inst_dict will be used again below if cache_hash is True + + def fmt_setter( + attr_name: str, value_var: str, has_on_setattr: bool + ) -> str: + if _is_slot_attr(attr_name, base_attr_map): + return _setattr(attr_name, value_var, has_on_setattr) + + return f"_inst_dict['{attr_name}'] = {value_var}" + + def fmt_setter_with_converter( + attr_name: str, + value_var: str, + has_on_setattr: bool, + converter: Converter, + ) -> str: + if has_on_setattr or _is_slot_attr(attr_name, base_attr_map): + return _setattr_with_converter( + attr_name, value_var, has_on_setattr, converter + ) + + return f"_inst_dict['{attr_name}'] = {converter._fmt_converter_call(attr_name, value_var)}" + + return ( + ("_inst_dict = self.__dict__",), + fmt_setter, + fmt_setter_with_converter, + ) + + # Not frozen -- we can just assign directly. + return (), _assign, _assign_with_converter + + +def _attrs_to_init_script( + attrs: list[Attribute], + is_frozen: bool, + is_slotted: bool, + call_pre_init: bool, + pre_init_has_args: bool, + call_post_init: bool, + does_cache_hash: bool, + base_attr_map: dict[str, type], + is_exc: bool, + needs_cached_setattr: bool, + has_cls_on_setattr: bool, + method_name: str, +) -> tuple[str, dict, dict]: + """ + Return a script of an initializer for *attrs*, a dict of globals, and + annotations for the initializer. + + The globals are required by the generated script. + """ + lines = ["self.__attrs_pre_init__()"] if call_pre_init else [] + + if needs_cached_setattr: + lines.append( + # Circumvent the __setattr__ descriptor to save one lookup per + # assignment. Note _setattr will be used again below if + # does_cache_hash is True. + "_setattr = _cached_setattr_get(self)" + ) + + extra_lines, fmt_setter, fmt_setter_with_converter = _determine_setters( + is_frozen, is_slotted, base_attr_map + ) + lines.extend(extra_lines) + + args = [] + kw_only_args = [] + attrs_to_validate = [] + + # This is a dictionary of names to validator and converter callables. + # Injecting this into __init__ globals lets us avoid lookups. + names_for_globals = {} + annotations = {"return": None} + + for a in attrs: + if a.validator: + attrs_to_validate.append(a) + + attr_name = a.name + has_on_setattr = a.on_setattr is not None or ( + a.on_setattr is not setters.NO_OP and has_cls_on_setattr + ) + # a.alias is set to maybe-mangled attr_name in _ClassBuilder if not + # explicitly provided + arg_name = a.alias + + has_factory = isinstance(a.default, Factory) + maybe_self = "self" if has_factory and a.default.takes_self else "" + + if a.converter is not None and not isinstance(a.converter, Converter): + converter = Converter(a.converter) + else: + converter = a.converter + + if a.init is False: + if has_factory: + init_factory_name = _INIT_FACTORY_PAT % (a.name,) + if converter is not None: + lines.append( + fmt_setter_with_converter( + attr_name, + init_factory_name + f"({maybe_self})", + has_on_setattr, + converter, + ) + ) + names_for_globals[converter._get_global_name(a.name)] = ( + converter.converter + ) + else: + lines.append( + fmt_setter( + attr_name, + init_factory_name + f"({maybe_self})", + has_on_setattr, + ) + ) + names_for_globals[init_factory_name] = a.default.factory + elif converter is not None: + lines.append( + fmt_setter_with_converter( + attr_name, + f"attr_dict['{attr_name}'].default", + has_on_setattr, + converter, + ) + ) + names_for_globals[converter._get_global_name(a.name)] = ( + converter.converter + ) + else: + lines.append( + fmt_setter( + attr_name, + f"attr_dict['{attr_name}'].default", + has_on_setattr, + ) + ) + elif a.default is not NOTHING and not has_factory: + arg = f"{arg_name}=attr_dict['{attr_name}'].default" + if a.kw_only: + kw_only_args.append(arg) + else: + args.append(arg) + + if converter is not None: + lines.append( + fmt_setter_with_converter( + attr_name, arg_name, has_on_setattr, converter + ) + ) + names_for_globals[converter._get_global_name(a.name)] = ( + converter.converter + ) + else: + lines.append(fmt_setter(attr_name, arg_name, has_on_setattr)) + + elif has_factory: + arg = f"{arg_name}=NOTHING" + if a.kw_only: + kw_only_args.append(arg) + else: + args.append(arg) + lines.append(f"if {arg_name} is not NOTHING:") + + init_factory_name = _INIT_FACTORY_PAT % (a.name,) + if converter is not None: + lines.append( + " " + + fmt_setter_with_converter( + attr_name, arg_name, has_on_setattr, converter + ) + ) + lines.append("else:") + lines.append( + " " + + fmt_setter_with_converter( + attr_name, + init_factory_name + "(" + maybe_self + ")", + has_on_setattr, + converter, + ) + ) + names_for_globals[converter._get_global_name(a.name)] = ( + converter.converter + ) + else: + lines.append( + " " + fmt_setter(attr_name, arg_name, has_on_setattr) + ) + lines.append("else:") + lines.append( + " " + + fmt_setter( + attr_name, + init_factory_name + "(" + maybe_self + ")", + has_on_setattr, + ) + ) + names_for_globals[init_factory_name] = a.default.factory + else: + if a.kw_only: + kw_only_args.append(arg_name) + else: + args.append(arg_name) + + if converter is not None: + lines.append( + fmt_setter_with_converter( + attr_name, arg_name, has_on_setattr, converter + ) + ) + names_for_globals[converter._get_global_name(a.name)] = ( + converter.converter + ) + else: + lines.append(fmt_setter(attr_name, arg_name, has_on_setattr)) + + if a.init is True: + if a.type is not None and converter is None: + annotations[arg_name] = a.type + elif converter is not None and converter._first_param_type: + # Use the type from the converter if present. + annotations[arg_name] = converter._first_param_type + + if attrs_to_validate: # we can skip this if there are no validators. + names_for_globals["_config"] = _config + lines.append("if _config._run_validators is True:") + for a in attrs_to_validate: + val_name = "__attr_validator_" + a.name + attr_name = "__attr_" + a.name + lines.append(f" {val_name}(self, {attr_name}, self.{a.name})") + names_for_globals[val_name] = a.validator + names_for_globals[attr_name] = a + + if call_post_init: + lines.append("self.__attrs_post_init__()") + + # Because this is set only after __attrs_post_init__ is called, a crash + # will result if post-init tries to access the hash code. This seemed + # preferable to setting this beforehand, in which case alteration to field + # values during post-init combined with post-init accessing the hash code + # would result in silent bugs. + if does_cache_hash: + if is_frozen: + if is_slotted: + init_hash_cache = f"_setattr('{_HASH_CACHE_FIELD}', None)" + else: + init_hash_cache = f"_inst_dict['{_HASH_CACHE_FIELD}'] = None" + else: + init_hash_cache = f"self.{_HASH_CACHE_FIELD} = None" + lines.append(init_hash_cache) + + # For exceptions we rely on BaseException.__init__ for proper + # initialization. + if is_exc: + vals = ",".join(f"self.{a.name}" for a in attrs if a.init) + + lines.append(f"BaseException.__init__(self, {vals})") + + args = ", ".join(args) + pre_init_args = args + if kw_only_args: + # leading comma & kw_only args + args += f"{', ' if args else ''}*, {', '.join(kw_only_args)}" + pre_init_kw_only_args = ", ".join( + [ + f"{kw_arg_name}={kw_arg_name}" + # We need to remove the defaults from the kw_only_args. + for kw_arg_name in (kwa.split("=")[0] for kwa in kw_only_args) + ] + ) + pre_init_args += ", " if pre_init_args else "" + pre_init_args += pre_init_kw_only_args + + if call_pre_init and pre_init_has_args: + # If pre init method has arguments, pass same arguments as `__init__`. + lines[0] = f"self.__attrs_pre_init__({pre_init_args})" + + # Python <3.12 doesn't allow backslashes in f-strings. + NL = "\n " + return ( + f"""def {method_name}(self, {args}): + {NL.join(lines) if lines else "pass"} +""", + names_for_globals, + annotations, + ) + + +def _default_init_alias_for(name: str) -> str: + """ + The default __init__ parameter name for a field. + + This performs private-name adjustment via leading-unscore stripping, + and is the default value of Attribute.alias if not provided. + """ + + return name.lstrip("_") + + +class Attribute: + """ + *Read-only* representation of an attribute. + + .. warning:: + + You should never instantiate this class yourself. + + The class has *all* arguments of `attr.ib` (except for ``factory`` which is + only syntactic sugar for ``default=Factory(...)`` plus the following: + + - ``name`` (`str`): The name of the attribute. + - ``alias`` (`str`): The __init__ parameter name of the attribute, after + any explicit overrides and default private-attribute-name handling. + - ``inherited`` (`bool`): Whether or not that attribute has been inherited + from a base class. + - ``eq_key`` and ``order_key`` (`typing.Callable` or `None`): The + callables that are used for comparing and ordering objects by this + attribute, respectively. These are set by passing a callable to + `attr.ib`'s ``eq``, ``order``, or ``cmp`` arguments. See also + :ref:`comparison customization `. + + Instances of this class are frequently used for introspection purposes + like: + + - `fields` returns a tuple of them. + - Validators get them passed as the first argument. + - The :ref:`field transformer ` hook receives a list of + them. + - The ``alias`` property exposes the __init__ parameter name of the field, + with any overrides and default private-attribute handling applied. + + + .. versionadded:: 20.1.0 *inherited* + .. versionadded:: 20.1.0 *on_setattr* + .. versionchanged:: 20.2.0 *inherited* is not taken into account for + equality checks and hashing anymore. + .. versionadded:: 21.1.0 *eq_key* and *order_key* + .. versionadded:: 22.2.0 *alias* + + For the full version history of the fields, see `attr.ib`. + """ + + # These slots must NOT be reordered because we use them later for + # instantiation. + __slots__ = ( # noqa: RUF023 + "name", + "default", + "validator", + "repr", + "eq", + "eq_key", + "order", + "order_key", + "hash", + "init", + "metadata", + "type", + "converter", + "kw_only", + "inherited", + "on_setattr", + "alias", + ) + + def __init__( + self, + name, + default, + validator, + repr, + cmp, # XXX: unused, remove along with other cmp code. + hash, + init, + inherited, + metadata=None, + type=None, + converter=None, + kw_only=False, + eq=None, + eq_key=None, + order=None, + order_key=None, + on_setattr=None, + alias=None, + ): + eq, eq_key, order, order_key = _determine_attrib_eq_order( + cmp, eq_key or eq, order_key or order, True + ) + + # Cache this descriptor here to speed things up later. + bound_setattr = _OBJ_SETATTR.__get__(self) + + # Despite the big red warning, people *do* instantiate `Attribute` + # themselves. + bound_setattr("name", name) + bound_setattr("default", default) + bound_setattr("validator", validator) + bound_setattr("repr", repr) + bound_setattr("eq", eq) + bound_setattr("eq_key", eq_key) + bound_setattr("order", order) + bound_setattr("order_key", order_key) + bound_setattr("hash", hash) + bound_setattr("init", init) + bound_setattr("converter", converter) + bound_setattr( + "metadata", + ( + types.MappingProxyType(dict(metadata)) # Shallow copy + if metadata + else _EMPTY_METADATA_SINGLETON + ), + ) + bound_setattr("type", type) + bound_setattr("kw_only", kw_only) + bound_setattr("inherited", inherited) + bound_setattr("on_setattr", on_setattr) + bound_setattr("alias", alias) + + def __setattr__(self, name, value): + raise FrozenInstanceError + + @classmethod + def from_counting_attr(cls, name: str, ca: _CountingAttr, type=None): + # type holds the annotated value. deal with conflicts: + if type is None: + type = ca.type + elif ca.type is not None: + msg = f"Type annotation and type argument cannot both be present for '{name}'." + raise ValueError(msg) + return cls( + name, + ca._default, + ca._validator, + ca.repr, + None, + ca.hash, + ca.init, + False, + ca.metadata, + type, + ca.converter, + ca.kw_only, + ca.eq, + ca.eq_key, + ca.order, + ca.order_key, + ca.on_setattr, + ca.alias, + ) + + # Don't use attrs.evolve since fields(Attribute) doesn't work + def evolve(self, **changes): + """ + Copy *self* and apply *changes*. + + This works similarly to `attrs.evolve` but that function does not work + with :class:`attrs.Attribute`. + + It is mainly meant to be used for `transform-fields`. + + .. versionadded:: 20.3.0 + """ + new = copy.copy(self) + + new._setattrs(changes.items()) + + return new + + # Don't use _add_pickle since fields(Attribute) doesn't work + def __getstate__(self): + """ + Play nice with pickle. + """ + return tuple( + getattr(self, name) if name != "metadata" else dict(self.metadata) + for name in self.__slots__ + ) + + def __setstate__(self, state): + """ + Play nice with pickle. + """ + self._setattrs(zip(self.__slots__, state)) + + def _setattrs(self, name_values_pairs): + bound_setattr = _OBJ_SETATTR.__get__(self) + for name, value in name_values_pairs: + if name != "metadata": + bound_setattr(name, value) + else: + bound_setattr( + name, + ( + types.MappingProxyType(dict(value)) + if value + else _EMPTY_METADATA_SINGLETON + ), + ) + + +_a = [ + Attribute( + name=name, + default=NOTHING, + validator=None, + repr=True, + cmp=None, + eq=True, + order=False, + hash=(name != "metadata"), + init=True, + inherited=False, + alias=_default_init_alias_for(name), + ) + for name in Attribute.__slots__ +] + +Attribute = _add_hash( + _add_eq( + _add_repr(Attribute, attrs=_a), + attrs=[a for a in _a if a.name != "inherited"], + ), + attrs=[a for a in _a if a.hash and a.name != "inherited"], +) + + +class _CountingAttr: + """ + Intermediate representation of attributes that uses a counter to preserve + the order in which the attributes have been defined. + + *Internal* data structure of the attrs library. Running into is most + likely the result of a bug like a forgotten `@attr.s` decorator. + """ + + __slots__ = ( + "_default", + "_validator", + "alias", + "converter", + "counter", + "eq", + "eq_key", + "hash", + "init", + "kw_only", + "metadata", + "on_setattr", + "order", + "order_key", + "repr", + "type", + ) + __attrs_attrs__ = ( + *tuple( + Attribute( + name=name, + alias=_default_init_alias_for(name), + default=NOTHING, + validator=None, + repr=True, + cmp=None, + hash=True, + init=True, + kw_only=False, + eq=True, + eq_key=None, + order=False, + order_key=None, + inherited=False, + on_setattr=None, + ) + for name in ( + "counter", + "_default", + "repr", + "eq", + "order", + "hash", + "init", + "on_setattr", + "alias", + ) + ), + Attribute( + name="metadata", + alias="metadata", + default=None, + validator=None, + repr=True, + cmp=None, + hash=False, + init=True, + kw_only=False, + eq=True, + eq_key=None, + order=False, + order_key=None, + inherited=False, + on_setattr=None, + ), + ) + cls_counter = 0 + + def __init__( + self, + default, + validator, + repr, + cmp, + hash, + init, + converter, + metadata, + type, + kw_only, + eq, + eq_key, + order, + order_key, + on_setattr, + alias, + ): + _CountingAttr.cls_counter += 1 + self.counter = _CountingAttr.cls_counter + self._default = default + self._validator = validator + self.converter = converter + self.repr = repr + self.eq = eq + self.eq_key = eq_key + self.order = order + self.order_key = order_key + self.hash = hash + self.init = init + self.metadata = metadata + self.type = type + self.kw_only = kw_only + self.on_setattr = on_setattr + self.alias = alias + + def validator(self, meth): + """ + Decorator that adds *meth* to the list of validators. + + Returns *meth* unchanged. + + .. versionadded:: 17.1.0 + """ + if self._validator is None: + self._validator = meth + else: + self._validator = and_(self._validator, meth) + return meth + + def default(self, meth): + """ + Decorator that allows to set the default for an attribute. + + Returns *meth* unchanged. + + Raises: + DefaultAlreadySetError: If default has been set before. + + .. versionadded:: 17.1.0 + """ + if self._default is not NOTHING: + raise DefaultAlreadySetError + + self._default = Factory(meth, takes_self=True) + + return meth + + +_CountingAttr = _add_eq(_add_repr(_CountingAttr)) + + +class Factory: + """ + Stores a factory callable. + + If passed as the default value to `attrs.field`, the factory is used to + generate a new value. + + Args: + factory (typing.Callable): + A callable that takes either none or exactly one mandatory + positional argument depending on *takes_self*. + + takes_self (bool): + Pass the partially initialized instance that is being initialized + as a positional argument. + + .. versionadded:: 17.1.0 *takes_self* + """ + + __slots__ = ("factory", "takes_self") + + def __init__(self, factory, takes_self=False): + self.factory = factory + self.takes_self = takes_self + + def __getstate__(self): + """ + Play nice with pickle. + """ + return tuple(getattr(self, name) for name in self.__slots__) + + def __setstate__(self, state): + """ + Play nice with pickle. + """ + for name, value in zip(self.__slots__, state): + setattr(self, name, value) + + +_f = [ + Attribute( + name=name, + default=NOTHING, + validator=None, + repr=True, + cmp=None, + eq=True, + order=False, + hash=True, + init=True, + inherited=False, + ) + for name in Factory.__slots__ +] + +Factory = _add_hash(_add_eq(_add_repr(Factory, attrs=_f), attrs=_f), attrs=_f) + + +class Converter: + """ + Stores a converter callable. + + Allows for the wrapped converter to take additional arguments. The + arguments are passed in the order they are documented. + + Args: + converter (Callable): A callable that converts the passed value. + + takes_self (bool): + Pass the partially initialized instance that is being initialized + as a positional argument. (default: `False`) + + takes_field (bool): + Pass the field definition (an :class:`Attribute`) into the + converter as a positional argument. (default: `False`) + + .. versionadded:: 24.1.0 + """ + + __slots__ = ( + "__call__", + "_first_param_type", + "_global_name", + "converter", + "takes_field", + "takes_self", + ) + + def __init__(self, converter, *, takes_self=False, takes_field=False): + self.converter = converter + self.takes_self = takes_self + self.takes_field = takes_field + + ex = _AnnotationExtractor(converter) + self._first_param_type = ex.get_first_param_type() + + if not (self.takes_self or self.takes_field): + self.__call__ = lambda value, _, __: self.converter(value) + elif self.takes_self and not self.takes_field: + self.__call__ = lambda value, instance, __: self.converter( + value, instance + ) + elif not self.takes_self and self.takes_field: + self.__call__ = lambda value, __, field: self.converter( + value, field + ) + else: + self.__call__ = lambda value, instance, field: self.converter( + value, instance, field + ) + + rt = ex.get_return_type() + if rt is not None: + self.__call__.__annotations__["return"] = rt + + @staticmethod + def _get_global_name(attr_name: str) -> str: + """ + Return the name that a converter for an attribute name *attr_name* + would have. + """ + return f"__attr_converter_{attr_name}" + + def _fmt_converter_call(self, attr_name: str, value_var: str) -> str: + """ + Return a string that calls the converter for an attribute name + *attr_name* and the value in variable named *value_var* according to + `self.takes_self` and `self.takes_field`. + """ + if not (self.takes_self or self.takes_field): + return f"{self._get_global_name(attr_name)}({value_var})" + + if self.takes_self and self.takes_field: + return f"{self._get_global_name(attr_name)}({value_var}, self, attr_dict['{attr_name}'])" + + if self.takes_self: + return f"{self._get_global_name(attr_name)}({value_var}, self)" + + return f"{self._get_global_name(attr_name)}({value_var}, attr_dict['{attr_name}'])" + + def __getstate__(self): + """ + Return a dict containing only converter and takes_self -- the rest gets + computed when loading. + """ + return { + "converter": self.converter, + "takes_self": self.takes_self, + "takes_field": self.takes_field, + } + + def __setstate__(self, state): + """ + Load instance from state. + """ + self.__init__(**state) + + +_f = [ + Attribute( + name=name, + default=NOTHING, + validator=None, + repr=True, + cmp=None, + eq=True, + order=False, + hash=True, + init=True, + inherited=False, + ) + for name in ("converter", "takes_self", "takes_field") +] + +Converter = _add_hash( + _add_eq(_add_repr(Converter, attrs=_f), attrs=_f), attrs=_f +) + + +def make_class( + name, attrs, bases=(object,), class_body=None, **attributes_arguments +): + r""" + A quick way to create a new class called *name* with *attrs*. + + .. note:: + + ``make_class()`` is a thin wrapper around `attr.s`, not `attrs.define` + which means that it doesn't come with some of the improved defaults. + + For example, if you want the same ``on_setattr`` behavior as in + `attrs.define`, you have to pass the hooks yourself: ``make_class(..., + on_setattr=setters.pipe(setters.convert, setters.validate)`` + + .. warning:: + + It is *your* duty to ensure that the class name and the attribute names + are valid identifiers. ``make_class()`` will *not* validate them for + you. + + Args: + name (str): The name for the new class. + + attrs (list | dict): + A list of names or a dictionary of mappings of names to `attr.ib`\ + s / `attrs.field`\ s. + + The order is deduced from the order of the names or attributes + inside *attrs*. Otherwise the order of the definition of the + attributes is used. + + bases (tuple[type, ...]): Classes that the new class will subclass. + + class_body (dict): + An optional dictionary of class attributes for the new class. + + attributes_arguments: Passed unmodified to `attr.s`. + + Returns: + type: A new class with *attrs*. + + .. versionadded:: 17.1.0 *bases* + .. versionchanged:: 18.1.0 If *attrs* is ordered, the order is retained. + .. versionchanged:: 23.2.0 *class_body* + .. versionchanged:: 25.2.0 Class names can now be unicode. + """ + # Class identifiers are converted into the normal form NFKC while parsing + name = unicodedata.normalize("NFKC", name) + + if isinstance(attrs, dict): + cls_dict = attrs + elif isinstance(attrs, (list, tuple)): + cls_dict = {a: attrib() for a in attrs} + else: + msg = "attrs argument must be a dict or a list." + raise TypeError(msg) + + pre_init = cls_dict.pop("__attrs_pre_init__", None) + post_init = cls_dict.pop("__attrs_post_init__", None) + user_init = cls_dict.pop("__init__", None) + + body = {} + if class_body is not None: + body.update(class_body) + if pre_init is not None: + body["__attrs_pre_init__"] = pre_init + if post_init is not None: + body["__attrs_post_init__"] = post_init + if user_init is not None: + body["__init__"] = user_init + + type_ = types.new_class(name, bases, {}, lambda ns: ns.update(body)) + + # For pickling to work, the __module__ variable needs to be set to the + # frame where the class is created. Bypass this step in environments where + # sys._getframe is not defined (Jython for example) or sys._getframe is not + # defined for arguments greater than 0 (IronPython). + with contextlib.suppress(AttributeError, ValueError): + type_.__module__ = sys._getframe(1).f_globals.get( + "__name__", "__main__" + ) + + # We do it here for proper warnings with meaningful stacklevel. + cmp = attributes_arguments.pop("cmp", None) + ( + attributes_arguments["eq"], + attributes_arguments["order"], + ) = _determine_attrs_eq_order( + cmp, + attributes_arguments.get("eq"), + attributes_arguments.get("order"), + True, + ) + + cls = _attrs(these=cls_dict, **attributes_arguments)(type_) + # Only add type annotations now or "_attrs()" will complain: + cls.__annotations__ = { + k: v.type for k, v in cls_dict.items() if v.type is not None + } + return cls + + +# These are required by within this module so we define them here and merely +# import into .validators / .converters. + + +@attrs(slots=True, unsafe_hash=True) +class _AndValidator: + """ + Compose many validators to a single one. + """ + + _validators = attrib() + + def __call__(self, inst, attr, value): + for v in self._validators: + v(inst, attr, value) + + +def and_(*validators): + """ + A validator that composes multiple validators into one. + + When called on a value, it runs all wrapped validators. + + Args: + validators (~collections.abc.Iterable[typing.Callable]): + Arbitrary number of validators. + + .. versionadded:: 17.1.0 + """ + vals = [] + for validator in validators: + vals.extend( + validator._validators + if isinstance(validator, _AndValidator) + else [validator] + ) + + return _AndValidator(tuple(vals)) + + +def pipe(*converters): + """ + A converter that composes multiple converters into one. + + When called on a value, it runs all wrapped converters, returning the + *last* value. + + Type annotations will be inferred from the wrapped converters', if they + have any. + + converters (~collections.abc.Iterable[typing.Callable]): + Arbitrary number of converters. + + .. versionadded:: 20.1.0 + """ + + return_instance = any(isinstance(c, Converter) for c in converters) + + if return_instance: + + def pipe_converter(val, inst, field): + for c in converters: + val = ( + c(val, inst, field) if isinstance(c, Converter) else c(val) + ) + + return val + + else: + + def pipe_converter(val): + for c in converters: + val = c(val) + + return val + + if not converters: + # If the converter list is empty, pipe_converter is the identity. + A = TypeVar("A") + pipe_converter.__annotations__.update({"val": A, "return": A}) + else: + # Get parameter type from first converter. + t = _AnnotationExtractor(converters[0]).get_first_param_type() + if t: + pipe_converter.__annotations__["val"] = t + + last = converters[-1] + if not PY_3_11_PLUS and isinstance(last, Converter): + last = last.__call__ + + # Get return type from last converter. + rt = _AnnotationExtractor(last).get_return_type() + if rt: + pipe_converter.__annotations__["return"] = rt + + if return_instance: + return Converter(pipe_converter, takes_self=True, takes_field=True) + return pipe_converter diff --git a/venv/lib/python3.12/site-packages/attr/_next_gen.py b/venv/lib/python3.12/site-packages/attr/_next_gen.py new file mode 100644 index 00000000..9290664b --- /dev/null +++ b/venv/lib/python3.12/site-packages/attr/_next_gen.py @@ -0,0 +1,623 @@ +# SPDX-License-Identifier: MIT + +""" +These are keyword-only APIs that call `attr.s` and `attr.ib` with different +default values. +""" + +from functools import partial + +from . import setters +from ._funcs import asdict as _asdict +from ._funcs import astuple as _astuple +from ._make import ( + _DEFAULT_ON_SETATTR, + NOTHING, + _frozen_setattrs, + attrib, + attrs, +) +from .exceptions import UnannotatedAttributeError + + +def define( + maybe_cls=None, + *, + these=None, + repr=None, + unsafe_hash=None, + hash=None, + init=None, + slots=True, + frozen=False, + weakref_slot=True, + str=False, + auto_attribs=None, + kw_only=False, + cache_hash=False, + auto_exc=True, + eq=None, + order=False, + auto_detect=True, + getstate_setstate=None, + on_setattr=None, + field_transformer=None, + match_args=True, +): + r""" + A class decorator that adds :term:`dunder methods` according to + :term:`fields ` specified using :doc:`type annotations `, + `field()` calls, or the *these* argument. + + Since *attrs* patches or replaces an existing class, you cannot use + `object.__init_subclass__` with *attrs* classes, because it runs too early. + As a replacement, you can define ``__attrs_init_subclass__`` on your class. + It will be called by *attrs* classes that subclass it after they're + created. See also :ref:`init-subclass`. + + Args: + slots (bool): + Create a :term:`slotted class ` that's more + memory-efficient. Slotted classes are generally superior to the + default dict classes, but have some gotchas you should know about, + so we encourage you to read the :term:`glossary entry `. + + auto_detect (bool): + Instead of setting the *init*, *repr*, *eq*, and *hash* arguments + explicitly, assume they are set to True **unless any** of the + involved methods for one of the arguments is implemented in the + *current* class (meaning, it is *not* inherited from some base + class). + + So, for example by implementing ``__eq__`` on a class yourself, + *attrs* will deduce ``eq=False`` and will create *neither* + ``__eq__`` *nor* ``__ne__`` (but Python classes come with a + sensible ``__ne__`` by default, so it *should* be enough to only + implement ``__eq__`` in most cases). + + Passing True or False` to *init*, *repr*, *eq*, or *hash* + overrides whatever *auto_detect* would determine. + + auto_exc (bool): + If the class subclasses `BaseException` (which implicitly includes + any subclass of any exception), the following happens to behave + like a well-behaved Python exception class: + + - the values for *eq*, *order*, and *hash* are ignored and the + instances compare and hash by the instance's ids [#]_ , + - all attributes that are either passed into ``__init__`` or have a + default value are additionally available as a tuple in the + ``args`` attribute, + - the value of *str* is ignored leaving ``__str__`` to base + classes. + + .. [#] + Note that *attrs* will *not* remove existing implementations of + ``__hash__`` or the equality methods. It just won't add own + ones. + + on_setattr (~typing.Callable | list[~typing.Callable] | None | ~typing.Literal[attrs.setters.NO_OP]): + A callable that is run whenever the user attempts to set an + attribute (either by assignment like ``i.x = 42`` or by using + `setattr` like ``setattr(i, "x", 42)``). It receives the same + arguments as validators: the instance, the attribute that is being + modified, and the new value. + + If no exception is raised, the attribute is set to the return value + of the callable. + + If a list of callables is passed, they're automatically wrapped in + an `attrs.setters.pipe`. + + If left None, the default behavior is to run converters and + validators whenever an attribute is set. + + init (bool): + Create a ``__init__`` method that initializes the *attrs* + attributes. Leading underscores are stripped for the argument name, + unless an alias is set on the attribute. + + .. seealso:: + `init` shows advanced ways to customize the generated + ``__init__`` method, including executing code before and after. + + repr(bool): + Create a ``__repr__`` method with a human readable representation + of *attrs* attributes. + + str (bool): + Create a ``__str__`` method that is identical to ``__repr__``. This + is usually not necessary except for `Exception`\ s. + + eq (bool | None): + If True or None (default), add ``__eq__`` and ``__ne__`` methods + that check two instances for equality. + + .. seealso:: + `comparison` describes how to customize the comparison behavior + going as far comparing NumPy arrays. + + order (bool | None): + If True, add ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` + methods that behave like *eq* above and allow instances to be + ordered. + + They compare the instances as if they were tuples of their *attrs* + attributes if and only if the types of both classes are + *identical*. + + If `None` mirror value of *eq*. + + .. seealso:: `comparison` + + unsafe_hash (bool | None): + If None (default), the ``__hash__`` method is generated according + how *eq* and *frozen* are set. + + 1. If *both* are True, *attrs* will generate a ``__hash__`` for + you. + 2. If *eq* is True and *frozen* is False, ``__hash__`` will be set + to None, marking it unhashable (which it is). + 3. If *eq* is False, ``__hash__`` will be left untouched meaning + the ``__hash__`` method of the base class will be used. If the + base class is `object`, this means it will fall back to id-based + hashing. + + Although not recommended, you can decide for yourself and force + *attrs* to create one (for example, if the class is immutable even + though you didn't freeze it programmatically) by passing True or + not. Both of these cases are rather special and should be used + carefully. + + .. seealso:: + + - Our documentation on `hashing`, + - Python's documentation on `object.__hash__`, + - and the `GitHub issue that led to the default \ behavior + `_ for more + details. + + hash (bool | None): + Deprecated alias for *unsafe_hash*. *unsafe_hash* takes precedence. + + cache_hash (bool): + Ensure that the object's hash code is computed only once and stored + on the object. If this is set to True, hashing must be either + explicitly or implicitly enabled for this class. If the hash code + is cached, avoid any reassignments of fields involved in hash code + computation or mutations of the objects those fields point to after + object creation. If such changes occur, the behavior of the + object's hash code is undefined. + + frozen (bool): + Make instances immutable after initialization. If someone attempts + to modify a frozen instance, `attrs.exceptions.FrozenInstanceError` + is raised. + + .. note:: + + 1. This is achieved by installing a custom ``__setattr__`` + method on your class, so you can't implement your own. + + 2. True immutability is impossible in Python. + + 3. This *does* have a minor a runtime performance `impact + ` when initializing new instances. In other + words: ``__init__`` is slightly slower with ``frozen=True``. + + 4. If a class is frozen, you cannot modify ``self`` in + ``__attrs_post_init__`` or a self-written ``__init__``. You + can circumvent that limitation by using + ``object.__setattr__(self, "attribute_name", value)``. + + 5. Subclasses of a frozen class are frozen too. + + kw_only (bool): + Make all attributes keyword-only in the generated ``__init__`` (if + *init* is False, this parameter is ignored). + + weakref_slot (bool): + Make instances weak-referenceable. This has no effect unless + *slots* is True. + + field_transformer (~typing.Callable | None): + A function that is called with the original class object and all + fields right before *attrs* finalizes the class. You can use this, + for example, to automatically add converters or validators to + fields based on their types. + + .. seealso:: `transform-fields` + + match_args (bool): + If True (default), set ``__match_args__`` on the class to support + :pep:`634` (*Structural Pattern Matching*). It is a tuple of all + non-keyword-only ``__init__`` parameter names on Python 3.10 and + later. Ignored on older Python versions. + + collect_by_mro (bool): + If True, *attrs* collects attributes from base classes correctly + according to the `method resolution order + `_. If False, *attrs* + will mimic the (wrong) behavior of `dataclasses` and :pep:`681`. + + See also `issue #428 + `_. + + getstate_setstate (bool | None): + .. note:: + + This is usually only interesting for slotted classes and you + should probably just set *auto_detect* to True. + + If True, ``__getstate__`` and ``__setstate__`` are generated and + attached to the class. This is necessary for slotted classes to be + pickleable. If left None, it's True by default for slotted classes + and False for dict classes. + + If *auto_detect* is True, and *getstate_setstate* is left None, and + **either** ``__getstate__`` or ``__setstate__`` is detected + directly on the class (meaning: not inherited), it is set to False + (this is usually what you want). + + auto_attribs (bool | None): + If True, look at type annotations to determine which attributes to + use, like `dataclasses`. If False, it will only look for explicit + :func:`field` class attributes, like classic *attrs*. + + If left None, it will guess: + + 1. If any attributes are annotated and no unannotated + `attrs.field`\ s are found, it assumes *auto_attribs=True*. + 2. Otherwise it assumes *auto_attribs=False* and tries to collect + `attrs.field`\ s. + + If *attrs* decides to look at type annotations, **all** fields + **must** be annotated. If *attrs* encounters a field that is set to + a :func:`field` / `attr.ib` but lacks a type annotation, an + `attrs.exceptions.UnannotatedAttributeError` is raised. Use + ``field_name: typing.Any = field(...)`` if you don't want to set a + type. + + .. warning:: + + For features that use the attribute name to create decorators + (for example, :ref:`validators `), you still *must* + assign :func:`field` / `attr.ib` to them. Otherwise Python will + either not find the name or try to use the default value to + call, for example, ``validator`` on it. + + Attributes annotated as `typing.ClassVar`, and attributes that are + neither annotated nor set to an `field()` are **ignored**. + + these (dict[str, object]): + A dictionary of name to the (private) return value of `field()` + mappings. This is useful to avoid the definition of your attributes + within the class body because you can't (for example, if you want + to add ``__repr__`` methods to Django models) or don't want to. + + If *these* is not `None`, *attrs* will *not* search the class body + for attributes and will *not* remove any attributes from it. + + The order is deduced from the order of the attributes inside + *these*. + + Arguably, this is a rather obscure feature. + + .. versionadded:: 20.1.0 + .. versionchanged:: 21.3.0 Converters are also run ``on_setattr``. + .. versionadded:: 22.2.0 + *unsafe_hash* as an alias for *hash* (for :pep:`681` compliance). + .. versionchanged:: 24.1.0 + Instances are not compared as tuples of attributes anymore, but using a + big ``and`` condition. This is faster and has more correct behavior for + uncomparable values like `math.nan`. + .. versionadded:: 24.1.0 + If a class has an *inherited* classmethod called + ``__attrs_init_subclass__``, it is executed after the class is created. + .. deprecated:: 24.1.0 *hash* is deprecated in favor of *unsafe_hash*. + .. versionadded:: 24.3.0 + Unless already present, a ``__replace__`` method is automatically + created for `copy.replace` (Python 3.13+ only). + + .. note:: + + The main differences to the classic `attr.s` are: + + - Automatically detect whether or not *auto_attribs* should be `True` + (c.f. *auto_attribs* parameter). + - Converters and validators run when attributes are set by default -- + if *frozen* is `False`. + - *slots=True* + + Usually, this has only upsides and few visible effects in everyday + programming. But it *can* lead to some surprising behaviors, so + please make sure to read :term:`slotted classes`. + + - *auto_exc=True* + - *auto_detect=True* + - *order=False* + - Some options that were only relevant on Python 2 or were kept around + for backwards-compatibility have been removed. + + """ + + def do_it(cls, auto_attribs): + return attrs( + maybe_cls=cls, + these=these, + repr=repr, + hash=hash, + unsafe_hash=unsafe_hash, + init=init, + slots=slots, + frozen=frozen, + weakref_slot=weakref_slot, + str=str, + auto_attribs=auto_attribs, + kw_only=kw_only, + cache_hash=cache_hash, + auto_exc=auto_exc, + eq=eq, + order=order, + auto_detect=auto_detect, + collect_by_mro=True, + getstate_setstate=getstate_setstate, + on_setattr=on_setattr, + field_transformer=field_transformer, + match_args=match_args, + ) + + def wrap(cls): + """ + Making this a wrapper ensures this code runs during class creation. + + We also ensure that frozen-ness of classes is inherited. + """ + nonlocal frozen, on_setattr + + had_on_setattr = on_setattr not in (None, setters.NO_OP) + + # By default, mutable classes convert & validate on setattr. + if frozen is False and on_setattr is None: + on_setattr = _DEFAULT_ON_SETATTR + + # However, if we subclass a frozen class, we inherit the immutability + # and disable on_setattr. + for base_cls in cls.__bases__: + if base_cls.__setattr__ is _frozen_setattrs: + if had_on_setattr: + msg = "Frozen classes can't use on_setattr (frozen-ness was inherited)." + raise ValueError(msg) + + on_setattr = setters.NO_OP + break + + if auto_attribs is not None: + return do_it(cls, auto_attribs) + + try: + return do_it(cls, True) + except UnannotatedAttributeError: + return do_it(cls, False) + + # maybe_cls's type depends on the usage of the decorator. It's a class + # if it's used as `@attrs` but `None` if used as `@attrs()`. + if maybe_cls is None: + return wrap + + return wrap(maybe_cls) + + +mutable = define +frozen = partial(define, frozen=True, on_setattr=None) + + +def field( + *, + default=NOTHING, + validator=None, + repr=True, + hash=None, + init=True, + metadata=None, + type=None, + converter=None, + factory=None, + kw_only=False, + eq=None, + order=None, + on_setattr=None, + alias=None, +): + """ + Create a new :term:`field` / :term:`attribute` on a class. + + .. warning:: + + Does **nothing** unless the class is also decorated with + `attrs.define` (or similar)! + + Args: + default: + A value that is used if an *attrs*-generated ``__init__`` is used + and no value is passed while instantiating or the attribute is + excluded using ``init=False``. + + If the value is an instance of `attrs.Factory`, its callable will + be used to construct a new value (useful for mutable data types + like lists or dicts). + + If a default is not set (or set manually to `attrs.NOTHING`), a + value *must* be supplied when instantiating; otherwise a + `TypeError` will be raised. + + .. seealso:: `defaults` + + factory (~typing.Callable): + Syntactic sugar for ``default=attr.Factory(factory)``. + + validator (~typing.Callable | list[~typing.Callable]): + Callable that is called by *attrs*-generated ``__init__`` methods + after the instance has been initialized. They receive the + initialized instance, the :func:`~attrs.Attribute`, and the passed + value. + + The return value is *not* inspected so the validator has to throw + an exception itself. + + If a `list` is passed, its items are treated as validators and must + all pass. + + Validators can be globally disabled and re-enabled using + `attrs.validators.get_disabled` / `attrs.validators.set_disabled`. + + The validator can also be set using decorator notation as shown + below. + + .. seealso:: :ref:`validators` + + repr (bool | ~typing.Callable): + Include this attribute in the generated ``__repr__`` method. If + True, include the attribute; if False, omit it. By default, the + built-in ``repr()`` function is used. To override how the attribute + value is formatted, pass a ``callable`` that takes a single value + and returns a string. Note that the resulting string is used as-is, + which means it will be used directly *instead* of calling + ``repr()`` (the default). + + eq (bool | ~typing.Callable): + If True (default), include this attribute in the generated + ``__eq__`` and ``__ne__`` methods that check two instances for + equality. To override how the attribute value is compared, pass a + callable that takes a single value and returns the value to be + compared. + + .. seealso:: `comparison` + + order (bool | ~typing.Callable): + If True (default), include this attributes in the generated + ``__lt__``, ``__le__``, ``__gt__`` and ``__ge__`` methods. To + override how the attribute value is ordered, pass a callable that + takes a single value and returns the value to be ordered. + + .. seealso:: `comparison` + + hash (bool | None): + Include this attribute in the generated ``__hash__`` method. If + None (default), mirror *eq*'s value. This is the correct behavior + according the Python spec. Setting this value to anything else + than None is *discouraged*. + + .. seealso:: `hashing` + + init (bool): + Include this attribute in the generated ``__init__`` method. + + It is possible to set this to False and set a default value. In + that case this attributed is unconditionally initialized with the + specified default value or factory. + + .. seealso:: `init` + + converter (typing.Callable | Converter): + A callable that is called by *attrs*-generated ``__init__`` methods + to convert attribute's value to the desired format. + + If a vanilla callable is passed, it is given the passed-in value as + the only positional argument. It is possible to receive additional + arguments by wrapping the callable in a `Converter`. + + Either way, the returned value will be used as the new value of the + attribute. The value is converted before being passed to the + validator, if any. + + .. seealso:: :ref:`converters` + + metadata (dict | None): + An arbitrary mapping, to be used by third-party code. + + .. seealso:: `extending-metadata`. + + type (type): + The type of the attribute. Nowadays, the preferred method to + specify the type is using a variable annotation (see :pep:`526`). + This argument is provided for backwards-compatibility and for usage + with `make_class`. Regardless of the approach used, the type will + be stored on ``Attribute.type``. + + Please note that *attrs* doesn't do anything with this metadata by + itself. You can use it as part of your own code or for `static type + checking `. + + kw_only (bool): + Make this attribute keyword-only in the generated ``__init__`` (if + ``init`` is False, this parameter is ignored). + + on_setattr (~typing.Callable | list[~typing.Callable] | None | ~typing.Literal[attrs.setters.NO_OP]): + Allows to overwrite the *on_setattr* setting from `attr.s`. If left + None, the *on_setattr* value from `attr.s` is used. Set to + `attrs.setters.NO_OP` to run **no** `setattr` hooks for this + attribute -- regardless of the setting in `define()`. + + alias (str | None): + Override this attribute's parameter name in the generated + ``__init__`` method. If left None, default to ``name`` stripped + of leading underscores. See `private-attributes`. + + .. versionadded:: 20.1.0 + .. versionchanged:: 21.1.0 + *eq*, *order*, and *cmp* also accept a custom callable + .. versionadded:: 22.2.0 *alias* + .. versionadded:: 23.1.0 + The *type* parameter has been re-added; mostly for `attrs.make_class`. + Please note that type checkers ignore this metadata. + + .. seealso:: + + `attr.ib` + """ + return attrib( + default=default, + validator=validator, + repr=repr, + hash=hash, + init=init, + metadata=metadata, + type=type, + converter=converter, + factory=factory, + kw_only=kw_only, + eq=eq, + order=order, + on_setattr=on_setattr, + alias=alias, + ) + + +def asdict(inst, *, recurse=True, filter=None, value_serializer=None): + """ + Same as `attr.asdict`, except that collections types are always retained + and dict is always used as *dict_factory*. + + .. versionadded:: 21.3.0 + """ + return _asdict( + inst=inst, + recurse=recurse, + filter=filter, + value_serializer=value_serializer, + retain_collection_types=True, + ) + + +def astuple(inst, *, recurse=True, filter=None): + """ + Same as `attr.astuple`, except that collections types are always retained + and `tuple` is always used as the *tuple_factory*. + + .. versionadded:: 21.3.0 + """ + return _astuple( + inst=inst, recurse=recurse, filter=filter, retain_collection_types=True + ) diff --git a/venv/lib/python3.12/site-packages/attr/_typing_compat.pyi b/venv/lib/python3.12/site-packages/attr/_typing_compat.pyi new file mode 100644 index 00000000..ca7b71e9 --- /dev/null +++ b/venv/lib/python3.12/site-packages/attr/_typing_compat.pyi @@ -0,0 +1,15 @@ +from typing import Any, ClassVar, Protocol + +# MYPY is a special constant in mypy which works the same way as `TYPE_CHECKING`. +MYPY = False + +if MYPY: + # A protocol to be able to statically accept an attrs class. + class AttrsInstance_(Protocol): + __attrs_attrs__: ClassVar[Any] + +else: + # For type checkers without plug-in support use an empty protocol that + # will (hopefully) be combined into a union. + class AttrsInstance_(Protocol): + pass diff --git a/venv/lib/python3.12/site-packages/attr/_version_info.py b/venv/lib/python3.12/site-packages/attr/_version_info.py new file mode 100644 index 00000000..51a1312f --- /dev/null +++ b/venv/lib/python3.12/site-packages/attr/_version_info.py @@ -0,0 +1,86 @@ +# SPDX-License-Identifier: MIT + + +from functools import total_ordering + +from ._funcs import astuple +from ._make import attrib, attrs + + +@total_ordering +@attrs(eq=False, order=False, slots=True, frozen=True) +class VersionInfo: + """ + A version object that can be compared to tuple of length 1--4: + + >>> attr.VersionInfo(19, 1, 0, "final") <= (19, 2) + True + >>> attr.VersionInfo(19, 1, 0, "final") < (19, 1, 1) + True + >>> vi = attr.VersionInfo(19, 2, 0, "final") + >>> vi < (19, 1, 1) + False + >>> vi < (19,) + False + >>> vi == (19, 2,) + True + >>> vi == (19, 2, 1) + False + + .. versionadded:: 19.2 + """ + + year = attrib(type=int) + minor = attrib(type=int) + micro = attrib(type=int) + releaselevel = attrib(type=str) + + @classmethod + def _from_version_string(cls, s): + """ + Parse *s* and return a _VersionInfo. + """ + v = s.split(".") + if len(v) == 3: + v.append("final") + + return cls( + year=int(v[0]), minor=int(v[1]), micro=int(v[2]), releaselevel=v[3] + ) + + def _ensure_tuple(self, other): + """ + Ensure *other* is a tuple of a valid length. + + Returns a possibly transformed *other* and ourselves as a tuple of + the same length as *other*. + """ + + if self.__class__ is other.__class__: + other = astuple(other) + + if not isinstance(other, tuple): + raise NotImplementedError + + if not (1 <= len(other) <= 4): + raise NotImplementedError + + return astuple(self)[: len(other)], other + + def __eq__(self, other): + try: + us, them = self._ensure_tuple(other) + except NotImplementedError: + return NotImplemented + + return us == them + + def __lt__(self, other): + try: + us, them = self._ensure_tuple(other) + except NotImplementedError: + return NotImplemented + + # Since alphabetically "dev0" < "final" < "post1" < "post2", we don't + # have to do anything special with releaselevel for now. + return us < them diff --git a/venv/lib/python3.12/site-packages/attr/_version_info.pyi b/venv/lib/python3.12/site-packages/attr/_version_info.pyi new file mode 100644 index 00000000..45ced086 --- /dev/null +++ b/venv/lib/python3.12/site-packages/attr/_version_info.pyi @@ -0,0 +1,9 @@ +class VersionInfo: + @property + def year(self) -> int: ... + @property + def minor(self) -> int: ... + @property + def micro(self) -> int: ... + @property + def releaselevel(self) -> str: ... diff --git a/venv/lib/python3.12/site-packages/attr/converters.py b/venv/lib/python3.12/site-packages/attr/converters.py new file mode 100644 index 00000000..0a79deef --- /dev/null +++ b/venv/lib/python3.12/site-packages/attr/converters.py @@ -0,0 +1,162 @@ +# SPDX-License-Identifier: MIT + +""" +Commonly useful converters. +""" + +import typing + +from ._compat import _AnnotationExtractor +from ._make import NOTHING, Converter, Factory, pipe + + +__all__ = [ + "default_if_none", + "optional", + "pipe", + "to_bool", +] + + +def optional(converter): + """ + A converter that allows an attribute to be optional. An optional attribute + is one which can be set to `None`. + + Type annotations will be inferred from the wrapped converter's, if it has + any. + + Args: + converter (typing.Callable): + the converter that is used for non-`None` values. + + .. versionadded:: 17.1.0 + """ + + if isinstance(converter, Converter): + + def optional_converter(val, inst, field): + if val is None: + return None + return converter(val, inst, field) + + else: + + def optional_converter(val): + if val is None: + return None + return converter(val) + + xtr = _AnnotationExtractor(converter) + + t = xtr.get_first_param_type() + if t: + optional_converter.__annotations__["val"] = typing.Optional[t] + + rt = xtr.get_return_type() + if rt: + optional_converter.__annotations__["return"] = typing.Optional[rt] + + if isinstance(converter, Converter): + return Converter(optional_converter, takes_self=True, takes_field=True) + + return optional_converter + + +def default_if_none(default=NOTHING, factory=None): + """ + A converter that allows to replace `None` values by *default* or the result + of *factory*. + + Args: + default: + Value to be used if `None` is passed. Passing an instance of + `attrs.Factory` is supported, however the ``takes_self`` option is + *not*. + + factory (typing.Callable): + A callable that takes no parameters whose result is used if `None` + is passed. + + Raises: + TypeError: If **neither** *default* or *factory* is passed. + + TypeError: If **both** *default* and *factory* are passed. + + ValueError: + If an instance of `attrs.Factory` is passed with + ``takes_self=True``. + + .. versionadded:: 18.2.0 + """ + if default is NOTHING and factory is None: + msg = "Must pass either `default` or `factory`." + raise TypeError(msg) + + if default is not NOTHING and factory is not None: + msg = "Must pass either `default` or `factory` but not both." + raise TypeError(msg) + + if factory is not None: + default = Factory(factory) + + if isinstance(default, Factory): + if default.takes_self: + msg = "`takes_self` is not supported by default_if_none." + raise ValueError(msg) + + def default_if_none_converter(val): + if val is not None: + return val + + return default.factory() + + else: + + def default_if_none_converter(val): + if val is not None: + return val + + return default + + return default_if_none_converter + + +def to_bool(val): + """ + Convert "boolean" strings (for example, from environment variables) to real + booleans. + + Values mapping to `True`: + + - ``True`` + - ``"true"`` / ``"t"`` + - ``"yes"`` / ``"y"`` + - ``"on"`` + - ``"1"`` + - ``1`` + + Values mapping to `False`: + + - ``False`` + - ``"false"`` / ``"f"`` + - ``"no"`` / ``"n"`` + - ``"off"`` + - ``"0"`` + - ``0`` + + Raises: + ValueError: For any other value. + + .. versionadded:: 21.3.0 + """ + if isinstance(val, str): + val = val.lower() + + if val in (True, "true", "t", "yes", "y", "on", "1", 1): + return True + if val in (False, "false", "f", "no", "n", "off", "0", 0): + return False + + msg = f"Cannot convert value to bool: {val!r}" + raise ValueError(msg) diff --git a/venv/lib/python3.12/site-packages/attr/converters.pyi b/venv/lib/python3.12/site-packages/attr/converters.pyi new file mode 100644 index 00000000..12bd0c4f --- /dev/null +++ b/venv/lib/python3.12/site-packages/attr/converters.pyi @@ -0,0 +1,19 @@ +from typing import Callable, Any, overload + +from attrs import _ConverterType, _CallableConverterType + +@overload +def pipe(*validators: _CallableConverterType) -> _CallableConverterType: ... +@overload +def pipe(*validators: _ConverterType) -> _ConverterType: ... +@overload +def optional(converter: _CallableConverterType) -> _CallableConverterType: ... +@overload +def optional(converter: _ConverterType) -> _ConverterType: ... +@overload +def default_if_none(default: Any) -> _CallableConverterType: ... +@overload +def default_if_none( + *, factory: Callable[[], Any] +) -> _CallableConverterType: ... +def to_bool(val: str | int | bool) -> bool: ... diff --git a/venv/lib/python3.12/site-packages/attr/exceptions.py b/venv/lib/python3.12/site-packages/attr/exceptions.py new file mode 100644 index 00000000..3b7abb81 --- /dev/null +++ b/venv/lib/python3.12/site-packages/attr/exceptions.py @@ -0,0 +1,95 @@ +# SPDX-License-Identifier: MIT + +from __future__ import annotations + +from typing import ClassVar + + +class FrozenError(AttributeError): + """ + A frozen/immutable instance or attribute have been attempted to be + modified. + + It mirrors the behavior of ``namedtuples`` by using the same error message + and subclassing `AttributeError`. + + .. versionadded:: 20.1.0 + """ + + msg = "can't set attribute" + args: ClassVar[tuple[str]] = [msg] + + +class FrozenInstanceError(FrozenError): + """ + A frozen instance has been attempted to be modified. + + .. versionadded:: 16.1.0 + """ + + +class FrozenAttributeError(FrozenError): + """ + A frozen attribute has been attempted to be modified. + + .. versionadded:: 20.1.0 + """ + + +class AttrsAttributeNotFoundError(ValueError): + """ + An *attrs* function couldn't find an attribute that the user asked for. + + .. versionadded:: 16.2.0 + """ + + +class NotAnAttrsClassError(ValueError): + """ + A non-*attrs* class has been passed into an *attrs* function. + + .. versionadded:: 16.2.0 + """ + + +class DefaultAlreadySetError(RuntimeError): + """ + A default has been set when defining the field and is attempted to be reset + using the decorator. + + .. versionadded:: 17.1.0 + """ + + +class UnannotatedAttributeError(RuntimeError): + """ + A class with ``auto_attribs=True`` has a field without a type annotation. + + .. versionadded:: 17.3.0 + """ + + +class PythonTooOldError(RuntimeError): + """ + It was attempted to use an *attrs* feature that requires a newer Python + version. + + .. versionadded:: 18.2.0 + """ + + +class NotCallableError(TypeError): + """ + A field requiring a callable has been set with a value that is not + callable. + + .. versionadded:: 19.2.0 + """ + + def __init__(self, msg, value): + super(TypeError, self).__init__(msg, value) + self.msg = msg + self.value = value + + def __str__(self): + return str(self.msg) diff --git a/venv/lib/python3.12/site-packages/attr/exceptions.pyi b/venv/lib/python3.12/site-packages/attr/exceptions.pyi new file mode 100644 index 00000000..f2680118 --- /dev/null +++ b/venv/lib/python3.12/site-packages/attr/exceptions.pyi @@ -0,0 +1,17 @@ +from typing import Any + +class FrozenError(AttributeError): + msg: str = ... + +class FrozenInstanceError(FrozenError): ... +class FrozenAttributeError(FrozenError): ... +class AttrsAttributeNotFoundError(ValueError): ... +class NotAnAttrsClassError(ValueError): ... +class DefaultAlreadySetError(RuntimeError): ... +class UnannotatedAttributeError(RuntimeError): ... +class PythonTooOldError(RuntimeError): ... + +class NotCallableError(TypeError): + msg: str = ... + value: Any = ... + def __init__(self, msg: str, value: Any) -> None: ... diff --git a/venv/lib/python3.12/site-packages/attr/filters.py b/venv/lib/python3.12/site-packages/attr/filters.py new file mode 100644 index 00000000..689b1705 --- /dev/null +++ b/venv/lib/python3.12/site-packages/attr/filters.py @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: MIT + +""" +Commonly useful filters for `attrs.asdict` and `attrs.astuple`. +""" + +from ._make import Attribute + + +def _split_what(what): + """ + Returns a tuple of `frozenset`s of classes and attributes. + """ + return ( + frozenset(cls for cls in what if isinstance(cls, type)), + frozenset(cls for cls in what if isinstance(cls, str)), + frozenset(cls for cls in what if isinstance(cls, Attribute)), + ) + + +def include(*what): + """ + Create a filter that only allows *what*. + + Args: + what (list[type, str, attrs.Attribute]): + What to include. Can be a type, a name, or an attribute. + + Returns: + Callable: + A callable that can be passed to `attrs.asdict`'s and + `attrs.astuple`'s *filter* argument. + + .. versionchanged:: 23.1.0 Accept strings with field names. + """ + cls, names, attrs = _split_what(what) + + def include_(attribute, value): + return ( + value.__class__ in cls + or attribute.name in names + or attribute in attrs + ) + + return include_ + + +def exclude(*what): + """ + Create a filter that does **not** allow *what*. + + Args: + what (list[type, str, attrs.Attribute]): + What to exclude. Can be a type, a name, or an attribute. + + Returns: + Callable: + A callable that can be passed to `attrs.asdict`'s and + `attrs.astuple`'s *filter* argument. + + .. versionchanged:: 23.3.0 Accept field name string as input argument + """ + cls, names, attrs = _split_what(what) + + def exclude_(attribute, value): + return not ( + value.__class__ in cls + or attribute.name in names + or attribute in attrs + ) + + return exclude_ diff --git a/venv/lib/python3.12/site-packages/attr/filters.pyi b/venv/lib/python3.12/site-packages/attr/filters.pyi new file mode 100644 index 00000000..974abdcd --- /dev/null +++ b/venv/lib/python3.12/site-packages/attr/filters.pyi @@ -0,0 +1,6 @@ +from typing import Any + +from . import Attribute, _FilterType + +def include(*what: type | str | Attribute[Any]) -> _FilterType[Any]: ... +def exclude(*what: type | str | Attribute[Any]) -> _FilterType[Any]: ... diff --git a/venv/lib/python3.12/site-packages/attr/py.typed b/venv/lib/python3.12/site-packages/attr/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/venv/lib/python3.12/site-packages/attr/setters.py b/venv/lib/python3.12/site-packages/attr/setters.py new file mode 100644 index 00000000..78b08398 --- /dev/null +++ b/venv/lib/python3.12/site-packages/attr/setters.py @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: MIT + +""" +Commonly used hooks for on_setattr. +""" + +from . import _config +from .exceptions import FrozenAttributeError + + +def pipe(*setters): + """ + Run all *setters* and return the return value of the last one. + + .. versionadded:: 20.1.0 + """ + + def wrapped_pipe(instance, attrib, new_value): + rv = new_value + + for setter in setters: + rv = setter(instance, attrib, rv) + + return rv + + return wrapped_pipe + + +def frozen(_, __, ___): + """ + Prevent an attribute to be modified. + + .. versionadded:: 20.1.0 + """ + raise FrozenAttributeError + + +def validate(instance, attrib, new_value): + """ + Run *attrib*'s validator on *new_value* if it has one. + + .. versionadded:: 20.1.0 + """ + if _config._run_validators is False: + return new_value + + v = attrib.validator + if not v: + return new_value + + v(instance, attrib, new_value) + + return new_value + + +def convert(instance, attrib, new_value): + """ + Run *attrib*'s converter -- if it has one -- on *new_value* and return the + result. + + .. versionadded:: 20.1.0 + """ + c = attrib.converter + if c: + # This can be removed once we drop 3.8 and use attrs.Converter instead. + from ._make import Converter + + if not isinstance(c, Converter): + return c(new_value) + + return c(new_value, instance, attrib) + + return new_value + + +# Sentinel for disabling class-wide *on_setattr* hooks for certain attributes. +# Sphinx's autodata stopped working, so the docstring is inlined in the API +# docs. +NO_OP = object() diff --git a/venv/lib/python3.12/site-packages/attr/setters.pyi b/venv/lib/python3.12/site-packages/attr/setters.pyi new file mode 100644 index 00000000..73abf36e --- /dev/null +++ b/venv/lib/python3.12/site-packages/attr/setters.pyi @@ -0,0 +1,20 @@ +from typing import Any, NewType, NoReturn, TypeVar + +from . import Attribute +from attrs import _OnSetAttrType + +_T = TypeVar("_T") + +def frozen( + instance: Any, attribute: Attribute[Any], new_value: Any +) -> NoReturn: ... +def pipe(*setters: _OnSetAttrType) -> _OnSetAttrType: ... +def validate(instance: Any, attribute: Attribute[_T], new_value: _T) -> _T: ... + +# convert is allowed to return Any, because they can be chained using pipe. +def convert( + instance: Any, attribute: Attribute[Any], new_value: Any +) -> Any: ... + +_NoOpType = NewType("_NoOpType", object) +NO_OP: _NoOpType diff --git a/venv/lib/python3.12/site-packages/attr/validators.py b/venv/lib/python3.12/site-packages/attr/validators.py new file mode 100644 index 00000000..e7b75525 --- /dev/null +++ b/venv/lib/python3.12/site-packages/attr/validators.py @@ -0,0 +1,710 @@ +# SPDX-License-Identifier: MIT + +""" +Commonly useful validators. +""" + +import operator +import re + +from contextlib import contextmanager +from re import Pattern + +from ._config import get_run_validators, set_run_validators +from ._make import _AndValidator, and_, attrib, attrs +from .converters import default_if_none +from .exceptions import NotCallableError + + +__all__ = [ + "and_", + "deep_iterable", + "deep_mapping", + "disabled", + "ge", + "get_disabled", + "gt", + "in_", + "instance_of", + "is_callable", + "le", + "lt", + "matches_re", + "max_len", + "min_len", + "not_", + "optional", + "or_", + "set_disabled", +] + + +def set_disabled(disabled): + """ + Globally disable or enable running validators. + + By default, they are run. + + Args: + disabled (bool): If `True`, disable running all validators. + + .. warning:: + + This function is not thread-safe! + + .. versionadded:: 21.3.0 + """ + set_run_validators(not disabled) + + +def get_disabled(): + """ + Return a bool indicating whether validators are currently disabled or not. + + Returns: + bool:`True` if validators are currently disabled. + + .. versionadded:: 21.3.0 + """ + return not get_run_validators() + + +@contextmanager +def disabled(): + """ + Context manager that disables running validators within its context. + + .. warning:: + + This context manager is not thread-safe! + + .. versionadded:: 21.3.0 + """ + set_run_validators(False) + try: + yield + finally: + set_run_validators(True) + + +@attrs(repr=False, slots=True, unsafe_hash=True) +class _InstanceOfValidator: + type = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not isinstance(value, self.type): + msg = f"'{attr.name}' must be {self.type!r} (got {value!r} that is a {value.__class__!r})." + raise TypeError( + msg, + attr, + self.type, + value, + ) + + def __repr__(self): + return f"" + + +def instance_of(type): + """ + A validator that raises a `TypeError` if the initializer is called with a + wrong type for this particular attribute (checks are performed using + `isinstance` therefore it's also valid to pass a tuple of types). + + Args: + type (type | tuple[type]): The type to check for. + + Raises: + TypeError: + With a human readable error message, the attribute (of type + `attrs.Attribute`), the expected type, and the value it got. + """ + return _InstanceOfValidator(type) + + +@attrs(repr=False, frozen=True, slots=True) +class _MatchesReValidator: + pattern = attrib() + match_func = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not self.match_func(value): + msg = f"'{attr.name}' must match regex {self.pattern.pattern!r} ({value!r} doesn't)" + raise ValueError( + msg, + attr, + self.pattern, + value, + ) + + def __repr__(self): + return f"" + + +def matches_re(regex, flags=0, func=None): + r""" + A validator that raises `ValueError` if the initializer is called with a + string that doesn't match *regex*. + + Args: + regex (str, re.Pattern): + A regex string or precompiled pattern to match against + + flags (int): + Flags that will be passed to the underlying re function (default 0) + + func (typing.Callable): + Which underlying `re` function to call. Valid options are + `re.fullmatch`, `re.search`, and `re.match`; the default `None` + means `re.fullmatch`. For performance reasons, the pattern is + always precompiled using `re.compile`. + + .. versionadded:: 19.2.0 + .. versionchanged:: 21.3.0 *regex* can be a pre-compiled pattern. + """ + valid_funcs = (re.fullmatch, None, re.search, re.match) + if func not in valid_funcs: + msg = "'func' must be one of {}.".format( + ", ".join( + sorted((e and e.__name__) or "None" for e in set(valid_funcs)) + ) + ) + raise ValueError(msg) + + if isinstance(regex, Pattern): + if flags: + msg = "'flags' can only be used with a string pattern; pass flags to re.compile() instead" + raise TypeError(msg) + pattern = regex + else: + pattern = re.compile(regex, flags) + + if func is re.match: + match_func = pattern.match + elif func is re.search: + match_func = pattern.search + else: + match_func = pattern.fullmatch + + return _MatchesReValidator(pattern, match_func) + + +@attrs(repr=False, slots=True, unsafe_hash=True) +class _OptionalValidator: + validator = attrib() + + def __call__(self, inst, attr, value): + if value is None: + return + + self.validator(inst, attr, value) + + def __repr__(self): + return f"" + + +def optional(validator): + """ + A validator that makes an attribute optional. An optional attribute is one + which can be set to `None` in addition to satisfying the requirements of + the sub-validator. + + Args: + validator + (typing.Callable | tuple[typing.Callable] | list[typing.Callable]): + A validator (or validators) that is used for non-`None` values. + + .. versionadded:: 15.1.0 + .. versionchanged:: 17.1.0 *validator* can be a list of validators. + .. versionchanged:: 23.1.0 *validator* can also be a tuple of validators. + """ + if isinstance(validator, (list, tuple)): + return _OptionalValidator(_AndValidator(validator)) + + return _OptionalValidator(validator) + + +@attrs(repr=False, slots=True, unsafe_hash=True) +class _InValidator: + options = attrib() + _original_options = attrib(hash=False) + + def __call__(self, inst, attr, value): + try: + in_options = value in self.options + except TypeError: # e.g. `1 in "abc"` + in_options = False + + if not in_options: + msg = f"'{attr.name}' must be in {self._original_options!r} (got {value!r})" + raise ValueError( + msg, + attr, + self._original_options, + value, + ) + + def __repr__(self): + return f"" + + +def in_(options): + """ + A validator that raises a `ValueError` if the initializer is called with a + value that does not belong in the *options* provided. + + The check is performed using ``value in options``, so *options* has to + support that operation. + + To keep the validator hashable, dicts, lists, and sets are transparently + transformed into a `tuple`. + + Args: + options: Allowed options. + + Raises: + ValueError: + With a human readable error message, the attribute (of type + `attrs.Attribute`), the expected options, and the value it got. + + .. versionadded:: 17.1.0 + .. versionchanged:: 22.1.0 + The ValueError was incomplete until now and only contained the human + readable error message. Now it contains all the information that has + been promised since 17.1.0. + .. versionchanged:: 24.1.0 + *options* that are a list, dict, or a set are now transformed into a + tuple to keep the validator hashable. + """ + repr_options = options + if isinstance(options, (list, dict, set)): + options = tuple(options) + + return _InValidator(options, repr_options) + + +@attrs(repr=False, slots=False, unsafe_hash=True) +class _IsCallableValidator: + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not callable(value): + message = ( + "'{name}' must be callable " + "(got {value!r} that is a {actual!r})." + ) + raise NotCallableError( + msg=message.format( + name=attr.name, value=value, actual=value.__class__ + ), + value=value, + ) + + def __repr__(self): + return "" + + +def is_callable(): + """ + A validator that raises a `attrs.exceptions.NotCallableError` if the + initializer is called with a value for this particular attribute that is + not callable. + + .. versionadded:: 19.1.0 + + Raises: + attrs.exceptions.NotCallableError: + With a human readable error message containing the attribute + (`attrs.Attribute`) name, and the value it got. + """ + return _IsCallableValidator() + + +@attrs(repr=False, slots=True, unsafe_hash=True) +class _DeepIterable: + member_validator = attrib(validator=is_callable()) + iterable_validator = attrib( + default=None, validator=optional(is_callable()) + ) + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if self.iterable_validator is not None: + self.iterable_validator(inst, attr, value) + + for member in value: + self.member_validator(inst, attr, member) + + def __repr__(self): + iterable_identifier = ( + "" + if self.iterable_validator is None + else f" {self.iterable_validator!r}" + ) + return ( + f"" + ) + + +def deep_iterable(member_validator, iterable_validator=None): + """ + A validator that performs deep validation of an iterable. + + Args: + member_validator: Validator to apply to iterable members. + + iterable_validator: + Validator to apply to iterable itself (optional). + + Raises + TypeError: if any sub-validators fail + + .. versionadded:: 19.1.0 + """ + if isinstance(member_validator, (list, tuple)): + member_validator = and_(*member_validator) + return _DeepIterable(member_validator, iterable_validator) + + +@attrs(repr=False, slots=True, unsafe_hash=True) +class _DeepMapping: + key_validator = attrib(validator=is_callable()) + value_validator = attrib(validator=is_callable()) + mapping_validator = attrib(default=None, validator=optional(is_callable())) + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if self.mapping_validator is not None: + self.mapping_validator(inst, attr, value) + + for key in value: + self.key_validator(inst, attr, key) + self.value_validator(inst, attr, value[key]) + + def __repr__(self): + return f"" + + +def deep_mapping(key_validator, value_validator, mapping_validator=None): + """ + A validator that performs deep validation of a dictionary. + + Args: + key_validator: Validator to apply to dictionary keys. + + value_validator: Validator to apply to dictionary values. + + mapping_validator: + Validator to apply to top-level mapping attribute (optional). + + .. versionadded:: 19.1.0 + + Raises: + TypeError: if any sub-validators fail + """ + return _DeepMapping(key_validator, value_validator, mapping_validator) + + +@attrs(repr=False, frozen=True, slots=True) +class _NumberValidator: + bound = attrib() + compare_op = attrib() + compare_func = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not self.compare_func(value, self.bound): + msg = f"'{attr.name}' must be {self.compare_op} {self.bound}: {value}" + raise ValueError(msg) + + def __repr__(self): + return f"" + + +def lt(val): + """ + A validator that raises `ValueError` if the initializer is called with a + number larger or equal to *val*. + + The validator uses `operator.lt` to compare the values. + + Args: + val: Exclusive upper bound for values. + + .. versionadded:: 21.3.0 + """ + return _NumberValidator(val, "<", operator.lt) + + +def le(val): + """ + A validator that raises `ValueError` if the initializer is called with a + number greater than *val*. + + The validator uses `operator.le` to compare the values. + + Args: + val: Inclusive upper bound for values. + + .. versionadded:: 21.3.0 + """ + return _NumberValidator(val, "<=", operator.le) + + +def ge(val): + """ + A validator that raises `ValueError` if the initializer is called with a + number smaller than *val*. + + The validator uses `operator.ge` to compare the values. + + Args: + val: Inclusive lower bound for values + + .. versionadded:: 21.3.0 + """ + return _NumberValidator(val, ">=", operator.ge) + + +def gt(val): + """ + A validator that raises `ValueError` if the initializer is called with a + number smaller or equal to *val*. + + The validator uses `operator.ge` to compare the values. + + Args: + val: Exclusive lower bound for values + + .. versionadded:: 21.3.0 + """ + return _NumberValidator(val, ">", operator.gt) + + +@attrs(repr=False, frozen=True, slots=True) +class _MaxLengthValidator: + max_length = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if len(value) > self.max_length: + msg = f"Length of '{attr.name}' must be <= {self.max_length}: {len(value)}" + raise ValueError(msg) + + def __repr__(self): + return f"" + + +def max_len(length): + """ + A validator that raises `ValueError` if the initializer is called + with a string or iterable that is longer than *length*. + + Args: + length (int): Maximum length of the string or iterable + + .. versionadded:: 21.3.0 + """ + return _MaxLengthValidator(length) + + +@attrs(repr=False, frozen=True, slots=True) +class _MinLengthValidator: + min_length = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if len(value) < self.min_length: + msg = f"Length of '{attr.name}' must be >= {self.min_length}: {len(value)}" + raise ValueError(msg) + + def __repr__(self): + return f"" + + +def min_len(length): + """ + A validator that raises `ValueError` if the initializer is called + with a string or iterable that is shorter than *length*. + + Args: + length (int): Minimum length of the string or iterable + + .. versionadded:: 22.1.0 + """ + return _MinLengthValidator(length) + + +@attrs(repr=False, slots=True, unsafe_hash=True) +class _SubclassOfValidator: + type = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not issubclass(value, self.type): + msg = f"'{attr.name}' must be a subclass of {self.type!r} (got {value!r})." + raise TypeError( + msg, + attr, + self.type, + value, + ) + + def __repr__(self): + return f"" + + +def _subclass_of(type): + """ + A validator that raises a `TypeError` if the initializer is called with a + wrong type for this particular attribute (checks are performed using + `issubclass` therefore it's also valid to pass a tuple of types). + + Args: + type (type | tuple[type, ...]): The type(s) to check for. + + Raises: + TypeError: + With a human readable error message, the attribute (of type + `attrs.Attribute`), the expected type, and the value it got. + """ + return _SubclassOfValidator(type) + + +@attrs(repr=False, slots=True, unsafe_hash=True) +class _NotValidator: + validator = attrib() + msg = attrib( + converter=default_if_none( + "not_ validator child '{validator!r}' " + "did not raise a captured error" + ) + ) + exc_types = attrib( + validator=deep_iterable( + member_validator=_subclass_of(Exception), + iterable_validator=instance_of(tuple), + ), + ) + + def __call__(self, inst, attr, value): + try: + self.validator(inst, attr, value) + except self.exc_types: + pass # suppress error to invert validity + else: + raise ValueError( + self.msg.format( + validator=self.validator, + exc_types=self.exc_types, + ), + attr, + self.validator, + value, + self.exc_types, + ) + + def __repr__(self): + return f"" + + +def not_(validator, *, msg=None, exc_types=(ValueError, TypeError)): + """ + A validator that wraps and logically 'inverts' the validator passed to it. + It will raise a `ValueError` if the provided validator *doesn't* raise a + `ValueError` or `TypeError` (by default), and will suppress the exception + if the provided validator *does*. + + Intended to be used with existing validators to compose logic without + needing to create inverted variants, for example, ``not_(in_(...))``. + + Args: + validator: A validator to be logically inverted. + + msg (str): + Message to raise if validator fails. Formatted with keys + ``exc_types`` and ``validator``. + + exc_types (tuple[type, ...]): + Exception type(s) to capture. Other types raised by child + validators will not be intercepted and pass through. + + Raises: + ValueError: + With a human readable error message, the attribute (of type + `attrs.Attribute`), the validator that failed to raise an + exception, the value it got, and the expected exception types. + + .. versionadded:: 22.2.0 + """ + try: + exc_types = tuple(exc_types) + except TypeError: + exc_types = (exc_types,) + return _NotValidator(validator, msg, exc_types) + + +@attrs(repr=False, slots=True, unsafe_hash=True) +class _OrValidator: + validators = attrib() + + def __call__(self, inst, attr, value): + for v in self.validators: + try: + v(inst, attr, value) + except Exception: # noqa: BLE001, PERF203, S112 + continue + else: + return + + msg = f"None of {self.validators!r} satisfied for value {value!r}" + raise ValueError(msg) + + def __repr__(self): + return f"" + + +def or_(*validators): + """ + A validator that composes multiple validators into one. + + When called on a value, it runs all wrapped validators until one of them is + satisfied. + + Args: + validators (~collections.abc.Iterable[typing.Callable]): + Arbitrary number of validators. + + Raises: + ValueError: + If no validator is satisfied. Raised with a human-readable error + message listing all the wrapped validators and the value that + failed all of them. + + .. versionadded:: 24.1.0 + """ + vals = [] + for v in validators: + vals.extend(v.validators if isinstance(v, _OrValidator) else [v]) + + return _OrValidator(tuple(vals)) diff --git a/venv/lib/python3.12/site-packages/attr/validators.pyi b/venv/lib/python3.12/site-packages/attr/validators.pyi new file mode 100644 index 00000000..a0fdda7c --- /dev/null +++ b/venv/lib/python3.12/site-packages/attr/validators.pyi @@ -0,0 +1,86 @@ +from types import UnionType +from typing import ( + Any, + AnyStr, + Callable, + Container, + ContextManager, + Iterable, + Mapping, + Match, + Pattern, + TypeVar, + overload, +) + +from attrs import _ValidatorType +from attrs import _ValidatorArgType + +_T = TypeVar("_T") +_T1 = TypeVar("_T1") +_T2 = TypeVar("_T2") +_T3 = TypeVar("_T3") +_I = TypeVar("_I", bound=Iterable) +_K = TypeVar("_K") +_V = TypeVar("_V") +_M = TypeVar("_M", bound=Mapping) + +def set_disabled(run: bool) -> None: ... +def get_disabled() -> bool: ... +def disabled() -> ContextManager[None]: ... + +# To be more precise on instance_of use some overloads. +# If there are more than 3 items in the tuple then we fall back to Any +@overload +def instance_of(type: type[_T]) -> _ValidatorType[_T]: ... +@overload +def instance_of(type: tuple[type[_T]]) -> _ValidatorType[_T]: ... +@overload +def instance_of( + type: tuple[type[_T1], type[_T2]], +) -> _ValidatorType[_T1 | _T2]: ... +@overload +def instance_of( + type: tuple[type[_T1], type[_T2], type[_T3]], +) -> _ValidatorType[_T1 | _T2 | _T3]: ... +@overload +def instance_of(type: tuple[type, ...]) -> _ValidatorType[Any]: ... +@overload +def instance_of(type: UnionType) -> _ValidatorType[Any]: ... +def optional( + validator: ( + _ValidatorType[_T] + | list[_ValidatorType[_T]] + | tuple[_ValidatorType[_T]] + ), +) -> _ValidatorType[_T | None]: ... +def in_(options: Container[_T]) -> _ValidatorType[_T]: ... +def and_(*validators: _ValidatorType[_T]) -> _ValidatorType[_T]: ... +def matches_re( + regex: Pattern[AnyStr] | AnyStr, + flags: int = ..., + func: Callable[[AnyStr, AnyStr, int], Match[AnyStr] | None] | None = ..., +) -> _ValidatorType[AnyStr]: ... +def deep_iterable( + member_validator: _ValidatorArgType[_T], + iterable_validator: _ValidatorType[_I] | None = ..., +) -> _ValidatorType[_I]: ... +def deep_mapping( + key_validator: _ValidatorType[_K], + value_validator: _ValidatorType[_V], + mapping_validator: _ValidatorType[_M] | None = ..., +) -> _ValidatorType[_M]: ... +def is_callable() -> _ValidatorType[_T]: ... +def lt(val: _T) -> _ValidatorType[_T]: ... +def le(val: _T) -> _ValidatorType[_T]: ... +def ge(val: _T) -> _ValidatorType[_T]: ... +def gt(val: _T) -> _ValidatorType[_T]: ... +def max_len(length: int) -> _ValidatorType[_T]: ... +def min_len(length: int) -> _ValidatorType[_T]: ... +def not_( + validator: _ValidatorType[_T], + *, + msg: str | None = None, + exc_types: type[Exception] | Iterable[type[Exception]] = ..., +) -> _ValidatorType[_T]: ... +def or_(*validators: _ValidatorType[_T]) -> _ValidatorType[_T]: ... diff --git a/venv/lib/python3.12/site-packages/attrs-25.3.0.dist-info/INSTALLER b/venv/lib/python3.12/site-packages/attrs-25.3.0.dist-info/INSTALLER new file mode 100644 index 00000000..a1b589e3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/attrs-25.3.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.12/site-packages/attrs-25.3.0.dist-info/METADATA b/venv/lib/python3.12/site-packages/attrs-25.3.0.dist-info/METADATA new file mode 100644 index 00000000..029afeeb --- /dev/null +++ b/venv/lib/python3.12/site-packages/attrs-25.3.0.dist-info/METADATA @@ -0,0 +1,232 @@ +Metadata-Version: 2.4 +Name: attrs +Version: 25.3.0 +Summary: Classes Without Boilerplate +Project-URL: Documentation, https://www.attrs.org/ +Project-URL: Changelog, https://www.attrs.org/en/stable/changelog.html +Project-URL: GitHub, https://github.com/python-attrs/attrs +Project-URL: Funding, https://github.com/sponsors/hynek +Project-URL: Tidelift, https://tidelift.com/subscription/pkg/pypi-attrs?utm_source=pypi-attrs&utm_medium=pypi +Author-email: Hynek Schlawack +License-Expression: MIT +License-File: LICENSE +Keywords: attribute,boilerplate,class +Classifier: Development Status :: 5 - Production/Stable +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Typing :: Typed +Requires-Python: >=3.8 +Provides-Extra: benchmark +Requires-Dist: cloudpickle; (platform_python_implementation == 'CPython') and extra == 'benchmark' +Requires-Dist: hypothesis; extra == 'benchmark' +Requires-Dist: mypy>=1.11.1; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'benchmark' +Requires-Dist: pympler; extra == 'benchmark' +Requires-Dist: pytest-codspeed; extra == 'benchmark' +Requires-Dist: pytest-mypy-plugins; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'benchmark' +Requires-Dist: pytest-xdist[psutil]; extra == 'benchmark' +Requires-Dist: pytest>=4.3.0; extra == 'benchmark' +Provides-Extra: cov +Requires-Dist: cloudpickle; (platform_python_implementation == 'CPython') and extra == 'cov' +Requires-Dist: coverage[toml]>=5.3; extra == 'cov' +Requires-Dist: hypothesis; extra == 'cov' +Requires-Dist: mypy>=1.11.1; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'cov' +Requires-Dist: pympler; extra == 'cov' +Requires-Dist: pytest-mypy-plugins; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'cov' +Requires-Dist: pytest-xdist[psutil]; extra == 'cov' +Requires-Dist: pytest>=4.3.0; extra == 'cov' +Provides-Extra: dev +Requires-Dist: cloudpickle; (platform_python_implementation == 'CPython') and extra == 'dev' +Requires-Dist: hypothesis; extra == 'dev' +Requires-Dist: mypy>=1.11.1; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'dev' +Requires-Dist: pre-commit-uv; extra == 'dev' +Requires-Dist: pympler; extra == 'dev' +Requires-Dist: pytest-mypy-plugins; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'dev' +Requires-Dist: pytest-xdist[psutil]; extra == 'dev' +Requires-Dist: pytest>=4.3.0; extra == 'dev' +Provides-Extra: docs +Requires-Dist: cogapp; extra == 'docs' +Requires-Dist: furo; extra == 'docs' +Requires-Dist: myst-parser; extra == 'docs' +Requires-Dist: sphinx; extra == 'docs' +Requires-Dist: sphinx-notfound-page; extra == 'docs' +Requires-Dist: sphinxcontrib-towncrier; extra == 'docs' +Requires-Dist: towncrier; extra == 'docs' +Provides-Extra: tests +Requires-Dist: cloudpickle; (platform_python_implementation == 'CPython') and extra == 'tests' +Requires-Dist: hypothesis; extra == 'tests' +Requires-Dist: mypy>=1.11.1; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'tests' +Requires-Dist: pympler; extra == 'tests' +Requires-Dist: pytest-mypy-plugins; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'tests' +Requires-Dist: pytest-xdist[psutil]; extra == 'tests' +Requires-Dist: pytest>=4.3.0; extra == 'tests' +Provides-Extra: tests-mypy +Requires-Dist: mypy>=1.11.1; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'tests-mypy' +Requires-Dist: pytest-mypy-plugins; (platform_python_implementation == 'CPython' and python_version >= '3.10') and extra == 'tests-mypy' +Description-Content-Type: text/markdown + +

    + + attrs + +

    + + +*attrs* is the Python package that will bring back the **joy** of **writing classes** by relieving you from the drudgery of implementing object protocols (aka [dunder methods](https://www.attrs.org/en/latest/glossary.html#term-dunder-methods)). +[Trusted by NASA](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-github-profile/customizing-your-profile/personalizing-your-profile#list-of-qualifying-repositories-for-mars-2020-helicopter-contributor-achievement) for Mars missions since 2020! + +Its main goal is to help you to write **concise** and **correct** software without slowing down your code. + + +## Sponsors + +*attrs* would not be possible without our [amazing sponsors](https://github.com/sponsors/hynek). +Especially those generously supporting us at the *The Organization* tier and higher: + + + +

    + + + + + + + + + + + +

    + + + +

    + Please consider joining them to help make attrs’s maintenance more sustainable! +

    + + + +## Example + +*attrs* gives you a class decorator and a way to declaratively define the attributes on that class: + + + +```pycon +>>> from attrs import asdict, define, make_class, Factory + +>>> @define +... class SomeClass: +... a_number: int = 42 +... list_of_numbers: list[int] = Factory(list) +... +... def hard_math(self, another_number): +... return self.a_number + sum(self.list_of_numbers) * another_number + + +>>> sc = SomeClass(1, [1, 2, 3]) +>>> sc +SomeClass(a_number=1, list_of_numbers=[1, 2, 3]) + +>>> sc.hard_math(3) +19 +>>> sc == SomeClass(1, [1, 2, 3]) +True +>>> sc != SomeClass(2, [3, 2, 1]) +True + +>>> asdict(sc) +{'a_number': 1, 'list_of_numbers': [1, 2, 3]} + +>>> SomeClass() +SomeClass(a_number=42, list_of_numbers=[]) + +>>> C = make_class("C", ["a", "b"]) +>>> C("foo", "bar") +C(a='foo', b='bar') +``` + +After *declaring* your attributes, *attrs* gives you: + +- a concise and explicit overview of the class's attributes, +- a nice human-readable `__repr__`, +- equality-checking methods, +- an initializer, +- and much more, + +*without* writing dull boilerplate code again and again and *without* runtime performance penalties. + +--- + +This example uses *attrs*'s modern APIs that have been introduced in version 20.1.0, and the *attrs* package import name that has been added in version 21.3.0. +The classic APIs (`@attr.s`, `attr.ib`, plus their serious-business aliases) and the `attr` package import name will remain **indefinitely**. + +Check out [*On The Core API Names*](https://www.attrs.org/en/latest/names.html) for an in-depth explanation! + + +### Hate Type Annotations!? + +No problem! +Types are entirely **optional** with *attrs*. +Simply assign `attrs.field()` to the attributes instead of annotating them with types: + +```python +from attrs import define, field + +@define +class SomeClass: + a_number = field(default=42) + list_of_numbers = field(factory=list) +``` + + +## Data Classes + +On the tin, *attrs* might remind you of `dataclasses` (and indeed, `dataclasses` [are a descendant](https://hynek.me/articles/import-attrs/) of *attrs*). +In practice it does a lot more and is more flexible. +For instance, it allows you to define [special handling of NumPy arrays for equality checks](https://www.attrs.org/en/stable/comparison.html#customization), allows more ways to [plug into the initialization process](https://www.attrs.org/en/stable/init.html#hooking-yourself-into-initialization), has a replacement for `__init_subclass__`, and allows for stepping through the generated methods using a debugger. + +For more details, please refer to our [comparison page](https://www.attrs.org/en/stable/why.html#data-classes), but generally speaking, we are more likely to commit crimes against nature to make things work that one would expect to work, but that are quite complicated in practice. + + +## Project Information + +- [**Changelog**](https://www.attrs.org/en/stable/changelog.html) +- [**Documentation**](https://www.attrs.org/) +- [**PyPI**](https://pypi.org/project/attrs/) +- [**Source Code**](https://github.com/python-attrs/attrs) +- [**Contributing**](https://github.com/python-attrs/attrs/blob/main/.github/CONTRIBUTING.md) +- [**Third-party Extensions**](https://github.com/python-attrs/attrs/wiki/Extensions-to-attrs) +- **Get Help**: use the `python-attrs` tag on [Stack Overflow](https://stackoverflow.com/questions/tagged/python-attrs) + + +### *attrs* for Enterprise + +Available as part of the [Tidelift Subscription](https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek). + +The maintainers of *attrs* and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. +Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. + +## Release Information + +### Changes + +- Restore support for generator-based `field_transformer`s. + [#1417](https://github.com/python-attrs/attrs/issues/1417) + + + +--- + +[Full changelog →](https://www.attrs.org/en/stable/changelog.html) diff --git a/venv/lib/python3.12/site-packages/attrs-25.3.0.dist-info/RECORD b/venv/lib/python3.12/site-packages/attrs-25.3.0.dist-info/RECORD new file mode 100644 index 00000000..b04b5418 --- /dev/null +++ b/venv/lib/python3.12/site-packages/attrs-25.3.0.dist-info/RECORD @@ -0,0 +1,55 @@ +attr/__init__.py,sha256=fOYIvt1eGSqQre4uCS3sJWKZ0mwAuC8UD6qba5OS9_U,2057 +attr/__init__.pyi,sha256=QIXnnHPoucmDWkbpNsWTP-cgJ1bn8le7DjyRa_wYdew,11281 +attr/__pycache__/__init__.cpython-312.pyc,, +attr/__pycache__/_cmp.cpython-312.pyc,, +attr/__pycache__/_compat.cpython-312.pyc,, +attr/__pycache__/_config.cpython-312.pyc,, +attr/__pycache__/_funcs.cpython-312.pyc,, +attr/__pycache__/_make.cpython-312.pyc,, +attr/__pycache__/_next_gen.cpython-312.pyc,, +attr/__pycache__/_version_info.cpython-312.pyc,, +attr/__pycache__/converters.cpython-312.pyc,, +attr/__pycache__/exceptions.cpython-312.pyc,, +attr/__pycache__/filters.cpython-312.pyc,, +attr/__pycache__/setters.cpython-312.pyc,, +attr/__pycache__/validators.cpython-312.pyc,, +attr/_cmp.py,sha256=3Nn1TjxllUYiX_nJoVnEkXoDk0hM1DYKj5DE7GZe4i0,4117 +attr/_cmp.pyi,sha256=U-_RU_UZOyPUEQzXE6RMYQQcjkZRY25wTH99sN0s7MM,368 +attr/_compat.py,sha256=4hlXbWhdDjQCDK6FKF1EgnZ3POiHgtpp54qE0nxaGHg,2704 +attr/_config.py,sha256=dGq3xR6fgZEF6UBt_L0T-eUHIB4i43kRmH0P28sJVw8,843 +attr/_funcs.py,sha256=5-tUKJtp3h5El55EcDl6GWXFp68fT8D8U7uCRN6497I,15854 +attr/_make.py,sha256=lBUPPmxiA1BeHzB6OlHoCEh--tVvM1ozXO8eXOa6g4c,96664 +attr/_next_gen.py,sha256=7FRkbtl_N017SuBhf_Vw3mw2c2pGZhtCGOzadgz7tp4,24395 +attr/_typing_compat.pyi,sha256=XDP54TUn-ZKhD62TOQebmzrwFyomhUCoGRpclb6alRA,469 +attr/_version_info.py,sha256=exSqb3b5E-fMSsgZAlEw9XcLpEgobPORCZpcaEglAM4,2121 +attr/_version_info.pyi,sha256=x_M3L3WuB7r_ULXAWjx959udKQ4HLB8l-hsc1FDGNvk,209 +attr/converters.py,sha256=GlDeOzPeTFgeBBLbj9G57Ez5lAk68uhSALRYJ_exe84,3861 +attr/converters.pyi,sha256=orU2bff-VjQa2kMDyvnMQV73oJT2WRyQuw4ZR1ym1bE,643 +attr/exceptions.py,sha256=HRFq4iybmv7-DcZwyjl6M1euM2YeJVK_hFxuaBGAngI,1977 +attr/exceptions.pyi,sha256=zZq8bCUnKAy9mDtBEw42ZhPhAUIHoTKedDQInJD883M,539 +attr/filters.py,sha256=ZBiKWLp3R0LfCZsq7X11pn9WX8NslS2wXM4jsnLOGc8,1795 +attr/filters.pyi,sha256=3J5BG-dTxltBk1_-RuNRUHrv2qu1v8v4aDNAQ7_mifA,208 +attr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +attr/setters.py,sha256=5-dcT63GQK35ONEzSgfXCkbB7pPkaR-qv15mm4PVSzQ,1617 +attr/setters.pyi,sha256=NnVkaFU1BB4JB8E4JuXyrzTUgvtMpj8p3wBdJY7uix4,584 +attr/validators.py,sha256=WaB1HLAHHqRHWsrv_K9H-sJ7ESil3H3Cmv2d8TtVZx4,20046 +attr/validators.pyi,sha256=s2WhKPqskxbsckJfKk8zOuuB088GfgpyxcCYSNFLqNU,2603 +attrs-25.3.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +attrs-25.3.0.dist-info/METADATA,sha256=W38cREj7s1wqNf1fg4hVwZmL1xh0AdSp4IhtTMROinw,10993 +attrs-25.3.0.dist-info/RECORD,, +attrs-25.3.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87 +attrs-25.3.0.dist-info/licenses/LICENSE,sha256=iCEVyV38KvHutnFPjsbVy8q_Znyv-HKfQkINpj9xTp8,1109 +attrs/__init__.py,sha256=qeQJZ4O08yczSn840v9bYOaZyRE81WsVi-QCrY3krCU,1107 +attrs/__init__.pyi,sha256=nZmInocjM7tHV4AQw0vxO_fo6oJjL_PonlV9zKKW8DY,7931 +attrs/__pycache__/__init__.cpython-312.pyc,, +attrs/__pycache__/converters.cpython-312.pyc,, +attrs/__pycache__/exceptions.cpython-312.pyc,, +attrs/__pycache__/filters.cpython-312.pyc,, +attrs/__pycache__/setters.cpython-312.pyc,, +attrs/__pycache__/validators.cpython-312.pyc,, +attrs/converters.py,sha256=8kQljrVwfSTRu8INwEk8SI0eGrzmWftsT7rM0EqyohM,76 +attrs/exceptions.py,sha256=ACCCmg19-vDFaDPY9vFl199SPXCQMN_bENs4DALjzms,76 +attrs/filters.py,sha256=VOUMZug9uEU6dUuA0dF1jInUK0PL3fLgP0VBS5d-CDE,73 +attrs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +attrs/setters.py,sha256=eL1YidYQV3T2h9_SYIZSZR1FAcHGb1TuCTy0E0Lv2SU,73 +attrs/validators.py,sha256=xcy6wD5TtTkdCG1f4XWbocPSO0faBjk5IfVJfP6SUj0,76 diff --git a/venv/lib/python3.12/site-packages/attrs-25.3.0.dist-info/WHEEL b/venv/lib/python3.12/site-packages/attrs-25.3.0.dist-info/WHEEL new file mode 100644 index 00000000..12228d41 --- /dev/null +++ b/venv/lib/python3.12/site-packages/attrs-25.3.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.27.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/venv/lib/python3.12/site-packages/attrs-25.3.0.dist-info/licenses/LICENSE b/venv/lib/python3.12/site-packages/attrs-25.3.0.dist-info/licenses/LICENSE new file mode 100644 index 00000000..2bd6453d --- /dev/null +++ b/venv/lib/python3.12/site-packages/attrs-25.3.0.dist-info/licenses/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Hynek Schlawack and the attrs contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/venv/lib/python3.12/site-packages/attrs/__init__.py b/venv/lib/python3.12/site-packages/attrs/__init__.py new file mode 100644 index 00000000..e8023ff6 --- /dev/null +++ b/venv/lib/python3.12/site-packages/attrs/__init__.py @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: MIT + +from attr import ( + NOTHING, + Attribute, + AttrsInstance, + Converter, + Factory, + NothingType, + _make_getattr, + assoc, + cmp_using, + define, + evolve, + field, + fields, + fields_dict, + frozen, + has, + make_class, + mutable, + resolve_types, + validate, +) +from attr._next_gen import asdict, astuple + +from . import converters, exceptions, filters, setters, validators + + +__all__ = [ + "NOTHING", + "Attribute", + "AttrsInstance", + "Converter", + "Factory", + "NothingType", + "__author__", + "__copyright__", + "__description__", + "__doc__", + "__email__", + "__license__", + "__title__", + "__url__", + "__version__", + "__version_info__", + "asdict", + "assoc", + "astuple", + "cmp_using", + "converters", + "define", + "evolve", + "exceptions", + "field", + "fields", + "fields_dict", + "filters", + "frozen", + "has", + "make_class", + "mutable", + "resolve_types", + "setters", + "validate", + "validators", +] + +__getattr__ = _make_getattr(__name__) diff --git a/venv/lib/python3.12/site-packages/attrs/__init__.pyi b/venv/lib/python3.12/site-packages/attrs/__init__.pyi new file mode 100644 index 00000000..648fa7a3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/attrs/__init__.pyi @@ -0,0 +1,263 @@ +import sys + +from typing import ( + Any, + Callable, + Mapping, + Sequence, + overload, + TypeVar, +) + +# Because we need to type our own stuff, we have to make everything from +# attr explicitly public too. +from attr import __author__ as __author__ +from attr import __copyright__ as __copyright__ +from attr import __description__ as __description__ +from attr import __email__ as __email__ +from attr import __license__ as __license__ +from attr import __title__ as __title__ +from attr import __url__ as __url__ +from attr import __version__ as __version__ +from attr import __version_info__ as __version_info__ +from attr import assoc as assoc +from attr import Attribute as Attribute +from attr import AttrsInstance as AttrsInstance +from attr import cmp_using as cmp_using +from attr import converters as converters +from attr import Converter as Converter +from attr import evolve as evolve +from attr import exceptions as exceptions +from attr import Factory as Factory +from attr import fields as fields +from attr import fields_dict as fields_dict +from attr import filters as filters +from attr import has as has +from attr import make_class as make_class +from attr import NOTHING as NOTHING +from attr import resolve_types as resolve_types +from attr import setters as setters +from attr import validate as validate +from attr import validators as validators +from attr import attrib, asdict as asdict, astuple as astuple +from attr import NothingType as NothingType + +if sys.version_info >= (3, 11): + from typing import dataclass_transform +else: + from typing_extensions import dataclass_transform + +_T = TypeVar("_T") +_C = TypeVar("_C", bound=type) + +_EqOrderType = bool | Callable[[Any], Any] +_ValidatorType = Callable[[Any, "Attribute[_T]", _T], Any] +_CallableConverterType = Callable[[Any], Any] +_ConverterType = _CallableConverterType | Converter[Any, Any] +_ReprType = Callable[[Any], str] +_ReprArgType = bool | _ReprType +_OnSetAttrType = Callable[[Any, "Attribute[Any]", Any], Any] +_OnSetAttrArgType = _OnSetAttrType | list[_OnSetAttrType] | setters._NoOpType +_FieldTransformer = Callable[ + [type, list["Attribute[Any]"]], list["Attribute[Any]"] +] +# FIXME: in reality, if multiple validators are passed they must be in a list +# or tuple, but those are invariant and so would prevent subtypes of +# _ValidatorType from working when passed in a list or tuple. +_ValidatorArgType = _ValidatorType[_T] | Sequence[_ValidatorType[_T]] + +@overload +def field( + *, + default: None = ..., + validator: None = ..., + repr: _ReprArgType = ..., + hash: bool | None = ..., + init: bool = ..., + metadata: Mapping[Any, Any] | None = ..., + converter: None = ..., + factory: None = ..., + kw_only: bool = ..., + eq: bool | None = ..., + order: bool | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + alias: str | None = ..., + type: type | None = ..., +) -> Any: ... + +# This form catches an explicit None or no default and infers the type from the +# other arguments. +@overload +def field( + *, + default: None = ..., + validator: _ValidatorArgType[_T] | None = ..., + repr: _ReprArgType = ..., + hash: bool | None = ..., + init: bool = ..., + metadata: Mapping[Any, Any] | None = ..., + converter: _ConverterType + | list[_ConverterType] + | tuple[_ConverterType] + | None = ..., + factory: Callable[[], _T] | None = ..., + kw_only: bool = ..., + eq: _EqOrderType | None = ..., + order: _EqOrderType | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + alias: str | None = ..., + type: type | None = ..., +) -> _T: ... + +# This form catches an explicit default argument. +@overload +def field( + *, + default: _T, + validator: _ValidatorArgType[_T] | None = ..., + repr: _ReprArgType = ..., + hash: bool | None = ..., + init: bool = ..., + metadata: Mapping[Any, Any] | None = ..., + converter: _ConverterType + | list[_ConverterType] + | tuple[_ConverterType] + | None = ..., + factory: Callable[[], _T] | None = ..., + kw_only: bool = ..., + eq: _EqOrderType | None = ..., + order: _EqOrderType | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + alias: str | None = ..., + type: type | None = ..., +) -> _T: ... + +# This form covers type=non-Type: e.g. forward references (str), Any +@overload +def field( + *, + default: _T | None = ..., + validator: _ValidatorArgType[_T] | None = ..., + repr: _ReprArgType = ..., + hash: bool | None = ..., + init: bool = ..., + metadata: Mapping[Any, Any] | None = ..., + converter: _ConverterType + | list[_ConverterType] + | tuple[_ConverterType] + | None = ..., + factory: Callable[[], _T] | None = ..., + kw_only: bool = ..., + eq: _EqOrderType | None = ..., + order: _EqOrderType | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + alias: str | None = ..., + type: type | None = ..., +) -> Any: ... +@overload +@dataclass_transform(field_specifiers=(attrib, field)) +def define( + maybe_cls: _C, + *, + these: dict[str, Any] | None = ..., + repr: bool = ..., + unsafe_hash: bool | None = ..., + hash: bool | None = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: bool | None = ..., + order: bool | None = ..., + auto_detect: bool = ..., + getstate_setstate: bool | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + field_transformer: _FieldTransformer | None = ..., + match_args: bool = ..., +) -> _C: ... +@overload +@dataclass_transform(field_specifiers=(attrib, field)) +def define( + maybe_cls: None = ..., + *, + these: dict[str, Any] | None = ..., + repr: bool = ..., + unsafe_hash: bool | None = ..., + hash: bool | None = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: bool | None = ..., + order: bool | None = ..., + auto_detect: bool = ..., + getstate_setstate: bool | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + field_transformer: _FieldTransformer | None = ..., + match_args: bool = ..., +) -> Callable[[_C], _C]: ... + +mutable = define + +@overload +@dataclass_transform(frozen_default=True, field_specifiers=(attrib, field)) +def frozen( + maybe_cls: _C, + *, + these: dict[str, Any] | None = ..., + repr: bool = ..., + unsafe_hash: bool | None = ..., + hash: bool | None = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: bool | None = ..., + order: bool | None = ..., + auto_detect: bool = ..., + getstate_setstate: bool | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + field_transformer: _FieldTransformer | None = ..., + match_args: bool = ..., +) -> _C: ... +@overload +@dataclass_transform(frozen_default=True, field_specifiers=(attrib, field)) +def frozen( + maybe_cls: None = ..., + *, + these: dict[str, Any] | None = ..., + repr: bool = ..., + unsafe_hash: bool | None = ..., + hash: bool | None = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: bool | None = ..., + order: bool | None = ..., + auto_detect: bool = ..., + getstate_setstate: bool | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + field_transformer: _FieldTransformer | None = ..., + match_args: bool = ..., +) -> Callable[[_C], _C]: ... diff --git a/venv/lib/python3.12/site-packages/attrs/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/attrs/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4c891b96e30efb30e685bc21ebe1238129d46d7e GIT binary patch literal 1171 zcmaKrJ8#@Z5XYDIAn&2O(_6M4jsnERA(m(<2;jm9U>Qhk7iR>rn{5^=a&@;bcS-Cn z&pKE32XLK~K{~^qAfF*+;AUGFhPxyx47kb+b%Fs035y?R2FscM%npC=^*RKe-(K!a zjvIu$Md$LV&yDk6!1#%zBn>j60vf0qt*JV#s|IbTCT*&ahAN_wYSETz)3)l+j_T5` zTA&N6M|-MI`)WW3YLPCgCAy@R>9Sg(D{7Ul2AH>&t*Ldot~Tff`1Q1rT~Sx*RkcYs z)fU}S+jLv)(4BycN!t81px0_dMB;Oz|gzjfLazp>J|)^Tf9k zRj|^+As?pVRBGWvG0n57@Xb>xvebvw%lhuco24>w5H$HSp?!VAt?yKclMFKYNR^JC zWKhlsi)omH;?}pOJd-JRVp#Jbw^fpeTUQpDc#k~~o4%7=wg5TBSt1H2a}7C9Wd?nL zVTG%V&OBRg?C>jtmuldqiD@E2M1*Joe1|b!x=C&rgBh?SFJ?xLCl1^JW2vx-kyRlG zL=eamFxrd>#bpL&m$6JHLR)bWchY5O!r9Wy55V9pNQLMkW0#K9r#WM01C`)Lnk$Gd zViU1|=pnWceZ&BC7W;f)C+ZQ2Rjsjq@sYg9Kl{BS&w@(cj_qZtZ#W*C-%^?Vs=c(ZBwpYi>fCe*mLn BM?3%k literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/attrs/__pycache__/converters.cpython-312.pyc b/venv/lib/python3.12/site-packages/attrs/__pycache__/converters.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..05a0804c23cdafd5cc83cbde2b447ac3832d60b6 GIT binary patch literal 256 zcmX@j%ge<81Uq|WGkk#bV-N=hn4pZ$d_cx@h7^Vr#vF#VOpFYbOq$FuL6Vw`w-~kj zfFyrnNlB4ja(-S}YEemQQSnNK&mj3<75bsYK(2mbUP@7Fc~x>oYMy?uu2*SZW`2== za6wUKUb;eHX(C9EzH_jGp{bF6axsuh$}cI_O)ttXEwIopOU*0O&&f>EFQ_cZ$j>v@ zGc?jK&MZmQEl5nxPE1b)nhvzQSRY}#UP0wA4x8Nkl+v73yCM#tLl}X$806Cr%#4hT NU)dNK<%-yVTmX5HN38$= literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/attrs/__pycache__/exceptions.cpython-312.pyc b/venv/lib/python3.12/site-packages/attrs/__pycache__/exceptions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5b43174b28f241e3fca57bbfc2eec9e1e1b2b1b9 GIT binary patch literal 256 zcmX@j%ge<81Uq|WGkk#bV-N=hn4pZ$d_cx@h7^Vr#vF#VOpFYbOq$FuL6Vw`w-~kj zfFyrnNlB4jYDIEtK}lwQUhztX&mj3<75bsYsYS*5iFqkSspVD48L4^t!Ma|hd71e| z`oRT7nR)37fu)H>C8RF+CM%I?(cBeT40L1(m-zY;yBcN^?@}ia3A{VFco0kWW7_ QGcq!MWn*BJD`Eq30ddAhn*aa+ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/attrs/__pycache__/filters.cpython-312.pyc b/venv/lib/python3.12/site-packages/attrs/__pycache__/filters.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..48827900d08a611ab6ba76080b36f9f82af6740d GIT binary patch literal 250 zcmX@j%ge<81Uq|WGdzLxV-N=hn4pZ$d_cx@h7^Vr#vF#VOpFYbOq$FuL6Vw`w-~kj zfFw_1NlB4jT4qj3YEkh@hR-0$U#0q?#XzopVqQv7YI#+1MrxjZu&!5WUS@ugesDoi zW?s5NU}<6zP>;TIu!5nfk$!S9kW9)iDb`Id$}cUj&@W5PE7Q-(Owuo?EXl~vGuAUS z(l5>|N!2Y#OwLYBPX(F|w7FOxYPDWL;TIu!5nfk$!S9kW9)iDb`Id$}cUj&@W5PE7Q-(Owuo?EXl~vGuAUS z(l5>|N!2Y#OwLYBPX(F|w7FOxYPDWLC8RF+CM%I?(cBeT40L1(m-zY;yBcN^?@}ia3A{VFco0kWW7_ QGcq!MWn*BJD`Eq30cre4i2wiq literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/attrs/converters.py b/venv/lib/python3.12/site-packages/attrs/converters.py new file mode 100644 index 00000000..7821f6c0 --- /dev/null +++ b/venv/lib/python3.12/site-packages/attrs/converters.py @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: MIT + +from attr.converters import * # noqa: F403 diff --git a/venv/lib/python3.12/site-packages/attrs/exceptions.py b/venv/lib/python3.12/site-packages/attrs/exceptions.py new file mode 100644 index 00000000..3323f9d2 --- /dev/null +++ b/venv/lib/python3.12/site-packages/attrs/exceptions.py @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: MIT + +from attr.exceptions import * # noqa: F403 diff --git a/venv/lib/python3.12/site-packages/attrs/filters.py b/venv/lib/python3.12/site-packages/attrs/filters.py new file mode 100644 index 00000000..3080f483 --- /dev/null +++ b/venv/lib/python3.12/site-packages/attrs/filters.py @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: MIT + +from attr.filters import * # noqa: F403 diff --git a/venv/lib/python3.12/site-packages/attrs/py.typed b/venv/lib/python3.12/site-packages/attrs/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/venv/lib/python3.12/site-packages/attrs/setters.py b/venv/lib/python3.12/site-packages/attrs/setters.py new file mode 100644 index 00000000..f3d73bb7 --- /dev/null +++ b/venv/lib/python3.12/site-packages/attrs/setters.py @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: MIT + +from attr.setters import * # noqa: F403 diff --git a/venv/lib/python3.12/site-packages/attrs/validators.py b/venv/lib/python3.12/site-packages/attrs/validators.py new file mode 100644 index 00000000..037e124f --- /dev/null +++ b/venv/lib/python3.12/site-packages/attrs/validators.py @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: MIT + +from attr.validators import * # noqa: F403 diff --git a/venv/lib/python3.12/site-packages/certifi-2025.4.26.dist-info/INSTALLER b/venv/lib/python3.12/site-packages/certifi-2025.4.26.dist-info/INSTALLER new file mode 100644 index 00000000..a1b589e3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/certifi-2025.4.26.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.12/site-packages/certifi-2025.4.26.dist-info/METADATA b/venv/lib/python3.12/site-packages/certifi-2025.4.26.dist-info/METADATA new file mode 100644 index 00000000..bba2b699 --- /dev/null +++ b/venv/lib/python3.12/site-packages/certifi-2025.4.26.dist-info/METADATA @@ -0,0 +1,78 @@ +Metadata-Version: 2.4 +Name: certifi +Version: 2025.4.26 +Summary: Python package for providing Mozilla's CA Bundle. +Home-page: https://github.com/certifi/python-certifi +Author: Kenneth Reitz +Author-email: me@kennethreitz.com +License: MPL-2.0 +Project-URL: Source, https://github.com/certifi/python-certifi +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0) +Classifier: Natural Language :: English +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Requires-Python: >=3.6 +License-File: LICENSE +Dynamic: author +Dynamic: author-email +Dynamic: classifier +Dynamic: description +Dynamic: home-page +Dynamic: license +Dynamic: license-file +Dynamic: project-url +Dynamic: requires-python +Dynamic: summary + +Certifi: Python SSL Certificates +================================ + +Certifi provides Mozilla's carefully curated collection of Root Certificates for +validating the trustworthiness of SSL certificates while verifying the identity +of TLS hosts. It has been extracted from the `Requests`_ project. + +Installation +------------ + +``certifi`` is available on PyPI. Simply install it with ``pip``:: + + $ pip install certifi + +Usage +----- + +To reference the installed certificate authority (CA) bundle, you can use the +built-in function:: + + >>> import certifi + + >>> certifi.where() + '/usr/local/lib/python3.7/site-packages/certifi/cacert.pem' + +Or from the command line:: + + $ python -m certifi + /usr/local/lib/python3.7/site-packages/certifi/cacert.pem + +Enjoy! + +.. _`Requests`: https://requests.readthedocs.io/en/master/ + +Addition/Removal of Certificates +-------------------------------- + +Certifi does not support any addition/removal or other modification of the +CA trust store content. This project is intended to provide a reliable and +highly portable root of trust to python deployments. Look to upstream projects +for methods to use alternate trust. diff --git a/venv/lib/python3.12/site-packages/certifi-2025.4.26.dist-info/RECORD b/venv/lib/python3.12/site-packages/certifi-2025.4.26.dist-info/RECORD new file mode 100644 index 00000000..86cf5a39 --- /dev/null +++ b/venv/lib/python3.12/site-packages/certifi-2025.4.26.dist-info/RECORD @@ -0,0 +1,14 @@ +certifi-2025.4.26.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +certifi-2025.4.26.dist-info/METADATA,sha256=Q1SDFkY5LOQAJmDltZz2wU3VTv1Kh5X-rjGI4KiPHNM,2473 +certifi-2025.4.26.dist-info/RECORD,, +certifi-2025.4.26.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91 +certifi-2025.4.26.dist-info/licenses/LICENSE,sha256=6TcW2mucDVpKHfYP5pWzcPBpVgPSH2-D8FPkLPwQyvc,989 +certifi-2025.4.26.dist-info/top_level.txt,sha256=KMu4vUCfsjLrkPbSNdgdekS-pVJzBAJFO__nI8NF6-U,8 +certifi/__init__.py,sha256=9pyWUGr6sbAlksfOHo0BTV0Gxljjh4IK1kXAjHgjL4I,94 +certifi/__main__.py,sha256=xBBoj905TUWBLRGANOcf7oi6e-3dMP4cEoG9OyMs11g,243 +certifi/__pycache__/__init__.cpython-312.pyc,, +certifi/__pycache__/__main__.cpython-312.pyc,, +certifi/__pycache__/core.cpython-312.pyc,, +certifi/cacert.pem,sha256=K3sQJvGKKX4hSBicoMvn0-f578NvcjHMwoIKQE_rVZY,283771 +certifi/core.py,sha256=qRDDFyXVJwTB_EmoGppaXU_R9qCZvhl-EzxPMuV3nTA,4426 +certifi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/venv/lib/python3.12/site-packages/certifi-2025.4.26.dist-info/WHEEL b/venv/lib/python3.12/site-packages/certifi-2025.4.26.dist-info/WHEEL new file mode 100644 index 00000000..8acb9559 --- /dev/null +++ b/venv/lib/python3.12/site-packages/certifi-2025.4.26.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: setuptools (79.0.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/venv/lib/python3.12/site-packages/certifi-2025.4.26.dist-info/licenses/LICENSE b/venv/lib/python3.12/site-packages/certifi-2025.4.26.dist-info/licenses/LICENSE new file mode 100644 index 00000000..62b076cd --- /dev/null +++ b/venv/lib/python3.12/site-packages/certifi-2025.4.26.dist-info/licenses/LICENSE @@ -0,0 +1,20 @@ +This package contains a modified version of ca-bundle.crt: + +ca-bundle.crt -- Bundle of CA Root Certificates + +This is a bundle of X.509 certificates of public Certificate Authorities +(CA). These were automatically extracted from Mozilla's root certificates +file (certdata.txt). This file can be found in the mozilla source tree: +https://hg.mozilla.org/mozilla-central/file/tip/security/nss/lib/ckfw/builtins/certdata.txt +It contains the certificates in PEM format and therefore +can be directly used with curl / libcurl / php_curl, or with +an Apache+mod_ssl webserver for SSL client authentication. +Just configure this file as the SSLCACertificateFile.# + +***** BEGIN LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public License, +v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain +one at http://mozilla.org/MPL/2.0/. + +***** END LICENSE BLOCK ***** +@(#) $RCSfile: certdata.txt,v $ $Revision: 1.80 $ $Date: 2011/11/03 15:11:58 $ diff --git a/venv/lib/python3.12/site-packages/certifi-2025.4.26.dist-info/top_level.txt b/venv/lib/python3.12/site-packages/certifi-2025.4.26.dist-info/top_level.txt new file mode 100644 index 00000000..963eac53 --- /dev/null +++ b/venv/lib/python3.12/site-packages/certifi-2025.4.26.dist-info/top_level.txt @@ -0,0 +1 @@ +certifi diff --git a/venv/lib/python3.12/site-packages/certifi/__init__.py b/venv/lib/python3.12/site-packages/certifi/__init__.py new file mode 100644 index 00000000..bf83fa93 --- /dev/null +++ b/venv/lib/python3.12/site-packages/certifi/__init__.py @@ -0,0 +1,4 @@ +from .core import contents, where + +__all__ = ["contents", "where"] +__version__ = "2025.04.26" diff --git a/venv/lib/python3.12/site-packages/certifi/__main__.py b/venv/lib/python3.12/site-packages/certifi/__main__.py new file mode 100644 index 00000000..8945b5da --- /dev/null +++ b/venv/lib/python3.12/site-packages/certifi/__main__.py @@ -0,0 +1,12 @@ +import argparse + +from certifi import contents, where + +parser = argparse.ArgumentParser() +parser.add_argument("-c", "--contents", action="store_true") +args = parser.parse_args() + +if args.contents: + print(contents()) +else: + print(where()) diff --git a/venv/lib/python3.12/site-packages/certifi/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/certifi/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5a7de74ced8f471f419cf17506e376c30cddd1bf GIT binary patch literal 344 zcmYjMJxc>Y5Z%4In3yAWA_!tEQ{*-|Kd=xRI}1UA%@r<}+x2eovU|+#B_@^r0Kv}R z;9t?kQm#?3vJ=v!asvv!;?0})W?<%})oLP(=liYf($>#q^9Scw%-dExB8C{w(FjL) z6n8SN>ciS=5`e=ZpekU9*HFbKA9yMmt@dAEu~OE1_cP2w$IBL z3rCLJ)*S5skPVS`j?7g6PRZQGy`3EZf~N*_fSOW@cLxJQP7x zir`KE1SS3@dNH(;I$kOs#GBAtPtK&-=HkG-_s#cx@9}2lOReSsxjw%+-#wK1mpW9- zoPonV3EqJOB(M+KDrBdj+d2dqz@X<;Me{tG!M2IbUTw}-DA5xmF+W)&{g{D3 z`W7p7o=^HX*y$N_zCv_CPT7z0Y^{KLs`sFL=uX(hH)1Y)C%sEB+V&m zDQm}nP)3wvite=h^J1 z+txm?CZIkB^|yE5U;FUvE2!^*)qT4*u^VH%v1^~(HV$;aOHqn) zXdf}}y`7yI&ivl*z1hEacgG3H-~RB*{N+AE{*4czbOlcHXOxip#3DsvQA?`OBK56Q zl&rL+e5e#$Kv1dUq>fc$ft7E-HYdwFzy~SSN_7(fUc31irlEow?cGB)EAK%$^ z=;7WDz(a8WM#Qb2;3*v=F=7o`x;KvySptJg&vJb|NpvFIbn z9F%gjWjnPcg>OS^C?d=`BHH;>?(Uq`@*f3V?U_XA;iz(N=1!8eE-~B->jC9yW!I_J3^C8}yq?Sj^I|{*U?3}%yoez%9G=GP zIfp}^9}R{$_^7iO&Qh1=ZDun}vjJ%Q3aC}`qL(Bxn_bx#X)-kYm!l72_2IGY;d5KV z=RTjP5C6P=@baB2PlpbF^1JQq>8UxgA|tAP`IbR0(GTmg*#fQc4(N?x_Yh9p@qS zG`niL7BD|A`v5W|r59tiVU++Xu@@RGOlFpYfuqp)4?qEp_0-z+x}M$Ek8kP69~`Rd zZ*A-6xAgOWJ+`Tzuj^Br+EhSnhID$4m;sT^BPNn@w7Qxl-m4bNFSC) zHHa#M3UhxCtUlFzbp~GYAA#!NTZRn1x^ebFrGD_-|IM&=jW`Tz?`D`K`Ak8yL8b{C z0`rhEjLF`8=CBXd6tpJt2_v6bKd>?J`P+~6@l9>K6=dqE??GLy-tKbw=rzd43Fn6G zMT07d`N!Qw2Dy#<@gk6jF5_l9ZqONl<}=_HIGsD*iGLW$73otN^59MKfwH3Pmk;4+ zQwpw+fH@S-{35*4i9^SAM zsPGi*HBg>n8N%QQcMiobC@m-vPXii%9TbE&L3;ZCc=Y3A8jPZ@ha<>9vP93li+3;jmGn|Qar6%TO7FY3ba(0A%H5Uq3+pR&{p6;0^1G$=e1V?=libVH_;ej}+=X(kBm z`jT`v6-r-gXhex_%gHS{xwiC$eE4f+>{)+$^$Ku!b)umRs)yFzXc91uF{)0}HS+~Q z+lY`zY+D`JQU})4U#Quym7jD@%e1C}X`H6&JHfPfXj3C<&zDN?zm!AIdXj7JZl{iH zrH*Wvo2mR(&xzHGPvHKUULV;UI0o0x>ZL|MIgopjKKxBAs%D?`Wg0TrXZ;5oDp=S; jGTn%xr;)x?1IIMtB;MWZLN6_=Be-=ijd None: + _CACERT_CTX.__exit__(None, None, None) # type: ignore[union-attr] + + +if sys.version_info >= (3, 11): + + from importlib.resources import as_file, files + + _CACERT_CTX = None + _CACERT_PATH = None + + def where() -> str: + # This is slightly terrible, but we want to delay extracting the file + # in cases where we're inside of a zipimport situation until someone + # actually calls where(), but we don't want to re-extract the file + # on every call of where(), so we'll do it once then store it in a + # global variable. + global _CACERT_CTX + global _CACERT_PATH + if _CACERT_PATH is None: + # This is slightly janky, the importlib.resources API wants you to + # manage the cleanup of this file, so it doesn't actually return a + # path, it returns a context manager that will give you the path + # when you enter it and will do any cleanup when you leave it. In + # the common case of not needing a temporary file, it will just + # return the file system location and the __exit__() is a no-op. + # + # We also have to hold onto the actual context manager, because + # it will do the cleanup whenever it gets garbage collected, so + # we will also store that at the global level as well. + _CACERT_CTX = as_file(files("certifi").joinpath("cacert.pem")) + _CACERT_PATH = str(_CACERT_CTX.__enter__()) + atexit.register(exit_cacert_ctx) + + return _CACERT_PATH + + def contents() -> str: + return files("certifi").joinpath("cacert.pem").read_text(encoding="ascii") + +elif sys.version_info >= (3, 7): + + from importlib.resources import path as get_path, read_text + + _CACERT_CTX = None + _CACERT_PATH = None + + def where() -> str: + # This is slightly terrible, but we want to delay extracting the + # file in cases where we're inside of a zipimport situation until + # someone actually calls where(), but we don't want to re-extract + # the file on every call of where(), so we'll do it once then store + # it in a global variable. + global _CACERT_CTX + global _CACERT_PATH + if _CACERT_PATH is None: + # This is slightly janky, the importlib.resources API wants you + # to manage the cleanup of this file, so it doesn't actually + # return a path, it returns a context manager that will give + # you the path when you enter it and will do any cleanup when + # you leave it. In the common case of not needing a temporary + # file, it will just return the file system location and the + # __exit__() is a no-op. + # + # We also have to hold onto the actual context manager, because + # it will do the cleanup whenever it gets garbage collected, so + # we will also store that at the global level as well. + _CACERT_CTX = get_path("certifi", "cacert.pem") + _CACERT_PATH = str(_CACERT_CTX.__enter__()) + atexit.register(exit_cacert_ctx) + + return _CACERT_PATH + + def contents() -> str: + return read_text("certifi", "cacert.pem", encoding="ascii") + +else: + import os + import types + from typing import Union + + Package = Union[types.ModuleType, str] + Resource = Union[str, "os.PathLike"] + + # This fallback will work for Python versions prior to 3.7 that lack the + # importlib.resources module but relies on the existing `where` function + # so won't address issues with environments like PyOxidizer that don't set + # __file__ on modules. + def read_text( + package: Package, + resource: Resource, + encoding: str = 'utf-8', + errors: str = 'strict' + ) -> str: + with open(where(), encoding=encoding) as data: + return data.read() + + # If we don't have importlib.resources, then we will just do the old logic + # of assuming we're on the filesystem and munge the path directly. + def where() -> str: + f = os.path.dirname(__file__) + + return os.path.join(f, "cacert.pem") + + def contents() -> str: + return read_text("certifi", "cacert.pem", encoding="ascii") diff --git a/venv/lib/python3.12/site-packages/certifi/py.typed b/venv/lib/python3.12/site-packages/certifi/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/INSTALLER b/venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/INSTALLER new file mode 100644 index 00000000..a1b589e3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/METADATA b/venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/METADATA new file mode 100644 index 00000000..573d88b9 --- /dev/null +++ b/venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/METADATA @@ -0,0 +1,731 @@ +Metadata-Version: 2.4 +Name: charset-normalizer +Version: 3.4.2 +Summary: The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet. +Author-email: "Ahmed R. TAHRI" +Maintainer-email: "Ahmed R. TAHRI" +License: MIT +Project-URL: Changelog, https://github.com/jawah/charset_normalizer/blob/master/CHANGELOG.md +Project-URL: Documentation, https://charset-normalizer.readthedocs.io/ +Project-URL: Code, https://github.com/jawah/charset_normalizer +Project-URL: Issue tracker, https://github.com/jawah/charset_normalizer/issues +Keywords: encoding,charset,charset-detector,detector,normalization,unicode,chardet,detect +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Text Processing :: Linguistic +Classifier: Topic :: Utilities +Classifier: Typing :: Typed +Requires-Python: >=3.7 +Description-Content-Type: text/markdown +License-File: LICENSE +Provides-Extra: unicode-backport +Dynamic: license-file + +

    Charset Detection, for Everyone 👋

    + +

    + The Real First Universal Charset Detector
    + + + + + Download Count Total + + + + +

    +

    + Featured Packages
    + + Static Badge + + + Static Badge + +

    +

    + In other language (unofficial port - by the community)
    + + Static Badge + +

    + +> A library that helps you read text from an unknown charset encoding.
    Motivated by `chardet`, +> I'm trying to resolve the issue by taking a new approach. +> All IANA character set names for which the Python core library provides codecs are supported. + +

    + >>>>> 👉 Try Me Online Now, Then Adopt Me 👈 <<<<< +

    + +This project offers you an alternative to **Universal Charset Encoding Detector**, also known as **Chardet**. + +| Feature | [Chardet](https://github.com/chardet/chardet) | Charset Normalizer | [cChardet](https://github.com/PyYoshi/cChardet) | +|--------------------------------------------------|:---------------------------------------------:|:--------------------------------------------------------------------------------------------------:|:-----------------------------------------------:| +| `Fast` | ❌ | ✅ | ✅ | +| `Universal**` | ❌ | ✅ | ❌ | +| `Reliable` **without** distinguishable standards | ❌ | ✅ | ✅ | +| `Reliable` **with** distinguishable standards | ✅ | ✅ | ✅ | +| `License` | LGPL-2.1
    _restrictive_ | MIT | MPL-1.1
    _restrictive_ | +| `Native Python` | ✅ | ✅ | ❌ | +| `Detect spoken language` | ❌ | ✅ | N/A | +| `UnicodeDecodeError Safety` | ❌ | ✅ | ❌ | +| `Whl Size (min)` | 193.6 kB | 42 kB | ~200 kB | +| `Supported Encoding` | 33 | 🎉 [99](https://charset-normalizer.readthedocs.io/en/latest/user/support.html#supported-encodings) | 40 | + +

    +Reading Normalized TextCat Reading Text +

    + +*\*\* : They are clearly using specific code for a specific encoding even if covering most of used one*
    + +## ⚡ Performance + +This package offer better performance than its counterpart Chardet. Here are some numbers. + +| Package | Accuracy | Mean per file (ms) | File per sec (est) | +|-----------------------------------------------|:--------:|:------------------:|:------------------:| +| [chardet](https://github.com/chardet/chardet) | 86 % | 63 ms | 16 file/sec | +| charset-normalizer | **98 %** | **10 ms** | 100 file/sec | + +| Package | 99th percentile | 95th percentile | 50th percentile | +|-----------------------------------------------|:---------------:|:---------------:|:---------------:| +| [chardet](https://github.com/chardet/chardet) | 265 ms | 71 ms | 7 ms | +| charset-normalizer | 100 ms | 50 ms | 5 ms | + +_updated as of december 2024 using CPython 3.12_ + +Chardet's performance on larger file (1MB+) are very poor. Expect huge difference on large payload. + +> Stats are generated using 400+ files using default parameters. More details on used files, see GHA workflows. +> And yes, these results might change at any time. The dataset can be updated to include more files. +> The actual delays heavily depends on your CPU capabilities. The factors should remain the same. +> Keep in mind that the stats are generous and that Chardet accuracy vs our is measured using Chardet initial capability +> (e.g. Supported Encoding) Challenge-them if you want. + +## ✨ Installation + +Using pip: + +```sh +pip install charset-normalizer -U +``` + +## 🚀 Basic Usage + +### CLI +This package comes with a CLI. + +``` +usage: normalizer [-h] [-v] [-a] [-n] [-m] [-r] [-f] [-t THRESHOLD] + file [file ...] + +The Real First Universal Charset Detector. Discover originating encoding used +on text file. Normalize text to unicode. + +positional arguments: + files File(s) to be analysed + +optional arguments: + -h, --help show this help message and exit + -v, --verbose Display complementary information about file if any. + Stdout will contain logs about the detection process. + -a, --with-alternative + Output complementary possibilities if any. Top-level + JSON WILL be a list. + -n, --normalize Permit to normalize input file. If not set, program + does not write anything. + -m, --minimal Only output the charset detected to STDOUT. Disabling + JSON output. + -r, --replace Replace file when trying to normalize it instead of + creating a new one. + -f, --force Replace file without asking if you are sure, use this + flag with caution. + -t THRESHOLD, --threshold THRESHOLD + Define a custom maximum amount of chaos allowed in + decoded content. 0. <= chaos <= 1. + --version Show version information and exit. +``` + +```bash +normalizer ./data/sample.1.fr.srt +``` + +or + +```bash +python -m charset_normalizer ./data/sample.1.fr.srt +``` + +🎉 Since version 1.4.0 the CLI produce easily usable stdout result in JSON format. + +```json +{ + "path": "/home/default/projects/charset_normalizer/data/sample.1.fr.srt", + "encoding": "cp1252", + "encoding_aliases": [ + "1252", + "windows_1252" + ], + "alternative_encodings": [ + "cp1254", + "cp1256", + "cp1258", + "iso8859_14", + "iso8859_15", + "iso8859_16", + "iso8859_3", + "iso8859_9", + "latin_1", + "mbcs" + ], + "language": "French", + "alphabets": [ + "Basic Latin", + "Latin-1 Supplement" + ], + "has_sig_or_bom": false, + "chaos": 0.149, + "coherence": 97.152, + "unicode_path": null, + "is_preferred": true +} +``` + +### Python +*Just print out normalized text* +```python +from charset_normalizer import from_path + +results = from_path('./my_subtitle.srt') + +print(str(results.best())) +``` + +*Upgrade your code without effort* +```python +from charset_normalizer import detect +``` + +The above code will behave the same as **chardet**. We ensure that we offer the best (reasonable) BC result possible. + +See the docs for advanced usage : [readthedocs.io](https://charset-normalizer.readthedocs.io/en/latest/) + +## 😇 Why + +When I started using Chardet, I noticed that it was not suited to my expectations, and I wanted to propose a +reliable alternative using a completely different method. Also! I never back down on a good challenge! + +I **don't care** about the **originating charset** encoding, because **two different tables** can +produce **two identical rendered string.** +What I want is to get readable text, the best I can. + +In a way, **I'm brute forcing text decoding.** How cool is that ? 😎 + +Don't confuse package **ftfy** with charset-normalizer or chardet. ftfy goal is to repair Unicode string whereas charset-normalizer to convert raw file in unknown encoding to unicode. + +## 🍰 How + + - Discard all charset encoding table that could not fit the binary content. + - Measure noise, or the mess once opened (by chunks) with a corresponding charset encoding. + - Extract matches with the lowest mess detected. + - Additionally, we measure coherence / probe for a language. + +**Wait a minute**, what is noise/mess and coherence according to **YOU ?** + +*Noise :* I opened hundred of text files, **written by humans**, with the wrong encoding table. **I observed**, then +**I established** some ground rules about **what is obvious** when **it seems like** a mess (aka. defining noise in rendered text). + I know that my interpretation of what is noise is probably incomplete, feel free to contribute in order to + improve or rewrite it. + +*Coherence :* For each language there is on earth, we have computed ranked letter appearance occurrences (the best we can). So I thought +that intel is worth something here. So I use those records against decoded text to check if I can detect intelligent design. + +## ⚡ Known limitations + + - Language detection is unreliable when text contains two or more languages sharing identical letters. (eg. HTML (english tags) + Turkish content (Sharing Latin characters)) + - Every charset detector heavily depends on sufficient content. In common cases, do not bother run detection on very tiny content. + +## ⚠️ About Python EOLs + +**If you are running:** + +- Python >=2.7,<3.5: Unsupported +- Python 3.5: charset-normalizer < 2.1 +- Python 3.6: charset-normalizer < 3.1 +- Python 3.7: charset-normalizer < 4.0 + +Upgrade your Python interpreter as soon as possible. + +## 👤 Contributing + +Contributions, issues and feature requests are very much welcome.
    +Feel free to check [issues page](https://github.com/ousret/charset_normalizer/issues) if you want to contribute. + +## 📝 License + +Copyright © [Ahmed TAHRI @Ousret](https://github.com/Ousret).
    +This project is [MIT](https://github.com/Ousret/charset_normalizer/blob/master/LICENSE) licensed. + +Characters frequencies used in this project © 2012 [Denny Vrandečić](http://simia.net/letters/) + +## 💼 For Enterprise + +Professional support for charset-normalizer is available as part of the [Tidelift +Subscription][1]. Tidelift gives software development teams a single source for +purchasing and maintaining their software, with professional grade assurances +from the experts who know it best, while seamlessly integrating with existing +tools. + +[1]: https://tidelift.com/subscription/pkg/pypi-charset-normalizer?utm_source=pypi-charset-normalizer&utm_medium=readme + +[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/7297/badge)](https://www.bestpractices.dev/projects/7297) + +# Changelog +All notable changes to charset-normalizer will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +## [3.4.2](https://github.com/Ousret/charset_normalizer/compare/3.4.1...3.4.2) (2025-05-02) + +### Fixed +- Addressed the DeprecationWarning in our CLI regarding `argparse.FileType` by backporting the target class into the package. (#591) +- Improved the overall reliability of the detector with CJK Ideographs. (#605) (#587) + +### Changed +- Optional mypyc compilation upgraded to version 1.15 for Python >= 3.8 + +## [3.4.1](https://github.com/Ousret/charset_normalizer/compare/3.4.0...3.4.1) (2024-12-24) + +### Changed +- Project metadata are now stored using `pyproject.toml` instead of `setup.cfg` using setuptools as the build backend. +- Enforce annotation delayed loading for a simpler and consistent types in the project. +- Optional mypyc compilation upgraded to version 1.14 for Python >= 3.8 + +### Added +- pre-commit configuration. +- noxfile. + +### Removed +- `build-requirements.txt` as per using `pyproject.toml` native build configuration. +- `bin/integration.py` and `bin/serve.py` in favor of downstream integration test (see noxfile). +- `setup.cfg` in favor of `pyproject.toml` metadata configuration. +- Unused `utils.range_scan` function. + +### Fixed +- Converting content to Unicode bytes may insert `utf_8` instead of preferred `utf-8`. (#572) +- Deprecation warning "'count' is passed as positional argument" when converting to Unicode bytes on Python 3.13+ + +## [3.4.0](https://github.com/Ousret/charset_normalizer/compare/3.3.2...3.4.0) (2024-10-08) + +### Added +- Argument `--no-preemptive` in the CLI to prevent the detector to search for hints. +- Support for Python 3.13 (#512) + +### Fixed +- Relax the TypeError exception thrown when trying to compare a CharsetMatch with anything else than a CharsetMatch. +- Improved the general reliability of the detector based on user feedbacks. (#520) (#509) (#498) (#407) (#537) +- Declared charset in content (preemptive detection) not changed when converting to utf-8 bytes. (#381) + +## [3.3.2](https://github.com/Ousret/charset_normalizer/compare/3.3.1...3.3.2) (2023-10-31) + +### Fixed +- Unintentional memory usage regression when using large payload that match several encoding (#376) +- Regression on some detection case showcased in the documentation (#371) + +### Added +- Noise (md) probe that identify malformed arabic representation due to the presence of letters in isolated form (credit to my wife) + +## [3.3.1](https://github.com/Ousret/charset_normalizer/compare/3.3.0...3.3.1) (2023-10-22) + +### Changed +- Optional mypyc compilation upgraded to version 1.6.1 for Python >= 3.8 +- Improved the general detection reliability based on reports from the community + +## [3.3.0](https://github.com/Ousret/charset_normalizer/compare/3.2.0...3.3.0) (2023-09-30) + +### Added +- Allow to execute the CLI (e.g. normalizer) through `python -m charset_normalizer.cli` or `python -m charset_normalizer` +- Support for 9 forgotten encoding that are supported by Python but unlisted in `encoding.aliases` as they have no alias (#323) + +### Removed +- (internal) Redundant utils.is_ascii function and unused function is_private_use_only +- (internal) charset_normalizer.assets is moved inside charset_normalizer.constant + +### Changed +- (internal) Unicode code blocks in constants are updated using the latest v15.0.0 definition to improve detection +- Optional mypyc compilation upgraded to version 1.5.1 for Python >= 3.8 + +### Fixed +- Unable to properly sort CharsetMatch when both chaos/noise and coherence were close due to an unreachable condition in \_\_lt\_\_ (#350) + +## [3.2.0](https://github.com/Ousret/charset_normalizer/compare/3.1.0...3.2.0) (2023-06-07) + +### Changed +- Typehint for function `from_path` no longer enforce `PathLike` as its first argument +- Minor improvement over the global detection reliability + +### Added +- Introduce function `is_binary` that relies on main capabilities, and optimized to detect binaries +- Propagate `enable_fallback` argument throughout `from_bytes`, `from_path`, and `from_fp` that allow a deeper control over the detection (default True) +- Explicit support for Python 3.12 + +### Fixed +- Edge case detection failure where a file would contain 'very-long' camel cased word (Issue #289) + +## [3.1.0](https://github.com/Ousret/charset_normalizer/compare/3.0.1...3.1.0) (2023-03-06) + +### Added +- Argument `should_rename_legacy` for legacy function `detect` and disregard any new arguments without errors (PR #262) + +### Removed +- Support for Python 3.6 (PR #260) + +### Changed +- Optional speedup provided by mypy/c 1.0.1 + +## [3.0.1](https://github.com/Ousret/charset_normalizer/compare/3.0.0...3.0.1) (2022-11-18) + +### Fixed +- Multi-bytes cutter/chunk generator did not always cut correctly (PR #233) + +### Changed +- Speedup provided by mypy/c 0.990 on Python >= 3.7 + +## [3.0.0](https://github.com/Ousret/charset_normalizer/compare/2.1.1...3.0.0) (2022-10-20) + +### Added +- Extend the capability of explain=True when cp_isolation contains at most two entries (min one), will log in details of the Mess-detector results +- Support for alternative language frequency set in charset_normalizer.assets.FREQUENCIES +- Add parameter `language_threshold` in `from_bytes`, `from_path` and `from_fp` to adjust the minimum expected coherence ratio +- `normalizer --version` now specify if current version provide extra speedup (meaning mypyc compilation whl) + +### Changed +- Build with static metadata using 'build' frontend +- Make the language detection stricter +- Optional: Module `md.py` can be compiled using Mypyc to provide an extra speedup up to 4x faster than v2.1 + +### Fixed +- CLI with opt --normalize fail when using full path for files +- TooManyAccentuatedPlugin induce false positive on the mess detection when too few alpha character have been fed to it +- Sphinx warnings when generating the documentation + +### Removed +- Coherence detector no longer return 'Simple English' instead return 'English' +- Coherence detector no longer return 'Classical Chinese' instead return 'Chinese' +- Breaking: Method `first()` and `best()` from CharsetMatch +- UTF-7 will no longer appear as "detected" without a recognized SIG/mark (is unreliable/conflict with ASCII) +- Breaking: Class aliases CharsetDetector, CharsetDoctor, CharsetNormalizerMatch and CharsetNormalizerMatches +- Breaking: Top-level function `normalize` +- Breaking: Properties `chaos_secondary_pass`, `coherence_non_latin` and `w_counter` from CharsetMatch +- Support for the backport `unicodedata2` + +## [3.0.0rc1](https://github.com/Ousret/charset_normalizer/compare/3.0.0b2...3.0.0rc1) (2022-10-18) + +### Added +- Extend the capability of explain=True when cp_isolation contains at most two entries (min one), will log in details of the Mess-detector results +- Support for alternative language frequency set in charset_normalizer.assets.FREQUENCIES +- Add parameter `language_threshold` in `from_bytes`, `from_path` and `from_fp` to adjust the minimum expected coherence ratio + +### Changed +- Build with static metadata using 'build' frontend +- Make the language detection stricter + +### Fixed +- CLI with opt --normalize fail when using full path for files +- TooManyAccentuatedPlugin induce false positive on the mess detection when too few alpha character have been fed to it + +### Removed +- Coherence detector no longer return 'Simple English' instead return 'English' +- Coherence detector no longer return 'Classical Chinese' instead return 'Chinese' + +## [3.0.0b2](https://github.com/Ousret/charset_normalizer/compare/3.0.0b1...3.0.0b2) (2022-08-21) + +### Added +- `normalizer --version` now specify if current version provide extra speedup (meaning mypyc compilation whl) + +### Removed +- Breaking: Method `first()` and `best()` from CharsetMatch +- UTF-7 will no longer appear as "detected" without a recognized SIG/mark (is unreliable/conflict with ASCII) + +### Fixed +- Sphinx warnings when generating the documentation + +## [3.0.0b1](https://github.com/Ousret/charset_normalizer/compare/2.1.0...3.0.0b1) (2022-08-15) + +### Changed +- Optional: Module `md.py` can be compiled using Mypyc to provide an extra speedup up to 4x faster than v2.1 + +### Removed +- Breaking: Class aliases CharsetDetector, CharsetDoctor, CharsetNormalizerMatch and CharsetNormalizerMatches +- Breaking: Top-level function `normalize` +- Breaking: Properties `chaos_secondary_pass`, `coherence_non_latin` and `w_counter` from CharsetMatch +- Support for the backport `unicodedata2` + +## [2.1.1](https://github.com/Ousret/charset_normalizer/compare/2.1.0...2.1.1) (2022-08-19) + +### Deprecated +- Function `normalize` scheduled for removal in 3.0 + +### Changed +- Removed useless call to decode in fn is_unprintable (#206) + +### Fixed +- Third-party library (i18n xgettext) crashing not recognizing utf_8 (PEP 263) with underscore from [@aleksandernovikov](https://github.com/aleksandernovikov) (#204) + +## [2.1.0](https://github.com/Ousret/charset_normalizer/compare/2.0.12...2.1.0) (2022-06-19) + +### Added +- Output the Unicode table version when running the CLI with `--version` (PR #194) + +### Changed +- Re-use decoded buffer for single byte character sets from [@nijel](https://github.com/nijel) (PR #175) +- Fixing some performance bottlenecks from [@deedy5](https://github.com/deedy5) (PR #183) + +### Fixed +- Workaround potential bug in cpython with Zero Width No-Break Space located in Arabic Presentation Forms-B, Unicode 1.1 not acknowledged as space (PR #175) +- CLI default threshold aligned with the API threshold from [@oleksandr-kuzmenko](https://github.com/oleksandr-kuzmenko) (PR #181) + +### Removed +- Support for Python 3.5 (PR #192) + +### Deprecated +- Use of backport unicodedata from `unicodedata2` as Python is quickly catching up, scheduled for removal in 3.0 (PR #194) + +## [2.0.12](https://github.com/Ousret/charset_normalizer/compare/2.0.11...2.0.12) (2022-02-12) + +### Fixed +- ASCII miss-detection on rare cases (PR #170) + +## [2.0.11](https://github.com/Ousret/charset_normalizer/compare/2.0.10...2.0.11) (2022-01-30) + +### Added +- Explicit support for Python 3.11 (PR #164) + +### Changed +- The logging behavior have been completely reviewed, now using only TRACE and DEBUG levels (PR #163 #165) + +## [2.0.10](https://github.com/Ousret/charset_normalizer/compare/2.0.9...2.0.10) (2022-01-04) + +### Fixed +- Fallback match entries might lead to UnicodeDecodeError for large bytes sequence (PR #154) + +### Changed +- Skipping the language-detection (CD) on ASCII (PR #155) + +## [2.0.9](https://github.com/Ousret/charset_normalizer/compare/2.0.8...2.0.9) (2021-12-03) + +### Changed +- Moderating the logging impact (since 2.0.8) for specific environments (PR #147) + +### Fixed +- Wrong logging level applied when setting kwarg `explain` to True (PR #146) + +## [2.0.8](https://github.com/Ousret/charset_normalizer/compare/2.0.7...2.0.8) (2021-11-24) +### Changed +- Improvement over Vietnamese detection (PR #126) +- MD improvement on trailing data and long foreign (non-pure latin) data (PR #124) +- Efficiency improvements in cd/alphabet_languages from [@adbar](https://github.com/adbar) (PR #122) +- call sum() without an intermediary list following PEP 289 recommendations from [@adbar](https://github.com/adbar) (PR #129) +- Code style as refactored by Sourcery-AI (PR #131) +- Minor adjustment on the MD around european words (PR #133) +- Remove and replace SRTs from assets / tests (PR #139) +- Initialize the library logger with a `NullHandler` by default from [@nmaynes](https://github.com/nmaynes) (PR #135) +- Setting kwarg `explain` to True will add provisionally (bounded to function lifespan) a specific stream handler (PR #135) + +### Fixed +- Fix large (misleading) sequence giving UnicodeDecodeError (PR #137) +- Avoid using too insignificant chunk (PR #137) + +### Added +- Add and expose function `set_logging_handler` to configure a specific StreamHandler from [@nmaynes](https://github.com/nmaynes) (PR #135) +- Add `CHANGELOG.md` entries, format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) (PR #141) + +## [2.0.7](https://github.com/Ousret/charset_normalizer/compare/2.0.6...2.0.7) (2021-10-11) +### Added +- Add support for Kazakh (Cyrillic) language detection (PR #109) + +### Changed +- Further, improve inferring the language from a given single-byte code page (PR #112) +- Vainly trying to leverage PEP263 when PEP3120 is not supported (PR #116) +- Refactoring for potential performance improvements in loops from [@adbar](https://github.com/adbar) (PR #113) +- Various detection improvement (MD+CD) (PR #117) + +### Removed +- Remove redundant logging entry about detected language(s) (PR #115) + +### Fixed +- Fix a minor inconsistency between Python 3.5 and other versions regarding language detection (PR #117 #102) + +## [2.0.6](https://github.com/Ousret/charset_normalizer/compare/2.0.5...2.0.6) (2021-09-18) +### Fixed +- Unforeseen regression with the loss of the backward-compatibility with some older minor of Python 3.5.x (PR #100) +- Fix CLI crash when using --minimal output in certain cases (PR #103) + +### Changed +- Minor improvement to the detection efficiency (less than 1%) (PR #106 #101) + +## [2.0.5](https://github.com/Ousret/charset_normalizer/compare/2.0.4...2.0.5) (2021-09-14) +### Changed +- The project now comply with: flake8, mypy, isort and black to ensure a better overall quality (PR #81) +- The BC-support with v1.x was improved, the old staticmethods are restored (PR #82) +- The Unicode detection is slightly improved (PR #93) +- Add syntax sugar \_\_bool\_\_ for results CharsetMatches list-container (PR #91) + +### Removed +- The project no longer raise warning on tiny content given for detection, will be simply logged as warning instead (PR #92) + +### Fixed +- In some rare case, the chunks extractor could cut in the middle of a multi-byte character and could mislead the mess detection (PR #95) +- Some rare 'space' characters could trip up the UnprintablePlugin/Mess detection (PR #96) +- The MANIFEST.in was not exhaustive (PR #78) + +## [2.0.4](https://github.com/Ousret/charset_normalizer/compare/2.0.3...2.0.4) (2021-07-30) +### Fixed +- The CLI no longer raise an unexpected exception when no encoding has been found (PR #70) +- Fix accessing the 'alphabets' property when the payload contains surrogate characters (PR #68) +- The logger could mislead (explain=True) on detected languages and the impact of one MBCS match (PR #72) +- Submatch factoring could be wrong in rare edge cases (PR #72) +- Multiple files given to the CLI were ignored when publishing results to STDOUT. (After the first path) (PR #72) +- Fix line endings from CRLF to LF for certain project files (PR #67) + +### Changed +- Adjust the MD to lower the sensitivity, thus improving the global detection reliability (PR #69 #76) +- Allow fallback on specified encoding if any (PR #71) + +## [2.0.3](https://github.com/Ousret/charset_normalizer/compare/2.0.2...2.0.3) (2021-07-16) +### Changed +- Part of the detection mechanism has been improved to be less sensitive, resulting in more accurate detection results. Especially ASCII. (PR #63) +- According to the community wishes, the detection will fall back on ASCII or UTF-8 in a last-resort case. (PR #64) + +## [2.0.2](https://github.com/Ousret/charset_normalizer/compare/2.0.1...2.0.2) (2021-07-15) +### Fixed +- Empty/Too small JSON payload miss-detection fixed. Report from [@tseaver](https://github.com/tseaver) (PR #59) + +### Changed +- Don't inject unicodedata2 into sys.modules from [@akx](https://github.com/akx) (PR #57) + +## [2.0.1](https://github.com/Ousret/charset_normalizer/compare/2.0.0...2.0.1) (2021-07-13) +### Fixed +- Make it work where there isn't a filesystem available, dropping assets frequencies.json. Report from [@sethmlarson](https://github.com/sethmlarson). (PR #55) +- Using explain=False permanently disable the verbose output in the current runtime (PR #47) +- One log entry (language target preemptive) was not show in logs when using explain=True (PR #47) +- Fix undesired exception (ValueError) on getitem of instance CharsetMatches (PR #52) + +### Changed +- Public function normalize default args values were not aligned with from_bytes (PR #53) + +### Added +- You may now use charset aliases in cp_isolation and cp_exclusion arguments (PR #47) + +## [2.0.0](https://github.com/Ousret/charset_normalizer/compare/1.4.1...2.0.0) (2021-07-02) +### Changed +- 4x to 5 times faster than the previous 1.4.0 release. At least 2x faster than Chardet. +- Accent has been made on UTF-8 detection, should perform rather instantaneous. +- The backward compatibility with Chardet has been greatly improved. The legacy detect function returns an identical charset name whenever possible. +- The detection mechanism has been slightly improved, now Turkish content is detected correctly (most of the time) +- The program has been rewritten to ease the readability and maintainability. (+Using static typing)+ +- utf_7 detection has been reinstated. + +### Removed +- This package no longer require anything when used with Python 3.5 (Dropped cached_property) +- Removed support for these languages: Catalan, Esperanto, Kazakh, Baque, Volapük, Azeri, Galician, Nynorsk, Macedonian, and Serbocroatian. +- The exception hook on UnicodeDecodeError has been removed. + +### Deprecated +- Methods coherence_non_latin, w_counter, chaos_secondary_pass of the class CharsetMatch are now deprecated and scheduled for removal in v3.0 + +### Fixed +- The CLI output used the relative path of the file(s). Should be absolute. + +## [1.4.1](https://github.com/Ousret/charset_normalizer/compare/1.4.0...1.4.1) (2021-05-28) +### Fixed +- Logger configuration/usage no longer conflict with others (PR #44) + +## [1.4.0](https://github.com/Ousret/charset_normalizer/compare/1.3.9...1.4.0) (2021-05-21) +### Removed +- Using standard logging instead of using the package loguru. +- Dropping nose test framework in favor of the maintained pytest. +- Choose to not use dragonmapper package to help with gibberish Chinese/CJK text. +- Require cached_property only for Python 3.5 due to constraint. Dropping for every other interpreter version. +- Stop support for UTF-7 that does not contain a SIG. +- Dropping PrettyTable, replaced with pure JSON output in CLI. + +### Fixed +- BOM marker in a CharsetNormalizerMatch instance could be False in rare cases even if obviously present. Due to the sub-match factoring process. +- Not searching properly for the BOM when trying utf32/16 parent codec. + +### Changed +- Improving the package final size by compressing frequencies.json. +- Huge improvement over the larges payload. + +### Added +- CLI now produces JSON consumable output. +- Return ASCII if given sequences fit. Given reasonable confidence. + +## [1.3.9](https://github.com/Ousret/charset_normalizer/compare/1.3.8...1.3.9) (2021-05-13) + +### Fixed +- In some very rare cases, you may end up getting encode/decode errors due to a bad bytes payload (PR #40) + +## [1.3.8](https://github.com/Ousret/charset_normalizer/compare/1.3.7...1.3.8) (2021-05-12) + +### Fixed +- Empty given payload for detection may cause an exception if trying to access the `alphabets` property. (PR #39) + +## [1.3.7](https://github.com/Ousret/charset_normalizer/compare/1.3.6...1.3.7) (2021-05-12) + +### Fixed +- The legacy detect function should return UTF-8-SIG if sig is present in the payload. (PR #38) + +## [1.3.6](https://github.com/Ousret/charset_normalizer/compare/1.3.5...1.3.6) (2021-02-09) + +### Changed +- Amend the previous release to allow prettytable 2.0 (PR #35) + +## [1.3.5](https://github.com/Ousret/charset_normalizer/compare/1.3.4...1.3.5) (2021-02-08) + +### Fixed +- Fix error while using the package with a python pre-release interpreter (PR #33) + +### Changed +- Dependencies refactoring, constraints revised. + +### Added +- Add python 3.9 and 3.10 to the supported interpreters + +MIT License + +Copyright (c) 2025 TAHRI Ahmed R. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/RECORD b/venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/RECORD new file mode 100644 index 00000000..a6deed73 --- /dev/null +++ b/venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/RECORD @@ -0,0 +1,35 @@ +../../../bin/normalizer,sha256=dQi52WmoDZHF8ILPm8ppDc6AKz_bCNv7vuiFZIACC7I,328 +charset_normalizer-3.4.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +charset_normalizer-3.4.2.dist-info/METADATA,sha256=zNVWE4rQW-YZIMHKSayMypu37bLj_xayLorHl0-HAHQ,35743 +charset_normalizer-3.4.2.dist-info/RECORD,, +charset_normalizer-3.4.2.dist-info/WHEEL,sha256=trQsVbquLi1cIwkTyYa3WiXxabfsY-nlwY08-Yh9cWM,142 +charset_normalizer-3.4.2.dist-info/entry_points.txt,sha256=8C-Y3iXIfyXQ83Tpir2B8t-XLJYpxF5xbb38d_js-h4,65 +charset_normalizer-3.4.2.dist-info/licenses/LICENSE,sha256=bQ1Bv-FwrGx9wkjJpj4lTQ-0WmDVCoJX0K-SxuJJuIc,1071 +charset_normalizer-3.4.2.dist-info/top_level.txt,sha256=7ASyzePr8_xuZWJsnqJjIBtyV8vhEo0wBCv1MPRRi3Q,19 +charset_normalizer/__init__.py,sha256=OKRxRv2Zhnqk00tqkN0c1BtJjm165fWXLydE52IKuHc,1590 +charset_normalizer/__main__.py,sha256=yzYxMR-IhKRHYwcSlavEv8oGdwxsR89mr2X09qXGdps,109 +charset_normalizer/__pycache__/__init__.cpython-312.pyc,, +charset_normalizer/__pycache__/__main__.cpython-312.pyc,, +charset_normalizer/__pycache__/api.cpython-312.pyc,, +charset_normalizer/__pycache__/cd.cpython-312.pyc,, +charset_normalizer/__pycache__/constant.cpython-312.pyc,, +charset_normalizer/__pycache__/legacy.cpython-312.pyc,, +charset_normalizer/__pycache__/md.cpython-312.pyc,, +charset_normalizer/__pycache__/models.cpython-312.pyc,, +charset_normalizer/__pycache__/utils.cpython-312.pyc,, +charset_normalizer/__pycache__/version.cpython-312.pyc,, +charset_normalizer/api.py,sha256=qBRz8mJ_R5E713R6TOyqHEdnmyxbEDnCSHvx32ubDGg,22617 +charset_normalizer/cd.py,sha256=WKTo1HDb-H9HfCDc3Bfwq5jzS25Ziy9SE2a74SgTq88,12522 +charset_normalizer/cli/__init__.py,sha256=D8I86lFk2-py45JvqxniTirSj_sFyE6sjaY_0-G1shc,136 +charset_normalizer/cli/__main__.py,sha256=dMaXG6IJXRvqq8z2tig7Qb83-BpWTln55ooiku5_uvg,12646 +charset_normalizer/cli/__pycache__/__init__.cpython-312.pyc,, +charset_normalizer/cli/__pycache__/__main__.cpython-312.pyc,, +charset_normalizer/constant.py,sha256=7UVY4ldYhmQMHUdgQ_sgZmzcQ0xxYxpBunqSZ-XJZ8U,42713 +charset_normalizer/legacy.py,sha256=SZE_AJujOYB1y9Y3-FkFOW9Ye4H1EHTzPbZR8DEsgl8,2287 +charset_normalizer/md.cpython-312-darwin.so,sha256=ChECUH0FslhnG1PYcO5o6aM-2oZCkaUWT25s4jvxGfg,115744 +charset_normalizer/md.py,sha256=-_oN3h3_X99nkFfqamD3yu45DC_wfk5odH0Tr_CQiXs,20145 +charset_normalizer/md__mypyc.cpython-312-darwin.so,sha256=3tyG4nI1jhJk7LQNKEFtDdrxVWy6ZWKbUl_0BthNaBk,482040 +charset_normalizer/models.py,sha256=lKXhOnIPtiakbK3i__J9wpOfzx3JDTKj7Dn3Rg0VaRI,12394 +charset_normalizer/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +charset_normalizer/utils.py,sha256=sTejPgrdlNsKNucZfJCxJ95lMTLA0ShHLLE3n5wpT9Q,12170 +charset_normalizer/version.py,sha256=koLXlDwKAU5IlYP4qkOpFnsncn74hlphHAlBhlDKzyw,115 diff --git a/venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/WHEEL b/venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/WHEEL new file mode 100644 index 00000000..7c430659 --- /dev/null +++ b/venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: setuptools (80.1.0) +Root-Is-Purelib: false +Tag: cp312-cp312-macosx_10_13_universal2 +Generator: delocate 0.13.0 + diff --git a/venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/entry_points.txt b/venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/entry_points.txt new file mode 100644 index 00000000..ec920125 --- /dev/null +++ b/venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/entry_points.txt @@ -0,0 +1,2 @@ +[console_scripts] +normalizer = charset_normalizer:cli.cli_detect diff --git a/venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/licenses/LICENSE b/venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/licenses/LICENSE new file mode 100644 index 00000000..9725772c --- /dev/null +++ b/venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/licenses/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 TAHRI Ahmed R. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/top_level.txt b/venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/top_level.txt new file mode 100644 index 00000000..66958f0a --- /dev/null +++ b/venv/lib/python3.12/site-packages/charset_normalizer-3.4.2.dist-info/top_level.txt @@ -0,0 +1 @@ +charset_normalizer diff --git a/venv/lib/python3.12/site-packages/charset_normalizer/__init__.py b/venv/lib/python3.12/site-packages/charset_normalizer/__init__.py new file mode 100644 index 00000000..0d3a3799 --- /dev/null +++ b/venv/lib/python3.12/site-packages/charset_normalizer/__init__.py @@ -0,0 +1,48 @@ +""" +Charset-Normalizer +~~~~~~~~~~~~~~ +The Real First Universal Charset Detector. +A library that helps you read text from an unknown charset encoding. +Motivated by chardet, This package is trying to resolve the issue by taking a new approach. +All IANA character set names for which the Python core library provides codecs are supported. + +Basic usage: + >>> from charset_normalizer import from_bytes + >>> results = from_bytes('Bсеки човек има право на образование. Oбразованието!'.encode('utf_8')) + >>> best_guess = results.best() + >>> str(best_guess) + 'Bсеки човек има право на образование. Oбразованието!' + +Others methods and usages are available - see the full documentation +at . +:copyright: (c) 2021 by Ahmed TAHRI +:license: MIT, see LICENSE for more details. +""" + +from __future__ import annotations + +import logging + +from .api import from_bytes, from_fp, from_path, is_binary +from .legacy import detect +from .models import CharsetMatch, CharsetMatches +from .utils import set_logging_handler +from .version import VERSION, __version__ + +__all__ = ( + "from_fp", + "from_path", + "from_bytes", + "is_binary", + "detect", + "CharsetMatch", + "CharsetMatches", + "__version__", + "VERSION", + "set_logging_handler", +) + +# Attach a NullHandler to the top level logger by default +# https://docs.python.org/3.3/howto/logging.html#configuring-logging-for-a-library + +logging.getLogger("charset_normalizer").addHandler(logging.NullHandler()) diff --git a/venv/lib/python3.12/site-packages/charset_normalizer/__main__.py b/venv/lib/python3.12/site-packages/charset_normalizer/__main__.py new file mode 100644 index 00000000..e0e76f7b --- /dev/null +++ b/venv/lib/python3.12/site-packages/charset_normalizer/__main__.py @@ -0,0 +1,6 @@ +from __future__ import annotations + +from .cli import cli_detect + +if __name__ == "__main__": + cli_detect() diff --git a/venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..30fd920edc39ba9308fc891137fea637c14231ef GIT binary patch literal 1810 zcmcIky>A>v6ra62-`RV%gY5zdDPj;(dPdwQ97fDCKYdX@9dzYWsA4(y?Jlm?|sdm zV`Dmk?~m`Ux*wJidZL8ESIQafc>>J$$U!D@G^fBczhD+L#TQx8EIK7;h?V>ybI327 zWxrxp{9$t#&Pz_2jrh8$XMBZK{ZVt&A2Y`?d6PdC(H?d(wqcYH>V1S z7Vp#sKra7I^}d!%ciz9$4!F!~W*}Yu@Auh(uZFtC`e=Nwh>*VQ5-zBm-3+-;n0J?Q z{j2|c`mRgyHYE(NdR$1n7kC}Y1;~9@{0WuRmLYHGOPF~rPIwnfmq_eV775%9W6UXW zu%ur~yw5`)lK{uTK@c7W*v{i)8rY%Z1?`5u5lXK^Bz17Bn;kn;&fs0w6F4IF0cleV ztmIv=#xjJvMaVi7LaGB1Q{^YgfjTBQpof@55f6#&0zk&_`qJi7b}z9dhXK4i&RmPsL+_Gb<)s<8X93Y>VNr69p>8v(=tM_&CAo(RZ!M$&j)8r>5;N&Fv zH95w~@4chs7<8vN`Ax~E$&Z=l=gjgLlqbo92Htv|x_2)*eP_Cn)t}a;W4UkLn6B3c zXj)WAs~uCJ0QI3Yl(KeVA|$U}nq}($8?LTzLA$xYK7}qh(22mw>z+4-bcn}Di%~oa z4bEp{KZfQzp&k1)kVJZ6pu>#bbft_$(=ghebmLaT4t--Q7Mx1s)ut^r^rjs~UGBAA z*~B%wj_0q>f1a($TC-KDkdb-l?vn+Ae5@y7b@Oa|cg`tr)=&Pq08z8WbQYJeyj z`ZKkhbuF!uAP93@V)L2W@_H%N)w<;4kybK(KT1b3CL+>JM?7J*yZ|;1ZYaZ@u!!|S zI@({&4I*tf9e-J(0xYLs=q(nu+pr^+3$jiWLS|AMbz8LtBQ;(GN#BVkaY6Z+ST7oE0zWIx2#mRto>NVoLUx#M+l{rKA5yf zA}^0}8C1nf%Z#>(-Ob{rWgqsBiOcxuP%NREdGJafdyYpTQ;`W{5P76cC~| zvzF(cRyScd`oa(BIk=z~-xzxWieP{Vr-yfKmj=ep?5A?yKL=!zUkxX7YL(>n@d=Jeh3#-Q;JzQArEv%j`to?=7`Bk|2U#K`~IRF3v literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/__main__.cpython-312.pyc b/venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/__main__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..30049eb41f9df52d94ed53ead4c1c0df83bce181 GIT binary patch literal 385 zcmXv}F-rq66izO8Qd;V+QYcP#XhSQCgSfbf2y(b|3F#&FLhq6z$yKha2rkb42JxTh z=H`JQh(otRw@&7$eZ%*@@4fFm-g|F0>%hg^Q!7qg{;9+!yfuN#V@I9=0}Li0g+mAd z^B79J6b%ss+-Lse003R{07tL?(-0Iv5p=fZmF~c@L8VldTA`$w!*#75C4w++d1T8P zAt@D-kgHBm)(N@IZLT>X8aZ!?oKpuCb3RE^*LVR-r@`tT-x#h9rjluXH;ZB}aoD}c zrBE7&nHF-~zRsz(T;ubw-9H-O$T%D+Yr12t^6Ugpxt!uejBr-iSjod)e}Ij!yqnQz zLdV?TD5lzQOQg~%O~lMC+Z^1>idF42RV+{VnQpq9s`pIG!2&@Dzrg-4*!xC}$Jqzk Q`SiCRE*A*+ySm{Ve<=ZM3IG5A literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/api.cpython-312.pyc b/venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/api.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5862b2db2ea3b38737385df541d5e81031554fb6 GIT binary patch literal 18199 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

    59dYmek= zkK}8QE%JzyVNb0#u7ytJTTW3=a;GRmKm+kYUpzrf8rm{H7~t4L>N;_|mAQmOcUk=$>E*^6Nh4aCwW z3f*%qQdH89$Jh?E_k`6uE!W+X@l+&@H$ z$#s~R@Qc$UVXou_|Bh7q8M*y?+~#n^ND;H*NGd6pH15>P#>Xc!W+k@l+zAy@L5K0WNx}Ula3)xlqWqpLyt|6dAQ1cbGyf`)elj_e}8DOvkU8 z7W!ZKA6*{S@jn@I^E2$=ubK9LbXYmtl_A!%eU%m1n$MdV2mk%XEk}?&u(pyoOMGeCL1HNcPDgXcg literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/constant.cpython-312.pyc b/venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/constant.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..17ab1afe1b93b1f62d4f3a6e9debed43a7d81382 GIT binary patch literal 40840 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

    *3u^YaQ=9TkH6!qqUBA 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 uLCtmloJlXXIXgggIW;a{2{$sb=mbbF; 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 a=Xn>I9$XY{!g+pc>*a^}k2p%%w*Ei(`H@cm literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/utils.cpython-312.pyc b/venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/utils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e885ab403fb79abaf5d12651f8248f580be47c0a GIT binary patch literal 13786 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 CharsetMatches: + """ + Given a raw bytes sequence, return the best possibles charset usable to render str objects. + If there is no results, it is a strong indicator that the source is binary/not text. + By default, the process will extract 5 blocks of 512o each to assess the mess and coherence of a given sequence. + And will give up a particular code page after 20% of measured mess. Those criteria are customizable at will. + + The preemptive behavior DOES NOT replace the traditional detection workflow, it prioritize a particular code page + but never take it for granted. Can improve the performance. + + You may want to focus your attention to some code page or/and not others, use cp_isolation and cp_exclusion for that + purpose. + + This function will strip the SIG in the payload/sequence every time except on UTF-16, UTF-32. + By default the library does not setup any handler other than the NullHandler, if you choose to set the 'explain' + toggle to True it will alter the logger configuration to add a StreamHandler that is suitable for debugging. + Custom logging format and handler can be set manually. + """ + + if not isinstance(sequences, (bytearray, bytes)): + raise TypeError( + "Expected object of type bytes or bytearray, got: {}".format( + type(sequences) + ) + ) + + if explain: + previous_logger_level: int = logger.level + logger.addHandler(explain_handler) + logger.setLevel(TRACE) + + length: int = len(sequences) + + if length == 0: + logger.debug("Encoding detection on empty bytes, assuming utf_8 intention.") + if explain: # Defensive: ensure exit path clean handler + logger.removeHandler(explain_handler) + logger.setLevel(previous_logger_level or logging.WARNING) + return CharsetMatches([CharsetMatch(sequences, "utf_8", 0.0, False, [], "")]) + + if cp_isolation is not None: + logger.log( + TRACE, + "cp_isolation is set. use this flag for debugging purpose. " + "limited list of encoding allowed : %s.", + ", ".join(cp_isolation), + ) + cp_isolation = [iana_name(cp, False) for cp in cp_isolation] + else: + cp_isolation = [] + + if cp_exclusion is not None: + logger.log( + TRACE, + "cp_exclusion is set. use this flag for debugging purpose. " + "limited list of encoding excluded : %s.", + ", ".join(cp_exclusion), + ) + cp_exclusion = [iana_name(cp, False) for cp in cp_exclusion] + else: + cp_exclusion = [] + + if length <= (chunk_size * steps): + logger.log( + TRACE, + "override steps (%i) and chunk_size (%i) as content does not fit (%i byte(s) given) parameters.", + steps, + chunk_size, + length, + ) + steps = 1 + chunk_size = length + + if steps > 1 and length / steps < chunk_size: + chunk_size = int(length / steps) + + is_too_small_sequence: bool = len(sequences) < TOO_SMALL_SEQUENCE + is_too_large_sequence: bool = len(sequences) >= TOO_BIG_SEQUENCE + + if is_too_small_sequence: + logger.log( + TRACE, + "Trying to detect encoding from a tiny portion of ({}) byte(s).".format( + length + ), + ) + elif is_too_large_sequence: + logger.log( + TRACE, + "Using lazy str decoding because the payload is quite large, ({}) byte(s).".format( + length + ), + ) + + prioritized_encodings: list[str] = [] + + specified_encoding: str | None = ( + any_specified_encoding(sequences) if preemptive_behaviour else None + ) + + if specified_encoding is not None: + prioritized_encodings.append(specified_encoding) + logger.log( + TRACE, + "Detected declarative mark in sequence. Priority +1 given for %s.", + specified_encoding, + ) + + tested: set[str] = set() + tested_but_hard_failure: list[str] = [] + tested_but_soft_failure: list[str] = [] + + fallback_ascii: CharsetMatch | None = None + fallback_u8: CharsetMatch | None = None + fallback_specified: CharsetMatch | None = None + + results: CharsetMatches = CharsetMatches() + + early_stop_results: CharsetMatches = CharsetMatches() + + sig_encoding, sig_payload = identify_sig_or_bom(sequences) + + if sig_encoding is not None: + prioritized_encodings.append(sig_encoding) + logger.log( + TRACE, + "Detected a SIG or BOM mark on first %i byte(s). Priority +1 given for %s.", + len(sig_payload), + sig_encoding, + ) + + prioritized_encodings.append("ascii") + + if "utf_8" not in prioritized_encodings: + prioritized_encodings.append("utf_8") + + for encoding_iana in prioritized_encodings + IANA_SUPPORTED: + if cp_isolation and encoding_iana not in cp_isolation: + continue + + if cp_exclusion and encoding_iana in cp_exclusion: + continue + + if encoding_iana in tested: + continue + + tested.add(encoding_iana) + + decoded_payload: str | None = None + bom_or_sig_available: bool = sig_encoding == encoding_iana + strip_sig_or_bom: bool = bom_or_sig_available and should_strip_sig_or_bom( + encoding_iana + ) + + if encoding_iana in {"utf_16", "utf_32"} and not bom_or_sig_available: + logger.log( + TRACE, + "Encoding %s won't be tested as-is because it require a BOM. Will try some sub-encoder LE/BE.", + encoding_iana, + ) + continue + if encoding_iana in {"utf_7"} and not bom_or_sig_available: + logger.log( + TRACE, + "Encoding %s won't be tested as-is because detection is unreliable without BOM/SIG.", + encoding_iana, + ) + continue + + try: + is_multi_byte_decoder: bool = is_multi_byte_encoding(encoding_iana) + except (ModuleNotFoundError, ImportError): + logger.log( + TRACE, + "Encoding %s does not provide an IncrementalDecoder", + encoding_iana, + ) + continue + + try: + if is_too_large_sequence and is_multi_byte_decoder is False: + str( + ( + sequences[: int(50e4)] + if strip_sig_or_bom is False + else sequences[len(sig_payload) : int(50e4)] + ), + encoding=encoding_iana, + ) + else: + decoded_payload = str( + ( + sequences + if strip_sig_or_bom is False + else sequences[len(sig_payload) :] + ), + encoding=encoding_iana, + ) + except (UnicodeDecodeError, LookupError) as e: + if not isinstance(e, LookupError): + logger.log( + TRACE, + "Code page %s does not fit given bytes sequence at ALL. %s", + encoding_iana, + str(e), + ) + tested_but_hard_failure.append(encoding_iana) + continue + + similar_soft_failure_test: bool = False + + for encoding_soft_failed in tested_but_soft_failure: + if is_cp_similar(encoding_iana, encoding_soft_failed): + similar_soft_failure_test = True + break + + if similar_soft_failure_test: + logger.log( + TRACE, + "%s is deemed too similar to code page %s and was consider unsuited already. Continuing!", + encoding_iana, + encoding_soft_failed, + ) + continue + + r_ = range( + 0 if not bom_or_sig_available else len(sig_payload), + length, + int(length / steps), + ) + + multi_byte_bonus: bool = ( + is_multi_byte_decoder + and decoded_payload is not None + and len(decoded_payload) < length + ) + + if multi_byte_bonus: + logger.log( + TRACE, + "Code page %s is a multi byte encoding table and it appear that at least one character " + "was encoded using n-bytes.", + encoding_iana, + ) + + max_chunk_gave_up: int = int(len(r_) / 4) + + max_chunk_gave_up = max(max_chunk_gave_up, 2) + early_stop_count: int = 0 + lazy_str_hard_failure = False + + md_chunks: list[str] = [] + md_ratios = [] + + try: + for chunk in cut_sequence_chunks( + sequences, + encoding_iana, + r_, + chunk_size, + bom_or_sig_available, + strip_sig_or_bom, + sig_payload, + is_multi_byte_decoder, + decoded_payload, + ): + md_chunks.append(chunk) + + md_ratios.append( + mess_ratio( + chunk, + threshold, + explain is True and 1 <= len(cp_isolation) <= 2, + ) + ) + + if md_ratios[-1] >= threshold: + early_stop_count += 1 + + if (early_stop_count >= max_chunk_gave_up) or ( + bom_or_sig_available and strip_sig_or_bom is False + ): + break + except ( + UnicodeDecodeError + ) as e: # Lazy str loading may have missed something there + logger.log( + TRACE, + "LazyStr Loading: After MD chunk decode, code page %s does not fit given bytes sequence at ALL. %s", + encoding_iana, + str(e), + ) + early_stop_count = max_chunk_gave_up + lazy_str_hard_failure = True + + # We might want to check the sequence again with the whole content + # Only if initial MD tests passes + if ( + not lazy_str_hard_failure + and is_too_large_sequence + and not is_multi_byte_decoder + ): + try: + sequences[int(50e3) :].decode(encoding_iana, errors="strict") + except UnicodeDecodeError as e: + logger.log( + TRACE, + "LazyStr Loading: After final lookup, code page %s does not fit given bytes sequence at ALL. %s", + encoding_iana, + str(e), + ) + tested_but_hard_failure.append(encoding_iana) + continue + + mean_mess_ratio: float = sum(md_ratios) / len(md_ratios) if md_ratios else 0.0 + if mean_mess_ratio >= threshold or early_stop_count >= max_chunk_gave_up: + tested_but_soft_failure.append(encoding_iana) + logger.log( + TRACE, + "%s was excluded because of initial chaos probing. Gave up %i time(s). " + "Computed mean chaos is %f %%.", + encoding_iana, + early_stop_count, + round(mean_mess_ratio * 100, ndigits=3), + ) + # Preparing those fallbacks in case we got nothing. + if ( + enable_fallback + and encoding_iana in ["ascii", "utf_8", specified_encoding] + and not lazy_str_hard_failure + ): + fallback_entry = CharsetMatch( + sequences, + encoding_iana, + threshold, + False, + [], + decoded_payload, + preemptive_declaration=specified_encoding, + ) + if encoding_iana == specified_encoding: + fallback_specified = fallback_entry + elif encoding_iana == "ascii": + fallback_ascii = fallback_entry + else: + fallback_u8 = fallback_entry + continue + + logger.log( + TRACE, + "%s passed initial chaos probing. Mean measured chaos is %f %%", + encoding_iana, + round(mean_mess_ratio * 100, ndigits=3), + ) + + if not is_multi_byte_decoder: + target_languages: list[str] = encoding_languages(encoding_iana) + else: + target_languages = mb_encoding_languages(encoding_iana) + + if target_languages: + logger.log( + TRACE, + "{} should target any language(s) of {}".format( + encoding_iana, str(target_languages) + ), + ) + + cd_ratios = [] + + # We shall skip the CD when its about ASCII + # Most of the time its not relevant to run "language-detection" on it. + if encoding_iana != "ascii": + for chunk in md_chunks: + chunk_languages = coherence_ratio( + chunk, + language_threshold, + ",".join(target_languages) if target_languages else None, + ) + + cd_ratios.append(chunk_languages) + + cd_ratios_merged = merge_coherence_ratios(cd_ratios) + + if cd_ratios_merged: + logger.log( + TRACE, + "We detected language {} using {}".format( + cd_ratios_merged, encoding_iana + ), + ) + + current_match = CharsetMatch( + sequences, + encoding_iana, + mean_mess_ratio, + bom_or_sig_available, + cd_ratios_merged, + ( + decoded_payload + if ( + is_too_large_sequence is False + or encoding_iana in [specified_encoding, "ascii", "utf_8"] + ) + else None + ), + preemptive_declaration=specified_encoding, + ) + + results.append(current_match) + + if ( + encoding_iana in [specified_encoding, "ascii", "utf_8"] + and mean_mess_ratio < 0.1 + ): + # If md says nothing to worry about, then... stop immediately! + if mean_mess_ratio == 0.0: + logger.debug( + "Encoding detection: %s is most likely the one.", + current_match.encoding, + ) + if explain: # Defensive: ensure exit path clean handler + logger.removeHandler(explain_handler) + logger.setLevel(previous_logger_level) + return CharsetMatches([current_match]) + + early_stop_results.append(current_match) + + if ( + len(early_stop_results) + and (specified_encoding is None or specified_encoding in tested) + and "ascii" in tested + and "utf_8" in tested + ): + probable_result: CharsetMatch = early_stop_results.best() # type: ignore[assignment] + logger.debug( + "Encoding detection: %s is most likely the one.", + probable_result.encoding, + ) + if explain: # Defensive: ensure exit path clean handler + logger.removeHandler(explain_handler) + logger.setLevel(previous_logger_level) + + return CharsetMatches([probable_result]) + + if encoding_iana == sig_encoding: + logger.debug( + "Encoding detection: %s is most likely the one as we detected a BOM or SIG within " + "the beginning of the sequence.", + encoding_iana, + ) + if explain: # Defensive: ensure exit path clean handler + logger.removeHandler(explain_handler) + logger.setLevel(previous_logger_level) + return CharsetMatches([results[encoding_iana]]) + + if len(results) == 0: + if fallback_u8 or fallback_ascii or fallback_specified: + logger.log( + TRACE, + "Nothing got out of the detection process. Using ASCII/UTF-8/Specified fallback.", + ) + + if fallback_specified: + logger.debug( + "Encoding detection: %s will be used as a fallback match", + fallback_specified.encoding, + ) + results.append(fallback_specified) + elif ( + (fallback_u8 and fallback_ascii is None) + or ( + fallback_u8 + and fallback_ascii + and fallback_u8.fingerprint != fallback_ascii.fingerprint + ) + or (fallback_u8 is not None) + ): + logger.debug("Encoding detection: utf_8 will be used as a fallback match") + results.append(fallback_u8) + elif fallback_ascii: + logger.debug("Encoding detection: ascii will be used as a fallback match") + results.append(fallback_ascii) + + if results: + logger.debug( + "Encoding detection: Found %s as plausible (best-candidate) for content. With %i alternatives.", + results.best().encoding, # type: ignore + len(results) - 1, + ) + else: + logger.debug("Encoding detection: Unable to determine any suitable charset.") + + if explain: + logger.removeHandler(explain_handler) + logger.setLevel(previous_logger_level) + + return results + + +def from_fp( + fp: BinaryIO, + steps: int = 5, + chunk_size: int = 512, + threshold: float = 0.20, + cp_isolation: list[str] | None = None, + cp_exclusion: list[str] | None = None, + preemptive_behaviour: bool = True, + explain: bool = False, + language_threshold: float = 0.1, + enable_fallback: bool = True, +) -> CharsetMatches: + """ + Same thing than the function from_bytes but using a file pointer that is already ready. + Will not close the file pointer. + """ + return from_bytes( + fp.read(), + steps, + chunk_size, + threshold, + cp_isolation, + cp_exclusion, + preemptive_behaviour, + explain, + language_threshold, + enable_fallback, + ) + + +def from_path( + path: str | bytes | PathLike, # type: ignore[type-arg] + steps: int = 5, + chunk_size: int = 512, + threshold: float = 0.20, + cp_isolation: list[str] | None = None, + cp_exclusion: list[str] | None = None, + preemptive_behaviour: bool = True, + explain: bool = False, + language_threshold: float = 0.1, + enable_fallback: bool = True, +) -> CharsetMatches: + """ + Same thing than the function from_bytes but with one extra step. Opening and reading given file path in binary mode. + Can raise IOError. + """ + with open(path, "rb") as fp: + return from_fp( + fp, + steps, + chunk_size, + threshold, + cp_isolation, + cp_exclusion, + preemptive_behaviour, + explain, + language_threshold, + enable_fallback, + ) + + +def is_binary( + fp_or_path_or_payload: PathLike | str | BinaryIO | bytes, # type: ignore[type-arg] + steps: int = 5, + chunk_size: int = 512, + threshold: float = 0.20, + cp_isolation: list[str] | None = None, + cp_exclusion: list[str] | None = None, + preemptive_behaviour: bool = True, + explain: bool = False, + language_threshold: float = 0.1, + enable_fallback: bool = False, +) -> bool: + """ + Detect if the given input (file, bytes, or path) points to a binary file. aka. not a string. + Based on the same main heuristic algorithms and default kwargs at the sole exception that fallbacks match + are disabled to be stricter around ASCII-compatible but unlikely to be a string. + """ + if isinstance(fp_or_path_or_payload, (str, PathLike)): + guesses = from_path( + fp_or_path_or_payload, + steps=steps, + chunk_size=chunk_size, + threshold=threshold, + cp_isolation=cp_isolation, + cp_exclusion=cp_exclusion, + preemptive_behaviour=preemptive_behaviour, + explain=explain, + language_threshold=language_threshold, + enable_fallback=enable_fallback, + ) + elif isinstance( + fp_or_path_or_payload, + ( + bytes, + bytearray, + ), + ): + guesses = from_bytes( + fp_or_path_or_payload, + steps=steps, + chunk_size=chunk_size, + threshold=threshold, + cp_isolation=cp_isolation, + cp_exclusion=cp_exclusion, + preemptive_behaviour=preemptive_behaviour, + explain=explain, + language_threshold=language_threshold, + enable_fallback=enable_fallback, + ) + else: + guesses = from_fp( + fp_or_path_or_payload, + steps=steps, + chunk_size=chunk_size, + threshold=threshold, + cp_isolation=cp_isolation, + cp_exclusion=cp_exclusion, + preemptive_behaviour=preemptive_behaviour, + explain=explain, + language_threshold=language_threshold, + enable_fallback=enable_fallback, + ) + + return not guesses diff --git a/venv/lib/python3.12/site-packages/charset_normalizer/cd.py b/venv/lib/python3.12/site-packages/charset_normalizer/cd.py new file mode 100644 index 00000000..71a3ed51 --- /dev/null +++ b/venv/lib/python3.12/site-packages/charset_normalizer/cd.py @@ -0,0 +1,395 @@ +from __future__ import annotations + +import importlib +from codecs import IncrementalDecoder +from collections import Counter +from functools import lru_cache +from typing import Counter as TypeCounter + +from .constant import ( + FREQUENCIES, + KO_NAMES, + LANGUAGE_SUPPORTED_COUNT, + TOO_SMALL_SEQUENCE, + ZH_NAMES, +) +from .md import is_suspiciously_successive_range +from .models import CoherenceMatches +from .utils import ( + is_accentuated, + is_latin, + is_multi_byte_encoding, + is_unicode_range_secondary, + unicode_range, +) + + +def encoding_unicode_range(iana_name: str) -> list[str]: + """ + Return associated unicode ranges in a single byte code page. + """ + if is_multi_byte_encoding(iana_name): + raise OSError("Function not supported on multi-byte code page") + + decoder = importlib.import_module(f"encodings.{iana_name}").IncrementalDecoder + + p: IncrementalDecoder = decoder(errors="ignore") + seen_ranges: dict[str, int] = {} + character_count: int = 0 + + for i in range(0x40, 0xFF): + chunk: str = p.decode(bytes([i])) + + if chunk: + character_range: str | None = unicode_range(chunk) + + if character_range is None: + continue + + if is_unicode_range_secondary(character_range) is False: + if character_range not in seen_ranges: + seen_ranges[character_range] = 0 + seen_ranges[character_range] += 1 + character_count += 1 + + return sorted( + [ + character_range + for character_range in seen_ranges + if seen_ranges[character_range] / character_count >= 0.15 + ] + ) + + +def unicode_range_languages(primary_range: str) -> list[str]: + """ + Return inferred languages used with a unicode range. + """ + languages: list[str] = [] + + for language, characters in FREQUENCIES.items(): + for character in characters: + if unicode_range(character) == primary_range: + languages.append(language) + break + + return languages + + +@lru_cache() +def encoding_languages(iana_name: str) -> list[str]: + """ + Single-byte encoding language association. Some code page are heavily linked to particular language(s). + This function does the correspondence. + """ + unicode_ranges: list[str] = encoding_unicode_range(iana_name) + primary_range: str | None = None + + for specified_range in unicode_ranges: + if "Latin" not in specified_range: + primary_range = specified_range + break + + if primary_range is None: + return ["Latin Based"] + + return unicode_range_languages(primary_range) + + +@lru_cache() +def mb_encoding_languages(iana_name: str) -> list[str]: + """ + Multi-byte encoding language association. Some code page are heavily linked to particular language(s). + This function does the correspondence. + """ + if ( + iana_name.startswith("shift_") + or iana_name.startswith("iso2022_jp") + or iana_name.startswith("euc_j") + or iana_name == "cp932" + ): + return ["Japanese"] + if iana_name.startswith("gb") or iana_name in ZH_NAMES: + return ["Chinese"] + if iana_name.startswith("iso2022_kr") or iana_name in KO_NAMES: + return ["Korean"] + + return [] + + +@lru_cache(maxsize=LANGUAGE_SUPPORTED_COUNT) +def get_target_features(language: str) -> tuple[bool, bool]: + """ + Determine main aspects from a supported language if it contains accents and if is pure Latin. + """ + target_have_accents: bool = False + target_pure_latin: bool = True + + for character in FREQUENCIES[language]: + if not target_have_accents and is_accentuated(character): + target_have_accents = True + if target_pure_latin and is_latin(character) is False: + target_pure_latin = False + + return target_have_accents, target_pure_latin + + +def alphabet_languages( + characters: list[str], ignore_non_latin: bool = False +) -> list[str]: + """ + Return associated languages associated to given characters. + """ + languages: list[tuple[str, float]] = [] + + source_have_accents = any(is_accentuated(character) for character in characters) + + for language, language_characters in FREQUENCIES.items(): + target_have_accents, target_pure_latin = get_target_features(language) + + if ignore_non_latin and target_pure_latin is False: + continue + + if target_have_accents is False and source_have_accents: + continue + + character_count: int = len(language_characters) + + character_match_count: int = len( + [c for c in language_characters if c in characters] + ) + + ratio: float = character_match_count / character_count + + if ratio >= 0.2: + languages.append((language, ratio)) + + languages = sorted(languages, key=lambda x: x[1], reverse=True) + + return [compatible_language[0] for compatible_language in languages] + + +def characters_popularity_compare( + language: str, ordered_characters: list[str] +) -> float: + """ + Determine if a ordered characters list (by occurrence from most appearance to rarest) match a particular language. + The result is a ratio between 0. (absolutely no correspondence) and 1. (near perfect fit). + Beware that is function is not strict on the match in order to ease the detection. (Meaning close match is 1.) + """ + if language not in FREQUENCIES: + raise ValueError(f"{language} not available") + + character_approved_count: int = 0 + FREQUENCIES_language_set = set(FREQUENCIES[language]) + + ordered_characters_count: int = len(ordered_characters) + target_language_characters_count: int = len(FREQUENCIES[language]) + + large_alphabet: bool = target_language_characters_count > 26 + + for character, character_rank in zip( + ordered_characters, range(0, ordered_characters_count) + ): + if character not in FREQUENCIES_language_set: + continue + + character_rank_in_language: int = FREQUENCIES[language].index(character) + expected_projection_ratio: float = ( + target_language_characters_count / ordered_characters_count + ) + character_rank_projection: int = int(character_rank * expected_projection_ratio) + + if ( + large_alphabet is False + and abs(character_rank_projection - character_rank_in_language) > 4 + ): + continue + + if ( + large_alphabet is True + and abs(character_rank_projection - character_rank_in_language) + < target_language_characters_count / 3 + ): + character_approved_count += 1 + continue + + characters_before_source: list[str] = FREQUENCIES[language][ + 0:character_rank_in_language + ] + characters_after_source: list[str] = FREQUENCIES[language][ + character_rank_in_language: + ] + characters_before: list[str] = ordered_characters[0:character_rank] + characters_after: list[str] = ordered_characters[character_rank:] + + before_match_count: int = len( + set(characters_before) & set(characters_before_source) + ) + + after_match_count: int = len( + set(characters_after) & set(characters_after_source) + ) + + if len(characters_before_source) == 0 and before_match_count <= 4: + character_approved_count += 1 + continue + + if len(characters_after_source) == 0 and after_match_count <= 4: + character_approved_count += 1 + continue + + if ( + before_match_count / len(characters_before_source) >= 0.4 + or after_match_count / len(characters_after_source) >= 0.4 + ): + character_approved_count += 1 + continue + + return character_approved_count / len(ordered_characters) + + +def alpha_unicode_split(decoded_sequence: str) -> list[str]: + """ + Given a decoded text sequence, return a list of str. Unicode range / alphabet separation. + Ex. a text containing English/Latin with a bit a Hebrew will return two items in the resulting list; + One containing the latin letters and the other hebrew. + """ + layers: dict[str, str] = {} + + for character in decoded_sequence: + if character.isalpha() is False: + continue + + character_range: str | None = unicode_range(character) + + if character_range is None: + continue + + layer_target_range: str | None = None + + for discovered_range in layers: + if ( + is_suspiciously_successive_range(discovered_range, character_range) + is False + ): + layer_target_range = discovered_range + break + + if layer_target_range is None: + layer_target_range = character_range + + if layer_target_range not in layers: + layers[layer_target_range] = character.lower() + continue + + layers[layer_target_range] += character.lower() + + return list(layers.values()) + + +def merge_coherence_ratios(results: list[CoherenceMatches]) -> CoherenceMatches: + """ + This function merge results previously given by the function coherence_ratio. + The return type is the same as coherence_ratio. + """ + per_language_ratios: dict[str, list[float]] = {} + for result in results: + for sub_result in result: + language, ratio = sub_result + if language not in per_language_ratios: + per_language_ratios[language] = [ratio] + continue + per_language_ratios[language].append(ratio) + + merge = [ + ( + language, + round( + sum(per_language_ratios[language]) / len(per_language_ratios[language]), + 4, + ), + ) + for language in per_language_ratios + ] + + return sorted(merge, key=lambda x: x[1], reverse=True) + + +def filter_alt_coherence_matches(results: CoherenceMatches) -> CoherenceMatches: + """ + We shall NOT return "English—" in CoherenceMatches because it is an alternative + of "English". This function only keeps the best match and remove the em-dash in it. + """ + index_results: dict[str, list[float]] = dict() + + for result in results: + language, ratio = result + no_em_name: str = language.replace("—", "") + + if no_em_name not in index_results: + index_results[no_em_name] = [] + + index_results[no_em_name].append(ratio) + + if any(len(index_results[e]) > 1 for e in index_results): + filtered_results: CoherenceMatches = [] + + for language in index_results: + filtered_results.append((language, max(index_results[language]))) + + return filtered_results + + return results + + +@lru_cache(maxsize=2048) +def coherence_ratio( + decoded_sequence: str, threshold: float = 0.1, lg_inclusion: str | None = None +) -> CoherenceMatches: + """ + Detect ANY language that can be identified in given sequence. The sequence will be analysed by layers. + A layer = Character extraction by alphabets/ranges. + """ + + results: list[tuple[str, float]] = [] + ignore_non_latin: bool = False + + sufficient_match_count: int = 0 + + lg_inclusion_list = lg_inclusion.split(",") if lg_inclusion is not None else [] + if "Latin Based" in lg_inclusion_list: + ignore_non_latin = True + lg_inclusion_list.remove("Latin Based") + + for layer in alpha_unicode_split(decoded_sequence): + sequence_frequencies: TypeCounter[str] = Counter(layer) + most_common = sequence_frequencies.most_common() + + character_count: int = sum(o for c, o in most_common) + + if character_count <= TOO_SMALL_SEQUENCE: + continue + + popular_character_ordered: list[str] = [c for c, o in most_common] + + for language in lg_inclusion_list or alphabet_languages( + popular_character_ordered, ignore_non_latin + ): + ratio: float = characters_popularity_compare( + language, popular_character_ordered + ) + + if ratio < threshold: + continue + elif ratio >= 0.8: + sufficient_match_count += 1 + + results.append((language, round(ratio, 4))) + + if sufficient_match_count >= 3: + break + + return sorted( + filter_alt_coherence_matches(results), key=lambda x: x[1], reverse=True + ) diff --git a/venv/lib/python3.12/site-packages/charset_normalizer/cli/__init__.py b/venv/lib/python3.12/site-packages/charset_normalizer/cli/__init__.py new file mode 100644 index 00000000..543a5a4d --- /dev/null +++ b/venv/lib/python3.12/site-packages/charset_normalizer/cli/__init__.py @@ -0,0 +1,8 @@ +from __future__ import annotations + +from .__main__ import cli_detect, query_yes_no + +__all__ = ( + "cli_detect", + "query_yes_no", +) diff --git a/venv/lib/python3.12/site-packages/charset_normalizer/cli/__main__.py b/venv/lib/python3.12/site-packages/charset_normalizer/cli/__main__.py new file mode 100644 index 00000000..cb64156a --- /dev/null +++ b/venv/lib/python3.12/site-packages/charset_normalizer/cli/__main__.py @@ -0,0 +1,381 @@ +from __future__ import annotations + +import argparse +import sys +import typing +from json import dumps +from os.path import abspath, basename, dirname, join, realpath +from platform import python_version +from unicodedata import unidata_version + +import charset_normalizer.md as md_module +from charset_normalizer import from_fp +from charset_normalizer.models import CliDetectionResult +from charset_normalizer.version import __version__ + + +def query_yes_no(question: str, default: str = "yes") -> bool: + """Ask a yes/no question via input() and return their answer. + + "question" is a string that is presented to the user. + "default" is the presumed answer if the user just hits . + It must be "yes" (the default), "no" or None (meaning + an answer is required of the user). + + The "answer" return value is True for "yes" or False for "no". + + Credit goes to (c) https://stackoverflow.com/questions/3041986/apt-command-line-interface-like-yes-no-input + """ + valid = {"yes": True, "y": True, "ye": True, "no": False, "n": False} + if default is None: + prompt = " [y/n] " + elif default == "yes": + prompt = " [Y/n] " + elif default == "no": + prompt = " [y/N] " + else: + raise ValueError("invalid default answer: '%s'" % default) + + while True: + sys.stdout.write(question + prompt) + choice = input().lower() + if default is not None and choice == "": + return valid[default] + elif choice in valid: + return valid[choice] + else: + sys.stdout.write("Please respond with 'yes' or 'no' (or 'y' or 'n').\n") + + +class FileType: + """Factory for creating file object types + + Instances of FileType are typically passed as type= arguments to the + ArgumentParser add_argument() method. + + Keyword Arguments: + - mode -- A string indicating how the file is to be opened. Accepts the + same values as the builtin open() function. + - bufsize -- The file's desired buffer size. Accepts the same values as + the builtin open() function. + - encoding -- The file's encoding. Accepts the same values as the + builtin open() function. + - errors -- A string indicating how encoding and decoding errors are to + be handled. Accepts the same value as the builtin open() function. + + Backported from CPython 3.12 + """ + + def __init__( + self, + mode: str = "r", + bufsize: int = -1, + encoding: str | None = None, + errors: str | None = None, + ): + self._mode = mode + self._bufsize = bufsize + self._encoding = encoding + self._errors = errors + + def __call__(self, string: str) -> typing.IO: # type: ignore[type-arg] + # the special argument "-" means sys.std{in,out} + if string == "-": + if "r" in self._mode: + return sys.stdin.buffer if "b" in self._mode else sys.stdin + elif any(c in self._mode for c in "wax"): + return sys.stdout.buffer if "b" in self._mode else sys.stdout + else: + msg = f'argument "-" with mode {self._mode}' + raise ValueError(msg) + + # all other arguments are used as file names + try: + return open(string, self._mode, self._bufsize, self._encoding, self._errors) + except OSError as e: + message = f"can't open '{string}': {e}" + raise argparse.ArgumentTypeError(message) + + def __repr__(self) -> str: + args = self._mode, self._bufsize + kwargs = [("encoding", self._encoding), ("errors", self._errors)] + args_str = ", ".join( + [repr(arg) for arg in args if arg != -1] + + [f"{kw}={arg!r}" for kw, arg in kwargs if arg is not None] + ) + return f"{type(self).__name__}({args_str})" + + +def cli_detect(argv: list[str] | None = None) -> int: + """ + CLI assistant using ARGV and ArgumentParser + :param argv: + :return: 0 if everything is fine, anything else equal trouble + """ + parser = argparse.ArgumentParser( + description="The Real First Universal Charset Detector. " + "Discover originating encoding used on text file. " + "Normalize text to unicode." + ) + + parser.add_argument( + "files", type=FileType("rb"), nargs="+", help="File(s) to be analysed" + ) + parser.add_argument( + "-v", + "--verbose", + action="store_true", + default=False, + dest="verbose", + help="Display complementary information about file if any. " + "Stdout will contain logs about the detection process.", + ) + parser.add_argument( + "-a", + "--with-alternative", + action="store_true", + default=False, + dest="alternatives", + help="Output complementary possibilities if any. Top-level JSON WILL be a list.", + ) + parser.add_argument( + "-n", + "--normalize", + action="store_true", + default=False, + dest="normalize", + help="Permit to normalize input file. If not set, program does not write anything.", + ) + parser.add_argument( + "-m", + "--minimal", + action="store_true", + default=False, + dest="minimal", + help="Only output the charset detected to STDOUT. Disabling JSON output.", + ) + parser.add_argument( + "-r", + "--replace", + action="store_true", + default=False, + dest="replace", + help="Replace file when trying to normalize it instead of creating a new one.", + ) + parser.add_argument( + "-f", + "--force", + action="store_true", + default=False, + dest="force", + help="Replace file without asking if you are sure, use this flag with caution.", + ) + parser.add_argument( + "-i", + "--no-preemptive", + action="store_true", + default=False, + dest="no_preemptive", + help="Disable looking at a charset declaration to hint the detector.", + ) + parser.add_argument( + "-t", + "--threshold", + action="store", + default=0.2, + type=float, + dest="threshold", + help="Define a custom maximum amount of noise allowed in decoded content. 0. <= noise <= 1.", + ) + parser.add_argument( + "--version", + action="version", + version="Charset-Normalizer {} - Python {} - Unicode {} - SpeedUp {}".format( + __version__, + python_version(), + unidata_version, + "OFF" if md_module.__file__.lower().endswith(".py") else "ON", + ), + help="Show version information and exit.", + ) + + args = parser.parse_args(argv) + + if args.replace is True and args.normalize is False: + if args.files: + for my_file in args.files: + my_file.close() + print("Use --replace in addition of --normalize only.", file=sys.stderr) + return 1 + + if args.force is True and args.replace is False: + if args.files: + for my_file in args.files: + my_file.close() + print("Use --force in addition of --replace only.", file=sys.stderr) + return 1 + + if args.threshold < 0.0 or args.threshold > 1.0: + if args.files: + for my_file in args.files: + my_file.close() + print("--threshold VALUE should be between 0. AND 1.", file=sys.stderr) + return 1 + + x_ = [] + + for my_file in args.files: + matches = from_fp( + my_file, + threshold=args.threshold, + explain=args.verbose, + preemptive_behaviour=args.no_preemptive is False, + ) + + best_guess = matches.best() + + if best_guess is None: + print( + 'Unable to identify originating encoding for "{}". {}'.format( + my_file.name, + ( + "Maybe try increasing maximum amount of chaos." + if args.threshold < 1.0 + else "" + ), + ), + file=sys.stderr, + ) + x_.append( + CliDetectionResult( + abspath(my_file.name), + None, + [], + [], + "Unknown", + [], + False, + 1.0, + 0.0, + None, + True, + ) + ) + else: + x_.append( + CliDetectionResult( + abspath(my_file.name), + best_guess.encoding, + best_guess.encoding_aliases, + [ + cp + for cp in best_guess.could_be_from_charset + if cp != best_guess.encoding + ], + best_guess.language, + best_guess.alphabets, + best_guess.bom, + best_guess.percent_chaos, + best_guess.percent_coherence, + None, + True, + ) + ) + + if len(matches) > 1 and args.alternatives: + for el in matches: + if el != best_guess: + x_.append( + CliDetectionResult( + abspath(my_file.name), + el.encoding, + el.encoding_aliases, + [ + cp + for cp in el.could_be_from_charset + if cp != el.encoding + ], + el.language, + el.alphabets, + el.bom, + el.percent_chaos, + el.percent_coherence, + None, + False, + ) + ) + + if args.normalize is True: + if best_guess.encoding.startswith("utf") is True: + print( + '"{}" file does not need to be normalized, as it already came from unicode.'.format( + my_file.name + ), + file=sys.stderr, + ) + if my_file.closed is False: + my_file.close() + continue + + dir_path = dirname(realpath(my_file.name)) + file_name = basename(realpath(my_file.name)) + + o_: list[str] = file_name.split(".") + + if args.replace is False: + o_.insert(-1, best_guess.encoding) + if my_file.closed is False: + my_file.close() + elif ( + args.force is False + and query_yes_no( + 'Are you sure to normalize "{}" by replacing it ?'.format( + my_file.name + ), + "no", + ) + is False + ): + if my_file.closed is False: + my_file.close() + continue + + try: + x_[0].unicode_path = join(dir_path, ".".join(o_)) + + with open(x_[0].unicode_path, "wb") as fp: + fp.write(best_guess.output()) + except OSError as e: + print(str(e), file=sys.stderr) + if my_file.closed is False: + my_file.close() + return 2 + + if my_file.closed is False: + my_file.close() + + if args.minimal is False: + print( + dumps( + [el.__dict__ for el in x_] if len(x_) > 1 else x_[0].__dict__, + ensure_ascii=True, + indent=4, + ) + ) + else: + for my_file in args.files: + print( + ", ".join( + [ + el.encoding or "undefined" + for el in x_ + if el.path == abspath(my_file.name) + ] + ) + ) + + return 0 + + +if __name__ == "__main__": + cli_detect() diff --git a/venv/lib/python3.12/site-packages/charset_normalizer/cli/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/charset_normalizer/cli/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..96da2d564e11f166c980cab8f907d79bb46fe09f GIT binary patch literal 373 zcmXw!ze)o^5XN`!E`LZ&V=n};Ns%mx2o_>vXCX+ixn|hht+~a$-E(&@a_OwJvGy5! z6@7yPD+@^%uuJ6};uPP^?_*||`4|j(1mpeXAbZCA)xduQe+B(H!s3;rB&CYvG^UiK zK^m$c592V8;s`m6TU9h_ZJLo0t@~VSn=dfrABNa+IHi00Ju^BZ{!D&?4H<-6V@@VQ!5_UNhUO#k1tCt zjb-z~O1&Ijm)v?`*~NS~J(;n@p)QPfcHOhwq@@z)c7S&^|GIsYZAdBoB!}N*vW>!i K@Yu0^w0{AxV{4rN literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/charset_normalizer/cli/__pycache__/__main__.cpython-312.pyc b/venv/lib/python3.12/site-packages/charset_normalizer/cli/__pycache__/__main__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7f56d866a0116f40ab7e669eb959456c0985b823 GIT binary patch literal 14434 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 BJ4XNj literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/charset_normalizer/constant.py b/venv/lib/python3.12/site-packages/charset_normalizer/constant.py new file mode 100644 index 00000000..cc71a019 --- /dev/null +++ b/venv/lib/python3.12/site-packages/charset_normalizer/constant.py @@ -0,0 +1,2015 @@ +from __future__ import annotations + +from codecs import BOM_UTF8, BOM_UTF16_BE, BOM_UTF16_LE, BOM_UTF32_BE, BOM_UTF32_LE +from encodings.aliases import aliases +from re import IGNORECASE +from re import compile as re_compile + +# Contain for each eligible encoding a list of/item bytes SIG/BOM +ENCODING_MARKS: dict[str, bytes | list[bytes]] = { + "utf_8": BOM_UTF8, + "utf_7": [ + b"\x2b\x2f\x76\x38", + b"\x2b\x2f\x76\x39", + b"\x2b\x2f\x76\x2b", + b"\x2b\x2f\x76\x2f", + b"\x2b\x2f\x76\x38\x2d", + ], + "gb18030": b"\x84\x31\x95\x33", + "utf_32": [BOM_UTF32_BE, BOM_UTF32_LE], + "utf_16": [BOM_UTF16_BE, BOM_UTF16_LE], +} + +TOO_SMALL_SEQUENCE: int = 32 +TOO_BIG_SEQUENCE: int = int(10e6) + +UTF8_MAXIMAL_ALLOCATION: int = 1_112_064 + +# Up-to-date Unicode ucd/15.0.0 +UNICODE_RANGES_COMBINED: dict[str, range] = { + "Control character": range(32), + "Basic Latin": range(32, 128), + "Latin-1 Supplement": range(128, 256), + "Latin Extended-A": range(256, 384), + "Latin Extended-B": range(384, 592), + "IPA Extensions": range(592, 688), + "Spacing Modifier Letters": range(688, 768), + "Combining Diacritical Marks": range(768, 880), + "Greek and Coptic": range(880, 1024), + "Cyrillic": range(1024, 1280), + "Cyrillic Supplement": range(1280, 1328), + "Armenian": range(1328, 1424), + "Hebrew": range(1424, 1536), + "Arabic": range(1536, 1792), + "Syriac": range(1792, 1872), + "Arabic Supplement": range(1872, 1920), + "Thaana": range(1920, 1984), + "NKo": range(1984, 2048), + "Samaritan": range(2048, 2112), + "Mandaic": range(2112, 2144), + "Syriac Supplement": range(2144, 2160), + "Arabic Extended-B": range(2160, 2208), + "Arabic Extended-A": range(2208, 2304), + "Devanagari": range(2304, 2432), + "Bengali": range(2432, 2560), + "Gurmukhi": range(2560, 2688), + "Gujarati": range(2688, 2816), + "Oriya": range(2816, 2944), + "Tamil": range(2944, 3072), + "Telugu": range(3072, 3200), + "Kannada": range(3200, 3328), + "Malayalam": range(3328, 3456), + "Sinhala": range(3456, 3584), + "Thai": range(3584, 3712), + "Lao": range(3712, 3840), + "Tibetan": range(3840, 4096), + "Myanmar": range(4096, 4256), + "Georgian": range(4256, 4352), + "Hangul Jamo": range(4352, 4608), + "Ethiopic": range(4608, 4992), + "Ethiopic Supplement": range(4992, 5024), + "Cherokee": range(5024, 5120), + "Unified Canadian Aboriginal Syllabics": range(5120, 5760), + "Ogham": range(5760, 5792), + "Runic": range(5792, 5888), + "Tagalog": range(5888, 5920), + "Hanunoo": range(5920, 5952), + "Buhid": range(5952, 5984), + "Tagbanwa": range(5984, 6016), + "Khmer": range(6016, 6144), + "Mongolian": range(6144, 6320), + "Unified Canadian Aboriginal Syllabics Extended": range(6320, 6400), + "Limbu": range(6400, 6480), + "Tai Le": range(6480, 6528), + "New Tai Lue": range(6528, 6624), + "Khmer Symbols": range(6624, 6656), + "Buginese": range(6656, 6688), + "Tai Tham": range(6688, 6832), + "Combining Diacritical Marks Extended": range(6832, 6912), + "Balinese": range(6912, 7040), + "Sundanese": range(7040, 7104), + "Batak": range(7104, 7168), + "Lepcha": range(7168, 7248), + "Ol Chiki": range(7248, 7296), + "Cyrillic Extended-C": range(7296, 7312), + "Georgian Extended": range(7312, 7360), + "Sundanese Supplement": range(7360, 7376), + "Vedic Extensions": range(7376, 7424), + "Phonetic Extensions": range(7424, 7552), + "Phonetic Extensions Supplement": range(7552, 7616), + "Combining Diacritical Marks Supplement": range(7616, 7680), + "Latin Extended Additional": range(7680, 7936), + "Greek Extended": range(7936, 8192), + "General Punctuation": range(8192, 8304), + "Superscripts and Subscripts": range(8304, 8352), + "Currency Symbols": range(8352, 8400), + "Combining Diacritical Marks for Symbols": range(8400, 8448), + "Letterlike Symbols": range(8448, 8528), + "Number Forms": range(8528, 8592), + "Arrows": range(8592, 8704), + "Mathematical Operators": range(8704, 8960), + "Miscellaneous Technical": range(8960, 9216), + "Control Pictures": range(9216, 9280), + "Optical Character Recognition": range(9280, 9312), + "Enclosed Alphanumerics": range(9312, 9472), + "Box Drawing": range(9472, 9600), + "Block Elements": range(9600, 9632), + "Geometric Shapes": range(9632, 9728), + "Miscellaneous Symbols": range(9728, 9984), + "Dingbats": range(9984, 10176), + "Miscellaneous Mathematical Symbols-A": range(10176, 10224), + "Supplemental Arrows-A": range(10224, 10240), + "Braille Patterns": range(10240, 10496), + "Supplemental Arrows-B": range(10496, 10624), + "Miscellaneous Mathematical Symbols-B": range(10624, 10752), + "Supplemental Mathematical Operators": range(10752, 11008), + "Miscellaneous Symbols and Arrows": range(11008, 11264), + "Glagolitic": range(11264, 11360), + "Latin Extended-C": range(11360, 11392), + "Coptic": range(11392, 11520), + "Georgian Supplement": range(11520, 11568), + "Tifinagh": range(11568, 11648), + "Ethiopic Extended": range(11648, 11744), + "Cyrillic Extended-A": range(11744, 11776), + "Supplemental Punctuation": range(11776, 11904), + "CJK Radicals Supplement": range(11904, 12032), + "Kangxi Radicals": range(12032, 12256), + "Ideographic Description Characters": range(12272, 12288), + "CJK Symbols and Punctuation": range(12288, 12352), + "Hiragana": range(12352, 12448), + "Katakana": range(12448, 12544), + "Bopomofo": range(12544, 12592), + "Hangul Compatibility Jamo": range(12592, 12688), + "Kanbun": range(12688, 12704), + "Bopomofo Extended": range(12704, 12736), + "CJK Strokes": range(12736, 12784), + "Katakana Phonetic Extensions": range(12784, 12800), + "Enclosed CJK Letters and Months": range(12800, 13056), + "CJK Compatibility": range(13056, 13312), + "CJK Unified Ideographs Extension A": range(13312, 19904), + "Yijing Hexagram Symbols": range(19904, 19968), + "CJK Unified Ideographs": range(19968, 40960), + "Yi Syllables": range(40960, 42128), + "Yi Radicals": range(42128, 42192), + "Lisu": range(42192, 42240), + "Vai": range(42240, 42560), + "Cyrillic Extended-B": range(42560, 42656), + "Bamum": range(42656, 42752), + "Modifier Tone Letters": range(42752, 42784), + "Latin Extended-D": range(42784, 43008), + "Syloti Nagri": range(43008, 43056), + "Common Indic Number Forms": range(43056, 43072), + "Phags-pa": range(43072, 43136), + "Saurashtra": range(43136, 43232), + "Devanagari Extended": range(43232, 43264), + "Kayah Li": range(43264, 43312), + "Rejang": range(43312, 43360), + "Hangul Jamo Extended-A": range(43360, 43392), + "Javanese": range(43392, 43488), + "Myanmar Extended-B": range(43488, 43520), + "Cham": range(43520, 43616), + "Myanmar Extended-A": range(43616, 43648), + "Tai Viet": range(43648, 43744), + "Meetei Mayek Extensions": range(43744, 43776), + "Ethiopic Extended-A": range(43776, 43824), + "Latin Extended-E": range(43824, 43888), + "Cherokee Supplement": range(43888, 43968), + "Meetei Mayek": range(43968, 44032), + "Hangul Syllables": range(44032, 55216), + "Hangul Jamo Extended-B": range(55216, 55296), + "High Surrogates": range(55296, 56192), + "High Private Use Surrogates": range(56192, 56320), + "Low Surrogates": range(56320, 57344), + "Private Use Area": range(57344, 63744), + "CJK Compatibility Ideographs": range(63744, 64256), + "Alphabetic Presentation Forms": range(64256, 64336), + "Arabic Presentation Forms-A": range(64336, 65024), + "Variation Selectors": range(65024, 65040), + "Vertical Forms": range(65040, 65056), + "Combining Half Marks": range(65056, 65072), + "CJK Compatibility Forms": range(65072, 65104), + "Small Form Variants": range(65104, 65136), + "Arabic Presentation Forms-B": range(65136, 65280), + "Halfwidth and Fullwidth Forms": range(65280, 65520), + "Specials": range(65520, 65536), + "Linear B Syllabary": range(65536, 65664), + "Linear B Ideograms": range(65664, 65792), + "Aegean Numbers": range(65792, 65856), + "Ancient Greek Numbers": range(65856, 65936), + "Ancient Symbols": range(65936, 66000), + "Phaistos Disc": range(66000, 66048), + "Lycian": range(66176, 66208), + "Carian": range(66208, 66272), + "Coptic Epact Numbers": range(66272, 66304), + "Old Italic": range(66304, 66352), + "Gothic": range(66352, 66384), + "Old Permic": range(66384, 66432), + "Ugaritic": range(66432, 66464), + "Old Persian": range(66464, 66528), + "Deseret": range(66560, 66640), + "Shavian": range(66640, 66688), + "Osmanya": range(66688, 66736), + "Osage": range(66736, 66816), + "Elbasan": range(66816, 66864), + "Caucasian Albanian": range(66864, 66928), + "Vithkuqi": range(66928, 67008), + "Linear A": range(67072, 67456), + "Latin Extended-F": range(67456, 67520), + "Cypriot Syllabary": range(67584, 67648), + "Imperial Aramaic": range(67648, 67680), + "Palmyrene": range(67680, 67712), + "Nabataean": range(67712, 67760), + "Hatran": range(67808, 67840), + "Phoenician": range(67840, 67872), + "Lydian": range(67872, 67904), + "Meroitic Hieroglyphs": range(67968, 68000), + "Meroitic Cursive": range(68000, 68096), + "Kharoshthi": range(68096, 68192), + "Old South Arabian": range(68192, 68224), + "Old North Arabian": range(68224, 68256), + "Manichaean": range(68288, 68352), + "Avestan": range(68352, 68416), + "Inscriptional Parthian": range(68416, 68448), + "Inscriptional Pahlavi": range(68448, 68480), + "Psalter Pahlavi": range(68480, 68528), + "Old Turkic": range(68608, 68688), + "Old Hungarian": range(68736, 68864), + "Hanifi Rohingya": range(68864, 68928), + "Rumi Numeral Symbols": range(69216, 69248), + "Yezidi": range(69248, 69312), + "Arabic Extended-C": range(69312, 69376), + "Old Sogdian": range(69376, 69424), + "Sogdian": range(69424, 69488), + "Old Uyghur": range(69488, 69552), + "Chorasmian": range(69552, 69600), + "Elymaic": range(69600, 69632), + "Brahmi": range(69632, 69760), + "Kaithi": range(69760, 69840), + "Sora Sompeng": range(69840, 69888), + "Chakma": range(69888, 69968), + "Mahajani": range(69968, 70016), + "Sharada": range(70016, 70112), + "Sinhala Archaic Numbers": range(70112, 70144), + "Khojki": range(70144, 70224), + "Multani": range(70272, 70320), + "Khudawadi": range(70320, 70400), + "Grantha": range(70400, 70528), + "Newa": range(70656, 70784), + "Tirhuta": range(70784, 70880), + "Siddham": range(71040, 71168), + "Modi": range(71168, 71264), + "Mongolian Supplement": range(71264, 71296), + "Takri": range(71296, 71376), + "Ahom": range(71424, 71504), + "Dogra": range(71680, 71760), + "Warang Citi": range(71840, 71936), + "Dives Akuru": range(71936, 72032), + "Nandinagari": range(72096, 72192), + "Zanabazar Square": range(72192, 72272), + "Soyombo": range(72272, 72368), + "Unified Canadian Aboriginal Syllabics Extended-A": range(72368, 72384), + "Pau Cin Hau": range(72384, 72448), + "Devanagari Extended-A": range(72448, 72544), + "Bhaiksuki": range(72704, 72816), + "Marchen": range(72816, 72896), + "Masaram Gondi": range(72960, 73056), + "Gunjala Gondi": range(73056, 73136), + "Makasar": range(73440, 73472), + "Kawi": range(73472, 73568), + "Lisu Supplement": range(73648, 73664), + "Tamil Supplement": range(73664, 73728), + "Cuneiform": range(73728, 74752), + "Cuneiform Numbers and Punctuation": range(74752, 74880), + "Early Dynastic Cuneiform": range(74880, 75088), + "Cypro-Minoan": range(77712, 77824), + "Egyptian Hieroglyphs": range(77824, 78896), + "Egyptian Hieroglyph Format Controls": range(78896, 78944), + "Anatolian Hieroglyphs": range(82944, 83584), + "Bamum Supplement": range(92160, 92736), + "Mro": range(92736, 92784), + "Tangsa": range(92784, 92880), + "Bassa Vah": range(92880, 92928), + "Pahawh Hmong": range(92928, 93072), + "Medefaidrin": range(93760, 93856), + "Miao": range(93952, 94112), + "Ideographic Symbols and Punctuation": range(94176, 94208), + "Tangut": range(94208, 100352), + "Tangut Components": range(100352, 101120), + "Khitan Small Script": range(101120, 101632), + "Tangut Supplement": range(101632, 101760), + "Kana Extended-B": range(110576, 110592), + "Kana Supplement": range(110592, 110848), + "Kana Extended-A": range(110848, 110896), + "Small Kana Extension": range(110896, 110960), + "Nushu": range(110960, 111360), + "Duployan": range(113664, 113824), + "Shorthand Format Controls": range(113824, 113840), + "Znamenny Musical Notation": range(118528, 118736), + "Byzantine Musical Symbols": range(118784, 119040), + "Musical Symbols": range(119040, 119296), + "Ancient Greek Musical Notation": range(119296, 119376), + "Kaktovik Numerals": range(119488, 119520), + "Mayan Numerals": range(119520, 119552), + "Tai Xuan Jing Symbols": range(119552, 119648), + "Counting Rod Numerals": range(119648, 119680), + "Mathematical Alphanumeric Symbols": range(119808, 120832), + "Sutton SignWriting": range(120832, 121520), + "Latin Extended-G": range(122624, 122880), + "Glagolitic Supplement": range(122880, 122928), + "Cyrillic Extended-D": range(122928, 123024), + "Nyiakeng Puachue Hmong": range(123136, 123216), + "Toto": range(123536, 123584), + "Wancho": range(123584, 123648), + "Nag Mundari": range(124112, 124160), + "Ethiopic Extended-B": range(124896, 124928), + "Mende Kikakui": range(124928, 125152), + "Adlam": range(125184, 125280), + "Indic Siyaq Numbers": range(126064, 126144), + "Ottoman Siyaq Numbers": range(126208, 126288), + "Arabic Mathematical Alphabetic Symbols": range(126464, 126720), + "Mahjong Tiles": range(126976, 127024), + "Domino Tiles": range(127024, 127136), + "Playing Cards": range(127136, 127232), + "Enclosed Alphanumeric Supplement": range(127232, 127488), + "Enclosed Ideographic Supplement": range(127488, 127744), + "Miscellaneous Symbols and Pictographs": range(127744, 128512), + "Emoticons range(Emoji)": range(128512, 128592), + "Ornamental Dingbats": range(128592, 128640), + "Transport and Map Symbols": range(128640, 128768), + "Alchemical Symbols": range(128768, 128896), + "Geometric Shapes Extended": range(128896, 129024), + "Supplemental Arrows-C": range(129024, 129280), + "Supplemental Symbols and Pictographs": range(129280, 129536), + "Chess Symbols": range(129536, 129648), + "Symbols and Pictographs Extended-A": range(129648, 129792), + "Symbols for Legacy Computing": range(129792, 130048), + "CJK Unified Ideographs Extension B": range(131072, 173792), + "CJK Unified Ideographs Extension C": range(173824, 177984), + "CJK Unified Ideographs Extension D": range(177984, 178208), + "CJK Unified Ideographs Extension E": range(178208, 183984), + "CJK Unified Ideographs Extension F": range(183984, 191472), + "CJK Compatibility Ideographs Supplement": range(194560, 195104), + "CJK Unified Ideographs Extension G": range(196608, 201552), + "CJK Unified Ideographs Extension H": range(201552, 205744), + "Tags": range(917504, 917632), + "Variation Selectors Supplement": range(917760, 918000), + "Supplementary Private Use Area-A": range(983040, 1048576), + "Supplementary Private Use Area-B": range(1048576, 1114112), +} + + +UNICODE_SECONDARY_RANGE_KEYWORD: list[str] = [ + "Supplement", + "Extended", + "Extensions", + "Modifier", + "Marks", + "Punctuation", + "Symbols", + "Forms", + "Operators", + "Miscellaneous", + "Drawing", + "Block", + "Shapes", + "Supplemental", + "Tags", +] + +RE_POSSIBLE_ENCODING_INDICATION = re_compile( + r"(?:(?:encoding)|(?:charset)|(?:coding))(?:[\:= ]{1,10})(?:[\"\']?)([a-zA-Z0-9\-_]+)(?:[\"\']?)", + IGNORECASE, +) + +IANA_NO_ALIASES = [ + "cp720", + "cp737", + "cp856", + "cp874", + "cp875", + "cp1006", + "koi8_r", + "koi8_t", + "koi8_u", +] + +IANA_SUPPORTED: list[str] = sorted( + filter( + lambda x: x.endswith("_codec") is False + and x not in {"rot_13", "tactis", "mbcs"}, + list(set(aliases.values())) + IANA_NO_ALIASES, + ) +) + +IANA_SUPPORTED_COUNT: int = len(IANA_SUPPORTED) + +# pre-computed code page that are similar using the function cp_similarity. +IANA_SUPPORTED_SIMILAR: dict[str, list[str]] = { + "cp037": ["cp1026", "cp1140", "cp273", "cp500"], + "cp1026": ["cp037", "cp1140", "cp273", "cp500"], + "cp1125": ["cp866"], + "cp1140": ["cp037", "cp1026", "cp273", "cp500"], + "cp1250": ["iso8859_2"], + "cp1251": ["kz1048", "ptcp154"], + "cp1252": ["iso8859_15", "iso8859_9", "latin_1"], + "cp1253": ["iso8859_7"], + "cp1254": ["iso8859_15", "iso8859_9", "latin_1"], + "cp1257": ["iso8859_13"], + "cp273": ["cp037", "cp1026", "cp1140", "cp500"], + "cp437": ["cp850", "cp858", "cp860", "cp861", "cp862", "cp863", "cp865"], + "cp500": ["cp037", "cp1026", "cp1140", "cp273"], + "cp850": ["cp437", "cp857", "cp858", "cp865"], + "cp857": ["cp850", "cp858", "cp865"], + "cp858": ["cp437", "cp850", "cp857", "cp865"], + "cp860": ["cp437", "cp861", "cp862", "cp863", "cp865"], + "cp861": ["cp437", "cp860", "cp862", "cp863", "cp865"], + "cp862": ["cp437", "cp860", "cp861", "cp863", "cp865"], + "cp863": ["cp437", "cp860", "cp861", "cp862", "cp865"], + "cp865": ["cp437", "cp850", "cp857", "cp858", "cp860", "cp861", "cp862", "cp863"], + "cp866": ["cp1125"], + "iso8859_10": ["iso8859_14", "iso8859_15", "iso8859_4", "iso8859_9", "latin_1"], + "iso8859_11": ["tis_620"], + "iso8859_13": ["cp1257"], + "iso8859_14": [ + "iso8859_10", + "iso8859_15", + "iso8859_16", + "iso8859_3", + "iso8859_9", + "latin_1", + ], + "iso8859_15": [ + "cp1252", + "cp1254", + "iso8859_10", + "iso8859_14", + "iso8859_16", + "iso8859_3", + "iso8859_9", + "latin_1", + ], + "iso8859_16": [ + "iso8859_14", + "iso8859_15", + "iso8859_2", + "iso8859_3", + "iso8859_9", + "latin_1", + ], + "iso8859_2": ["cp1250", "iso8859_16", "iso8859_4"], + "iso8859_3": ["iso8859_14", "iso8859_15", "iso8859_16", "iso8859_9", "latin_1"], + "iso8859_4": ["iso8859_10", "iso8859_2", "iso8859_9", "latin_1"], + "iso8859_7": ["cp1253"], + "iso8859_9": [ + "cp1252", + "cp1254", + "cp1258", + "iso8859_10", + "iso8859_14", + "iso8859_15", + "iso8859_16", + "iso8859_3", + "iso8859_4", + "latin_1", + ], + "kz1048": ["cp1251", "ptcp154"], + "latin_1": [ + "cp1252", + "cp1254", + "cp1258", + "iso8859_10", + "iso8859_14", + "iso8859_15", + "iso8859_16", + "iso8859_3", + "iso8859_4", + "iso8859_9", + ], + "mac_iceland": ["mac_roman", "mac_turkish"], + "mac_roman": ["mac_iceland", "mac_turkish"], + "mac_turkish": ["mac_iceland", "mac_roman"], + "ptcp154": ["cp1251", "kz1048"], + "tis_620": ["iso8859_11"], +} + + +CHARDET_CORRESPONDENCE: dict[str, str] = { + "iso2022_kr": "ISO-2022-KR", + "iso2022_jp": "ISO-2022-JP", + "euc_kr": "EUC-KR", + "tis_620": "TIS-620", + "utf_32": "UTF-32", + "euc_jp": "EUC-JP", + "koi8_r": "KOI8-R", + "iso8859_1": "ISO-8859-1", + "iso8859_2": "ISO-8859-2", + "iso8859_5": "ISO-8859-5", + "iso8859_6": "ISO-8859-6", + "iso8859_7": "ISO-8859-7", + "iso8859_8": "ISO-8859-8", + "utf_16": "UTF-16", + "cp855": "IBM855", + "mac_cyrillic": "MacCyrillic", + "gb2312": "GB2312", + "gb18030": "GB18030", + "cp932": "CP932", + "cp866": "IBM866", + "utf_8": "utf-8", + "utf_8_sig": "UTF-8-SIG", + "shift_jis": "SHIFT_JIS", + "big5": "Big5", + "cp1250": "windows-1250", + "cp1251": "windows-1251", + "cp1252": "Windows-1252", + "cp1253": "windows-1253", + "cp1255": "windows-1255", + "cp1256": "windows-1256", + "cp1254": "Windows-1254", + "cp949": "CP949", +} + + +COMMON_SAFE_ASCII_CHARACTERS: set[str] = { + "<", + ">", + "=", + ":", + "/", + "&", + ";", + "{", + "}", + "[", + "]", + ",", + "|", + '"', + "-", + "(", + ")", +} + +# Sample character sets — replace with full lists if needed +COMMON_CHINESE_CHARACTERS = "的一是在不了有和人这中大为上个国我以要他时来用们生到作地于出就分对成会可主发年动同工也能下过子说产种面而方后多定行学法所民得经十三之进着等部度家电力里如水化高自二理起小物现实加量都两体制机当使点从业本去把性好应开它合还因由其些然前外天政四日那社义事平形相全表间样与关各重新线内数正心反你明看原又么利比或但质气第向道命此变条只没结解问意建月公无系军很情者最立代想已通并提直题党程展五果料象员革位入常文总次品式活设及管特件长求老头基资边流路级少图山统接知较将组见计别她手角期根论运农指几九区强放决西被干做必战先回则任取据处队南给色光门即保治北造百规热领七海口东导器压志世金增争济阶油思术极交受联什认六共权收证改清己美再采转更单风切打白教速花带安场身车例真务具万每目至达走积示议声报斗完类八离华名确才科张信马节话米整空元况今集温传土许步群广石记需段研界拉林律叫且究观越织装影算低持音众书布复容儿须际商非验连断深难近矿千周委素技备半办青省列习响约支般史感劳便团往酸历市克何除消构府太准精值号率族维划选标写存候毛亲快效斯院查江型眼王按格养易置派层片始却专状育厂京识适属圆包火住调满县局照参红细引听该铁价严龙飞" + +COMMON_JAPANESE_CHARACTERS = "日一国年大十二本中長出三時行見月分後前生五間上東四今金九入学高円子外八六下来気小七山話女北午百書先名川千水半男西電校語土木聞食車何南万毎白天母火右読友左休父雨" + +COMMON_KOREAN_CHARACTERS = "一二三四五六七八九十百千萬上下左右中人女子大小山川日月火水木金土父母天地國名年時文校學生" + +# Combine all into a set +COMMON_CJK_CHARACTERS = set( + "".join( + [ + COMMON_CHINESE_CHARACTERS, + COMMON_JAPANESE_CHARACTERS, + COMMON_KOREAN_CHARACTERS, + ] + ) +) + +KO_NAMES: set[str] = {"johab", "cp949", "euc_kr"} +ZH_NAMES: set[str] = {"big5", "cp950", "big5hkscs", "hz"} + +# Logging LEVEL below DEBUG +TRACE: int = 5 + + +# Language label that contain the em dash "—" +# character are to be considered alternative seq to origin +FREQUENCIES: dict[str, list[str]] = { + "English": [ + "e", + "a", + "t", + "i", + "o", + "n", + "s", + "r", + "h", + "l", + "d", + "c", + "u", + "m", + "f", + "p", + "g", + "w", + "y", + "b", + "v", + "k", + "x", + "j", + "z", + "q", + ], + "English—": [ + "e", + "a", + "t", + "i", + "o", + "n", + "s", + "r", + "h", + "l", + "d", + "c", + "m", + "u", + "f", + "p", + "g", + "w", + "b", + "y", + "v", + "k", + "j", + "x", + "z", + "q", + ], + "German": [ + "e", + "n", + "i", + "r", + "s", + "t", + "a", + "d", + "h", + "u", + "l", + "g", + "o", + "c", + "m", + "b", + "f", + "k", + "w", + "z", + "p", + "v", + "ü", + "ä", + "ö", + "j", + ], + "French": [ + "e", + "a", + "s", + "n", + "i", + "t", + "r", + "l", + "u", + "o", + "d", + "c", + "p", + "m", + "é", + "v", + "g", + "f", + "b", + "h", + "q", + "à", + "x", + "è", + "y", + "j", + ], + "Dutch": [ + "e", + "n", + "a", + "i", + "r", + "t", + "o", + "d", + "s", + "l", + "g", + "h", + "v", + "m", + "u", + "k", + "c", + "p", + "b", + "w", + "j", + "z", + "f", + "y", + "x", + "ë", + ], + "Italian": [ + "e", + "i", + "a", + "o", + "n", + "l", + "t", + "r", + "s", + "c", + "d", + "u", + "p", + "m", + "g", + "v", + "f", + "b", + "z", + "h", + "q", + "è", + "à", + "k", + "y", + "ò", + ], + "Polish": [ + "a", + "i", + "o", + "e", + "n", + "r", + "z", + "w", + "s", + "c", + "t", + "k", + "y", + "d", + "p", + "m", + "u", + "l", + "j", + "ł", + "g", + "b", + "h", + "ą", + "ę", + "ó", + ], + "Spanish": [ + "e", + "a", + "o", + "n", + "s", + "r", + "i", + "l", + "d", + "t", + "c", + "u", + "m", + "p", + "b", + "g", + "v", + "f", + "y", + "ó", + "h", + "q", + "í", + "j", + "z", + "á", + ], + "Russian": [ + "о", + "а", + "е", + "и", + "н", + "с", + "т", + "р", + "в", + "л", + "к", + "м", + "д", + "п", + "у", + "г", + "я", + "ы", + "з", + "б", + "й", + "ь", + "ч", + "х", + "ж", + "ц", + ], + # Jap-Kanji + "Japanese": [ + "人", + "一", + "大", + "亅", + "丁", + "丨", + "竹", + "笑", + "口", + "日", + "今", + "二", + "彳", + "行", + "十", + "土", + "丶", + "寸", + "寺", + "時", + "乙", + "丿", + "乂", + "气", + "気", + "冂", + "巾", + "亠", + "市", + "目", + "儿", + "見", + "八", + "小", + "凵", + "県", + "月", + "彐", + "門", + "間", + "木", + "東", + "山", + "出", + "本", + "中", + "刀", + "分", + "耳", + "又", + "取", + "最", + "言", + "田", + "心", + "思", + "刂", + "前", + "京", + "尹", + "事", + "生", + "厶", + "云", + "会", + "未", + "来", + "白", + "冫", + "楽", + "灬", + "馬", + "尸", + "尺", + "駅", + "明", + "耂", + "者", + "了", + "阝", + "都", + "高", + "卜", + "占", + "厂", + "广", + "店", + "子", + "申", + "奄", + "亻", + "俺", + "上", + "方", + "冖", + "学", + "衣", + "艮", + "食", + "自", + ], + # Jap-Katakana + "Japanese—": [ + "ー", + "ン", + "ス", + "・", + "ル", + "ト", + "リ", + "イ", + "ア", + "ラ", + "ッ", + "ク", + "ド", + "シ", + "レ", + "ジ", + "タ", + "フ", + "ロ", + "カ", + "テ", + "マ", + "ィ", + "グ", + "バ", + "ム", + "プ", + "オ", + "コ", + "デ", + "ニ", + "ウ", + "メ", + "サ", + "ビ", + "ナ", + "ブ", + "ャ", + "エ", + "ュ", + "チ", + "キ", + "ズ", + "ダ", + "パ", + "ミ", + "ェ", + "ョ", + "ハ", + "セ", + "ベ", + "ガ", + "モ", + "ツ", + "ネ", + "ボ", + "ソ", + "ノ", + "ァ", + "ヴ", + "ワ", + "ポ", + "ペ", + "ピ", + "ケ", + "ゴ", + "ギ", + "ザ", + "ホ", + "ゲ", + "ォ", + "ヤ", + "ヒ", + "ユ", + "ヨ", + "ヘ", + "ゼ", + "ヌ", + "ゥ", + "ゾ", + "ヶ", + "ヂ", + "ヲ", + "ヅ", + "ヵ", + "ヱ", + "ヰ", + "ヮ", + "ヽ", + "゠", + "ヾ", + "ヷ", + "ヿ", + "ヸ", + "ヹ", + "ヺ", + ], + # Jap-Hiragana + "Japanese——": [ + "の", + "に", + "る", + "た", + "と", + "は", + "し", + "い", + "を", + "で", + "て", + "が", + "な", + "れ", + "か", + "ら", + "さ", + "っ", + "り", + "す", + "あ", + "も", + "こ", + "ま", + "う", + "く", + "よ", + "き", + "ん", + "め", + "お", + "け", + "そ", + "つ", + "だ", + "や", + "え", + "ど", + "わ", + "ち", + "み", + "せ", + "じ", + "ば", + "へ", + "び", + "ず", + "ろ", + "ほ", + "げ", + "む", + "べ", + "ひ", + "ょ", + "ゆ", + "ぶ", + "ご", + "ゃ", + "ね", + "ふ", + "ぐ", + "ぎ", + "ぼ", + "ゅ", + "づ", + "ざ", + "ぞ", + "ぬ", + "ぜ", + "ぱ", + "ぽ", + "ぷ", + "ぴ", + "ぃ", + "ぁ", + "ぇ", + "ぺ", + "ゞ", + "ぢ", + "ぉ", + "ぅ", + "ゐ", + "ゝ", + "ゑ", + "゛", + "゜", + "ゎ", + "ゔ", + "゚", + "ゟ", + "゙", + "ゕ", + "ゖ", + ], + "Portuguese": [ + "a", + "e", + "o", + "s", + "i", + "r", + "d", + "n", + "t", + "m", + "u", + "c", + "l", + "p", + "g", + "v", + "b", + "f", + "h", + "ã", + "q", + "é", + "ç", + "á", + "z", + "í", + ], + "Swedish": [ + "e", + "a", + "n", + "r", + "t", + "s", + "i", + "l", + "d", + "o", + "m", + "k", + "g", + "v", + "h", + "f", + "u", + "p", + "ä", + "c", + "b", + "ö", + "å", + "y", + "j", + "x", + ], + "Chinese": [ + "的", + "一", + "是", + "不", + "了", + "在", + "人", + "有", + "我", + "他", + "这", + "个", + "们", + "中", + "来", + "上", + "大", + "为", + "和", + "国", + "地", + "到", + "以", + "说", + "时", + "要", + "就", + "出", + "会", + "可", + "也", + "你", + "对", + "生", + "能", + "而", + "子", + "那", + "得", + "于", + "着", + "下", + "自", + "之", + "年", + "过", + "发", + "后", + "作", + "里", + "用", + "道", + "行", + "所", + "然", + "家", + "种", + "事", + "成", + "方", + "多", + "经", + "么", + "去", + "法", + "学", + "如", + "都", + "同", + "现", + "当", + "没", + "动", + "面", + "起", + "看", + "定", + "天", + "分", + "还", + "进", + "好", + "小", + "部", + "其", + "些", + "主", + "样", + "理", + "心", + "她", + "本", + "前", + "开", + "但", + "因", + "只", + "从", + "想", + "实", + ], + "Ukrainian": [ + "о", + "а", + "н", + "і", + "и", + "р", + "в", + "т", + "е", + "с", + "к", + "л", + "у", + "д", + "м", + "п", + "з", + "я", + "ь", + "б", + "г", + "й", + "ч", + "х", + "ц", + "ї", + ], + "Norwegian": [ + "e", + "r", + "n", + "t", + "a", + "s", + "i", + "o", + "l", + "d", + "g", + "k", + "m", + "v", + "f", + "p", + "u", + "b", + "h", + "å", + "y", + "j", + "ø", + "c", + "æ", + "w", + ], + "Finnish": [ + "a", + "i", + "n", + "t", + "e", + "s", + "l", + "o", + "u", + "k", + "ä", + "m", + "r", + "v", + "j", + "h", + "p", + "y", + "d", + "ö", + "g", + "c", + "b", + "f", + "w", + "z", + ], + "Vietnamese": [ + "n", + "h", + "t", + "i", + "c", + "g", + "a", + "o", + "u", + "m", + "l", + "r", + "à", + "đ", + "s", + "e", + "v", + "p", + "b", + "y", + "ư", + "d", + "á", + "k", + "ộ", + "ế", + ], + "Czech": [ + "o", + "e", + "a", + "n", + "t", + "s", + "i", + "l", + "v", + "r", + "k", + "d", + "u", + "m", + "p", + "í", + "c", + "h", + "z", + "á", + "y", + "j", + "b", + "ě", + "é", + "ř", + ], + "Hungarian": [ + "e", + "a", + "t", + "l", + "s", + "n", + "k", + "r", + "i", + "o", + "z", + "á", + "é", + "g", + "m", + "b", + "y", + "v", + "d", + "h", + "u", + "p", + "j", + "ö", + "f", + "c", + ], + "Korean": [ + "이", + "다", + "에", + "의", + "는", + "로", + "하", + "을", + "가", + "고", + "지", + "서", + "한", + "은", + "기", + "으", + "년", + "대", + "사", + "시", + "를", + "리", + "도", + "인", + "스", + "일", + ], + "Indonesian": [ + "a", + "n", + "e", + "i", + "r", + "t", + "u", + "s", + "d", + "k", + "m", + "l", + "g", + "p", + "b", + "o", + "h", + "y", + "j", + "c", + "w", + "f", + "v", + "z", + "x", + "q", + ], + "Turkish": [ + "a", + "e", + "i", + "n", + "r", + "l", + "ı", + "k", + "d", + "t", + "s", + "m", + "y", + "u", + "o", + "b", + "ü", + "ş", + "v", + "g", + "z", + "h", + "c", + "p", + "ç", + "ğ", + ], + "Romanian": [ + "e", + "i", + "a", + "r", + "n", + "t", + "u", + "l", + "o", + "c", + "s", + "d", + "p", + "m", + "ă", + "f", + "v", + "î", + "g", + "b", + "ș", + "ț", + "z", + "h", + "â", + "j", + ], + "Farsi": [ + "ا", + "ی", + "ر", + "د", + "ن", + "ه", + "و", + "م", + "ت", + "ب", + "س", + "ل", + "ک", + "ش", + "ز", + "ف", + "گ", + "ع", + "خ", + "ق", + "ج", + "آ", + "پ", + "ح", + "ط", + "ص", + ], + "Arabic": [ + "ا", + "ل", + "ي", + "م", + "و", + "ن", + "ر", + "ت", + "ب", + "ة", + "ع", + "د", + "س", + "ف", + "ه", + "ك", + "ق", + "أ", + "ح", + "ج", + "ش", + "ط", + "ص", + "ى", + "خ", + "إ", + ], + "Danish": [ + "e", + "r", + "n", + "t", + "a", + "i", + "s", + "d", + "l", + "o", + "g", + "m", + "k", + "f", + "v", + "u", + "b", + "h", + "p", + "å", + "y", + "ø", + "æ", + "c", + "j", + "w", + ], + "Serbian": [ + "а", + "и", + "о", + "е", + "н", + "р", + "с", + "у", + "т", + "к", + "ј", + "в", + "д", + "м", + "п", + "л", + "г", + "з", + "б", + "a", + "i", + "e", + "o", + "n", + "ц", + "ш", + ], + "Lithuanian": [ + "i", + "a", + "s", + "o", + "r", + "e", + "t", + "n", + "u", + "k", + "m", + "l", + "p", + "v", + "d", + "j", + "g", + "ė", + "b", + "y", + "ų", + "š", + "ž", + "c", + "ą", + "į", + ], + "Slovene": [ + "e", + "a", + "i", + "o", + "n", + "r", + "s", + "l", + "t", + "j", + "v", + "k", + "d", + "p", + "m", + "u", + "z", + "b", + "g", + "h", + "č", + "c", + "š", + "ž", + "f", + "y", + ], + "Slovak": [ + "o", + "a", + "e", + "n", + "i", + "r", + "v", + "t", + "s", + "l", + "k", + "d", + "m", + "p", + "u", + "c", + "h", + "j", + "b", + "z", + "á", + "y", + "ý", + "í", + "č", + "é", + ], + "Hebrew": [ + "י", + "ו", + "ה", + "ל", + "ר", + "ב", + "ת", + "מ", + "א", + "ש", + "נ", + "ע", + "ם", + "ד", + "ק", + "ח", + "פ", + "ס", + "כ", + "ג", + "ט", + "צ", + "ן", + "ז", + "ך", + ], + "Bulgarian": [ + "а", + "и", + "о", + "е", + "н", + "т", + "р", + "с", + "в", + "л", + "к", + "д", + "п", + "м", + "з", + "г", + "я", + "ъ", + "у", + "б", + "ч", + "ц", + "й", + "ж", + "щ", + "х", + ], + "Croatian": [ + "a", + "i", + "o", + "e", + "n", + "r", + "j", + "s", + "t", + "u", + "k", + "l", + "v", + "d", + "m", + "p", + "g", + "z", + "b", + "c", + "č", + "h", + "š", + "ž", + "ć", + "f", + ], + "Hindi": [ + "क", + "र", + "स", + "न", + "त", + "म", + "ह", + "प", + "य", + "ल", + "व", + "ज", + "द", + "ग", + "ब", + "श", + "ट", + "अ", + "ए", + "थ", + "भ", + "ड", + "च", + "ध", + "ष", + "इ", + ], + "Estonian": [ + "a", + "i", + "e", + "s", + "t", + "l", + "u", + "n", + "o", + "k", + "r", + "d", + "m", + "v", + "g", + "p", + "j", + "h", + "ä", + "b", + "õ", + "ü", + "f", + "c", + "ö", + "y", + ], + "Thai": [ + "า", + "น", + "ร", + "อ", + "ก", + "เ", + "ง", + "ม", + "ย", + "ล", + "ว", + "ด", + "ท", + "ส", + "ต", + "ะ", + "ป", + "บ", + "ค", + "ห", + "แ", + "จ", + "พ", + "ช", + "ข", + "ใ", + ], + "Greek": [ + "α", + "τ", + "ο", + "ι", + "ε", + "ν", + "ρ", + "σ", + "κ", + "η", + "π", + "ς", + "υ", + "μ", + "λ", + "ί", + "ό", + "ά", + "γ", + "έ", + "δ", + "ή", + "ω", + "χ", + "θ", + "ύ", + ], + "Tamil": [ + "க", + "த", + "ப", + "ட", + "ர", + "ம", + "ல", + "ன", + "வ", + "ற", + "ய", + "ள", + "ச", + "ந", + "இ", + "ண", + "அ", + "ஆ", + "ழ", + "ங", + "எ", + "உ", + "ஒ", + "ஸ", + ], + "Kazakh": [ + "а", + "ы", + "е", + "н", + "т", + "р", + "л", + "і", + "д", + "с", + "м", + "қ", + "к", + "о", + "б", + "и", + "у", + "ғ", + "ж", + "ң", + "з", + "ш", + "й", + "п", + "г", + "ө", + ], +} + +LANGUAGE_SUPPORTED_COUNT: int = len(FREQUENCIES) diff --git a/venv/lib/python3.12/site-packages/charset_normalizer/legacy.py b/venv/lib/python3.12/site-packages/charset_normalizer/legacy.py new file mode 100644 index 00000000..e221beca --- /dev/null +++ b/venv/lib/python3.12/site-packages/charset_normalizer/legacy.py @@ -0,0 +1,64 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, Any +from warnings import warn + +from .api import from_bytes +from .constant import CHARDET_CORRESPONDENCE + +# TODO: remove this check when dropping Python 3.7 support +if TYPE_CHECKING: + from typing_extensions import TypedDict + + class ResultDict(TypedDict): + encoding: str | None + language: str + confidence: float | None + + +def detect( + byte_str: bytes, should_rename_legacy: bool = False, **kwargs: Any +) -> ResultDict: + """ + chardet legacy method + Detect the encoding of the given byte string. It should be mostly backward-compatible. + Encoding name will match Chardet own writing whenever possible. (Not on encoding name unsupported by it) + This function is deprecated and should be used to migrate your project easily, consult the documentation for + further information. Not planned for removal. + + :param byte_str: The byte sequence to examine. + :param should_rename_legacy: Should we rename legacy encodings + to their more modern equivalents? + """ + if len(kwargs): + warn( + f"charset-normalizer disregard arguments '{','.join(list(kwargs.keys()))}' in legacy function detect()" + ) + + if not isinstance(byte_str, (bytearray, bytes)): + raise TypeError( # pragma: nocover + f"Expected object of type bytes or bytearray, got: {type(byte_str)}" + ) + + if isinstance(byte_str, bytearray): + byte_str = bytes(byte_str) + + r = from_bytes(byte_str).best() + + encoding = r.encoding if r is not None else None + language = r.language if r is not None and r.language != "Unknown" else "" + confidence = 1.0 - r.chaos if r is not None else None + + # Note: CharsetNormalizer does not return 'UTF-8-SIG' as the sig get stripped in the detection/normalization process + # but chardet does return 'utf-8-sig' and it is a valid codec name. + if r is not None and encoding == "utf_8" and r.bom: + encoding += "_sig" + + if should_rename_legacy is False and encoding in CHARDET_CORRESPONDENCE: + encoding = CHARDET_CORRESPONDENCE[encoding] + + return { + "encoding": encoding, + "language": language, + "confidence": confidence, + } diff --git a/venv/lib/python3.12/site-packages/charset_normalizer/md.cpython-312-darwin.so b/venv/lib/python3.12/site-packages/charset_normalizer/md.cpython-312-darwin.so new file mode 100755 index 0000000000000000000000000000000000000000..de1a84d12033323ba5cf9e1d3b3faebd9e09b7d0 GIT binary patch literal 115744 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/charset_normalizer/md.py b/venv/lib/python3.12/site-packages/charset_normalizer/md.py new file mode 100644 index 00000000..12ce024b --- /dev/null +++ b/venv/lib/python3.12/site-packages/charset_normalizer/md.py @@ -0,0 +1,635 @@ +from __future__ import annotations + +from functools import lru_cache +from logging import getLogger + +from .constant import ( + COMMON_SAFE_ASCII_CHARACTERS, + TRACE, + UNICODE_SECONDARY_RANGE_KEYWORD, +) +from .utils import ( + is_accentuated, + is_arabic, + is_arabic_isolated_form, + is_case_variable, + is_cjk, + is_emoticon, + is_hangul, + is_hiragana, + is_katakana, + is_latin, + is_punctuation, + is_separator, + is_symbol, + is_thai, + is_unprintable, + remove_accent, + unicode_range, + is_cjk_uncommon, +) + + +class MessDetectorPlugin: + """ + Base abstract class used for mess detection plugins. + All detectors MUST extend and implement given methods. + """ + + def eligible(self, character: str) -> bool: + """ + Determine if given character should be fed in. + """ + raise NotImplementedError # pragma: nocover + + def feed(self, character: str) -> None: + """ + The main routine to be executed upon character. + Insert the logic in witch the text would be considered chaotic. + """ + raise NotImplementedError # pragma: nocover + + def reset(self) -> None: # pragma: no cover + """ + Permit to reset the plugin to the initial state. + """ + raise NotImplementedError + + @property + def ratio(self) -> float: + """ + Compute the chaos ratio based on what your feed() has seen. + Must NOT be lower than 0.; No restriction gt 0. + """ + raise NotImplementedError # pragma: nocover + + +class TooManySymbolOrPunctuationPlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._punctuation_count: int = 0 + self._symbol_count: int = 0 + self._character_count: int = 0 + + self._last_printable_char: str | None = None + self._frenzy_symbol_in_word: bool = False + + def eligible(self, character: str) -> bool: + return character.isprintable() + + def feed(self, character: str) -> None: + self._character_count += 1 + + if ( + character != self._last_printable_char + and character not in COMMON_SAFE_ASCII_CHARACTERS + ): + if is_punctuation(character): + self._punctuation_count += 1 + elif ( + character.isdigit() is False + and is_symbol(character) + and is_emoticon(character) is False + ): + self._symbol_count += 2 + + self._last_printable_char = character + + def reset(self) -> None: # Abstract + self._punctuation_count = 0 + self._character_count = 0 + self._symbol_count = 0 + + @property + def ratio(self) -> float: + if self._character_count == 0: + return 0.0 + + ratio_of_punctuation: float = ( + self._punctuation_count + self._symbol_count + ) / self._character_count + + return ratio_of_punctuation if ratio_of_punctuation >= 0.3 else 0.0 + + +class TooManyAccentuatedPlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._character_count: int = 0 + self._accentuated_count: int = 0 + + def eligible(self, character: str) -> bool: + return character.isalpha() + + def feed(self, character: str) -> None: + self._character_count += 1 + + if is_accentuated(character): + self._accentuated_count += 1 + + def reset(self) -> None: # Abstract + self._character_count = 0 + self._accentuated_count = 0 + + @property + def ratio(self) -> float: + if self._character_count < 8: + return 0.0 + + ratio_of_accentuation: float = self._accentuated_count / self._character_count + return ratio_of_accentuation if ratio_of_accentuation >= 0.35 else 0.0 + + +class UnprintablePlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._unprintable_count: int = 0 + self._character_count: int = 0 + + def eligible(self, character: str) -> bool: + return True + + def feed(self, character: str) -> None: + if is_unprintable(character): + self._unprintable_count += 1 + self._character_count += 1 + + def reset(self) -> None: # Abstract + self._unprintable_count = 0 + + @property + def ratio(self) -> float: + if self._character_count == 0: + return 0.0 + + return (self._unprintable_count * 8) / self._character_count + + +class SuspiciousDuplicateAccentPlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._successive_count: int = 0 + self._character_count: int = 0 + + self._last_latin_character: str | None = None + + def eligible(self, character: str) -> bool: + return character.isalpha() and is_latin(character) + + def feed(self, character: str) -> None: + self._character_count += 1 + if ( + self._last_latin_character is not None + and is_accentuated(character) + and is_accentuated(self._last_latin_character) + ): + if character.isupper() and self._last_latin_character.isupper(): + self._successive_count += 1 + # Worse if its the same char duplicated with different accent. + if remove_accent(character) == remove_accent(self._last_latin_character): + self._successive_count += 1 + self._last_latin_character = character + + def reset(self) -> None: # Abstract + self._successive_count = 0 + self._character_count = 0 + self._last_latin_character = None + + @property + def ratio(self) -> float: + if self._character_count == 0: + return 0.0 + + return (self._successive_count * 2) / self._character_count + + +class SuspiciousRange(MessDetectorPlugin): + def __init__(self) -> None: + self._suspicious_successive_range_count: int = 0 + self._character_count: int = 0 + self._last_printable_seen: str | None = None + + def eligible(self, character: str) -> bool: + return character.isprintable() + + def feed(self, character: str) -> None: + self._character_count += 1 + + if ( + character.isspace() + or is_punctuation(character) + or character in COMMON_SAFE_ASCII_CHARACTERS + ): + self._last_printable_seen = None + return + + if self._last_printable_seen is None: + self._last_printable_seen = character + return + + unicode_range_a: str | None = unicode_range(self._last_printable_seen) + unicode_range_b: str | None = unicode_range(character) + + if is_suspiciously_successive_range(unicode_range_a, unicode_range_b): + self._suspicious_successive_range_count += 1 + + self._last_printable_seen = character + + def reset(self) -> None: # Abstract + self._character_count = 0 + self._suspicious_successive_range_count = 0 + self._last_printable_seen = None + + @property + def ratio(self) -> float: + if self._character_count <= 13: + return 0.0 + + ratio_of_suspicious_range_usage: float = ( + self._suspicious_successive_range_count * 2 + ) / self._character_count + + return ratio_of_suspicious_range_usage + + +class SuperWeirdWordPlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._word_count: int = 0 + self._bad_word_count: int = 0 + self._foreign_long_count: int = 0 + + self._is_current_word_bad: bool = False + self._foreign_long_watch: bool = False + + self._character_count: int = 0 + self._bad_character_count: int = 0 + + self._buffer: str = "" + self._buffer_accent_count: int = 0 + self._buffer_glyph_count: int = 0 + + def eligible(self, character: str) -> bool: + return True + + def feed(self, character: str) -> None: + if character.isalpha(): + self._buffer += character + if is_accentuated(character): + self._buffer_accent_count += 1 + if ( + self._foreign_long_watch is False + and (is_latin(character) is False or is_accentuated(character)) + and is_cjk(character) is False + and is_hangul(character) is False + and is_katakana(character) is False + and is_hiragana(character) is False + and is_thai(character) is False + ): + self._foreign_long_watch = True + if ( + is_cjk(character) + or is_hangul(character) + or is_katakana(character) + or is_hiragana(character) + or is_thai(character) + ): + self._buffer_glyph_count += 1 + return + if not self._buffer: + return + if ( + character.isspace() or is_punctuation(character) or is_separator(character) + ) and self._buffer: + self._word_count += 1 + buffer_length: int = len(self._buffer) + + self._character_count += buffer_length + + if buffer_length >= 4: + if self._buffer_accent_count / buffer_length >= 0.5: + self._is_current_word_bad = True + # Word/Buffer ending with an upper case accentuated letter are so rare, + # that we will consider them all as suspicious. Same weight as foreign_long suspicious. + elif ( + is_accentuated(self._buffer[-1]) + and self._buffer[-1].isupper() + and all(_.isupper() for _ in self._buffer) is False + ): + self._foreign_long_count += 1 + self._is_current_word_bad = True + elif self._buffer_glyph_count == 1: + self._is_current_word_bad = True + self._foreign_long_count += 1 + if buffer_length >= 24 and self._foreign_long_watch: + camel_case_dst = [ + i + for c, i in zip(self._buffer, range(0, buffer_length)) + if c.isupper() + ] + probable_camel_cased: bool = False + + if camel_case_dst and (len(camel_case_dst) / buffer_length <= 0.3): + probable_camel_cased = True + + if not probable_camel_cased: + self._foreign_long_count += 1 + self._is_current_word_bad = True + + if self._is_current_word_bad: + self._bad_word_count += 1 + self._bad_character_count += len(self._buffer) + self._is_current_word_bad = False + + self._foreign_long_watch = False + self._buffer = "" + self._buffer_accent_count = 0 + self._buffer_glyph_count = 0 + elif ( + character not in {"<", ">", "-", "=", "~", "|", "_"} + and character.isdigit() is False + and is_symbol(character) + ): + self._is_current_word_bad = True + self._buffer += character + + def reset(self) -> None: # Abstract + self._buffer = "" + self._is_current_word_bad = False + self._foreign_long_watch = False + self._bad_word_count = 0 + self._word_count = 0 + self._character_count = 0 + self._bad_character_count = 0 + self._foreign_long_count = 0 + + @property + def ratio(self) -> float: + if self._word_count <= 10 and self._foreign_long_count == 0: + return 0.0 + + return self._bad_character_count / self._character_count + + +class CjkUncommonPlugin(MessDetectorPlugin): + """ + Detect messy CJK text that probably means nothing. + """ + + def __init__(self) -> None: + self._character_count: int = 0 + self._uncommon_count: int = 0 + + def eligible(self, character: str) -> bool: + return is_cjk(character) + + def feed(self, character: str) -> None: + self._character_count += 1 + + if is_cjk_uncommon(character): + self._uncommon_count += 1 + return + + def reset(self) -> None: # Abstract + self._character_count = 0 + self._uncommon_count = 0 + + @property + def ratio(self) -> float: + if self._character_count < 8: + return 0.0 + + uncommon_form_usage: float = self._uncommon_count / self._character_count + + # we can be pretty sure it's garbage when uncommon characters are widely + # used. otherwise it could just be traditional chinese for example. + return uncommon_form_usage / 10 if uncommon_form_usage > 0.5 else 0.0 + + +class ArchaicUpperLowerPlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._buf: bool = False + + self._character_count_since_last_sep: int = 0 + + self._successive_upper_lower_count: int = 0 + self._successive_upper_lower_count_final: int = 0 + + self._character_count: int = 0 + + self._last_alpha_seen: str | None = None + self._current_ascii_only: bool = True + + def eligible(self, character: str) -> bool: + return True + + def feed(self, character: str) -> None: + is_concerned = character.isalpha() and is_case_variable(character) + chunk_sep = is_concerned is False + + if chunk_sep and self._character_count_since_last_sep > 0: + if ( + self._character_count_since_last_sep <= 64 + and character.isdigit() is False + and self._current_ascii_only is False + ): + self._successive_upper_lower_count_final += ( + self._successive_upper_lower_count + ) + + self._successive_upper_lower_count = 0 + self._character_count_since_last_sep = 0 + self._last_alpha_seen = None + self._buf = False + self._character_count += 1 + self._current_ascii_only = True + + return + + if self._current_ascii_only is True and character.isascii() is False: + self._current_ascii_only = False + + if self._last_alpha_seen is not None: + if (character.isupper() and self._last_alpha_seen.islower()) or ( + character.islower() and self._last_alpha_seen.isupper() + ): + if self._buf is True: + self._successive_upper_lower_count += 2 + self._buf = False + else: + self._buf = True + else: + self._buf = False + + self._character_count += 1 + self._character_count_since_last_sep += 1 + self._last_alpha_seen = character + + def reset(self) -> None: # Abstract + self._character_count = 0 + self._character_count_since_last_sep = 0 + self._successive_upper_lower_count = 0 + self._successive_upper_lower_count_final = 0 + self._last_alpha_seen = None + self._buf = False + self._current_ascii_only = True + + @property + def ratio(self) -> float: + if self._character_count == 0: + return 0.0 + + return self._successive_upper_lower_count_final / self._character_count + + +class ArabicIsolatedFormPlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._character_count: int = 0 + self._isolated_form_count: int = 0 + + def reset(self) -> None: # Abstract + self._character_count = 0 + self._isolated_form_count = 0 + + def eligible(self, character: str) -> bool: + return is_arabic(character) + + def feed(self, character: str) -> None: + self._character_count += 1 + + if is_arabic_isolated_form(character): + self._isolated_form_count += 1 + + @property + def ratio(self) -> float: + if self._character_count < 8: + return 0.0 + + isolated_form_usage: float = self._isolated_form_count / self._character_count + + return isolated_form_usage + + +@lru_cache(maxsize=1024) +def is_suspiciously_successive_range( + unicode_range_a: str | None, unicode_range_b: str | None +) -> bool: + """ + Determine if two Unicode range seen next to each other can be considered as suspicious. + """ + if unicode_range_a is None or unicode_range_b is None: + return True + + if unicode_range_a == unicode_range_b: + return False + + if "Latin" in unicode_range_a and "Latin" in unicode_range_b: + return False + + if "Emoticons" in unicode_range_a or "Emoticons" in unicode_range_b: + return False + + # Latin characters can be accompanied with a combining diacritical mark + # eg. Vietnamese. + if ("Latin" in unicode_range_a or "Latin" in unicode_range_b) and ( + "Combining" in unicode_range_a or "Combining" in unicode_range_b + ): + return False + + keywords_range_a, keywords_range_b = ( + unicode_range_a.split(" "), + unicode_range_b.split(" "), + ) + + for el in keywords_range_a: + if el in UNICODE_SECONDARY_RANGE_KEYWORD: + continue + if el in keywords_range_b: + return False + + # Japanese Exception + range_a_jp_chars, range_b_jp_chars = ( + unicode_range_a + in ( + "Hiragana", + "Katakana", + ), + unicode_range_b in ("Hiragana", "Katakana"), + ) + if (range_a_jp_chars or range_b_jp_chars) and ( + "CJK" in unicode_range_a or "CJK" in unicode_range_b + ): + return False + if range_a_jp_chars and range_b_jp_chars: + return False + + if "Hangul" in unicode_range_a or "Hangul" in unicode_range_b: + if "CJK" in unicode_range_a or "CJK" in unicode_range_b: + return False + if unicode_range_a == "Basic Latin" or unicode_range_b == "Basic Latin": + return False + + # Chinese/Japanese use dedicated range for punctuation and/or separators. + if ("CJK" in unicode_range_a or "CJK" in unicode_range_b) or ( + unicode_range_a in ["Katakana", "Hiragana"] + and unicode_range_b in ["Katakana", "Hiragana"] + ): + if "Punctuation" in unicode_range_a or "Punctuation" in unicode_range_b: + return False + if "Forms" in unicode_range_a or "Forms" in unicode_range_b: + return False + if unicode_range_a == "Basic Latin" or unicode_range_b == "Basic Latin": + return False + + return True + + +@lru_cache(maxsize=2048) +def mess_ratio( + decoded_sequence: str, maximum_threshold: float = 0.2, debug: bool = False +) -> float: + """ + Compute a mess ratio given a decoded bytes sequence. The maximum threshold does stop the computation earlier. + """ + + detectors: list[MessDetectorPlugin] = [ + md_class() for md_class in MessDetectorPlugin.__subclasses__() + ] + + length: int = len(decoded_sequence) + 1 + + mean_mess_ratio: float = 0.0 + + if length < 512: + intermediary_mean_mess_ratio_calc: int = 32 + elif length <= 1024: + intermediary_mean_mess_ratio_calc = 64 + else: + intermediary_mean_mess_ratio_calc = 128 + + for character, index in zip(decoded_sequence + "\n", range(length)): + for detector in detectors: + if detector.eligible(character): + detector.feed(character) + + if ( + index > 0 and index % intermediary_mean_mess_ratio_calc == 0 + ) or index == length - 1: + mean_mess_ratio = sum(dt.ratio for dt in detectors) + + if mean_mess_ratio >= maximum_threshold: + break + + if debug: + logger = getLogger("charset_normalizer") + + logger.log( + TRACE, + "Mess-detector extended-analysis start. " + f"intermediary_mean_mess_ratio_calc={intermediary_mean_mess_ratio_calc} mean_mess_ratio={mean_mess_ratio} " + f"maximum_threshold={maximum_threshold}", + ) + + if len(decoded_sequence) > 16: + logger.log(TRACE, f"Starting with: {decoded_sequence[:16]}") + logger.log(TRACE, f"Ending with: {decoded_sequence[-16::]}") + + for dt in detectors: + logger.log(TRACE, f"{dt.__class__}: {dt.ratio}") + + return round(mean_mess_ratio, 3) diff --git a/venv/lib/python3.12/site-packages/charset_normalizer/md__mypyc.cpython-312-darwin.so b/venv/lib/python3.12/site-packages/charset_normalizer/md__mypyc.cpython-312-darwin.so new file mode 100755 index 0000000000000000000000000000000000000000..0d4bef621296b787934dca0e3059a6c1a0789a95 GIT binary patch literal 482040 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%0D(vO<0K&evl3a3kt&C<_~0Hg&ff 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 EA0<}H`Tzg` literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/charset_normalizer/models.py b/venv/lib/python3.12/site-packages/charset_normalizer/models.py new file mode 100644 index 00000000..1042758f --- /dev/null +++ b/venv/lib/python3.12/site-packages/charset_normalizer/models.py @@ -0,0 +1,360 @@ +from __future__ import annotations + +from encodings.aliases import aliases +from hashlib import sha256 +from json import dumps +from re import sub +from typing import Any, Iterator, List, Tuple + +from .constant import RE_POSSIBLE_ENCODING_INDICATION, TOO_BIG_SEQUENCE +from .utils import iana_name, is_multi_byte_encoding, unicode_range + + +class CharsetMatch: + def __init__( + self, + payload: bytes, + guessed_encoding: str, + mean_mess_ratio: float, + has_sig_or_bom: bool, + languages: CoherenceMatches, + decoded_payload: str | None = None, + preemptive_declaration: str | None = None, + ): + self._payload: bytes = payload + + self._encoding: str = guessed_encoding + self._mean_mess_ratio: float = mean_mess_ratio + self._languages: CoherenceMatches = languages + self._has_sig_or_bom: bool = has_sig_or_bom + self._unicode_ranges: list[str] | None = None + + self._leaves: list[CharsetMatch] = [] + self._mean_coherence_ratio: float = 0.0 + + self._output_payload: bytes | None = None + self._output_encoding: str | None = None + + self._string: str | None = decoded_payload + + self._preemptive_declaration: str | None = preemptive_declaration + + def __eq__(self, other: object) -> bool: + if not isinstance(other, CharsetMatch): + if isinstance(other, str): + return iana_name(other) == self.encoding + return False + return self.encoding == other.encoding and self.fingerprint == other.fingerprint + + def __lt__(self, other: object) -> bool: + """ + Implemented to make sorted available upon CharsetMatches items. + """ + if not isinstance(other, CharsetMatch): + raise ValueError + + chaos_difference: float = abs(self.chaos - other.chaos) + coherence_difference: float = abs(self.coherence - other.coherence) + + # Below 1% difference --> Use Coherence + if chaos_difference < 0.01 and coherence_difference > 0.02: + return self.coherence > other.coherence + elif chaos_difference < 0.01 and coherence_difference <= 0.02: + # When having a difficult decision, use the result that decoded as many multi-byte as possible. + # preserve RAM usage! + if len(self._payload) >= TOO_BIG_SEQUENCE: + return self.chaos < other.chaos + return self.multi_byte_usage > other.multi_byte_usage + + return self.chaos < other.chaos + + @property + def multi_byte_usage(self) -> float: + return 1.0 - (len(str(self)) / len(self.raw)) + + def __str__(self) -> str: + # Lazy Str Loading + if self._string is None: + self._string = str(self._payload, self._encoding, "strict") + return self._string + + def __repr__(self) -> str: + return f"" + + def add_submatch(self, other: CharsetMatch) -> None: + if not isinstance(other, CharsetMatch) or other == self: + raise ValueError( + "Unable to add instance <{}> as a submatch of a CharsetMatch".format( + other.__class__ + ) + ) + + other._string = None # Unload RAM usage; dirty trick. + self._leaves.append(other) + + @property + def encoding(self) -> str: + return self._encoding + + @property + def encoding_aliases(self) -> list[str]: + """ + Encoding name are known by many name, using this could help when searching for IBM855 when it's listed as CP855. + """ + also_known_as: list[str] = [] + for u, p in aliases.items(): + if self.encoding == u: + also_known_as.append(p) + elif self.encoding == p: + also_known_as.append(u) + return also_known_as + + @property + def bom(self) -> bool: + return self._has_sig_or_bom + + @property + def byte_order_mark(self) -> bool: + return self._has_sig_or_bom + + @property + def languages(self) -> list[str]: + """ + Return the complete list of possible languages found in decoded sequence. + Usually not really useful. Returned list may be empty even if 'language' property return something != 'Unknown'. + """ + return [e[0] for e in self._languages] + + @property + def language(self) -> str: + """ + Most probable language found in decoded sequence. If none were detected or inferred, the property will return + "Unknown". + """ + if not self._languages: + # Trying to infer the language based on the given encoding + # Its either English or we should not pronounce ourselves in certain cases. + if "ascii" in self.could_be_from_charset: + return "English" + + # doing it there to avoid circular import + from charset_normalizer.cd import encoding_languages, mb_encoding_languages + + languages = ( + mb_encoding_languages(self.encoding) + if is_multi_byte_encoding(self.encoding) + else encoding_languages(self.encoding) + ) + + if len(languages) == 0 or "Latin Based" in languages: + return "Unknown" + + return languages[0] + + return self._languages[0][0] + + @property + def chaos(self) -> float: + return self._mean_mess_ratio + + @property + def coherence(self) -> float: + if not self._languages: + return 0.0 + return self._languages[0][1] + + @property + def percent_chaos(self) -> float: + return round(self.chaos * 100, ndigits=3) + + @property + def percent_coherence(self) -> float: + return round(self.coherence * 100, ndigits=3) + + @property + def raw(self) -> bytes: + """ + Original untouched bytes. + """ + return self._payload + + @property + def submatch(self) -> list[CharsetMatch]: + return self._leaves + + @property + def has_submatch(self) -> bool: + return len(self._leaves) > 0 + + @property + def alphabets(self) -> list[str]: + if self._unicode_ranges is not None: + return self._unicode_ranges + # list detected ranges + detected_ranges: list[str | None] = [unicode_range(char) for char in str(self)] + # filter and sort + self._unicode_ranges = sorted(list({r for r in detected_ranges if r})) + return self._unicode_ranges + + @property + def could_be_from_charset(self) -> list[str]: + """ + The complete list of encoding that output the exact SAME str result and therefore could be the originating + encoding. + This list does include the encoding available in property 'encoding'. + """ + return [self._encoding] + [m.encoding for m in self._leaves] + + def output(self, encoding: str = "utf_8") -> bytes: + """ + Method to get re-encoded bytes payload using given target encoding. Default to UTF-8. + Any errors will be simply ignored by the encoder NOT replaced. + """ + if self._output_encoding is None or self._output_encoding != encoding: + self._output_encoding = encoding + decoded_string = str(self) + if ( + self._preemptive_declaration is not None + and self._preemptive_declaration.lower() + not in ["utf-8", "utf8", "utf_8"] + ): + patched_header = sub( + RE_POSSIBLE_ENCODING_INDICATION, + lambda m: m.string[m.span()[0] : m.span()[1]].replace( + m.groups()[0], + iana_name(self._output_encoding).replace("_", "-"), # type: ignore[arg-type] + ), + decoded_string[:8192], + count=1, + ) + + decoded_string = patched_header + decoded_string[8192:] + + self._output_payload = decoded_string.encode(encoding, "replace") + + return self._output_payload # type: ignore + + @property + def fingerprint(self) -> str: + """ + Retrieve the unique SHA256 computed using the transformed (re-encoded) payload. Not the original one. + """ + return sha256(self.output()).hexdigest() + + +class CharsetMatches: + """ + Container with every CharsetMatch items ordered by default from most probable to the less one. + Act like a list(iterable) but does not implements all related methods. + """ + + def __init__(self, results: list[CharsetMatch] | None = None): + self._results: list[CharsetMatch] = sorted(results) if results else [] + + def __iter__(self) -> Iterator[CharsetMatch]: + yield from self._results + + def __getitem__(self, item: int | str) -> CharsetMatch: + """ + Retrieve a single item either by its position or encoding name (alias may be used here). + Raise KeyError upon invalid index or encoding not present in results. + """ + if isinstance(item, int): + return self._results[item] + if isinstance(item, str): + item = iana_name(item, False) + for result in self._results: + if item in result.could_be_from_charset: + return result + raise KeyError + + def __len__(self) -> int: + return len(self._results) + + def __bool__(self) -> bool: + return len(self._results) > 0 + + def append(self, item: CharsetMatch) -> None: + """ + Insert a single match. Will be inserted accordingly to preserve sort. + Can be inserted as a submatch. + """ + if not isinstance(item, CharsetMatch): + raise ValueError( + "Cannot append instance '{}' to CharsetMatches".format( + str(item.__class__) + ) + ) + # We should disable the submatch factoring when the input file is too heavy (conserve RAM usage) + if len(item.raw) < TOO_BIG_SEQUENCE: + for match in self._results: + if match.fingerprint == item.fingerprint and match.chaos == item.chaos: + match.add_submatch(item) + return + self._results.append(item) + self._results = sorted(self._results) + + def best(self) -> CharsetMatch | None: + """ + Simply return the first match. Strict equivalent to matches[0]. + """ + if not self._results: + return None + return self._results[0] + + def first(self) -> CharsetMatch | None: + """ + Redundant method, call the method best(). Kept for BC reasons. + """ + return self.best() + + +CoherenceMatch = Tuple[str, float] +CoherenceMatches = List[CoherenceMatch] + + +class CliDetectionResult: + def __init__( + self, + path: str, + encoding: str | None, + encoding_aliases: list[str], + alternative_encodings: list[str], + language: str, + alphabets: list[str], + has_sig_or_bom: bool, + chaos: float, + coherence: float, + unicode_path: str | None, + is_preferred: bool, + ): + self.path: str = path + self.unicode_path: str | None = unicode_path + self.encoding: str | None = encoding + self.encoding_aliases: list[str] = encoding_aliases + self.alternative_encodings: list[str] = alternative_encodings + self.language: str = language + self.alphabets: list[str] = alphabets + self.has_sig_or_bom: bool = has_sig_or_bom + self.chaos: float = chaos + self.coherence: float = coherence + self.is_preferred: bool = is_preferred + + @property + def __dict__(self) -> dict[str, Any]: # type: ignore + return { + "path": self.path, + "encoding": self.encoding, + "encoding_aliases": self.encoding_aliases, + "alternative_encodings": self.alternative_encodings, + "language": self.language, + "alphabets": self.alphabets, + "has_sig_or_bom": self.has_sig_or_bom, + "chaos": self.chaos, + "coherence": self.coherence, + "unicode_path": self.unicode_path, + "is_preferred": self.is_preferred, + } + + def to_json(self) -> str: + return dumps(self.__dict__, ensure_ascii=True, indent=4) diff --git a/venv/lib/python3.12/site-packages/charset_normalizer/py.typed b/venv/lib/python3.12/site-packages/charset_normalizer/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/venv/lib/python3.12/site-packages/charset_normalizer/utils.py b/venv/lib/python3.12/site-packages/charset_normalizer/utils.py new file mode 100644 index 00000000..6bf0384c --- /dev/null +++ b/venv/lib/python3.12/site-packages/charset_normalizer/utils.py @@ -0,0 +1,414 @@ +from __future__ import annotations + +import importlib +import logging +import unicodedata +from codecs import IncrementalDecoder +from encodings.aliases import aliases +from functools import lru_cache +from re import findall +from typing import Generator + +from _multibytecodec import ( # type: ignore[import-not-found,import] + MultibyteIncrementalDecoder, +) + +from .constant import ( + ENCODING_MARKS, + IANA_SUPPORTED_SIMILAR, + RE_POSSIBLE_ENCODING_INDICATION, + UNICODE_RANGES_COMBINED, + UNICODE_SECONDARY_RANGE_KEYWORD, + UTF8_MAXIMAL_ALLOCATION, + COMMON_CJK_CHARACTERS, +) + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_accentuated(character: str) -> bool: + try: + description: str = unicodedata.name(character) + except ValueError: # Defensive: unicode database outdated? + return False + return ( + "WITH GRAVE" in description + or "WITH ACUTE" in description + or "WITH CEDILLA" in description + or "WITH DIAERESIS" in description + or "WITH CIRCUMFLEX" in description + or "WITH TILDE" in description + or "WITH MACRON" in description + or "WITH RING ABOVE" in description + ) + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def remove_accent(character: str) -> str: + decomposed: str = unicodedata.decomposition(character) + if not decomposed: + return character + + codes: list[str] = decomposed.split(" ") + + return chr(int(codes[0], 16)) + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def unicode_range(character: str) -> str | None: + """ + Retrieve the Unicode range official name from a single character. + """ + character_ord: int = ord(character) + + for range_name, ord_range in UNICODE_RANGES_COMBINED.items(): + if character_ord in ord_range: + return range_name + + return None + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_latin(character: str) -> bool: + try: + description: str = unicodedata.name(character) + except ValueError: # Defensive: unicode database outdated? + return False + return "LATIN" in description + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_punctuation(character: str) -> bool: + character_category: str = unicodedata.category(character) + + if "P" in character_category: + return True + + character_range: str | None = unicode_range(character) + + if character_range is None: + return False + + return "Punctuation" in character_range + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_symbol(character: str) -> bool: + character_category: str = unicodedata.category(character) + + if "S" in character_category or "N" in character_category: + return True + + character_range: str | None = unicode_range(character) + + if character_range is None: + return False + + return "Forms" in character_range and character_category != "Lo" + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_emoticon(character: str) -> bool: + character_range: str | None = unicode_range(character) + + if character_range is None: + return False + + return "Emoticons" in character_range or "Pictographs" in character_range + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_separator(character: str) -> bool: + if character.isspace() or character in {"|", "+", "<", ">"}: + return True + + character_category: str = unicodedata.category(character) + + return "Z" in character_category or character_category in {"Po", "Pd", "Pc"} + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_case_variable(character: str) -> bool: + return character.islower() != character.isupper() + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_cjk(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: # Defensive: unicode database outdated? + return False + + return "CJK" in character_name + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_hiragana(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: # Defensive: unicode database outdated? + return False + + return "HIRAGANA" in character_name + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_katakana(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: # Defensive: unicode database outdated? + return False + + return "KATAKANA" in character_name + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_hangul(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: # Defensive: unicode database outdated? + return False + + return "HANGUL" in character_name + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_thai(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: # Defensive: unicode database outdated? + return False + + return "THAI" in character_name + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_arabic(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: # Defensive: unicode database outdated? + return False + + return "ARABIC" in character_name + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_arabic_isolated_form(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: # Defensive: unicode database outdated? + return False + + return "ARABIC" in character_name and "ISOLATED FORM" in character_name + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_cjk_uncommon(character: str) -> bool: + return character not in COMMON_CJK_CHARACTERS + + +@lru_cache(maxsize=len(UNICODE_RANGES_COMBINED)) +def is_unicode_range_secondary(range_name: str) -> bool: + return any(keyword in range_name for keyword in UNICODE_SECONDARY_RANGE_KEYWORD) + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_unprintable(character: str) -> bool: + return ( + character.isspace() is False # includes \n \t \r \v + and character.isprintable() is False + and character != "\x1a" # Why? Its the ASCII substitute character. + and character != "\ufeff" # bug discovered in Python, + # Zero Width No-Break Space located in Arabic Presentation Forms-B, Unicode 1.1 not acknowledged as space. + ) + + +def any_specified_encoding(sequence: bytes, search_zone: int = 8192) -> str | None: + """ + Extract using ASCII-only decoder any specified encoding in the first n-bytes. + """ + if not isinstance(sequence, bytes): + raise TypeError + + seq_len: int = len(sequence) + + results: list[str] = findall( + RE_POSSIBLE_ENCODING_INDICATION, + sequence[: min(seq_len, search_zone)].decode("ascii", errors="ignore"), + ) + + if len(results) == 0: + return None + + for specified_encoding in results: + specified_encoding = specified_encoding.lower().replace("-", "_") + + encoding_alias: str + encoding_iana: str + + for encoding_alias, encoding_iana in aliases.items(): + if encoding_alias == specified_encoding: + return encoding_iana + if encoding_iana == specified_encoding: + return encoding_iana + + return None + + +@lru_cache(maxsize=128) +def is_multi_byte_encoding(name: str) -> bool: + """ + Verify is a specific encoding is a multi byte one based on it IANA name + """ + return name in { + "utf_8", + "utf_8_sig", + "utf_16", + "utf_16_be", + "utf_16_le", + "utf_32", + "utf_32_le", + "utf_32_be", + "utf_7", + } or issubclass( + importlib.import_module(f"encodings.{name}").IncrementalDecoder, + MultibyteIncrementalDecoder, + ) + + +def identify_sig_or_bom(sequence: bytes) -> tuple[str | None, bytes]: + """ + Identify and extract SIG/BOM in given sequence. + """ + + for iana_encoding in ENCODING_MARKS: + marks: bytes | list[bytes] = ENCODING_MARKS[iana_encoding] + + if isinstance(marks, bytes): + marks = [marks] + + for mark in marks: + if sequence.startswith(mark): + return iana_encoding, mark + + return None, b"" + + +def should_strip_sig_or_bom(iana_encoding: str) -> bool: + return iana_encoding not in {"utf_16", "utf_32"} + + +def iana_name(cp_name: str, strict: bool = True) -> str: + """Returns the Python normalized encoding name (Not the IANA official name).""" + cp_name = cp_name.lower().replace("-", "_") + + encoding_alias: str + encoding_iana: str + + for encoding_alias, encoding_iana in aliases.items(): + if cp_name in [encoding_alias, encoding_iana]: + return encoding_iana + + if strict: + raise ValueError(f"Unable to retrieve IANA for '{cp_name}'") + + return cp_name + + +def cp_similarity(iana_name_a: str, iana_name_b: str) -> float: + if is_multi_byte_encoding(iana_name_a) or is_multi_byte_encoding(iana_name_b): + return 0.0 + + decoder_a = importlib.import_module(f"encodings.{iana_name_a}").IncrementalDecoder + decoder_b = importlib.import_module(f"encodings.{iana_name_b}").IncrementalDecoder + + id_a: IncrementalDecoder = decoder_a(errors="ignore") + id_b: IncrementalDecoder = decoder_b(errors="ignore") + + character_match_count: int = 0 + + for i in range(255): + to_be_decoded: bytes = bytes([i]) + if id_a.decode(to_be_decoded) == id_b.decode(to_be_decoded): + character_match_count += 1 + + return character_match_count / 254 + + +def is_cp_similar(iana_name_a: str, iana_name_b: str) -> bool: + """ + Determine if two code page are at least 80% similar. IANA_SUPPORTED_SIMILAR dict was generated using + the function cp_similarity. + """ + return ( + iana_name_a in IANA_SUPPORTED_SIMILAR + and iana_name_b in IANA_SUPPORTED_SIMILAR[iana_name_a] + ) + + +def set_logging_handler( + name: str = "charset_normalizer", + level: int = logging.INFO, + format_string: str = "%(asctime)s | %(levelname)s | %(message)s", +) -> None: + logger = logging.getLogger(name) + logger.setLevel(level) + + handler = logging.StreamHandler() + handler.setFormatter(logging.Formatter(format_string)) + logger.addHandler(handler) + + +def cut_sequence_chunks( + sequences: bytes, + encoding_iana: str, + offsets: range, + chunk_size: int, + bom_or_sig_available: bool, + strip_sig_or_bom: bool, + sig_payload: bytes, + is_multi_byte_decoder: bool, + decoded_payload: str | None = None, +) -> Generator[str, None, None]: + if decoded_payload and is_multi_byte_decoder is False: + for i in offsets: + chunk = decoded_payload[i : i + chunk_size] + if not chunk: + break + yield chunk + else: + for i in offsets: + chunk_end = i + chunk_size + if chunk_end > len(sequences) + 8: + continue + + cut_sequence = sequences[i : i + chunk_size] + + if bom_or_sig_available and strip_sig_or_bom is False: + cut_sequence = sig_payload + cut_sequence + + chunk = cut_sequence.decode( + encoding_iana, + errors="ignore" if is_multi_byte_decoder else "strict", + ) + + # multi-byte bad cutting detector and adjustment + # not the cleanest way to perform that fix but clever enough for now. + if is_multi_byte_decoder and i > 0: + chunk_partial_size_chk: int = min(chunk_size, 16) + + if ( + decoded_payload + and chunk[:chunk_partial_size_chk] not in decoded_payload + ): + for j in range(i, i - 4, -1): + cut_sequence = sequences[j:chunk_end] + + if bom_or_sig_available and strip_sig_or_bom is False: + cut_sequence = sig_payload + cut_sequence + + chunk = cut_sequence.decode(encoding_iana, errors="ignore") + + if chunk[:chunk_partial_size_chk] in decoded_payload: + break + + yield chunk diff --git a/venv/lib/python3.12/site-packages/charset_normalizer/version.py b/venv/lib/python3.12/site-packages/charset_normalizer/version.py new file mode 100644 index 00000000..e5687e3c --- /dev/null +++ b/venv/lib/python3.12/site-packages/charset_normalizer/version.py @@ -0,0 +1,8 @@ +""" +Expose version +""" + +from __future__ import annotations + +__version__ = "3.4.2" +VERSION = __version__.split(".") diff --git a/venv/lib/python3.12/site-packages/discord/__init__.py b/venv/lib/python3.12/site-packages/discord/__init__.py new file mode 100644 index 00000000..0efb6553 --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/__init__.py @@ -0,0 +1,96 @@ +""" +Discord API Wrapper +~~~~~~~~~~~~~~~~~~~ + +A basic wrapper for the Discord API. + +:copyright: (c) 2015-present Rapptz +:license: MIT, see LICENSE for more details. + +""" + +__title__ = 'discord' +__author__ = 'Rapptz' +__license__ = 'MIT' +__copyright__ = 'Copyright 2015-present Rapptz' +__version__ = '2.5.2' + +__path__ = __import__('pkgutil').extend_path(__path__, __name__) + +import logging +from typing import NamedTuple, Literal + +from .client import * +from .appinfo import * +from .user import * +from .emoji import * +from .partial_emoji import * +from .activity import * +from .channel import * +from .guild import * +from .flags import * +from .member import * +from .message import * +from .asset import * +from .errors import * +from .permissions import * +from .role import * +from .file import * +from .colour import * +from .integrations import * +from .invite import * +from .template import * +from .welcome_screen import * +from .sku import * +from .widget import * +from .object import * +from .reaction import * +from . import ( + utils as utils, + opus as opus, + abc as abc, + ui as ui, + app_commands as app_commands, +) +from .enums import * +from .embeds import * +from .mentions import * +from .shard import * +from .player import * +from .webhook import * +from .voice_client import * +from .audit_logs import * +from .raw_models import * +from .team import * +from .sticker import * +from .stage_instance import * +from .scheduled_event import * +from .interactions import * +from .components import * +from .threads import * +from .automod import * +from .poll import * +from .soundboard import * +from .subscription import * +from .presences import * + + +class VersionInfo(NamedTuple): + major: int + minor: int + micro: int + releaselevel: Literal["alpha", "beta", "candidate", "final"] + serial: int + + +version_info: VersionInfo = VersionInfo(major=2, minor=5, micro=2, releaselevel='final', serial=0) + +logging.getLogger(__name__).addHandler(logging.NullHandler()) + +# This is a backwards compatibility hack and should be removed in v3 +# Essentially forcing the exception to have different base classes +# In the future, this should only inherit from ClientException +if len(MissingApplicationID.__bases__) == 1: + MissingApplicationID.__bases__ = (app_commands.AppCommandError, ClientException) + +del logging, NamedTuple, Literal, VersionInfo diff --git a/venv/lib/python3.12/site-packages/discord/__main__.py b/venv/lib/python3.12/site-packages/discord/__main__.py new file mode 100644 index 00000000..f8556fcd --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/__main__.py @@ -0,0 +1,357 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from __future__ import annotations + +from typing import Optional, Tuple, Dict + +import argparse +import sys +from pathlib import Path, PurePath, PureWindowsPath + +import discord +import importlib.metadata +import aiohttp +import platform + + +def show_version() -> None: + entries = [] + + entries.append('- Python v{0.major}.{0.minor}.{0.micro}-{0.releaselevel}'.format(sys.version_info)) + version_info = discord.version_info + entries.append('- discord.py v{0.major}.{0.minor}.{0.micro}-{0.releaselevel}'.format(version_info)) + if version_info.releaselevel != 'final': + version = importlib.metadata.version('discord.py') + if version: + entries.append(f' - discord.py metadata: v{version}') + + entries.append(f'- aiohttp v{aiohttp.__version__}') + uname = platform.uname() + entries.append('- system info: {0.system} {0.release} {0.version}'.format(uname)) + print('\n'.join(entries)) + + +def core(parser: argparse.ArgumentParser, args: argparse.Namespace) -> None: + if args.version: + show_version() + else: + parser.print_help() + + +_bot_template = """#!/usr/bin/env python3 + +from discord.ext import commands +import discord +import config + +class Bot(commands.{base}): + def __init__(self, intents: discord.Intents, **kwargs): + super().__init__(command_prefix=commands.when_mentioned_or('{prefix}'), intents=intents, **kwargs) + + async def setup_hook(self): + for cog in config.cogs: + try: + await self.load_extension(cog) + except Exception as exc: + print(f'Could not load extension {{cog}} due to {{exc.__class__.__name__}}: {{exc}}') + + async def on_ready(self): + print(f'Logged on as {{self.user}} (ID: {{self.user.id}})') + + +intents = discord.Intents.default() +intents.message_content = True +bot = Bot(intents=intents) + +# write general commands here + +bot.run(config.token) +""" + +_gitignore_template = """# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# Our configuration files +config.py +""" + +_cog_template = '''from discord.ext import commands +import discord + +class {name}(commands.Cog{attrs}): + """The description for {name} goes here.""" + + def __init__(self, bot): + self.bot = bot +{extra} +async def setup(bot): + await bot.add_cog({name}(bot)) +''' + +_cog_extras = ''' + async def cog_load(self): + # loading logic goes here + pass + + async def cog_unload(self): + # clean up logic goes here + pass + + async def cog_check(self, ctx): + # checks that apply to every command in here + return True + + async def bot_check(self, ctx): + # checks that apply to every command to the bot + return True + + async def bot_check_once(self, ctx): + # check that apply to every command but is guaranteed to be called only once + return True + + async def cog_command_error(self, ctx, error): + # error handling to every command in here + pass + + async def cog_app_command_error(self, interaction, error): + # error handling to every application command in here + pass + + async def cog_before_invoke(self, ctx): + # called before a command is called here + pass + + async def cog_after_invoke(self, ctx): + # called after a command is called here + pass + +''' + + +# certain file names and directory names are forbidden +# see: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx +# although some of this doesn't apply to Linux, we might as well be consistent +_base_table: Dict[str, Optional[str]] = { + '<': '-', + '>': '-', + ':': '-', + '"': '-', + # '/': '-', these are fine + # '\\': '-', + '|': '-', + '?': '-', + '*': '-', +} + +# NUL (0) and 1-31 are disallowed +_base_table.update((chr(i), None) for i in range(32)) + +_translation_table = str.maketrans(_base_table) + + +def to_path(parser: argparse.ArgumentParser, name: str, *, replace_spaces: bool = False) -> Path: + if isinstance(name, Path): + return name + + if sys.platform == 'win32': + forbidden = ( + 'CON', + 'PRN', + 'AUX', + 'NUL', + 'COM1', + 'COM2', + 'COM3', + 'COM4', + 'COM5', + 'COM6', + 'COM7', + 'COM8', + 'COM9', + 'LPT1', + 'LPT2', + 'LPT3', + 'LPT4', + 'LPT5', + 'LPT6', + 'LPT7', + 'LPT8', + 'LPT9', + ) + if len(name) <= 4 and name.upper() in forbidden: + parser.error('invalid directory name given, use a different one') + path = PurePath(name) + if isinstance(path, PureWindowsPath) and path.drive: + drive, rest = path.parts[0], path.parts[1:] + transformed = tuple(map(lambda p: p.translate(_translation_table), rest)) + name = drive + '\\'.join(transformed) + + else: + name = name.translate(_translation_table) + if replace_spaces: + name = name.replace(' ', '-') + return Path(name) + + +def newbot(parser: argparse.ArgumentParser, args: argparse.Namespace) -> None: + new_directory = to_path(parser, args.directory) / to_path(parser, args.name) + + # as a note exist_ok for Path is a 3.5+ only feature + # since we already checked above that we're >3.5 + try: + new_directory.mkdir(exist_ok=True, parents=True) + except OSError as exc: + parser.error(f'could not create our bot directory ({exc})') + + cogs = new_directory / 'cogs' + + try: + cogs.mkdir(exist_ok=True) + init = cogs / '__init__.py' + init.touch() + except OSError as exc: + print(f'warning: could not create cogs directory ({exc})') + + try: + with open(str(new_directory / 'config.py'), 'w', encoding='utf-8') as fp: + fp.write('token = "place your token here"\ncogs = []\n') + except OSError as exc: + parser.error(f'could not create config file ({exc})') + + try: + with open(str(new_directory / 'bot.py'), 'w', encoding='utf-8') as fp: + base = 'Bot' if not args.sharded else 'AutoShardedBot' + fp.write(_bot_template.format(base=base, prefix=args.prefix)) + except OSError as exc: + parser.error(f'could not create bot file ({exc})') + + if not args.no_git: + try: + with open(str(new_directory / '.gitignore'), 'w', encoding='utf-8') as fp: + fp.write(_gitignore_template) + except OSError as exc: + print(f'warning: could not create .gitignore file ({exc})') + + print('successfully made bot at', new_directory) + + +def newcog(parser: argparse.ArgumentParser, args: argparse.Namespace) -> None: + cog_dir = to_path(parser, args.directory) + try: + cog_dir.mkdir(exist_ok=True) + except OSError as exc: + print(f'warning: could not create cogs directory ({exc})') + + directory = cog_dir / to_path(parser, args.name) + directory = directory.with_suffix('.py') + try: + with open(str(directory), 'w', encoding='utf-8') as fp: + attrs = '' + extra = _cog_extras if args.full else '' + if args.class_name: + name = args.class_name + else: + name = str(directory.stem) + if '-' in name or '_' in name: + translation = str.maketrans('-_', ' ') + name = name.translate(translation).title().replace(' ', '') + else: + name = name.title() + + if args.display_name: + attrs += f', name="{args.display_name}"' + if args.hide_commands: + attrs += ', command_attrs=dict(hidden=True)' + fp.write(_cog_template.format(name=name, extra=extra, attrs=attrs)) + except OSError as exc: + parser.error(f'could not create cog file ({exc})') + else: + print('successfully made cog at', directory) + + +def add_newbot_args(subparser: argparse._SubParsersAction[argparse.ArgumentParser]) -> None: + parser = subparser.add_parser('newbot', help='creates a command bot project quickly') + parser.set_defaults(func=newbot) + + parser.add_argument('name', help='the bot project name') + parser.add_argument('directory', help='the directory to place it in (default: .)', nargs='?', default=Path.cwd()) + parser.add_argument('--prefix', help='the bot prefix (default: $)', default='$', metavar='') + parser.add_argument('--sharded', help='whether to use AutoShardedBot', action='store_true') + parser.add_argument('--no-git', help='do not create a .gitignore file', action='store_true', dest='no_git') + + +def add_newcog_args(subparser: argparse._SubParsersAction[argparse.ArgumentParser]) -> None: + parser = subparser.add_parser('newcog', help='creates a new cog template quickly') + parser.set_defaults(func=newcog) + + parser.add_argument('name', help='the cog name') + parser.add_argument('directory', help='the directory to place it in (default: cogs)', nargs='?', default=Path('cogs')) + parser.add_argument('--class-name', help='the class name of the cog (default: )', dest='class_name') + parser.add_argument('--display-name', help='the cog name (default: )') + parser.add_argument('--hide-commands', help='whether to hide all commands in the cog', action='store_true') + parser.add_argument('--full', help='add all special methods as well', action='store_true') + + +def parse_args() -> Tuple[argparse.ArgumentParser, argparse.Namespace]: + parser = argparse.ArgumentParser(prog='discord', description='Tools for helping with discord.py') + parser.add_argument('-v', '--version', action='store_true', help='shows the library version') + parser.set_defaults(func=core) + + subparser = parser.add_subparsers(dest='subcommand', title='subcommands') + add_newbot_args(subparser) + add_newcog_args(subparser) + return parser, parser.parse_args() + + +def main() -> None: + parser, args = parse_args() + args.func(parser, args) + + +if __name__ == '__main__': + main() diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2497dd75b3850fae57dbdbe75b1ab25bdd65bee0 GIT binary patch literal 2812 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/abc.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/abc.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..de6718cb1385efe3daa8eaa5bdf0df5448659bc9 GIT binary patch literal 82878 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 H1)BaJkycO1 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/activity.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/activity.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d02726c02f55df4bbf0362b18626a4e72ec599ed GIT binary patch literal 36624 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 J9KBh${a@JtzfAxD literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/audit_logs.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/audit_logs.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ff3a35acbf4e95d2267124fddd4444bb357c81bd GIT binary patch literal 47442 zcmdVD3s_v)buM^LQB_n?1;zXQC7EU3bzbR>ta#=eCm1ccRYq9k;(}$8}V+3!kVbO480_CO1PH`Nrw_ z=DYK+eI9kHC`s*havw)xpI!T`{aSnNz1LoQ?X~}p)SKjU z^g4XbUZ*d)H`$lco8oizx)9GSSVmKQX}xK_^xkw|MsEfSvyNu^vU;^V>)BeFeP*%%3z`=qu_iVt&VHv9F}J#OLmHv)|6qQs0{1HNLXmGGBRb zISWf3UF)mptziC?(RIGc-b&_ojaK>A_pWFD)X@#T>fUPRPaCcA)%MmhfBI;hZ)5L9 z=Fb?d_cio3Fn{LgCSPN3BlBmCZuV{I-NO9Yqg#F3dbjzu_ip#?=-q*^oZg*Yvp5Bu z<&N&^-31)v0SCK#cQg3>(LKJsy?dFzV053aske#w3rF|+ntNM(t-S|)2YU~(u%gj6 z)U_Sy9`+sS?Of7H_$?*4yVjE#wZS3G47aCp<4y;yqyJBL9R_ zLKVUUp;uUsw^ukVY`}X^I3rZ!JtXuAHF%#FUJz>W9u_=89o{3tSz#mI7a}RyIiX*u zN7$%vPH4c}hxaDD$M9~%dt4Y0HsgI!5QHswe@^fUTk#f6oHs?-=1m* zG%5bxfG{ZR0Q>}l-|0;s`3DUu@;1O<7KVgffPXQnjOT^j2%9u<2RUKS%bc)RPk+j5 z70SJqA(PiKXkwWBJcHT?s3sk1nuYC0ShF5>g@v^stkrwvn+a-pzraEdAoQRi^d%O0 z2%&9;(5o!89ifK}plWZ?L_ENL+G!t&|?TaZU}vug`PlYmm%~O7TS%_ za&LiN-qy+7s^R_}7%fA5}?7&Epp*#o?jz0e9sOLN#Nh!-qZ&X1qZ0y^LHj&9>>E~cNTTSh{(dU?gda7aa#p*2Rs(!68i0Tfj!0yO|Dgwm?&C;$0=l>MAnMHuoO9!sJitvaaP#5sQe4L=Or zUmO=%ezDc8MgE6c-CaiybU)X0qSf8j2P;BM+Xq)~>FkqbJ;L9mkHewIZyov-wC*OIznb_kP6d zJPJx~0|_J1?xSwXP)(|>wTlw#Xg$$<2q`!1Z#&Y~eX2U?KwEbw(sUm{qD}5&O((kB zntP5kop2xPIdSZ0S1Yn_L9(4~od-@Jm)4Hf&hA>|iZFNUN&Ikk9cnsqgtAI%>OtvG zAfFTN=A*|>ooG9FsM~$$=#iFI1nzG|$(r^bX;rd9rJ9d4wRKdxTbeqW4pQk(xQ`;0 z6G;T7l+OL!p;ii_{F?B;xx4LXCsm{QXlM5c{H#VTPju^1pKI%Ct#&t^XzM~zlMb9X zisT8Mh(S2(qz)Uj4i^P$#ewAn#9p=oSVwl#xX`p=De;TuJ#KG`qIi5(b5K%uhzpm)qG z_6NpA*?a_@NVXllNCebBDqFfIE+Ue-d-9@JP9&FNT6)It`R{qkK0&s4$0mG!*)llV zKZMsrV0hGzQdye(esAD5FI$_(N5>~b1XEL=^Lez9cT{$=|JBym(kW2 z2pdIB7cXLukGu5^r`T|0f7D7aGkKZfa=H(6#OJ){&X12@ zU?m+;c@dO@<7l48AHPx!&kZg>w8x$iBa|98&3{w<-o@SKJF84$2ENEi7yCuO*Ap1_ zd2gGDY=KGHOm+5CB5wC5Q*~4})cFo8MYP$AN0 z%YS`W(3~T-BH%OT4kAbxMicC#gcbZN`5O`8*Jw>_2bhmQwKAm41b%&c(44ut3>JVf zS{a4s1~<)LL$WimavG3d2_Zq)l5;X5yjS?GDU?_PN9zsbA_ZmN78bagsHFDe) z{$C$G*G;c(F(bb#d>34v`7U$f5frG(EFQ&6&N3j&GcI}pY-oKN+KN}B%^!*B7rT+{ zW&HVfz`4pTTe(wwAO9mqU+`G>OzUfhuN@9MYb0mQoq@aM-y9A(w>@wk{?38>!gr2J z&chD?X72lEy!=EGuWWDP%~8az6WT6(HV~RVI3ZYl0y?3sCaNxubw^Bq4i90#$EG8t z+WQdyiM>Ms^b8B)a{#+Spe1mkNG0qjlpKYxcg<)1&Z&@NUC_L4HFfCqIEL7Udf->= z^NV&Et!@dj)q@cY^LY}hBkLVcsA7hpQ5hW7@H9&DEBN!5!HKHjYrC%Pis=kNbIs~n z>V4pANI~rbCbbW22l`B(sSlX6p+S3Nh)9bXB1{3wnLQXR)aeSnVJGViCcQV9E_1ip z0Adb+&#JO0eZoc*A%cT3bOUN+Ow&zxiTmNmi39*F`H9NhZujbeoB;gdIefl`KR@bA zNIY})M~?pB@#nR!;Fg^3H#6p+`$l2NS^L0wV*PO`_4oro*~XW4?){Nt z-`(t256lj}x$Q^JYD|2X^8Wd!30&$${-0&XKE@%uYu~)zZT?eB?*6sWR7w=ZsC1T5 zX#hW!Cmtg?qSL1a#c|Jw5szZ^$Z_+~M+Y73S$Qy_b_AMy&nT7NDZ6Ren;NZrc0by66p~mnUQarZzM6|V3*QUQX9n7hf5^Ep2GQ+M? z$yFM5)kv~g_F>@#;W{mFWRmu~O)-fl<=~2_Bs1bDS z>UpusghiZeVGIPD@z4%zeQIY-LrXaE6tazK9zJF|%rZ2DVcdEN@qQ0~ei}G2ZnYfx zk)!S2=UzP&b{0#{;`yGp&fGe4kN=T##{)-O(Ai3b7&PMSg zI!X|%K7zh#0J}iDO(x^S7#B&{kJ2VIH4aTF)FA8`i8G7<-EoGBY14GV9kV8h?&7K} zopO?wWFwxjexFz7WSjB}>zD+QMswLrAK1)OWt9^!i6{%|G{(yH`#q6m+8P2+B5|(5 z?kUY;m}JB+0z&*1I5E?Uv7ZQv)WL&}&cqJl4B!c?{th@1?(b1r){WfjxpUQ_v~>^C zY8D!frZ|XYuf|YzI!cK4?T3`C_Lgq*0&087v5`sZ`-1yJ815H3XT6y zY=#&j&JgRRzW>1HaJ?}Nd`g1A)2dG66}0yibEG#!L9-1H4N7}ou|yW0@%WQz^Rz`H zfGgJN1R;U)ypkA|ve{UUD>i|NKGQb6RQ9oKq+n$! zq#=c54JPt7LQmVT76x=qYTBmfZVl-3#+W5CQ`||^>tqLCMiPmbXWBk(9n`sOo_qB_ znz?Ck%~iHe*#fEN_+`j&yknD$Ct@@z^BZNpUi2cNDu-Brm%=-fSW8w$jEnulBIB>c zv-J5SIfOcqSZfg@8CWRrINmX#D#Eo+hXXsJuKEcLs^qUnV$lbHENf zvM269$c@C|i$LRXc%KoSdbJcea4eBQ)R2?DE-*koDW^Dm(ljsdcTC?@=Sk3cLZ@t| z4CHb^-e!a3U{{7>A*2IRGp zYwf)EtfhYvi3^$0r^s*DuO{^`@kD`QkH27dy&ab=(&sX_> zc`AxG*-rDTg#Hz!R0rqhpiGBrX4g_iPK1-1cx(FB^xd9! zPQQKnofqDI;eI!yr;Dzhpsk0s!)>cFMb=Uw_rv)lS=&H7jV<{;*(!Pi*fO7T>A`Go zu1Y}o1Z&^EQPb-=;V#x)_#?N<5^qr<7S z3^Y>z_+92dBc7i+Er<|Z<+U$d`@)XscqFsEX|u3LE-O#1a3HoI7yP1KuJ3 zsveNGsubcq0R9YrE2(f8?emuP*wcuxS2BO#m%};DtPJPd;31q}GsRoK8WtToQALPL z>l8GyvN}hhJz-!}6Olw?okSwf!a4_v@@Fg6Uvj0t_R_VNUiZ&8{?6pn@cxO5DJ-1E zb|VyZFd~Vp4gQ#lr?$brCx4tah%J-&Cjk5}1pG(jw8Dv+RfuLmQT)nxP*4mvafRUV z_>&RBe9RM(5{TtbU+D*EHe*j*M%U0Ue#sK)!=Z@Y2BF1e? ziiWYs+cwl-A6c;UocDKR&kSSBTw&9^Tm z)~SQh>)vp2om5VSNz8L2Q(4?9zKIqS?(Me7i^^VClk4JzyqQ^t4 zE2sz#`f18inUF+}2QVJb6tq|($~m=aXeKoVaUnGRr_VOt*nNF>$WZGs!{ZX*%*=m4<29mX?mFkjyR1JZxGaK-@<7=ttqcSBs$Ii4pi>H zj{P=>F+btmQKcbVZX&E#z@uTk4>AG7#Oi$tgXY)x8$4u64l_5&6CSHfQ5@wzuWyz-`joR&4;ATheDg%7xNB>(hfs9lvXltoqKWq zbHNB(6E)u<8D+jR!*c@!$p}%KRjG_(7*13H9UhV!_Xh$*in+$hqHF12+$iP>(G!a4 zbSYgbwsYV&zY-_s1O+<@7rc|QML`iob!%IhC;@a6pHKq*OBqTa{smQmrg>5$V{Ahk zeyIMb3SD*bG}Dx%^$yfO$0qx#-JRoO&_pJ;@3sdtR~C)k8PYSYsJjlQy*L5EIaU1Nr6V)0sQF? zjf8mkl}6+m8R~nWIY#GdaE>6sYmUdAXx(|x^c8ey9nz_!XLO?=%?vWptBa~xd`sL= zYuwO8!Q{2GST@1#O=7+z!Qpittc6LYnGJ7cx{|rkZy02o0SvPgIGs zglsiVj*zSR@`QZVS0EI6U6c#(RU{MxU#UV#RD8Ek%0kyfg_a5BEOc#DXoaxOo5spq zDO7pWnQy(Y0T`|pYT(uib>0jXx>2ad?*?I$+Cr5vRlv`vlp9%nsVzxl6Z1qtZq^}* zSYnU2yAg_|g;2~BDUqHY z@i#F~9H?C}Aoyv3+T|@7H0desdn&BfpY}f;%DaYA^p-KVoVjb6Tfy9Q%&mmG+gk;9 z4^h0Z_jT9r^1bVYecla16BSu#6ZV4@s}|aYX1r^J!$J$*wNYn%jtH#?tBVTj5Dp-0 zqcKeL3!TD2e5)6Z3WxA+m^4)#6Kjx}oDPBF@Sv(x3O^C8>{4(_1A>^j*8Tgd)B|1n>6*0{F zjS$IEA#xr&|1#iFg#S^H+3`QgSrJ5e44Y50gnWnpBF+b#_mI#~wkkic4q|~&LwB4b z#RyUTto)D@mA7BcVw%lpzDbWUnbg?esdPQ0Mo-#Kn+r<9X0|KgPz2{{Udj(S1A63M z4?8C0K{Y%R(AS1)K#CvxfS41#9_VxQPj<>{G?|sE1QI`5Q4CaUDmGpHkOZ)@nG~H! z5rGN9I%Pe&4@w^pfP3h?jz+nJ4s{zlIyn8(u;3kMv-WUcl4f$~szA5=QvblDLhiDI zw7~nJsznPw4`p3A0PT9{p)0EPShM))^n~D%L(*+n|-f(Hkzv;cIMVbSY3=RMzl z3CioT-8a~;C2o|z)6_4U85Uh=Z}3DDXl3*-DjH=kr{dJvAUYb-XL4g`a58DX(k@OM zxuSCz3T%?HC&1z*s$xyq<$clXyQovSUv{biOeaxxYPw{ETy(Tc{ln~}ilSAPPL_l_w&pG~V? z-c}{HIKMRXgr$^6*9>70#0kbc5r}CM)Ejz9y#dQIm5(z5$6u^X^V102e%s>({5vBcweM^9YF=&mv9%f_6S)9zo~H&!ER#v0SlUNu0K*txi`Geacy6p7c|_VHejdL_d&J3OmVb4#oyzKFnMOI&O!?*vYH`H|wHuq5 zFm1bHCVmHHWeP%9lBVrql8J*#3qPHt?NwY!vU34aK4Z@l@L&eKIvVjxii{esI1DK| z^b{R2DaNa{dD;<45%s!d<^r@et(7899Ko*TAhySEnRsi0_>dkF;%j-uY56Cl6bCYr z(lg7i<6Jx(zf>b})*ta9J$j$P_c*0`LP~KUBPmT{EGy#zYc$LR$~E7hshkrb{UwF2 zQyA-B-Ef(EG2s+Z!p`_;Q)|i2sNJizMf&%43oR*?P_kUd9VetwG|}FVT0J2^7VZ zBFz0@=-IhJV&_!$U1etFocN#pIKv19T>gyqN26K;v_i{EH%YZ zaP*%D2ZSg&HJVk!L0Ko0UPaW-#OqWRGmFd+2=g4MomLMP{+9&e&^P~q>P-L=8{sgC zEks}Xqo@jyGb?i+jHNm{mX z&NMoE^ZMp+L7h}k7cS_K@ZZs~)X+H7LT9TMopnp~o8WK1*1qVheUw}HQ_hi`K5K?X zTR62*N^M-q%)N2=`r)O_Jn|j7erWD=D6{HuqB$*n*~z74MWEWRx5q&Jj6u1O;BqdP zobf0#cZJ(xubF9q?!uhq`p%gaY>lR7&R+WR7g&C!QfldZ`CA)qZCD6=YwGsYz0LQ_ z?|)v}-?f<9y_A{@ZMeC-2We}JuJe3?MoO(&@ZRmd z*SMIvkENA;qwsp+n_1z~%~I*+aA})_|7mUS2|pbF{&?_({>9F7kJi_ItM+#7y^PTM z-BRkhS?e4>x9d?x-rUIt8D+pmII~g8Y=m4ES{L`rzqkI~_3wFuJ^jIfq2PJHG!Xb8 zb7Bcfc#{vZDvi*+Z};BM{9eJk1<}xpnG-)w&0RKIlS`J$)`iO&r81-~mF zs+8uIrQE`~(^78LtVMw@T(@9Zm` z_WJPp7HNHp7IodyhPrRo!@5>HV6t4wK~vJWsC0(UEESK?YB5j-#W(@`JTJ+^Ag&Vqn<9fYE2@XNK7b8i03CCA!%Vyj%P+Qil9mA0J}(iJ0g(BA1U0 z3d;7uAJL#d%oS}PR4tT$Ys2jg3nljw@0-7u^ls9lf6sbIFoP|Hxs9PZLLtKPQfhx8IYYuZPYQS+>r_ETyV3iJqXno}a<>M$->npZt z>jxDPlJVMB>ibU0}fLOe@OL~Z$H`uQ3h=q&#kUNFfp zEW(_F)$fI9MNlRbnoE>JgZz-p<5)iZz5yqmp0cj_6`2%Os zavD-Xhqb3-^h})3{J>VBP@R!Nh#FY;`b~JS?V3QR!I`Bm&c|OdV{K}ROHr2i#{@xX zd_2v*cxv?E^vzhGS*IT2g=^iR%-aVCpEkw zYXjTn{~^&rGm?UOf|GNmLXFUw{xd6Q-}@*v>xT2X6FTScIIcV3u{p!Ga>-V%9CVVZ zo9+jKUC#&4dKaq)Kd=q0Zb)4Kvj@#f2HUQf@n?yMTH=q60v`ooBn_059uR{*$Y{-k zfyQ#R)i9LAZS+8rk^;o|Dq}BheFAyJ+0Od3dgfQmW6o(yJPq_K5OU1&SL*`07$)Ay zJLp(|?6netfURFF#XuNGoPhoG_~B-aZ1q%-^VJn}k+`X7(8@ujVQz#5shCF>jKxnw z&+*fwF$MaCh#}FxHjuAn6K^|iq*(hJdB?}=*eil%IuWNDpOvCJl9J|oLW*YuE2Zc+ z3n=NQNLgP7YU$$a11bK+JfMy`0q1O3$~f)wDN-(vNdiBgkg`cg!YQV88vIC{%|Q%t z@mo+=?$T%`e*g49oT@yZF&~{$4Ee9){)kl&!lYWjOv=K}s zLi^-@0r^1q_I<5wrMM8gQAEU_dnAx z>O!JdxrLUyS+@`0+ap!CT~)X4VY87F>)^clzvX-F@3sezy%0Prgm!sDIfFCKM~yHRpChTYpG_x7-RujJl)JsBU1s=|e}Qeo{($0J9szlH z|DbT|-4o%0-BQ8sP{H2&jo;h$?zZ<1hnk;%(ELL1%nRZDg0x=N;+Qu*QQ9ZOlo^OaK8dc)_VQu)zvd5=`yL!Z|!Lv3`skN3~(J%c}KXsODgZW-T_RkT{qkD zQE_#+c#BlLT58~c#tT^n%N{zg0)oV3+o zu2>@#*D@>=H4VU;@vb0)!^TQ`7)0vP(Vn4s~j_ zJty`eIoaxc5nJa1PS!&X#VjQ%GAcWDK<2Gd*hR4o;9@&DO{loIpM3ktcN)Ic+~O{T zPHlMBh)1J{DqeG9u=PKO1eqeMT|MMJ*E8R`Xj{LOo*hoFkkTvWFF}TozIi5b*<`k- zks#sVTzAO1ChV+|oLG9|IKq+OfU2I3YtvZyCzpt zX2QD}Jlv@LJiV3EQTQjWMlTxLEbclX(lT0mily;a6meG#Is+M@uPX^-<$+}FcRVIB zvL=l;Z3`x?Bsd?gGln?xtxw3)yoYMfp7`u46DF|67GXP=6JG!3dk(t>F5$3>z^c34t?TBfBS`3l+Akhcsne|{J!B41`tYCIlBid7cLh-473MFh3|Azd3OU~bs zbB~-fIC9!agT~JhQuvXRn-w*m1B#Z^wC)F~$z9inj>(G#ojt)1axL zrjpMr^vSMPrf;!dQMVvnqmBbjN<2p^os;ZRG%J!?nPvrJc&tb07@k*rlS)NBMmLs7 zwk%mJmdm&3dp9}f$nlZ$5;;@k%#iaoIcyWcJs`7P1XxqtP{d3ESEZoM~UD4ro77jBg+0o$+7VhNi z$#=_x+l~b5JC>7KPzoho8QjH!Tr4P+vuE607uA!QID$^(U4y zSP;ZUEQmp6v7l_uo_Dt<*whuQ?_SPfLAjj0Fxap^*uqMk$HMYCdx>7xb5i@c(6)hK zy|7%sz7|HsC}Ls7oW0;~U9h<)SbuW4gax@ddwH;-J$Qtnsg#AS;q30a)xmuP_Hh{t zDkn@-O1rv(-7kc8d4lz4m)Ein6_F2ppIY5V14Iu4GXH}?8U+Qw&gnZYa?f`3D!TqT+eDHY>klpOWg(cV z?CXLJ&B4}F!TR3iCZ2_2__F8gnRujjPiWiOV155`v+}(K-!s+kKdk+JZD0FK`turixLuIih0r!{uznC>!EGmk^jy1$R)3{d9oU;_8uLdd~{iV6m=@@F#i8L4M^Tl)jJgE7mm2y5))#%X$7$O8&Bi zJm|TpMazlIYvWv7R_x5{-e5VyV=1w0ArF9Do0b!q7rRAuD|Y7X&y`M8HtG;tJm5ip%FEe;d-rwGRmIWf3-^*3bsnWTB79lMc` zGLz1$43BKR02}JiXX7u({G}Lvhlb>-oah4Ud#>wHTg?AavedRhcVP@R-WHLSf`oQ)N<+`YYU0Zb8Ug zu#}a%XwFsYO#r`eof1$xGpmyYV)%9O>ePXf9u+$jZO|5GhU}9P_ldvj- z0=wbNx@n*I7=={u0DWcXb9Ra|aVqv@3L~eUDn`o#R4lnVWUgLvq`cg&)Qi5yuNP^n z#BZy~1azO`c(rLEJH^bVG%KF?DpHSMxZkA0k+TJbTOkrc;UdMNFY$}@6cUO?cT9IV zHmsVG7Jr?xj-W6}Q^g$?;urNg!IQIN6&_PFURHK3+4uMbeg+;(qwxr?FJe5riJ7vR zN{yuiR{Hpb{cS2NIeV$FB&niCFIqGgDeX<4K2td(M!?x{sZ#9ziO~xR)jq4izeWWk zrx^tkU!z~GC>;xmUm#l6#3#VWU?G^%#Vo9gS*sGEa-%I?SRqxpp@K$sd`eD>(%fOz z%krXvG+|u;?D|xdzKVKAmsI*>{3e;Bx{`B{nj}+clAQdIIe)2SO~|}vDS6AHd5eM# z0*jB0XOPkQ=$b17=3$ter@@76)zccXhnYPTe;-AVQ;p}7sj~44|2h?(oDKs$WtT0Q z%aj7sr}zba4__k9C-A)q+Ch$ZZ`>B5oa-%B&h-jw*qL6dP{z*mCJN<(6^A}-!df8_ zZ@W+-*zivBIz|XHF^{lLu)l29Cg@%q%ZdwCDI^)7Ql0=+B{&RFt|vgP7n}yD)F(h~ z5Rwg0X-|YoF+io`0G11N%@AsYRJ=2B6e|tyETK+F$2(itC}iNBBh(9-c<17K7T$R{ zqLqzzzOYHi!Mi|c6msz{6gCTacozvS zvZQJ!v#;Mzg2xj$tjaEx@#6v#H|uY1TteW+l2x3 zrQv?}4oJYy?>NgQwc38&mi<{ZR&6a^eL|Pac*Pw%+~Zg;D_2w~iBiG<5xo8Zh$6j! zc+tIkw|g@3l^~kWdj~G~-NU$>=JGfz6kXp!x6^p()T5eJytGPxfwZt*enxt99H#O` z+{!~)Y0n8})dttZoJVm8U+ZuQ4*(+wz)={woo9gQ)d{F$eeG5~2?g0O{~uK^7`zAG zd{8{3T^M#N45djw)O2;>t)C@T6M5Kg<=Djz_l^O&=wruOZ46b$&9i#;-6*vJiwg7y z+?V_PxXWe?xlsM+P{oeOF$pa(n!9@N>197f6|Jr1 zDW!`vD(F#dF(|uwsl6I%8(5(zGp*>9hh9>`B5QkhTZ>XSc4R05&ALZ4JcCe>&akA! zKj$4C9~+`ehm>>_lWaTaFmY6FO1Khz2!yK=S1tHS6y-&r+)WdJexH-zB{PP&^Jq*@ z2I$qA{+yTYw1~7jPT1gfs5qE~j4uYW3aGK6V`vDw4Pt+E1zITxRHB@3Lf2S@1`xXv z=3{qX;nE`z7q;{iq!4LB0EauE`~kHJe%x$Dw1)p@&ypbZ?AcoPq4CQYtVHC5%b9#$ z_dvfN(he=`r~DZ*!lgkhNu!k&921L5Fxkl0`E?U4 z{)mE9oSj@+?oMIDSux(x%H}jpxfwURasETd9a~V@TxAW}I3oq;rNUBDZ(dqo$A0ZS zJY!z80KOw|EhL&<^pg9&5uXR39%mPh1`T9-t0 zhn`%sJ5H@kF(vuxXDUf$qy(Cem1KkV>ob((*k>vUt*v98r}wychm!`$hJQJ>uH*Im zWDRrB2CLVynl|4_(ZZuJY8v~8`1KfR(BekkBby_B%_q3Dbe}=bTeTR-?_ZQ^quMUj z*gx*1Y2#H)onb2dGmKi>v>HU-7!i(qrnGiM($IXLd2}HuOw0r7z8cu81&-{~e33U) z+HD$kt|X9l?sS4!^)KBv(D`lF@M(8d5YpKLJMji? zV(ba?|EI=sftH7OBnr#1v*A%a|M;WFaqWBL9X03CJx_)?FK|MGi{Rl-p;nft8lL$j z>8MCcRoog?!(!t|g<~q*NRL*g$a`8pl7e|Vx(@chNe%8!iPo0Jl0ShnbmN$g)_XXQ zJ|8_}wBUtOLo8A`V9ygMnj7iWAR=!K4=5w)*|6uCxvnwfTBpT=R&ZG-47)HXy<&NT z_6x~)F)fK<+n?Et@Qc3+rbqlWI5GEPMBgL2WLjb4O9WU zBAme2s*MJ9uyM+gom^$dmI$p(Em-^miezC+aB+w-gqAOfx1o+qn}f7XCp*+2cJ4Su z+ul)j4B3X5a^j_n5+&-F)6@v;oQ$%4MH^701+7?VIfrcyvJ-<#g4l+IY`y@|x}2`Y zV^~oS_A-I_%ap2(gec6mCv6_dS=w^+9E_q|z|JL0TF%shncY||G+PTLGc9DKMahY2 zNsGTq1!uboOl$7D^piTFc$SYgR}8Cf&$&sq`bMJ=QwmFQicm;t z6|oov7Qc=U>bWpw$xP??6sjePRNGr40JNZNgP2I^2RA5Dx(@@vagT}pE>eh`7*yBU z`qeyNqm{PTOe^h&)%D-%yxsYo&EcI#B`D||?+Kn9kd6zXYA>y}ALiuGHO`xF?)b_} z_?ZaBf{OKTJ%8)@h4Z1cTiJ3vHS>n;x@|5mlv*}pSuW&~)0T6f6!dD+<3gB0o)vCf zxPIZy&Ec}GQrXrI9NYf5hjjZsf9>;RsDNoo6_(tY^d!;4+d zhr5QPuAy+(B?kSnidQjN^{(<1hvx`UipO)(Z$$dadJMdA_&hM7p_r7=V-LcUAp2eb*R7jj% zjxORM$$dylJM>Y}uJ3NTKk?pk?|vcFd~&hqIU}%sIC+Ouy5l>o;a$h1UB|+^2BcjB zLAM~K36IJu-`aj_d$4A2sBB*_)%~#OVDQxNV$p~pm2g_AlvWx}TQ8*nnTu)lAH~+b z@u@X_Sh8k*^FpCiwk1@uHB$W~oc*SAVy{nV+MI1rahFotaJHKc627@Myk?8EW=nX@ zVF~{;4zCLDkk)ia866)LtqB)3N=1!#d+r?x6}8PKE#()_CVp(?GK+EQ_l=R8BjMsb zQt_U9Q=#Ja2gL*L4+ftn6~4i;?nuG3+7uJLdCVSj->+k z8{2PgpFfFfTV`!b83l9x-`cxWx;9)|FO}Bc-4H6>Gu!gD_NA<%`HZi4mI_MV*l}}5 zxS&=ls9pGcs9@)8%Ti9k?DWHuwF?E`XyEs8 zB(&)`LhTRpOTzi}Qhxp2@_UX@e#?ycH&jcZDl>wC%OGrh5kE-(=NG#V7*?S%ywL-8 z2__rBo?tACeMWTQS>#J3re=>`z34WHtiGv}z&wqv{nbc@6mCXiIc`;JV zNDBXjhF4mY<3P3}eP%DZ0uIo=Hg#<(>?)UB<@3+sR-gy2w!4|{6ue#VPRZLP_j5w^ zbn^<^^o^2OLRzUvEcd|k%b-fDut~fXQ$IPyICEh_p{CLdv!=#QZBxZ@>TO8Cf)X=D zB&vK~&{3+?Uc1tc-8(ZDa%~RUHm|NNH6!BlD}#pGK7A$m=^J0$ub$>3x7$Ij9yi(X z;=cn=;7b4q6Y($NesqndN2UQr3b_J zbd*@6bI3|-!=pdcL0M}Pcl8uI3%EH3t!x}X)FfbOnhd1H>HM(3VE%d{TG!G!m9AT0 zV2$J+7IshB)Lo+8Q&zUKsv2QPU}h>6&X_T2KR`}~?)I7D$+u(>Y%N9HEw9vjM0k;RD`iGu2qhB zbVAb$4tqs*-JlQo>0^^tzqUTT!o!3B#f`HY62Uu;huIK`Jum^aj!jW_BP6(!Mgnshi!@dL+@l$~|(pUfX$Xr*fBL(6JuF{jxdHUi&b& zWZoRC*mke+Pj>#%&hX9?68=}52<3Low0-R4GK=QA-|*b@gfeP^&YGV;c5tc1Kjjka zwX{6I9U?(j#gB6e9>V$#16$0fdEl&BP6WUwe%e2}S=N-oy_=HNv?t-+wb|tE=Hcpl zx`cbe8lx8yMEoN3!g@}RuAHWIA#LJoViJjF(D=}}IC-{j2ixg~AyD>P+2_~x^Q+xZ zmBDaGXM{*&1SqF3qs1@R`Ws^_-2!tRYK@gX09_c^h=u9{*=S`AOSMp}_{0o}EHJhwDQ19n z#I`7oy@g$CB-fgtO}V})szrafN^Sl$mGV!V^Fx;lEf`a?Myg(H%_wjxL+cqz%Q3S? zd*fD&?lso$<1iASUNPE4eNtc5cvzlEm~N}=`8~unQj?q&J18>!o~g3vQpN>pp;9{; zwb4KXmOW_8Q)tUrT0kiyOZQVsJ3>$~Ph$k)tuN`P_MyhyQ#HLudE7okg8jXl)#P)gwiS2m0=M=XoF|NFor1}$D4r2VWfFb;FM6=OAlt};?tsga2k3yU9ai%% zj*I=`Br`$oSGG&c?9TCsUY8P@rYw`vkey;XG+8m&uL<%a)=B;o$U*!^a{eE3mdW{; z970z_k&PuQ{*=OqL&Xi8O!`8@J2+H@=kNw(=V1Q@FHEVh!`>n@_CdYJO^;$oGdp%r zPzpAsAH7zlsrXPm)CK-mB*<8-^2)b%-rD)?wc&;XQp168L$`$gW!+?N@wW~KdtV6m z3R15yW5*bhTN=)(lyWMU;K^Mt<*r}KEV|Koy>lsVO*pSw%B$9X=M;RLoVYFt7D>`M zSJqtP8#{0ATsQ+8k@@fD2YX%!_Y6usgNrFcGYQM41bf<2epxtwgOtBvruo&w$R{;p zCh6yoEsS4=Wd*Q6i~(Ab+|(7cb*&z~ zbhP}d&1d4@5z((2tyj(A>Mqr@=5Q6vN3~XGGTZ-PGnt%DG!ebksZ4BZ;}S=4Y@dye zI#vDji9Z_p5+SY}`4}drMWw8#xq| zVS^Mlg;__ch>NRLWToDn_$;zg!6xH$rV7bbF^`Kq>mRtzeEa0R$@ixhH=haG&ir?Q z9O8^*CdXH97*TMuE-r3X%@9hIXUz}_)O0jvB4T}InCWK2%*n+~@ddd0F!NuJY#3%T z7}-SM6|SI&y1?pDX>Dv*V~Z$H%x&XSo1Wg|;zoKYPRFZ}Tr~?=b!>a!@_y&Q{o%!v z!s0G((B^##ZMCD|jLpQb8vA^PB?sBE!IJCGXpm<8ini`oBc>o0F$Q`6RMpebVF3LS zA;FCt*yy8f3@H@U2MVfMY(KNOsV`{jdkO+hAo{ZrK-{oDgBe)meKE2-O)h#rPb3iauJ8Bcm|_O2gK`v#@0V zeTA@9h2()P7$HxqkkV)*N~@o-{@9iE6X(W{V0pW3p?xuH>&$^iuB@5lr=V>ks_|^J zDXLgt*pYSY6QM4K+#Wj?0D@`MfR)<^^6eqb~(776+y28)Cg5Clp0*%PT*w6K|O z$$*tcw(Av33`}ul2+^6c3)@Rmb_Q54V!XU+#f*6Q2&u?Ps(cy^EqN+o$e;F)?2w3i}%JS1D|xl(zA1UMOwngEY^*KzMJrw6`1Fd1$YP zk=(K=Il1vCsg2M^fzm?n&EDChkGAZ)pTF4QS=@4VE+1QY5AqsOS-}9^1Iw;<@1kVKHY@Fm)3nS(1Wht|3$BRj{=@Hyp~Te2`j6w#}

    tgb)VsJ}h+b>3SZmQ<# zjTQs`4QeUk57m*A1QcPHfj4;`yh+>phZi?LAGAIHlyTr3(x7ce^jxw$ja?=5Tr&b= zo~LUPV4O%s53*~K&?`;G9!EB%*>JiO5Xx|BkrUO!S0ZV3i*H6@k>(%@Wu1k-`)LHy zSGTM9IyI?h@pUTL?-BNhW4y}!#8ysv3Ai^}*`1%S!p<9nUf;IfoxFc}aicEu>a0o; ze-CAxO4ly(LJzFQAyVAYCB8);+)*En(Ip-IqivDnXnkz%n97X;Ytk)j_ldVDmAvTB zP_TsAFS5PWC;mQt&x-o~oO0)P9}`TFsV>8zGR=+}6PIm7Z82Hx$4kt_FcxKxWdjoa zBw63gBOW>j#J>W@%}CQmDs|Q+0ro@<0S!B-42aeGnBo zm8mCUM9fE2c;&X*sWffxR^P-`zsO15Y^Sdq8+{sZg`S*uY{KWS)$kL&d)23cvrQV! zPwK)bA0t4fAWEteqKd}o(5WX{Q#pEW1omtDv~+Z2O|8`n77xQ}G(Dc4|5Szoegbkz z+!q&}`WT^-m6BviTAq=(nM&MN-}uPzs>l(rLIteLXeHz+-~|f!L9!yF8l!s(be00G zSebbWT#;G`jaO%e=bi#zs=%+Nyr;xbi914QPl2s@a{8Yte!ddFDbk&vl3BI_toH2) zU|EdeBpFx13*!TtJw4KQRW=J4`%bz!3YYSbD3|FjxCZ(OqhweayWxRJF-$;%^qsa` z#mMd*+vxg;!v2PwzbEJaCg*45{G6Om$oc=s;b;&@Aje9MjT{F#DdeP*lR?fM%BYo` zW^!sZ=Quw4$C1*@+{dO`i*5NVpKd88Ip3P)MDp3VoUO}t@+EOOb;}O&Il0{WVn8*HIj$s$@RZ#fQs22x(nTe{&*q~LVkBEZjE`k0Ff z!avB|7vS0~*(;gpa4LDrDgLq5j5w?#YZ)n+{v^E_+-%0|ns zPM6NqDFYOZHmkmWlA-6;rK#8`^U$X-lA{lqR>h(#qpkhO<`WmQ1{#}U4GUE|TCD9O z%?g&@^WxOCfaqDND}1Z!BI@6#Tzak87#Sz6LM^SSJVU9X#`vekDl)`^9fAp8cmL4S z${rc(ixmVgPKFK#_-mV$z0(8qV|AueSu86plPH6+Qz=p3R!5ezTa>G3Pk5E{EEK?s4QtWr|no1<5=X9%@TImyuPMlq}yOkJ=e;S;)B38pJ3GrbnqhJhDXFDZ`+3x*SF%KOBmKi*Q6M+fb z8|)Ej5g=OwlQ^g}B+@EHu`NhyWg^LQM3Om(c5-M-RCJI-stjT>IV4#SX|GWH5;<(! zj@FdQN0Sb@WkR zGAO&Aq{ofxoY8>(h)pH2fkLx1mYQ05Nb7^j)Xvr!n~9!1g+ z)55g&+e#TTHCQ?mZIJ$@qcCjcDm&S@u2Q*}OW`d9dypKG¬yyUF()Ib`hFU^aP* ze!fJ`3^`vV=iiWXi<~#f`2%vkMb6uBWOFNek@$!7`yTza?}sHBHe`!`Oo4ww&U@t0 zDn@p6NA8nW6w#P<%~yytzD&+TkJHi7Wk(%l(kcXa5V~{sp)FFSurjYyObS zW}nuvPa8husy-y(f)BZBz)0NoWwY5~x|;ZL3TICHb92T|%vm3r3qLeh{FBLSv3|_K z`KKh!_p>C6^E?<+o0ae3m(#QP zY?chY-TRgk@O}h_)Pna)gO%?BpO?V5u=GyBwIVp3rvMbD4A&f5oHNa{6E~)=Pc53) zTm|1}=Cgr0HTb3LFD;taslm%BN&Hrp8NI2cQj(@UFCh&zHbL9Thi-`%m`(qByW2cGFn@@Sn;q^Gl#Jd*8$nScb z#PhEC7antXJ+_(n%sCdGN#Vr{fXC}Gs^FSOID<*xx6ao-Mw(k617qcPiz&SPvF((F QKgQ1<`WeSOjD!9E0hJR};Q#;t literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/automod.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/automod.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..06ca2d5c75d639a71461009fb5eadc06ce4151a8 GIT binary patch literal 32556 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

    5>0nJG6Nppu{cPaQ7 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 DNCrGz literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/channel.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/channel.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..751b493137e23625e0b616e37d043b0f8cb3721c GIT binary patch literal 152117 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/colour.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/colour.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a3ded252d773b1c8ab36c8e19aaf9dc4ce390072 GIT binary patch literal 20306 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/components.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/components.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b680e439f79a3f970ddd2638599c8786896d989b GIT binary patch literal 26296 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 yPgUZfOG<7IjGola3=5cq$6(=qG- literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/context_managers.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/context_managers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c827d34661df9a6a7f130e042488a0b82ff545f9 GIT binary patch literal 5237 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%0Dgl;oTIX%rklY|G71my>q7ujTh_ah?%w;Y^* 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/errors.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/errors.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4b43a06e04fbb26506470eaeb2e23c19c14a0bcb GIT binary patch literal 12946 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/flags.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/flags.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..db5d16fb0298b67b9074d3c6f3f2298e42b61a86 GIT binary patch literal 87706 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/gateway.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/gateway.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..883b795d2c394cffd3de02156b4931b37da6b6f7 GIT binary patch literal 52022 zcmc${3w#^bbtjAg2Ec#>36KQeFYx^)^`KtV%MeLPlqE_QDa)cQ!w?6QNb!{cD2WK^ zIJUbX6Q`EeX(escwbbUT<=So3er;Fo?GYSAkqbb)pphWvfK6kw!3uXY#b%O z-S2juOBOE1b}mOb3P zM~nu;MT2MLJ9OcH014fSgrcu*?3BUX(KV}{rDvi~C{WWiJ^4mbIm_AVF&y@;LhJCbttYM&m<&iPkIMy`K#Qd3~&0{SC zEzIv2Z5?YHXrsLM7)0lb1~JRO<_%LKx3w%Z8=*N#q3c+v3!%CGJT>lm7Mh39{5R11 z^bEAKumXe?`t2hla%i%vrryY679nP_f1?_@iG`LRwA5cTGMSuG_Ny_spl=GqGO_$k zw_17!OI?A~zANEa72199Shy2pma3C-|G437? zxKH^d|A}e$Ny#@J^oz~zA<6G|PYk&SPx+*i{$_V@!tEQMc2D}H01`}`2>OP{hsRI4 zeQARzied&&A)CO&Q1Glz@*}e7_5}hHgTp@L=N2ahr^ZmaFG%GL4UhT*?)o6=UfGvO zQQ6R(hC)QYZ`3_Jj@K$o!+NBo09 z3Za@0O^l9CoTa7>PK=Ag)ZRcx8XIfhiHS3Q))skq$0vfQs$2yc09FZkR1=>9r+ldU z34fx)Q10+}8U-oMLF=YY1cDg&Vf6jvgv82AZDuRV-`nl(JGi_5sONCEyQj~6=pp@V(hD838X_V)DdK8#Yj4|MnT zx1v;pxw{|7i@R^HXa9aGD$R2QwLgq<4!b)K9y)foXV2b#_uhm1ySfp$s~a`*?AqTg z7llT3?)UT@Xm)pb4tVxZ?GC#SBA3Hy6iu$3`{>?o3Zn8n_}|&zbFi11(Rr}9|1e&g z(aOX9YSN=UecjD&&*7dvR5fk);e*JYx)Uj=&w43cZ?~Kabv5fCbwm(_I_wAA*I-tJBe^`3ZIuW!sR_D@YBp>S}LCX{b9 zZtb6*^gr&C;%4^cW7-y|MC3XefXBYe7w~(qyw3~=r}3WAH|h7C#xm$b{rm`Uc210s zW1S$o&e4g0Uu-bPon6C$!3jw`>OavpF?iY^j5{Co`zJl4!)N?^v3f`SQatzZ2`rM8 z!HJ~otCl|dupi5g%2C5mHs9wT9m21rb95Mh3_gce8>NCSmQ_mlpu8K%ZesJ|?v>&F zqQP$%;D87iMGhOkQ8ZoQu+{P}S_b%ObAweXM5It--|$IvAA=|X-;jTF8h|iSLk2F+ z`cDARqUo*uucLy1l7O{?iEYk6y-a?T%-!3?N}b_m3|{!;XU2%P#1?HZ%oru083<9* z8>S5+#YlQ@F!jbQSjtBZbjJlifZqO|-NzbCaRIPK61~Hs)C^s^;Q+tZluwBJ27 zi7iT!w<;fPTc>$}SfawPh+tW7kX@NoAw!qwVz1o*TcOKKZJMH75H^O@nZFrO7Z zfqc`phO~G_H>OgMK$(BsFWq-5VDHH%3CKMO+yHQSeERtDW;c!I@wg4>lsG(ySrs?o zYuxOo4DL6mk@dc*G2ZtwGcTZu0_@AV&amx^US=niEhu50~u`xGN zI*__SBIgkP0yG7F%@A|6E%0rz^voCb#q1jv_zf|8`66E~_bA2H?@<~qtw)I-5V;r4 z091l#e32jEMVn~CuUSk3$l?bq09onr>^<^IJB%NOkol#-#26vFBv3TNa!&z81b9?X zv>XgEFs0@cw6Waaj4+Bzd6R$NNW3C9i}FP@;LWPMO&c1Fy??K~H3)IjnD1QNCi%x? z#5QgL{v}SFjhlc`#jS}k!fppZ8|O#ivIXB@l4_Aj+&nljH6E1qz^?!}d7;wE4Hd8K z6BW)pK}l!~pEKMoC}HUCa4!fdg+CV-v{HhzO@ zcOehz9{h3lo`>h6A*g=Sp>7OHC(Uv+2qP+dN7BTDP+swCzae-}13XIHG^JBJSc@SV zPov#^2J92NCCayfkMqG{;M}|M!g@*ShVONw+wM>`TmPfUU>3q`)ix8ZI0wN-A-?c{-9dj+JK}^I1Og$0Qt3vfth7s zvqS2IZ`qWvo%9F2qJPvk9V*e84eHmElyDl(vWak4cOsNly!yoDC+50d>b;xpczMVC zj!XR%a67#wR#buDN0s2mZl{;Ua`G>3zOeby+3T+F7QbE`DQ}PDYzW&o+!gFEXMR2N zQbj~4{$^&(k-c&@5#)J+mS!`?<56H`7twQi%d*|@0#L#)V;TRZ@uKOUnazlcn0QZp zk{7VFBdCtv2$hxc5G>Ujr5R4)QgDV~x{_$buK2WH#7xYj7r?t>^)o5;6A>aB6#m2u z#?<;x8#WnU^5ZWbf3_;aS_6xN8viECW0S#b2ykb?1v`e;azHuHnT{FGa=&jn%K=V@ zwyTH<@dg-{>F()r*93@lkpv`~-DiCumw`Ffw5}Th)ebaS3;>bdhjvJZ;lz3G=)}pm z6-)}^U&wgrUix4TjDl`xNPr}eL8C$6ve{=oL0~^rpfmH>movyEK)c$1Hhc!85mRN$ zg)Kif@V2H;$cecMF7{sNU2s*;b^qAmy5n?Rv|q4?OP>lqeIokw>B!Tk!(-B-GjJ!b z^y1isv8&w+d5uwLW7ygFa~qOt8GW`S7_yo^TcXgPUWtBKUdS^`EHvEx*#W=wcf0g!0H8%mKM(TX<}aT8GkFSZc*31YL5pOFH^r~N9R4k?J( zVNbAB@r@8Mo$@55pv{IopF2g?7fz9_rl?bVqD=vqsI^N8MSnIbe(e`AXmYRzsA(GL zYtiQ)n;7qp^F$1W3Qq$#wfKmu(Q-;=YjiL;*aC<}Q(F?@gfj8yppZkC?$ zO930f!xw%MT8>^s~ylHaQ%%8{s-4Hi3x(>v4AUHAU^`BwLM%<19 zhrA4B2Xb%oj`{*YFE|Du#hDj;a#8Vv)pAB6kQKL%0vjD4oQ~(ATIalKH+c!O1#2vx zwIZm&#t>ZT6xCa+JP)3FAZ|I0P3UAm8$Hy-JBSJdyxst<5^zb_^IQ@sQJBibQVEH# zAVnYy2b<55(@;=$F?1nxwf=h7LjKx0OUzYtao>e~m(GM6cD=p%?Z$B3fdyCZ9Dhg1 zn72lRf=ks`&)n#W2%R@~-xfM!)wQ5AtoV6t|F!*d{Gw12Ygmh*422g`a1d`GRgU5( zGgeMNjynzOzFYo!`9ebn#k}LLj=I-I+-n!y>nYNmikfJ}x=6*kg^G3-JN3P+>T375 zNAbxXt8a|fdm{CoIsPM|Y$Yy5zy<({yLTNxXf-@a4`b5Dag}9yo(ueQ#85#QN=ZEW zxDydV55}1kAaojpjWid`RPq~90gMs?E(Kv|Dj3ni6)?}RKoyK=-$zuysfA&4NNgIj zT#$GG>=`LieA+L=@AYym(c&n+H%&@iX0boc7)OXbmhvbqX0@$J`G{BT`!r#-DzMaI zDlukFN&Q6(qLc@zbpfefAI_LWGj)T8>ms#Ys|g=Td1g%i^nEE>W_iLl^!rq_DmCB` z=kv`tY$%mVL(o>moAmp|*GIs3o_p!SG_dn3L(r{cRSiZYXa{X>S1Dh#Uy;{ZaLj;Q z9A^_4eihAv2hJ0s2^4w&dOr4N)}AZ~_{N3&I7t zCgZpRyts+U&?e$jOA_#ui9yCp65VG{;gne}fMttwRW;9^lj9R~z|b1!M8=T#nDEfJ zA+#oKKe7X!Lnw$lDES8cCx95Z>&GSnbpDJ};h=kvPEQF@Xy{05sFEfrDNlr_yu}Cc zE}bRk06AYGr=Of7Sl#L@e)+1pG4~5eSL%BNM~pz|fR_iQ9o1j`@N>uh2`?P@ETiL0{Y)#F^tL$VJK=C?HEt6=p1d1@Vy?fhP1#$h89RLFgq)05J{& z$ZatES}wFiv#TT7)mQspJAUo>N7?I%$M==_uUvISD>g;&-?8a0s-qo`Mmio{=s0lO zaX=-)hr_2QqNmSAPM=$JPRH_#FP^<{_Tub?*{l5v`HkoKJFeoWt3BdsztR6T|AFd2WffWEIC;xfl0d*!!)0pv-d%FZNvM`PQRAxbEiUM{}woIaLceHFI5e z?9P|>&F?!Oym;=yxvQ?%O0SjP;BWN(p>5ILLCk_p7dAz68X`Fj*Q*zD+7REFA9b#Y zIM>{8-R%0_p11aVZ~t5S7o9zGo+V>$#>Tq^h3Cz&yrLzeJ@*kVR#5n=a9OyTeZ?Lt zDE+j|P*oSLTpy`izfig1JpV1n(m~FEGE#adn!P@pz5cULfh|`2)WBsu&E1ii6yd6; zqORjhCJOrHl0|J)+*S0;Pm2sCwbA01NO4QFxFb^B@l%71)u8lh_T}_T<|U)0aDuy2 zT^Ft16sg{{P`%|Q`n)%S|J4UCb)$=F>R#J(ZO@xM(dJ!|=3Q@ZSZMB9sNQ#}J66;1 z+SAvb4p+B_+lRs@N5ey7;mYyLou7SbGq~$f!NRq%%G%djueJV*PSmY%?fp;F427ky z+ArI$_Fb?3Zp-T}H*^1{VCPZ}Rp|aFHbZ{#XXp!8Dbi+?#K3W}U9eqDN7{^%`+;+q zJ@0ID?(Q(WUuoLcZg{^oYtKf*_dCk=l$bs!FzqQfd{E4hzl8bAv-hkweXy}|Uz_Q} z!it_X#t%C-!vBLcx%&k356wpSe`w{%FI1Di*@!%U*vgT=%}oCG!bh`AKXP(#Rhl1l z(75(QW~_?NVw$Hu0OF}Zc-Ld&irf_=SP;fuFl1=Am55rv;RO*UaogT*$W83(_VnWf zH$fJ@&arhHAT&~D$V+qZhDuhf!z9S_4q^mq;ovL->#^=aT{OEYl3f+c%DtF>AwQZ` z5y`6f#B6e=Eg4L6_JzM@in}M za#ys2;OK`Gm2hwX6tHwN<};!~VMHkWNGN_lWeJH`c0QmpR7wSbm#JT;4bn9v#V}|a z1=~DQYD{M*U_7p@G6nxgtMZ+qvS?9Lq^N13s0HUkj+Ipgxg_`RfBgbgmd}T@YBQ2S zhe)F105p$B*6hLT6coSqi{pka%)gC6+Hu)40<f33)hS0qWC&r! z%$J@+5)kBCUrPvJo0K#~K5dU4qt|LUSS>W2;{tX!M&>VL2%8Y9voRs`-yl(d^1}fH zZ35Mi902v&IU!b9L9}ozzx->dGp&2*!xQuf&(sw!(k<+Lw zTFHwrG?W7FXD&bPZb;K*&Hf9@g}{MCYf1VJIoILDGZGApL5RzFy?`M^BD1ykh|I$v zCKqFa5?T`=eBrYf4NGZ;ng&4jPtx?JdKuXI;=Xi74Jv(PExo6?btv|Pz&3ic3bFBD5l&n4p zc*5Nyieecvm}l%>?nOJ;z2?NBw?#hmW^7#xV5(Ij0(==jw<3TsasLP&#>6$Q#>CYa zvNHySE)Y%M=98GVrXUS6d**pCZS7cQ9JmFhVQ$7Kvuw4~aFKsgr8BS?)s&18t1eo` zh^1PxhcRN+C4|Ld>y^2Qg=a`^s^#=b)?>(6b?##qQj;;qe7fb_NG-DzZX`g$ z5E>FULTu?IJd6`5@f75e5q@F~f-y*$LjIHC)eO~@2u|PtlR$*L8rkv^>6J}<>V3jx zlNoqrOhjzO?xTnuMUf;h00&&WWS-r7>)saM-TdLMw_Cz>hZbCqC3Eh=Li^QzIM*M) zEwtZRx9O&|xNa9Q?J8mgj|04bP4^UoI^|D3WLqFoX4P$1-M0`a@n|zMsLm!m{+Y7- ziChSMqRw-ivoIlnkN-24pmYV9LP+Qoex%zbBLMk$;a20tDAm z@R2)Nu5a~UJa*yOD-a5ZWwkg!2dg+zwwY~zf;}qW?7Si>)JKGRd@FgqvfdJHnCL>64^#Y+ml4oPXfZzpIXP@1KewCB zo8+B?0eVDGAA%BixO??*m+c%lpMx}~Q8cq1gr@^Twqx*^@RoR4Lh@9WB~=f%4>K+Z zcmgxXjurX3F%HUE^vA7$l>taJs{0JBMk@XVDt;F{zro2;1vH-WGmoRVZ(=F|VKctT zDZE?t^gbb7&_`$UeBz{CdJ9Q`Ju^UvtZ6|q@J3T#`g3v^WTTQbz(x^6)emk{E8}+j zH^dCM;e5sp$?xPAT{wE-_;voq$@9k-a(6@>JHo<_uw%#l08RTBa?80(Tq%FqT+ZRF znbm;-1*%Bgd}2BXa7^o4YJvkuOw7R~0Yj>n{-EEaFXa3K{usuOL60@Gylwiqfiv&C zM~*z^6e(`%I@%`@f`#qQd;+3g;vinsC$aFjd&G;-&XP$6alqu~r54fXH;bliNFeg? znVHW5pOyIp_-xFV246b!+2PAjeVNSXK$w&Hvf#@mA2dcRdZ@CPqbz-B4Y{B(lnZU4 zJZK8#LrbUt8bXBwnPSm^Lo6O}iX{VCV(CD(ST>L&mJhf@_du?=L#)8*b)G+8+$mPR z$SV+hpaAbx_);i7B39$KNc4y`_$~IAh_zx};$N*;FE)scR|LIN^p#=aF0tuFi&{ph z%^-Fzk0o}A&5%7T6T8J0lva-4R{Xlf-C`SlD^Slp;+mv-R-&G3@udne*WtHX+$*lf zZw-Fi@mnkQh#T-*hu@9(t!FjgByPT9N-24txCH{)4OAz@p*D7;#z{^gJ}Pc~(K^sb zVdDPeFS1`eAZ|lTn#5l5ptv2r=IOeILu_{WDzI96#vnCMx-tQ`&#i(6b_SbRVRZq8 zlj%OQb`2CW2*>aQ6Z$Iw_S&L7?7gd}?~tdzb1!?L_z->e<1pDhF+Muo>hAJG2>`k+ zINoJ~ti*+d$_P^!f;UkxDXI*ff?kjNaJQ%HSS!m+Wge(mAB8A4o zUqUCrVI?gVMVenen3nUS%CQ_+;l99W2>A@TrzfVQ)XfUZ zo#k@4`>`Y4ef{18-3N9-r$)^=shu7gZ&kQ_3XJwK|JVt?3tmf zEnVn;Zy&UPpk1Tp`S99KB=k}+friH+j5AE*%qC`HZm4M@ zMYLf663{DZcD|%BhTL3WDlt#?9O>ELer4~K=HXr4NzO7iJ3tFVM0zGoH*?tUzXT6h4}Fwh#Rm})flUTc*5Z)UB`H}z z^8PrTB_N(ug55Bljzbg$sDw&2W`-(_-`d)mkmQd$y@_mba3YZ^N+^3}G#r@Vw8wjD zV&ZgwVHxo(rab~xIY_8bWrwCE##*Un7A*-0(>`gm^~mA`LC1~Eg0 zX9IzbHdQZ0Y2nF}ZJLDa$Asj4Y$Ascu8)Z<_}D@YQClAi8t*H zhA*J)NVp3=`B|>|1L=NZ;8CIMIZ1C+I(wM>JXM1|pZgSAr3+blsxo`n8`YgXLBg%r zGeR7qlt;k}P#bCFz;EY>j1_e9QgRl?A ze9{*jJQdGTy?<1yN=NW~YxBj`T|Jw1p|E5SJG!*ZcBNX%E!&!j04fy8N14XCpErG$EeM5Ga` zwT^N_;i`SIg?fN$4pzpd?I85hV{Ie~Wc$QoXnll(FZ1qZ$O|?vbt#5 z+DO^jg)$~I1Rh``sXREC$^(RoI(9}oo{V%nxzKT(5){SgGbLQxxv;jI8n?<)9qGmr(hN`YuAeK`Y|)QJZL?$VWVx z^O@oNrtAG5>9vOH&00gvN&ypzlL5}VtWN34wJBLqo20LgQ#}ZvvwE`ah@TA1?8nr3VP*NjO|onR(yMo1C|OCN7uJzh`+`g$BHJ^t34 zsu;>_I^<P4@59I&7&=rWW3Mq=72zhHWplT|8a?M7^FGj`;jy)yeZEef+_He;3Y ziT9oI%w%ZN%t)oPks$_c((KWXp(p!{RO&{DRD|cGJcyxgc96f$@H&+UtCUiyeAj-F zO6xx(-qe19gm{LR_+sp#w-H+1DNj-i-L~rr>t%S=jeo|BQq(?!OnQcwAP;+1X$3*^ zln1E_l^~>QSNz(qREhd;)ZP^zQmQ?R7#&Ku_KO&0%G)Y6+NpfkerGb2IS3)SN0ji9 zPQ|DF;!s8vu*90o80pr&DLw_nr_N`@w+4!kW{(n6`+Y!~45)8qjPz)672ku?Y$6f9 z-vQfjJN|0$m%-SFLTIcLa#M_t07YSF>S*UaMA9X|A#97lEQZhB!DO8~o{^cL&m{O5 zMECZSB@6tgL`+oz>hDC?%5=O+GB7PNaO7M)z5U&Xdp-NToLM9>l;P^iI5_ zc$)kc06TGDUr&P2M-;Lts%=AOZrlR4K3=_Lr(fBC|fqxmh7 z{FXNdZ&bZ;Y9W79G;7nG<;NM$^LdwsUOj#J^kPQioDs+?r0yBMM*;wIMx4YImPZSl zB85$O$&8g%N6Xek%GN~7Hq%LnaZxCa<(FRk%7w4svptquf}gZlL0Pn*F;dVNE!Yq# z*npsnSa~f)E{Wxp;Wa&0-8^TE3I!13r!zmLh-l%aNZ}?#$cz<~vt&y2#%T4%NcF~O z_1;MJUdpNBZhBTUz4mr`Z7i>Vw9n>ty|gD*S{^N38!26jm)^TVW>hGO2t`q$B_gz3 zKd~sR{Ru>5(&p2`IU8?U7llXATu0W+WAkI*n1~9cVWITz9J#S<*Ttp_O|P^>?d4&6 zc`PS)uIFy1^X1|B;cuLVY)x1wj5)IAY)jpoA$#*LmNpt}WuMW(znffJ(ft4cr{{MW z_O^2G7`eSQ{5z)ZI=p<)$nCA?KWHk1|3jYJ+sJ=tX8tm6Z!`a4xs}4}IdTybZZo-q z$!HD{(k4QVejT1wsRG1EeH7q0%WLPKbjE_Mm&Z9vqKsKHFn1~=%#{7Q7ATFG0k01$-9`ccRCFnSf38b-wTU0p8 zAVh}>kHJ)VM*T+1k@z|?SC~|hNCT4uV5e|I2$n2Nwh*_E#9s+s%Pbm7rB-NJULM## z8fO+4xstE#lYBabkcl|n2jsa?aN@2tt^q=z&!gQ2uq6M&ZS$33A zE`^#!Z?fDi%n%K^pLvGtfjsj}Gop}v5V_`5MAA4OmOrVvDubv7EH@#c2GcN5W5}+A z{vhFak1!o+GdbJH*#QS9Y0u&(o-xR_bFZ8OvnnCQDAJ!&B#V49sFNPnFrW}R9iZ7y zbx>6L1)3#Z3~6X3(?I$3ZGz&DAR)Av))^p0Sa_i@npGdks$a-zoU`0+ZLS1a_x^>cxeYr1H^!mBl5N0x}IQV&Tvm*|J=qW*oWXwUO zdbJ!CsuD~OE3oDr_^V@>b9ShRSnl%TS5F$qh!KoBh0=f#k`W^qFM^RC<3u2CJt0k; z1S0}R=FQrToY z=iM;VVSz+ea4HbzPXg58BdqMf!i{g}bX-u*zKAyg9wl%}#|b|cvtMO|gJVM|AS_lT zsezs%H4j8*kT0oiOjn_`!6{WC39Gn78!^g(s1>pulW|>!=DtfGY>>l}ZG*+Fq;Nph z6u^v^>teQQ;ypS$@TgIUSg?e=xlTY|FkFK2B2FKWd~7^NV;ZxM`Y zR4`2-Dza$(UC5#rT`u}bQR%DAmz!hdO|i1ZPpo`-HUu0?D`Hi(pJdsxGe0rgbJFIl zOC<&fdTyWJ9!{^m?us^Si8O2pH!vA^=q}voinez}+PlKl-E(`+cS0OAKVq-A>vTn( z?ugS3u$S(9dFTAjaC+_a8WMaDH+J4FDu1=*atq}DUv*q|#0raI`6Zv&%=MXx9Eu|L z>ZMGBJ&UYdgkj&Jw&}I;Yva+{j!11sB2Hn%UUfG!`{jxGiEvrl4cEUa{ln4^`RLxK zBYU5on^?&7Mg?zJ@WwK;qnYKA%<`+&h0J1WtkmCZeMmBrt~xG)N$y-~ugT zZ~$u`^6X!dX+B!$@-hz9ue#dQ^og}5NR^a~(Tj|7WVw`JB5Uh|tvZG03e&I4c&?Hg z=|lM|_?m>?jQQ_S?57cf5n%GN0P=qq>NHTLiIr8pI&pa-CNC1K3t9?RwiL1r;4ZH^ zpSIr&esA`z*^h(+pu}tq_nElP^B#+54R=f6JgxjKTP^&I@o7Zq^r#c37u#$?E(*1i z9}TbvmH37!gG8IJ&UDdbf2xy##QdJ)m@exBC(Y-#t^$o+b-Vr|dctUxNp2rDG;Ty? ztSPMqnxJU~11XTQ(O$i6)ik3Tj94`%Ri6_~V*RpIDdbro2fDSfypb3YP)g>nTEPHJ zI^RRxinN+5KB-7Qd_*+`p~OtqG$xZ2dL|-HZ!#Fp8>LeA-L0ime5b+Yly*I2G?H|4 zQ3~y4DUU)erpn!6M${-#kx~a?Qu^n4$a*72trA=NWi_nBw=dFH4O)7|r__;7V^~>@ z$`|dImG#IfWv$l_A8FCjD?X(xrv2KcglfMt>bzLlV~N`7Fn(F>z634b1VS82hn}uA zxL(N@%>Gq$Uf)bp)(z&L#%MQ;=+#ZPrytZxWeiugWtAS=pww9VReDSv9Ub;HYyUO0 zKOK;)1$qAy%|v$Yu96w-O+|%KDiMPz4|=ss2})W^I;?WhjvVyXK>|uML|vy{V#b@9 ztM~K6R+;DkX^<%4`DEDZQEILI0zZgFkrBGV)1^O;mzwZ!Aw0+8>%y`Z)z7uW8V{PbIB?n&2C(gh_#;#zM)DI~i zHV+IVyHl!%*BK-A!>oW~I$=iLZ8*b8!>ld%s1hG(_bYzwSLwYj!|}@o!&4aB*)$v^ zrjPV$aTMQ-k#+%zdnpg!4=JJA@2q{sKGLVXD?VjSVi&cI98p5G-p*SYvhOUXl*mx@qTW#TZm=bj(C&^TLEUaTZ|T74QJjNGpoCZhV_|xOuz#(o-^RH> zs3;*cC_1Ri;b2$l7s$I0axJz#8+K z)a)Q^jFYIq5Trn-(LZEvx=U>tnXSrFYAti85!A32%CgkUe@VUb@8HnEmm(X%PP=3& zsWjL%z`4?L-heD;VS)yceD=l&r5{sH-=UlYg$EzEsiP&mK%WU##WPe%Xp-V&sxq=3 z(;P)1Dl2Yg5~EB5kr_RZg7NH?GORL%_bH|NkTT|BEo*{VkBIXmQW!TurjQ*LO0Up& zn|~bC7s+kO+*#U$86P)p8}xyHGdk)Q8Ov5<^OEdX5XXJQ`<8xF=x(2>jmp2(<}Bl^N-V=F>rHw=X=A&tvAez_KkNl zoG%}pKYG6Z8^`C2FbMkc+4-~Q1K*gL<71gwFQ1%0d4BL4qjM(MWS-j@D=CMe(E~6v z8ci?0onDNrqV|%Ay(DU{0M};`ESdC-^RA1f7fKgkgVd1)d$vzsc>1=Z>Qh*P%)OX) zAuU|IY0!k~Mo5IdbcPU{sw+;$#w;gpbIRWDo zw{xmsmons@y>tYTz9 z=a`IR#LBCp+xbIlOV7X5iaU}JNUuut=UEAkwmv%70-_>s^9ZTq$Db6w}lB6hc$Xzz#Bf8Fwf7S^?=BF9cG+J~2Tvn`(uVSOa0{(5eNY>Rv% z7&5ZXyI$HyOq$#|>z$ICt75cvN2GSgLdnjb8nSJT^ZVzz&u@r1TrYol{>zvAm~1g; z!QI@Vi%(s6YHl}9SfY;dh@*VbQ4w?IU(CFad1-3VS%WxBye*?K!GyfdFBG(#H~%!v z;3|w&){zD4aOK9!)i=Azn8}B(g>Aj(JE7(pb=5>%HCG2|^0|u1OzPDQAGsQqYEY3+ z>kWBjmrgF^*20R1ZOvRan*{X{CpE^|_K69BOHUdNSyjJS$}{Ay`vrKMS$nx(Ks!9Q zj=ePB|FqWNETH7;6INKl`Hk1RqxN+$1!7zO%TKGBjSyo-Ev8e{Ssig!U+r6THmEI& zI%{q_Yks+8MwDL#{sd6#`EGN64fnp4JG_a1U)WWEmk-?B;ST;dQ8Ak?mmy2%hP1AMpF=K7oLun+>ES zc$V-IpIhBEnT4mMciKhi>{c;0Dfv;+*G&@JkO}c)3abfLW!$D>OUVM6EJ~XN#5Bhs)QzGQ5L8oa_~p7ZYcUnykm=0BTMF*HeoLo~jADO`x#>8ddKdI| zrIPnZwc^u$wSF2hR)gA?oB%qyd~2yfKYZkYylHj~QI1kxuu1XF7$00OrF~MDj5oNs3`)gBnHksGO$eht%GZ%$xio z^?yjd%fym{;Fie`YO8pYe)W56#`LD3@EobfMB}XSSz`)c#TNRjLy$C06?jXCo{^Z9 zymQD>5+_MZ3Sz+thJ>5UKqiY!`G%n`k*3ggn|yJ_d8#hYue-oOIaSPMKOd_v5C%uDF$c>H0V`3t*NprEgLd7|QoGikmhJ zkrYU5fUO~4g2k%HP?G~x9PAt#B!c;h;fm9giu1Ep1ZZQXA(o9%{ZG7widW!YenMe>@icYb&8>w6dSHbk8pBF+u5EZ4MoU{GrLED@ z4H5j$+VHvKw?|6bBU$Z4w=zaR>kZSQv;9t9ZP;0>WPUPQ))pyiiKL{E6G!2t3Tib; z7%w{3sr5g!=zL72uEDvu*&lX#R8yL_bGBa%zV_v7UyjyokJNzxW+-7z#8I>8s8jPG z;u(bdifn$ObP@>VMdv{@OwR0P|M!l+bv*pok;S~n!%saEc0TjVr3z}uub7p{=ed3B zxfdIDTMWO?b?@N+z$3tWYa_Rt<8N)^$-k9i+}h@$mv;@^Zk~UaV}3Jzc-OLP6F$7Z zonGGG!NLE1j=4N@Ek*m*n7;4sO5fLH`eBn9FF#ykLeym<4K#NdTKWz=50Zt^LrRrR zME4jHXm0AWTtyE+osi;`M^}(J8O=?(#D-l0(*Z=n%Gl^o`g0^H{gJd5JmW#rv25ume#HC+c1^$gIt4_m@aZpj_VbVoC5Bbl|T>=GG! zWSW5W*Q*zWHbi^*^!({)W@RL^@@l&r4TgzGo~hxpyClw3fh?ad^OSQ}IZrWvtsTBw zxtynzzm;bpe<=rd+4z}|f{ow5gy;Y0_|eQrc^)jZvT_!%v8h+aMpk*{lLmvvLGlr7 zT`>f|!Y3WgR~oYm)cJJK`{2%Bt+z?qM;0DS^mYdIwvE45>B-=3nK(~6e~Y(}Kb?cC zYCck5(41zyeIFjVw;2(KCZs+ZcSDbG(}aZ-luzwF_4*^$duE`=>MFr;)Ha6v>IelX zYcWu%DbZtvsfX%X{Sc~(0%@U|DW@5rQtY@2$P{krG^|9bUWdh3j&0*G#7rY4pMD75 z-~>DSh}#e2-a6nOvc+a~_hbu?r31sImeTzuIndHbx!;bCHOSDy@;g{t*@{ibUj7En z0w0pgyQq=39pT7aGwx@*(*0`h<=*S<3ngn7ve!oKYj4}v{^E|K_@@RVMIsh8SwvpU z0l#$_s9wx_H2fGghW<}Y23PYhmrNA@SAmTv<#}9l#JyOz9*5{_`8WCXh8q;{hunI@ z|84VZHvPpq&wA6XRx`qGtv4g!)@Bp@`jaOUtxK9b$UXJZ1Gbu0h#uJdLK8}*64eQn zo>~J<(g_nPS$<_@L}D8KZ%!ylM3-PLX#jx^ZKWZEN+-$DrVzu-P9ba=6G-|x;_GOh zvl*lE@UGCDIfG?!~p+4S&LI<^Po5Zum0__;YT%;V*5wjHX+bb)M~*E@lMY+HOY3J4O@y@;!FA z{ZF^bD*=B34h$rX;!9!!;J(_TUD7ziY4V5)%^FD8W|PKzWqb%L@=JLX z&~lQS<;RVXmEa-W!7gLOZLKOO(!h?M5`vP4XiB!#$f#325XI9aQz%7Ic`yf6{*xZh zNz-(iwFFguk*<886_Q|>2J|p?XTI!Db{{M&hV9JEPz|9sRHqD%du$4ZgkbK1j9)QL z)Z|;ITXEP*S4I;A(T}M9h;)BSzE1X__ zC#Uq%sWeg)M}gL4WWP&-4s$3#AE(;9ZTo+PQa{xn1k{cUmm)Ltt8f*02Qe z0$eMlv_B9xkK+ymzj`Yzp-(Eh@EyE72swkEpBcBwa0y{?%uz{T7pR$tjVQ8PhG%$$ z@wik?4rA8-W{h7IpdqM)S+*fIpfSOPlxIejC{+;+^&UtW(O`4h+Dpx2CYi|o3qg^% znVD^2V&P1=Lz<$=L8fftW~QbLrD#Wr5iTZ}khrBmI!p1V$vLN_WI4+jF==qxk=X1~ zCs?K=n~3rbo|+mz9ngX8%Oku?(@R1&^7P8XY>;94-ID59X)WeMvT*n(+0a;sRW~H5 zLHu2M4qZbf>qU@O15R4Q=_Sh}L5pFzNcn9-+X>>3=(v-Kj%Px2ocx2y6p#w03FCRl zRA4Hfm<&AA958F(n~n}rA25~8%K(}V0N23d0|%d{i=k<-V4e!Ad)!aPsNy!dY27;p zMZ|UE89tt#WX&##LqiCjqUy({$1Kf^XUX{r zIc!o;pUIO#hB@i11dwcCl<6pKCw=`pnhYv^hI`9sGE_#gD`_$SK43nS)}{alTZXK5 z+9KLQIL>3`Zy7D{FGKQZ>9OtjZFn9u&Wu@&IH`}`;#D?J z4%j$^H`OG}>{enkV+)^pEalOsrj3=VjXE_b8y59QuUy^D+5TLR}I^lbW;vWorga)}MBd95;oRh78T>c$Z6W8st6{7vbh0E<+k&i!%Oa7)u0$BAtdhHxd@TBQ^3kk9 z^-q(Zz>L-?>1p{BK`yyCwY^F&EKdNqPv}G_PiCh7G# zIPo+YOp={WS(|DdeF~AYk(_pN*29UXX@(W$+by9%$<)@TrT;*AlC*J>5sq|b4h8D^ zrzS+nM7dbW`Ck;vO%7wHPmzz&SpSoJza)pz^#rFGZ6!(M`!YFSC5M(bvuwvsx@FFH zE`^cvGyDa94~zWQ44)Wl%)%$VoI%KqIZ75_T_U%7L8y)uZCVgE#ay)uLMSM2u((68Q zcB@}0a+uGHRaQUOP0j&w_T95&nRjzbwFXP(PmP?p_MQp8CFaAu4(sW12j*m;bW0W# zErCteHbSr~R#8JP@XLZS=$w6$ztfz3*O|9u#xJaRWall}$d_iwu3kzfA1;${FJ+J~ z(~w=h>2Re5eo;qP`;wJ>5Zvov-%x|J(tGI$ySJ^ve2BZZo3opHxqBsJoO#XC)70Fb z8cpWCT%zU7n`SmY$=%DWHv1sH!n2O&=M;u2WbB!3-5QcbEy>#$jXU( zImm|$a+XkciknlrltI2sgR5Z4K|UwNqm<}9WS>JmWMAw?rc3GBi5&5Z9CIs|tmG3Y zwT*m`87pA1kT+EhVLz+4ByMz$^Iea_Bsb}K58_XK60A_}-cy+RI+nOypWhNUZgNh? zEzWk>&(47T>`d6tcEEnN6ZW&SU_Uz>_Oo+fKidWS*}1TvohRmB;g(x_7MsKZSdPvX zo5ey{n9dPf#3KB<{4UtnZWW8+&%QP1w z%4)!Gt+-L#BsL<~y6L=z&8+i%d(q=b7OTm+g?4rdco&=)oET+RJlH`gVW2YhnK;G7 zxhl>~+4<{3ELbb5NWx0BR)E&a$wsmhwvxSF-F=;hdk*!l zZZ~-kxFjr7ro9hIJcw>Hn<_-o4NHkraMt5;75ff#dmdfIhBeF+4-bKp!t#*mVVmy$8# zz9nTXqin+f=29s+?~=n1VnV<*+sT@NWa$U=;fLh>h@8J7=UC@?hVyX- zoL<UANH2mfu?u z!Tt-@=;w{F5TW)yJ`+9j0#)KVJaQ$1@X3!Jg}&lsTOBVY6$CDII5QgiT#sq~fI}TU z=AE%ORH<-|*#bz~G})D?q$$-3f>>h#pF;KI6IkuQnFtidM#9m>d&dEbcsqsM4QfFwid#3PRkYgshZ_skagRg0_FWFW3 zwj{Gh;2`CJu3;km1KDpT@Lrk48sf7_(32t#?7u}`jM)Z8{k!C^B9)iv zK~q_j@n&aqHfUb@(Qk=*x>F2>|aC|z8ze@b2$;YUn zO`XgjAR&q?wk=RXMExn6KMZKe9NcGGLl*hAi;%f(=b7#8AJY*rjD-<1lowtQn5m6r5{rCNQWh^-Z-?pqQmqwW?ZX4A6V0-_LKXANEy^zV65{DfT5_qV0`%dC&+1X{^|z^&r-Xt`eHw zeyFUa)ua_aC(gt7GOCebdr+X%(<_V~z_7e@LeF-$ljc@A_yCj3f{% zXf;ZaeY{MgvKJXCi{c`oHqf~?e|sMpK`bbV7Su-y>Z1iMk%E?GsP6;u7_$d(%?iO% z{+3{Yf7$TR1b%@Q2%VkC!}Ep6PAr8&WPwiSWGNBIR}s>g3>NX79%h?|?4Ic@8k2(N zu3R+Z|B>aWA{%mUYK~+zOou{}eyAU=M=dGn1FQ&rmzAZ1QnT9UJ*01v?E8#=o#mvX zt;lj}1@Jdh&!Lv8^qAJNqzgE7ZQDUZ3X_o@o&Gw&N~R-)l!ukP10^#HPokCC7UP2| zLN#O1?w=wHWC{}brcLoBGl5p=-}00~@v8MN(p0Sc4x47G?%vAwkgO1F*jRwR!5U8j zg-ZkDfx);`h6CyS(0!01aUL`qHKBYtc7nI4@e}2}t(KN{9h{SL?Ocxlnh|-)D@+ z=RJIP4tLAKb=&z{)?N8{dAE$~cJS|(d+PA=KE7n}?^`Y8cW~rpk-H4;s;J`cs&E%; z1H+m6Fv!X=NMZD1q~wQG-xFa8LXS8_G6bG6YIofwY3HUZX|-Q530|Re9rl8*4z{kj zZJ5MXNky#$gzD@BL#kcQm8%`~P>D$`9|eM>#wVL-Xs-(Y;aA&<{$LQc%kZ*k5HiGr z#^d0|V}Bz3R4r@Or*~!18Qie_Qpt?zg7Kwt9#Y7&rib*XMYQS>s2UQlKvIyi2^)`0 zBALz!QXcf3DdWHk7K*r#KD8(b5@W*}G+3sJNNvjzFkRfjPKxcajJa9K@uY zM+OK~hm5#6faY?jUM3dkzy@TvoToxxumf0dm)!L*z}4W8K`G&7@iZ3E%SfJdh3fW# zfYCV5L}J65HbjLLuq~@)rL)5v#{Ha>s9lWcfl`-JVJ~ZnbROv?+IJOb%wRAh!Wn_| z7xcfUOq-E%au=V*BS6APKg zqQbGTaO`ePL$qc?q-MiH&8BGirif62l7#a$-)g*DS$p;DwU)neK6R=3M*Ge7=+;Lg zTOW;XeKNB3$=mCn{O7K)6Sab)ZXVliir*W4YxqO+!j9fW;ox0|>-=N1c`)%triZrS zwawQyUqABQf!7Cax)w5bL~&EPutUuNW|BV=x|VVbwgK+5yXBki{|Dz&pyzEn6L+Y1 zc6MiR@4)u9g@4DGPyRx#Tj1X*Dj@&5((W|=T_;bj%aezo_ZkT}zt>a(|N8=9GxvU) z1@1Byu!;v~V+g)x_?q==!q;pvK0L1rExvBk2o_DB0XC0mJ7$j_JcQ;ypfuoa0xDv4 zK0Llzw0!RPR^%_t+eXwiuha%um{z6=FZHltQMHuF8PIkeTv(5#j52lb*azWttK?16 zTq%zN{l9J%opaVX!;n!-d(r-NVcx1|_jyj3vmr+Mi-Lk9qa8LqR^xnf3~MUnoHahg z96BzZ(4e`PL6nak?1#9tYHOABSg`-_MFu@f&!TGIa@L$QFUnH71Fx7z#$bgKu93E) zIfSuQ_JRaOW_d_E9MA+%*}mA9@HS-ZBe=hazh7gpKdblSeJCzu+_5+1)cWJya(E9r zxegU8$AQC>ZUwGRCoBLgTX8fSvD0(+o`>f*jAXb;WO$A!>-lU90uIX0jA}<#G%*^c zZr-TJKGzdgpVzf>f*ccg6WJoBe+?k~iCB|Q;@?Ht5G6N_;yz}!ZMfL&$$^Q9ac}Sx zc*kPEha1MWQ8W|7#p5PiF2j&?`F!KK=VT6928=Lb8^YDhWcxm}S$``~dI~YM3wW2M z{4s3}#Hjp?Sr0nznLm4}`s-i$&ibpt-`R4*_}e?NTadlCsIxWVY`q@%?z68y3qb1Z z!l8Hd`nj*HJoZM0@&FKJK?8tJRl6KPiDzEbgjTL&<>Gm=Wkhd6?OD0&7hUliNG1IM z*)ZnxvaXOm!ne@+FVF$X4aEPB+D^~~ZNF}ot?9jee4)PYIr&E7kUJr=A-Z*D9U}xu zf+BAA1qO$QLj@uvkp>A78J?t%ZbBN!1DcO*>3@mHp!wdVG`17dLBCIueA9HLh%_}A zga!`Al1!OS$oP;hhC!#)xLr!tFEpb=;#uI!dPQ841jA6HqbHC@Jcoi(I#Jq1k#Qdi znJ+B|pgAaDE1wIt5;W5&OG#c8F5bS@3 zv2fjwJo1PvM*B9RsCFqCp{xmBBu&kKP2;c!aev9^#U%XXPFB&Sb+44-S|hq%jV^El zC3WWNm#$YV3eBlum5V}4YFN#88((i+6gH?>%o^OwriaCBT*&N*3LRmg14zqj$F3cV z)@+N^Y+I<=F=zT8ywTRp5v~9$n57Y+bg`^&QRt5e8Bw7kB2-*$A=D_h;N|H#UM*UUeYcUrmKCjOl^j}tHN?&Nlx`S%RFc)Wby%)wm-I%(zN@1Mlt-2vs? zOR;#j9|Be5gVU=Tx+6g{Ri01R)Sa}KW?&DTWY)E8(N590PMLHGvv&W0R!Waj>IO7< zSs&2$!TR90;dzkNzpv8WxCvm7sOqDyklJThCYYg?=mJ>tnQ6F?U*R9by5+T&>bTJ$=7pUmN{1NKU1julO%9IQdR`hJ#;gfUrCc1I8 zQ<;=#_t2k=0i9|@Fdb@>C0Bc*)w^z2@4Ayya4GkdZMX#SCywm%TcSB@BROkvjrJe+ z-7Ji5A?tJt8=ir-|4xK*&G#`Zwt+efK-mBlvxESW>!H;mqQ~WU|t|-RD!}2V~QHf zkKW3|h$To7B^Lea9SbOkzsS9*qS~or!psipkUI|^VLh@2=JYn9ZaVTZ50-Dh`qyE} zD04{pO|3V(1VdN!>mfDQVeF&kn>C|#x}?Q&Lx3uiUVkh^gC;?u-#QqJ`^VJXojl^Q z{~@id{K6@!SEgVF1pg2B5PFWb@090FvqF45kIR(U!Np-fjL#SmW$8^EFYI_kdW;se zW=&0IbK%6oPtc$bPJ>I@i_B%^sZ-?Zr%z<6Ogci&|39?=|m2&BnL+MOSw;vzr+Se|hu#=5L*i=GRB^>*cG5Bk3)St6vw%u6q;6JsHft zne)AZw+a^OcP(UhM(v#udnXPfUVdW!i7WZh!p2BpW3+Hh1phPEsHX>w*E<*OYwl#j z%+YI`u5G%}znIdpo%<6YZ~UKnivPdHt|hjODvG`rX2z}^f08D#n>dk`rg5V<21jiXsA?OMrUKC{ zqE-k+l@}{E`1xsX;N{(zS6;)NYc0E<3t~lpT zoF*lxRMwgMKJ#WedEfi)c^BfnEB*J@HkF9qZR+?pZ?MIP!^hs z>AMj<)ob02I*{8(z+7jG;8NdwMTrJg&$8Q;&uOgK=!$$HlgXr$(^m}+IQ;O+;=nFozE0)G$#|!pNTj5h!H>SiZwUz5VU^Y{CVVD0rZ>&tZ&m`@O*s1_DlZ?^?7^TNaDBa(;8s6v~TlbIQNW#_5ZNlh40{qba0Wd`YrwMNZN>+@bq@1NR zOOWI<8~usm9H3g|kROHhsL7L+>`Xa3<0^SVk3G^#NA1(PH8Nz!8>jSM#7>k?x~F5m-==$t z81>l`t?qz5ub;+kJ0>)Nf^|m=Gt%n}x&v&zg9`RR z!5BEF$$0*p^JbL^zDrjxUIf|7{J}r)O%`#MKw~`fJ##qlsKN}=Cb?)ZRQnrF9u3zB zCO`-hItetaH`IR{S~+>6uF$KO8I%E+8Z$%H6kSCZF5_?=%8ne4nwRrCtNWnGdl#>U zxD4;(pbW>aIdmzxT(!%4CwMHudM_{kO*Z-+^nGd43C1n+VbWn-XOJ7f<_O^!VG2-n z&WUzXJhK=vB#3#otJ?~l`NjM-e9T32hd2F3pvv9cWZ_c#CmG~|Ta-i3{Kv8VRk*Zx z!ZeTtKX1f`#{sRI9evt*`kK-QAF6O&4c63wnhMucsHOrn6|AW!evehYBEPcABOBr$ zsr_{|Tvy4u8hPN07eB4|;$>g_R(#zzT(laN6YMDZno(tS)veJ-))266WnIV7Z{9lK zDqP%dI6PQeauqIar=^o?@3;z=&G3jGZz_O0r_XD&sPuu&CEC7_s##x%gZs~dE+zljvP3bVfbtMAs!2N81K$E z8w?i=lEG<^j8cZr=+AIw7|Ct&nVcr}H9O7hYjIleHTyFCSc&K!TP zGuLl(+WdLWJb%73-*0!?{RPeff1$I`Kf^i0U*s(E7dwmnCC(E6Oy^90sk78y<}6dn zndO`%S)@$gZ2uhR9RFPBT=-k0EZ;o;eCK@Tw)z(M9ZrXTp>rYoo$V|4S2!z}JIA-k zzu38$xpRF>{FTm1=C=8&{MF8C=FUT$rOu_yo$p)rYt%xEWcMxe*EnmKy8!Ox&gINq z=&SXwaIWyLbguNTa<1~PcCPlXajx;Nb*}ZVbFTBRcdqwuaBlE#bZ+$5IqUrO&U*hQ z=O+JV=Vt#F=N6X74BuA&L(YeoyU4fA-{5Ru?qc6|f1|UJxl4Ra{$^)0bIGa z(YQc3?d$Y=O5_&-|0TY;{(fh_Ki~|ow3WUA{}WExA9RNNgU;jr6V8+VA?J{P*g4F? zt9(zQeIv|W?K|av%J~#?FGa6E?R=WKm!Tg|J5T#R?)Ejxu+xZ_NLk^Eu{T;rq1zdFS)Yz0&s?|7V?Nkd5O8#`d;*Z#rYNHUgvwsKjEA( z8a$<*)1Hs_X3PR$oR{(IvgcXPGoCZOX6Ex*&rDCT=M1?$`JT_xSBd*e8HSw(Y5f_4 zw82yGvWdgh`OD0ABYf+0zF%d&_3+)K^Zga(yBWS)JP)Zk3^L!X@O?<<8yqrKZ*$j! zNaS=L@ip2I_qKH1$L@<=s~UfJVu1bQ7kN8ECsr^XQqINbe1 zjscGxM1sKKklWku?eBBAb9zt|#S9%mHo-t|=!9GLAhP6e2ZMnguN(O}q(IN0AEmoP zR9>&w=LtHhLa2LrhmxYax+VvONFKM(;q6Cm9)}2WobZN@1O`J6v>+sVdnk_@MC$Pk zN>m3C?DP7)yo4M|&e|WOnhyri0;*??!yk~mz4Z04W(^D;_IZOxY8;Z6vOYW*Ld+m} zGH}-9pdBj$vLop6`6vf3>do4!)vkuM6{P?+C|>~)EBC~afS+2DqqYPf>K&B(Q6zvu z%?$u#ti+?9o)Gy^&3gkrU*H5attZegd8xg@`W)8R?!$rO9@ZA#z5Rg@s>-WC9l$EV zdsPVv9&w}Yhdm0wP_DN>hrC2{(7M6H!4Nv$3)l|?WL92sGiy=)u4YHa-W{C>8`_&4 zEgg=1?RyWjG&MIl${RZHyS&D6u%&a?-mXpuVzf83bw29YyTj4Y_NZfbOIuToqxq42 z?adt>IeXh3Ev@_Zv^2x7rLA#KS5r&dPRDknYugJ3p;%XGcqC8}fAQK&B0jeGToMEsb4!8rmKEy4v^c?Px~vO~|&brENz$ zN@;FwZtJW?sqk|&AHWYs$F7Dwd#I?KhAz~;9p$t;8u#vdw7q5Lu1?3Uy?dIP;kmsT zHEY}=WFM$Ks4 z+t%5RpEYP@d#9T8U`t1HjiaHxr2|#X+0nii*%LUCf?(E0>DrokE(B@@Ahkyjg#gxt zMyqvcYHrwrywE*u36X1a-Xj`SZH(u-`++EITn5{!XT(hn{X_A*hTu?tPfN%nyF&pv zZf*2oEFW;oaS#@t510y!jAu6nWQhK`W9xs*Ri(B^&P_A(0bw0YU+10qKxe;iyGj8GOEM5In zs1@ih`vPw1JtNgWBW^(re8ITMeYgj$F}DYN9{6Uqdi;kysPBOQhDQh5=Rv5Y*&jIS zrAD{(A9wq_QjOB_OR~c zfq9JqQ1t%L4zCY@ju*CpU?j%KZtK`_P|2xvM+0|d?g{j`(Otz2gP{N_(?00)G#^Jk zto-~P0eR5BSC%|7`)y~x_qd0E599#=Sa-QWd4LRXo4bM@0%In?u7LKSSL*YG;Ad$F z2AN|<$51fj@heT<;dA!|t4-8XArEFHhH*3Yxj~%VKD}SD%d5rEbwGYc4`?iEEwO5& zq&%QOpQojtNL>#@l1|n|aU1_~l(}Y%+jdf?c7U)RW7ReTcGQeK(P8KbbaF;Kk7z?j zr)%%_hcPPSnR^ct6{moM9$!zu@9F5lG}<4}SAHsOqh{&AN{GN<+zFE2M}4FV zvt0~%JKcS8n*s)b&GwGKV83)Y;FcxkLRDwByHD(66Mm1UYd`|}b10bN7S=eWjfisG z>p2m(Zg=;KMrC*O2Tt_*+{ZkCm~eJ_{hsQ~xC!y(y%>1%KD^>HXteDM1lbJ5i%~M( z;c1ED}qz*n86 zv_;8Eew><|+vYhD6h2OZ#K-9M7`+bRMLFxxQyB~zAc-&{&WvUZeLe<21wliB?0N*F zkp_=^*2OLT1AJKZpaAtz7MaGoRn*l}vD%$u(rD&Xo7V z@j;%TvyWlHb10q(B83&5ycS_`GZsp6+ck6C>T>miWV>AP9G44ACJZCEZ7$anpiWAN z-R06v9WK{3!(HTI_+W4ajrQOQtej-eiD8Vw{uLd|A07nxmREEP$h52hk&{7;tdFihHJMa{D&bMntTEFTx)4-7;Cr-=d448+XaKIl7! zVbJag4*EjFHtNvF_`nA=57Rs##WQ=|AQ@7dJV2!m(u zT`+Fx#r%qy`LH(xx{Dc`E!Vxnp481bh3d%k`U?JnGx0)ma`T^kcrw56+1AOt8PB%C zb*7a!iz23ORtO{Gw*yWhj%n_udjxZP)k*9#MXB^{ z_kiU0W8;Gz3mBtyv|6q2M)uum z1v^Eh1oTijo-bA1D{09vCZ)mKqeK#ALwIX6S_JJ}stmtHKKb(GsJ-lq*#cVBF?@%dv>MEpax-LD>kP!hi zg)O$#wy^1^yT(ylTdQjl_KrL{n&QT$RRwL}M1PQHCx}UMhOC9k$|_a9B3=5Nv89j$ zC%piM$K_{>d{+;aKcQ(lP?yAkRWkMk)E_)Ch8AZwCl2{xbiNmzo7SD8H@d}b`ad|;n;#saBRyM&S z@j@4y4?&5Bgja@Fikk_;su}B8`pJ)4t&9=FD@MVJ?J!)+XuF2}6C)IH3m=GPY^~hYCV4J0i91}_(z*h&3%fod zPlNsL<5&mMCYUn;Si6vi5knIk#a?+F$%0fd$LZ5DEe=1hZYJKoxm>lIeY7zTZiRzK{4V9O5U(GeHe6af;fXET6Irt7?apr<{N};vlCJQf!(s2y zTeFXyR@R`OM$`nb5eOLA=ELy?V*=QW3NmThX0_ErF^%;77mR@J^sxFW}LGGvMrQwVT z-5`IG{60mmQM}@o5aT|X{O$pnAi$_$sywfm|!{oD%t%$l4vZ@l;7TsX5Q7gb%^b$Qp-1JOlm z@jGX7$a}AtD^-=?pjQF`FBm0r8!8J`+b{X%|=9v7HqoF`Q{^UJo47jaC>KTOIOr(;I1iS z4MobklWADK>eXG>c3pSAH6vQnM1GS?YhSIpR&{+#bZG+>S2l?#k6e2synbJF`F`?Q zJh@`ct0%9W3~%g=uIL&yzhkXr>-q$QqEQE=Hr|~L#|6WP;V8bz55|+R?V6E|a(oEp zK}zW0aL#gJs*_!=;o>APGvDu1Y@%BLvc2f+(AZGe%J)qP6(KsvDnh7;^HgASs;V4S zXCFjUo-Z3D4F6Q*0U;)YsI!PjVK96-Loy@8s`&^PLM#YTDZcPW8iSPiVlGBjR@(>0 z&BJCaMYjxRvZd*k;XE9N(C&b(^R^7Hv9+$tB|m{IwIRUA2^%rj z5TFMv5Lm`82aruhVD9|`icg#A(}s8R?dQxF^3UhT3MwN7m0^3;RrA%(R}Wr0c(vvF zfg4S4w!G1DW6Rrl;RDXtf!@f0-f)-qj=^};STz{3K=;=;we4L6GgFfqJBU|H1)M|XY7?Fl2)*tGA+ouIvZ<2 z0ZLJycz#fDzg!f|p_>fO98T*cmpe3Ent-ZWz`rB6yR_grZTNnsp`avYuZY+yCYrA7 zyu34NuL)agrhWrW#!CO9$1jB_1fTk3X z9WdNojj+=O5H?%E+4`~iaPGXxqSD*;;+TDL#J+e!x^nFDvFmGJ-|*T7;O@h3JRG&} z3|n_jg*^>z2K(pW_|JsBl<|t`Wiu*)2MBH+-uHm;XY6(dUp%Gm2=IN_7Qz#}20s0O zJ9GqH!=_EvHH8UX;|J?)n!b4f)f_HL=o_ASHucUrgo@tTJhnNUyFm2Ll8AlDMCi(s zm!G`e^!m=%c4E?c{Ef%M`<%DzkA%97;KGK8N7pc?q4P=Bn%&3#gmw5Krl*Snk3|?!s_xb^4BqZRvdWt8Y!any99ozB6V-E#`^-K(-xVbIR@4>S2ZSpi>eplQd6bkCC zl5r(u*sg+^(Vs)rd3*wtk%b(je6W6i%mJ9zm?MKeu$D3H{R)NtD!pE%C{{2Mz>^CN z$-hB>OoGJGJ!AM@MwP{Sr_-2Mn0dP8?))Ol0ps1JM$4?b znPyAQ9h)ID|NV>%%ksM>xbBeaj+ObDExU}0CpndvX3OK6@8g>90Qdb~hS@S;WB_LM zAP}n00`4;2or#T<#zdvF0M16uFnBBy&H^NhC-bPfF;mkUUda@6<^f}7NmeQQzVgfg zE7vCFC6$yf*`)%hQ1g{$T(UT=QjsTHD&C9=O7BP|VEE=peDrTE&UNvRCq zJn7rgEPV5&xHKDIyY#2h9DEC;+tOTo3#C7k=HWX-`g3VMzD3esNDJ^Smfn>d_?Ae2 zDJ{fzCcfqPmP&smRp48O?;?C>Nq;RZ#&@>#9cc-^bELnKD)F7`nJ4|NRHb7j&zJsA zsz%5Hk3;&dv{VwFf$=O3k7ozG(U{FAgo=d%Pp z|5sY6^QnZ-KTE50K2`9!Bdyl?RKw?c(i)x5Qt5qZE$Y5Zx+|^2w?_Itgqh6F<wMO*I9qf+YnjhhozFVv z^N`MGJ$(L6+NSf_0H6OSHRyacGN0`_pE~&byVR)jsb_JTbUvHl^B+>P&S$gqV`&H4 zx5eW)hto7^r!H(O^D|1jbbb#ZR)*Aq6x&#+NqSfp+Q9tG(r%sKcExXx&aaXAS)^8- zUlVf9l-iJUGYid<_Ub}+Ak-@DL+DNxnl0_uh3-OVj?|9O7PxYy4!9m>@oZA3F5YhD zmnU`U{Prk*2Xua|ir+z^UIeW)%ooMjQ?J8>U{RIet1mh)6UY_rN?!C z9jJMMbO<%?^mJu|yNKU~^qu+-Au}Y`8OzHGIddMkj}%2x_XDOVmfR1RqC`6UfGK85 zJr9_oRFWPrMVaJzz!bBj-h>nfrM}*bsr^7c=!;p>kuw(O0jUrFyq<&lf6~!QIjPg7 z^F@BMrDJC@osUp{33>T0S<|IT^hX|ZBtPV#y7cgQP`5OAY5x7z z;KPrHHZ72jqfOnIJ5Qi3ZumH)lW-lDh5*OmOBwK4C_RZdJ#dvvBM6h=s*p~><$-IF z^b}mZ6dx&`PVOPZSS+1J`abF7)HBjE$uX#1h_ys|7O{@NRVkf8j$XK`q))(g6zM*B z$%x<8(x(vT7+g!GQH1yqGR8udNzWm~kB}Pa(+KH@Yq|71TmiUhrO&`M0M`oXvv56u zdYrvvObt=QS}C1FZZeOB->ana_#Ko!F1^4?TP=MKzeDQpHPYwtd(hJ*eJtVM7cOO` zE+g3&WvrFHcqUV&rpKq`b>RW>S|^Q9lh?&dnaSl({f!!}m%cPjE?>USTsBCT5^_nT zO?}df_e)Wzj;Pf}=_`Qsak%QFm(Z6d;HsA<;5y0h>++=(R1$GENxy`2Lu#LHmVOz( zhY_+x`YKXCi8bc0;5(v+JaYV)^xy6UdE~KGx}t04sVR9}y^lN|lCCA>kqoI{y&p)S zF59G+(Xvx&OBH|6@(N_Y?HorCd>J0#PdpDPtm@;(l?Of^C)Yd^n0kyXW-f|{XSfu6?3%o2kG+H z_Y2asOMi&G&N5haNN?+4bx!g7rq1uY;`c{7zZVq0|E2T$99D^cjQV^Y-~Wy87x4W* z_Gk03o=NMwNi3)w(rq|sFBj+cfnJEylH|O|rK?2|R{2>80DXvp zKRm1d+5$hCn9nbSkV_7UpwN>_v}`2{b@v`)M-q^>o<{6N6LkrCz#^A|4v5KkeNZ^@ zd%$rcUDEq_$ zyD_vN3hq|qUUbLkT5Asn0zOSls|8vz5PFAl4hhPkEqx@xO)bRm zJVOpY>0qf@D~dSX-Nf11$ zNkJC9zIU*{r@lMTuN=S8>Wll5(0@ zSSP@a6kh)z+V3ZkECP{`7=qptgxS=t;Rr?rC}LPYVfI3ZD=Bjo;uu4KDugRFIML8z z#9i%Ef@z?iWV6HpmE*YA?Wp&ALPzSmYq{s^gwdx-yoefq0gXE`wQb@71 zG^w~zIx^M9qP{gr!ltWg*RoLEIdKX|k|bneN3rpNL8wc|+l2g8^$?d2*x=K~+yPw} z(-P4JAa%aTQ=f%{Wuav4h6KxyYf$ziZCvSGeh=VYgVIPK_+#RL>^3_7kQ8dBl6(wl03a`h=RL-Xe#J{ z1Y(r5>Aa_bnm#qu4Y^JLFF=UwJ-DE0f^;U6Hl>ad`C&LBf?FY$J??%8q(U?il7}kB zK{HS&Cc0%N5H1ff#O(7ppf0K`d1@V+m@B8eY7vy{VbW-XhKiaiki1^P@eG7?i6V%F zQ=*dSW~i?~`>F@R{w&W5_Ff)f6b;rZeIYC5gltgRuXAngMkfM z&LBiTd2~@xQoR%s9`}?n)n@c^%zwd9upC_|D(=u^OsS^@IQZ(-#iYh`!qHs4D-qjK zCuOb6V<(Ypnyn?r37RiC`qLc6!NR)`1Aj<`1we>F!PH>gINkL0(AaSJ-2HunI7LpB z2}eSbpr^%0pCUug7djlQ3cc?2dib0Uu?!4;2Wh;Cl>$vQpx8ReZw`R|VDE`!GN!7# zCAOaRK1d=33$mrQCOvua_qvk{5K45Z^KS)MyvuhmO+g1Vy#P;WUNG5iY&M=4^a6#6 z#3+R`$vIKbS!}Gjl~oXyXwU}N zsSU8{m?@ZhG?Ia#18h^KK*>EC@oE)kBKdpc`U(tXR+!s`#5D#doIj4nN_lFDBsdy`> zAWq`@0M?-Euv>;ED@n}iG&1gMtq+<b4h9&sMg9NkX>q8TwTrCz$b4v8+m3n#D^}E~%JMV>~ZmR}#|7Uej=8{XSfs(WlxR0aop}A80tK% zV*dj<6~#NqB;z2!!gL8`Cej1N4;iYq!FXPR&I`PKWS)ZwY$5D8DZ6tOks!(sGKFf9 zFO^@C><2yHz95&7E_BII^9<^v&vr5U7(K2*rb3($R-j-fZPiJiItV3{pisGX@ogle zrMVV-P?On?&lS)Y!%;uzE-0VNklN9~swCx*08Fv8Vmih_7fIt&!&QA~ z?hL+1qJi&`Oy%FPL*juSY^yfQPs7dSz@H)4vv|EH(F;N}hCcim4BLLZ?Y%GJ``&!K z6fb*&7h=k$_dXzh5>es)1Eu7@EwkFvCX+z1Jd?u7^_~f@;iZj=5rxOdSi)oKw1Mg3 zP>n;UmU-w9`U#dYT3fnWT|2v4_B6SeO^gmzwwW@eJn?6|`&BqD7`za(cEQCT_6z(@ z-7iYR9u`KawO{6hUj!!hu$Zcx^9bajU0EVbqViNpXNZnMgCO}CF}|$S!DtvV$X5_v zog@D(KJwqt>mTU#KE3YH>wEP20lhv!ulMkR`Y{s?rGAyEpMK_Cu>&n z*jC$F`d)^A|(?;B5X_{<#wuhR+Y*w3bh80QEe>B9d=Q zC+eC?bp}nMv`LSo>N{yYZemS~n+5^{T!cD{s;F<29TMrpiB#LgCDUt@y#JKakxBuY zhF(F#V%FIa>+JCjFV$bHp9sApl^s>-#2`Asi1-7`h!{y`kx6 zjgXdz=re?gXT+#!V4cb!5|j$VW6<~-$w2RY0S=J+t@v=#!e|b)9GY8vtPODK z)Oe;cUlEwG`Q*ANd6?>;g{#bEiiC4*g6DUrE0-bBX~XTp(sAkPqF0w)TXtjTt-_|! z%*jN^M68ZUd&y|tRPcNxqmgxcF6zri;|!{~zQ^;$uv0pnE8wVuk^7SM9j4yH$0B+? zW}OwW&Kh6xQuW2^iOzSdOQ$yPL&ROR2bGa1!)#$j?)8rZfD(EgN3Zn| z00jDdB)z~Ip!EVQDkfH6?FFR;Nxi^*|C#C!!;DHJ;7}iG3>#?=O811^hep6N*c=_V z^!Pk(S-ysh_4-8lP(gyfSm-JGTD6J3?^E+;Af*mn=0vP>5++qqca=!|7JMFrWQ(dd z8O~<(Wb~m|4}mlh*+@w=jK`{|DbE*;WSq}y6rVf;8#NVlm6UwAv=D^E@xv4>{k+TQDT?G%?E3wg6ZQ=AMN4Ly1hT_?w zfHDXjRZZKEk-EE0_>WH)Tz^P**&H4AB*iMOX4J=fxarBaXFE z$NE1h?i^orW8s_2-dOhb>}Y+*3;V;xouk=!P0n2KzQLGXJ-UPR4)f0EjrYFfz37b; zR6)HfyZT*w8T9Xd^nRA1q{|r0LFO+OHG*5oa&GPpWV$eRQ2;d`^wCQqRij4;FUlQKSZj{7WeuUhlTCb z5~iOLwz^2(!41#REp?LvjX(lscm`mqSv6{oSrQg=!}ut8?@Q3#_nuCriX^!3J)y{}`-6+4!1?^PN91 zI@EnUl|#d84ejHXz_Ht4WL*yOFl3q@yf9bcUh0TE>ebs#O|ze{!mZkDaR zS~y-hvFgP+k+QWv3KFcJu@@SLvo^Dw9P+Qh2YOyKm^m-79=IlNqSt%yi<^%Iy!~Q% zZK0!f7?$!vwnR?c!jmSJwuR@_%b~g)LjY8e^9s+cy|Cf@hS9x~c}3?sFFbnw(Xeg7 zWM1ib@k{eA&I{WrC-Y{Gn_seBw1sVpC-dfvcgE(eh|F6NwynIAn^~AMYPpkdC}hg= zXv$U3t+KVzg0-WT$-=VnlJTtZC&KoHVe3MUr_>qZQI{d#MWgh}$s5aX^8WZw;xepAjok6A~poFd|_Vdc>!Yegrk?#mK2J zgjC}riwrW1eus$l#vZEGD;c6*Xr(ShGU!5(S33C64)9UK^G8n@PMRJyoG>PpXMyo& z!>KI9cv!?B=A9k=U7f)VKv)T(i|~R{IO#NU^~DQtRp&CZ6Y*TK`Jv4FoIyY|KW-*- z!(ifa&S~7b+cVTG%Q#t{gS7D+O2nyxOdJiiEv?RGi$Pva6%|Z1k*NxCi@TSscV-^; zfN$VoH3I9Kn?EAvSdef43q=0#ZEKNIxSky`JWHVjyk7dC5*l^?fo!maWfm*y&Ih71 zmW*b>-eIHtXsA!jLjJ{FDy8}V4^fySdFc6 zZsF+GI~nG@`IGa@CpKQ}KbL!Z)`E%0ZkXT9eIxhnwYO&NJC_MH%7U5aj*kz9?TfPCm@8w-r| zuE=d%W%|ZSBi=u&MbdW(ABe6BCX<=5{%IlMk4QFZb_4~WXNNcpyQZ`7gT^D zlRK7suIa+g^E+=^=T2P-sf)V@-6m?hU5!1)YEIZMYMws0OT&6b3lg%2hyjC$1XW+y;wrrWg#|Hf>1}d>i%Zj7(gT%7lYoWZ4wp93 zglLb)o-{eA_O^8SsLL{4KB_8mntasBOP7zjh|}dmyoKrNlPP719K;tbyH_i$S}Md= z7l>)D~k?$CY-7fsI3 zFEbm)N{?0vKkX}5hn9(7q2%ZXsKXTsMT1&OhBa{YNCKesmSXmD7PqW zxyAP^w@j3q2G%874yYw{CwtPwo+(;|xU_&^PiTX19VK#}^Z-jr1x%1?o(N7;LYb}v zI{ai$nz*xcadlXklD5p&#dRpz0)tb=ouiAp@E&pJ>f)+6m?qzO3FErr9y!k!IV+pv zEI>~kMQKV{AkrZ2;(O%pNEqL=4P?(fdvl?#H`P&@rat8fEmp^yj)Jy}a?|8cAuST+ zi7(o=^d6}e>)@b`=X>Gl5?u*28?xt~@TkT+5sQt2RkSoo#MX=%!wR^KDlG984$N8nGI5^8jD*WM%U@&v3T<2~%TCp>F)P@pqP z_F!HRPTlu(hGgi^PaP($IQF=K<}MXi?pg9mUCAo_O9P2jI!M%sDoLwHjK>Xf6DZ|s zBEUEUAVzUL+hmi;7xs);q&524ma(8Sv8~MntGN`dIU!90DNs8HYG*~hLt1{qHDcAR5v-pa~ei?X*WWiMl8lPm*!?yKc9QT9tB zh4vj$*Oq|ua`2q-4~#SHO!)&wo!JPs+PSRf9V*-Gp*DFlcGR2|ypddgg4pqSLXguB z;a-wu)oZx~x*s}qmKI1I^(;HY5(C>K95&kv7G)>RG%g?ef8Hw9BZyO z-B=iPY!=l&4cKs_xi7#KFPtJ_$_CyE>TNws^r5Db`u(g;>kd37g7)K~;H|UPSu1`08D9 zy+f}b;}y?OlI6`$l0&sB%?!rPA-cfHrW5}P%EaJ}XK@xT;Wk5ShT!9rc{ZeEnVLZm z%rq6{<5|jqzDxuwZs!8xnh5Sp&WoBNhg+C@h8V2g$IfZw78qK>D8ldkXyyz5bP6<@6%+mU0{Q=L~Vu$6C!WG@eN( zVK@b}uPKW|Cmil|AAh`EIqj%CKqx2VG~s#fWpO>7f{$%inWDacj!g45to~7 zCD&R+sV?KE2!u*;qb%bVQiB|zER8+!EaieSI-7Jcq%=XFE^gz!q*OGQ|6AnfQeH3osDz}iGH@pwTp zb~5rFEJF*riIqC_*~Yl5G7fMI!v)EN`5~fXC%|p|5$srIn6e8e7cQB2Dzb3>Xwxm* zd>kIkUhvYai?b%yUtJxYRSVJJ?Az@UtNBqFzVPuUS*Sus;{(MZn@eUU9=7*!{Ya{E8ffA>(=O!I{dbws#j)R zo^^H0jm6Q0Odz@JcIoW#brZ!GH$_V;5hZJ~5^|Q$=aN82?)h9g$eej$*7;fE8z#0# z3oG9@WMo&3Hry^EA;iM#i*FTe1oOC}aqp-zkJdD!@_EV4zP)OFY}KyFs$FlF zg!lDCS4j-=IJJ4T`dan%*67mh9C|gYSVn*R07EYhN9@HWaSwimo_tbH!s}=VRnwIa#~r zRqr)#cwkg+2Q&<(Uq;_GynF=b+MH@BP(~lZ3*vnM^_%^zI9t; zb^9W9`+%?EM}pD15P4VL-nb>Uac^Yf-tazT{6uu4Ox{awFJAtNmzVg~=J5XZXkABi zaVPq~e!F7XE4!|H2wZRFzP&%Xes8p59|H0x>$dU=x}tTgYL$~4Hordf+EBRRvFL`! zDci-9t2ew}{aST+vorj-JGz?Hton9kO{{Wjq;l(x!MBb^D`7AmJzcvxR=X`yyDeP1 z>$3E=6l?2_v~`E2zDQdi!gFueu8Gw)M{1kj@`PItMQd3X%~cEBAKlPS1`|zHaLWQ69F&O(W0^Iponm_4!VsvIp_{l3AH-Dn)$b$iaL>nGm|{o#{e zd-B$tj?q1nIFxmrcTGGVTU-}eTo)~=AKme;y#x~IlLa%mz4xoO>&M1mhoT&7x`ug(+=d3(pLg&pq{bkebE7s1RnZvyET z0|enYH4$okM&85Jdkbr?cfMtOyZBpkzB%XC!me}qlbc%3nPUZuBL#~m`eRErM3!v0 zS+Ef_3-Lj}(J_OO+!~hAnn=l7%BYnxDqnfseIxYdlW#nEt9xIp8vZ$5Ub;?Zz{gSBpH zq+n@y*`{|2Hh&K}Y`J4H*s6Z`{T35Ddp2el#%%?J9)%wS>A2-g&g12V+vVAhuQ1)N zHR3&G!Ed77%HxQtmn}&p@041)A(hm~%gBu$u~EiBrg6AKT)3*<>V&IOYuTjP$gRDQ z`F2f#U#wcWb%4VjUjUaA@|%f;s(CG>>Ddx3PvpH1cQOre9hN0D_g_OTbW*}>0V2eF zL;y^HNX5ozMSax1DQw*|Rf>%Edmj}9kBe5S5bR_Z zhbF>JS($UN;UZLSOaTU_#Vy+~13>r5-IvBGEqN3m%jXH8@1wnPO3>0;OGx7>b-1pB zET7{Q$Zom3C04N^Qn4XgQ5Ut>hpqKfAq%K-$kIL}ot)t5HNZ-glKgy}WR+6*OGaYn zb{InHp&jC>2f|t|0&_)t#L@y)7fB}$PYNY=rXF1HNN)qk?WkmGl9fWGI!CN1f%T+6 z$^A+19Q+Detix75bswpmv-{UzD5D>$)hsd-&J7+3_@wS`*aLx`8#Oy+H&+8A3ErL~ znqdjtWGTC0I0FU1vIieanz0;c%CBCxlG`hwim}}#I-hMd-b16~CZDIDtIQ>htGI<# zX*id!f!U86)cGw)hSe{KcEQ8V_mw}kT6@&cw)RQItxk%?bPG0m-L^mAlbDH*t=J1!?gAl~p2j!Fy$Lar@1mDlyhsMK9l3RpJoe(C7NqgNNcy6D=X@VphLIjalT zNtlj#h9DaMw}{0^S3JiHy8~QZSa!k}w_pKWV15weGM>?MME*Eci6{__gA?SNpI8&2 zUy|ti`&65qhz^{$8Rjf_srF)RZ1#%C>=n`3tNz5+es243IN!?ny*=-&+y7j9*w#L3 z#B0);eKvC}Gg7o-H1n2q<)pn})cT|MErz@f zFMoxC*cH()k!u34BqUEPK_Gde@3&A&P(kv74*|*Luc96asI5-@5}J{Y(4?B)QwigP zOdC=yQuUI9Se{-H(|9YBX2nHK9k`nqGZ~RZ#lW6o?}gaKuuylh$1?!4Rdj(S00h$m z%oLwu(MHKdqojf`gYig)c3^^U24<=;B)(lV& zkI{>mb&wM#+Qrypdg1$chTk)6<)qZ_`BUmSI+y@?$}tp`@*QD$WJbBz7m}c3S|LXy zq}i6wxO?D8+cgv`=|Lx$lf3X#%#v(}a7495Ao}6}&5c;ovy0G^Z+A)^iLMt4zz!P625wc%dgzSE2-9B1`?59P@{m~{ENBt zxR!vnji3;H0eL7T>XHpt1bSgR@4v*Vdm6k|&XctkPhD1ga6d@Pv#yiSwTsZTD=oSn_%DO5iMzxd0eR4$5?7&!15;ySQTSgTUlpZP*6I}d zK{J*f_gn%Wng&-hdCtQ&PS5$Tf2R@f%d}>mvQ|}TVFBWh{Uf&CL;=aq^lXSjZD2oS z=-3Y#Q`rylJV<4wU^svcLHop{N0Zco{LIR1Nbw<_Eh!Ry()svN`&9oC9Sh_6eUSEn zHp>|^Q!<H5mR8Pn)8jpgllKkkHFP5{JJtk%$0X1L}jFwZGkWw^j>VhMgy<`^w zYVfDBP9bz8>nQPjlOE{J=;}L?1t~0?+p-+3r?N+~Q>BqiiHw@(XG7L8i>U*udJB*; z!g2FRMxQYq{OIf(s(XJaWRMuE$8;+5lm*Nli~H-qns#=H_hRy*3+C{f}J%% zI-b9MNDR#unATwTfetU_2+7|tm503~vzN!PkJUn%oDUtUwrQ+J&T^r(Q9K7McSQ`5 zwI~kx7QO@}CH+j8uJ!awIytE2)O6Yfz*ZgOOJ?=Sfx!Wf#58eP*T>Bynj{ly$Zt^9 zvmmA9^9Dn4BkVN7gV{jg7))=@$;{P(OIRe*d1Vp2{)55m&TIp$(q(~7f8nX~PsK`W zBBeFa(%Sb8*6g~`owx0?#w)-2&@KC#$%4{YL3yO0d}70u`pflK!qN`85TzP%fug(ouwU1^+s=zh1pS6wI#*0R6B(yN6oKDU68pn16 zzfVruib=UQGQV}S^&MLqormrX$=!m%P|J^Mx zRCgGe*w5GU=Qmble0@%FQ%2@DDrPl4WckKcBi^ZXZcp+NVZ?RVq`r<{$xo^^fX0V{ zUe6q+_@07MGJQ(HT<13KxEvjw)F}$E4BryiLIqHM4F-HVTX(`XT$2A%!iF`-3e+Pv zZ?t~WHiLLXYG+N9N9~Jm+P7XUes$ipdCKrw9j)FPwr=J84x)R4_7U;GpYg5?M>^s$ zeN%rLAXOXPevAq+9lOOGO6G<6k)>c6;V2F!()-!1BI@)pmA|~YcBRH&-shIxxT*n` zCDasRZo^mgQ>Iu9dd)UJnQB%e&`8A;kFtsN7=%$PeunoTbEwKm>*|M?WAb@%jk*S@ zO)+6ksR+Lx8T>S*>N;=%aAJz5s}N|(z)b9G{7U%`0C9nbBy5_1hb1IhDIgLM*1Lq2 zos@wq2_s2N61=wg34~)}Y1F>_roHWY@$2(mn-^QPJ+f;1TlLXZZDDKMG`P6&C&oqM zTDpHfB}OT%$8>lEK&8G6L?V0rOA)+O*YgT;!kE6=HySPy^fYVrY6QZf?rs5EFC7xY z<`+j$Ishi)_2MAT?ORUwj_9)gxx{6$2uy*r3C*U#lL}|=fvMo3vm?UGzz6w{k}y@? z0S_@->hQ9Gu#vVQo`y*h}BOZ-kx9@~|i0&K1O+(nQU_a4w z1hkNr$ujOj3f7QN0+!6UrUnPelmb!ROj<$NZ-AP4}vVy3qc&T*Py$LALlBRMtsl&~dg4t@L z5~wLN=fZ;opN&wJ`#hq<)GET%Q)8!Mc1OhSn3xr{FAH0jO@pc3sKHM*Uz6EGxiF3C zLj$R^$%xSblTy_gZW1hNS2oLZvxYx#)ce3w@*0gwPKzRH->_mBf&g<>U(sV9$}}wS zqM2Hxy8}rSqM`+hKojgeh*g_7!^)-}W-VZ9N$_SEVik>I*2NQdjS(Vcioq5&bw8m8 z=^U_WwXlSQx)ssKBhi8tqn2;y7M$z4@YwmsCYo-RR81C@L3q<%#Bl~0st@wvYdm#c z)rTt4Qg0AnR${W#z*o|&Vc3~qqarb=tz|v%kI#j{@2tb-{Xo44MJZY5qu0kxr)t&<1PZfjHJhlA@>xPSJHwYZ= zOg!)t;}uf^mtVu(H3IJJfEz4S2iKXxO)O0PPQQ@(DPV5mdN}DPZK!-CTs@%5GbH#v zNARx(0D$>6!_3*S5=aHtjOI+*XWg`K9+zI~zt|s}zcMm^<@MRo`J2Pm&C?+LHste@ z3DPDYe~SQi2dk=r?mOs~1V|>N0=WWV0eSW2E)WD7i1A!*!JgTF<%&p2XexVwz{9gS zMmtU1)wYws zb59%FL`eGBJ&yiCusm^#m>YL<`Tc`*jocJb&IiY5mHbRy@2pa8J)vm=9m#aXra||- z1f4^1IGo@)u0!@24B3}ON|ybE$o{kKQa4$Y{;7HucZ6Yy>X!VF&~boGu0q<6yZdA} zjH%WZ974a6NtO5Zbm(P^kbNlK++!COfg_?oWg3s}!XuVu~8XV3pw?fE1gmu`8YEf3Lw z+WEQWeZPxIWyV!UJ9VIPnUvKLM zJoxg5mXXNDc=t3M7w9}ICHosjZD36q2GC59v`2jY;9xbSY#@9yMI7zRj;pQOZ{ZR$ z`dGA@haVElCt|GftpIfY*_FWB-IZ*IgnN<$bUUOfB#0x=U~N37b#HsKtGRXW!!7T< zjUwb9;ssgS=kbY~ke6(t<^F97dYXcijd>2KY4Gh>!puu_T zdgOy8Xr^Ia_0^_VTd%c7=GL9>xFL_`+_uj+S3e$#EvSnusJpQ!R=+!f{|olS7PLne zv`6h7VQa_KmDkT(r+DwDQxx+Nsk=qn*ry_n+EtzLJl1_3oh^;Ko7+2NC}D8>9!d|& zbWMt`2T$vIFpu@1QjK6jC&I#o7pIc4(v3yRQd#f$e{>ybGc2g(tmw%6trs)iY8cI< zj@&Y_C|15XQoi{{XKYJb1pmwT#>yXwls^)+KN_|^I!#CZchqy*(KRdezFNv)qsENn zNslrXNr;6#Y%HeOC?ek!V=i5;31e}$==NS;z@0oA*;T$Fx|dgWFo9aJbxatN;!5D! zccobU}hip4si1iiCwBxAhAmmJY&?Q zWY&O<&8@qQZ%g0uf72h?^4PhiSaEHnxc2H3k>XXc;<}r~bz!$>G@E+4Zd{7Z-x!&{ z@kVj1?%@dj&)*%J-w~PL5w&-Qt({YQnV^oMjCXgzk#0kux_{I41KYrN3HVP(3l9$w zX9TxC;4Prduh@kgM!+p`IdzRnk_fd%0iQ*UlT|I_`7Af@ut$Nda&t_g@1GHH7Yg7K z@1r_mufDn{wscbj|LvP&_U4GaIc#m73NS)v1~8JB{mJ&+M^(f}7Rn=}lU@dmpoal* z=M>dTMZiBnWtGeC6Y8p(T3pEvi$%5s6bh?cm-26rdum-u8D$GyN+r|3B1n}ZMY5J^ zI$cV_C;FoYX*sBf6_5_MrayNjFt|Oamta1)m3wvXlRryqkhI5CSV`0MWmpG)_-9l~ z-XFzbs~BklH`L`Kt=MVv$ouj>*t;NG3_C8PzvO&CT~D=`#)qE4&$InI!Vn?_AXMdv z4F1xny*eyzAVF^GqmCg`gG+}PIweV{loL-el`s=5v=uPr$Rab{JY-BzdNdC2OpwzO z5Yj7r^Hu~wb^=`Pj9)J9k@UBV*8(y$I^uaS`NFPPhbmu>N1l-cqj-@T&Tlq9jB|Nm z@j6A&2L!xI0D)2YB}=b7e);h~u^$*;fBisgT}y=icfF8#(|#aqJ@6xZf;1hTEvzzM zHdiI;<*6X;W+2t>mP-XR&~u8P^h`&VB%^lc0LG+g__wE!rgoSq(<{rku^D}0knW03 z;C6r&#tfQ4lF4xd_tDZp-w<#UtP$P*h0r#ItRE9rI0> zH^nN}MJm=sD>l4kzNMQ)eioF`g?ed}kv0DwA^<5bn^%EF6r;PF^7&cOMJ4Z#k}kG0 z#7t--p%;VJy^p*w@)=%SCgkV@y!A8@=I?P1MmY)d4&t{J11w0WCCK8mhWrsP#cYYf zlAqKov6q#YY|*ew%m=L9^^Tn$w$t=DwlP8AK)=#-wp@Thpn6d~;}Jo1TM-u|n)f4Q zoJKiK*fwO1SMD*;`{7176#z`q4hO&Eoi81{co3pnVe8_lD=T%mKr(FUW`$JC1+jL5 z^z}?-rl4JD(j#JVb$XJQ?l91uLNKQAtjg3$fE`v@D)1EI?NBbw23=4#y7roG_qeKdy^5A}w5k%Ic!@Vi_Qd#9qfRCAzGVC>of?Uw<2;4cIwcPlypTF) zJpcskv>9LwXZQKtvEn6>;w91IDl(!q7iP1_WCE>=-?1-)EanTjWHoCpQ#72W?|vPb zrtLeiFx2%7(_27olAq}&BlPnk(p$jsKFx#3KN9;sFHKp8up{{vMLGKZ79>p5Tve#%J1KQwx^bA( zGbq!=l~A6R2mAYp!9HEzl6)r3r1T^#FqqZClnaa#==ovg8bnqbT? z;Y~27+5JP6pXnee4-KWJ6qW>y`&v{mT)2#G#Wc%gX9}k@F=3@KgH{%aQHIMnk)Il} zop5F@AM7Np8nZ8o*cZj@RS|ntxccY9tkhFe2d*%T*$f%z(0z_vk%qLK`a^mVkLj7U z3FGp6fKWxmtD(WH?b+L+Vk&126itSN*W7yjGvm2$Y ziKA3ho=3i`2W z6|GAck;QD-sdeB8A*9Yyg@p)L6zNDlfi8*Im&EK#Ble|NH%9Gi!`8LapvYEWD0V?V zu}+qvStaLVB`5zO5GJ8Dvs5)I4QNV}7I5588{rewu7zx2pi``h*>$a39kthnt+i7L zj=Dcr+4-ng@^c>yiux%#EsZZrOE=Du<;NL;6Of?-J5L;BWN;(l@1WRZCSBZu$R1g+ z>DZ4?Q*#wA46~3!R)#_^ow|4mIy=c~(CcgT`UJhk=#>mf;-m`e3p|etggfgHm+|IdNpkbp=5X$U$)eKR zb}XoA#7u;)JbC%a>rJokd~N5A&Nm-_lF7F1;6CqquTy{s^)!;nx`nBO5R{kfb1l=ctd}M8u|w*8%l$U4W!v{ zq#H==-0~ozPQh*3t%9*ARse+A3c+L6R1*9{hfWz%j z1V$Z9+{aDgfTS+Yk5)8mtaKT<_wXR3ACL&#LFiC91_zdh0?TpB0mN2y@~V`(y9c}v z1RyI?xq4#I3sqfVnXUyYSG4I;&d|CkOPt6A2RuFAUav<=$t9WQNVW~yfwHEE)7`B? z4^TVQ-K`zrR2%sP9?8R)uHg};(s-@-z4Nc2KZ9gm1A}=s+Ym2=v2XR}bLvy^ASUl$ zVwR=rUpkJYSztsr4}gwS+N9@YC2!I>0#;2S9b2 zQ&YOs!LHYlltVRqxQ?Ab0JY<}o}Gr6EmUcg!UX@-KJD(_;r0bR-Q9|M3)zW=E#X0* z#88Wl@F0?-)&>?te9-U{2NYWG?*Om-J-}K1JYdO=tg#eiOcV*2lzUV}#%l zIMN|Xs^eD`c~T;blrfx5raOi)V*_DK!`lS55a~#y9Kj>lfDx~YB$+fh8Ae0~27Evv znikn5Q}5wugv@%-6o@OIC?Ovjd_J6u)+B(fp1_u`Y^7Liuk=R*H$_`36L90&T9uK4 zN)>j+bTdcR`K1OQud102>G0HaLDVAsR8Rus(VXnaFhTFlAQ%4R{KX z1%BVO>{_Eg50G1Y05WE53<9L;<# z^OWg1%UEU*e`B!V@SNp2e5DK`2f_K8<)tx;NF|vlOkO%>neGfko~_-jnd+Ql)G`VS zMv@tK_GV~;aZ=`}vDYYB&e%?wr%w-CNV;^@S?aI&#&C^ehY%!WRgDm|+SMG^RJ;!*M=QJ|+~Po9&j99xqgU z{hkV%>tu+v_LDk=qe}AN9E=Q`NYyI!(8XSZb^aT!speFf>3MWuTX!|K}L;D%%YIKU1Lg6m~Vj44Zn(4E< zn@WE$aVBJ}0k6K^L9*Uzt7rkR2mM2xfexa>Es%7t+mQemhs0MPV*SyuuZ77|_IY$& zexJMvYJesi5DdvvIr|hvNR%jG#4JW=G&rCuP{CETEy5^<>Y=VJ1bJ=cCU_62F{t^3 zs-m+;VfY zd^Pi0=Jl#bRsGE>*NrFMeEN;2!|krfL$1>)_7rNXdy)DJ#obg z`t$3@JI`;uS+r+j|CK|R4_%ici|g_0hWpLlH+tVTztJDI?O{_DxS*_b+IcVoQE@XZ z7^^e6a9WNGImVEeR{m^d6wmSoC2yZM#IGwc<8lY7I*T78Q@^uR@;5Nk$;+ux)a7zD zUO^I2b#wzCw{7Frn+lS$rcZ zE@CYowVqpe?$GzZlPQ~AQhPlwY^xY;9pCtFZrOO_&D;fFZM>QnU9|qj!kddWy_FZ+ z))m>-b!*$f+eKv;>d)8Tn(qp`k3@^SVVn0~%*O0iBWZ?~oE;t;9$z$(6~!5swTc0( zwg<3Icyj4nn)?3&F7{*wz}SV9*D^J*;6gaA=gsek%b|VY3E2x#<+xQC&x&US1_;i< zAn{cIC_Efeb{Ai02>UYPR5!`nii+JOFau084B0lm6uHmZ%4?~Ul1i5A;F+ehB4jMr zQ}?nJ&(Eru`5#R&)gMhUYd@M|9{OmCdHAC#rYoVCwuJFV=+4I9E5Jk$b5jT&{27E| z42+nX`se60v`oZ>=Z{#z26ID{3wyMM_A|yl159+9Qkf|gVqXv%`Xj|OXVxjJt`uu1 zN93rMQm!i{W5k-ufa%eEkxKi1+3=!j4)hr#(iLi9!X@g%tT$$#%7Ky486r&kj^w2D z%{p4F#St#abjfroSJ$Gf5bgEYBU&WS50weOqcnXaJx57cAn6&&mCT#r*FWzbY3C;; z#7~iSB=hLPRG}|p(xC@NV*eQCPtCGz#GI;a&=kT|<}l4_I9kqA=-)>d>3?ze(Ir#; zkU9n2AU>7?^01C+9I=gLN|sBe5zAMNpM^+yb!OY}B5fMbsSDszS7_cs%^OSNo>1-Z zl4jZ`qC{=j;V>3K`gs*hVBdKowoH^V;25Z{6i04CU=vzfUP?s$oIeU?ir zy}CG_)!Ne0(bBe)+j%7Gy7BBzT(a9N%K=$tCLF0xWYXM{pP*p#fZHqM5>~fw(8Eh3 zk$stP0yY}d8sf6v_Pu+WJG z^xBA5+(IpY2wRBmnF^s6_$fD1a1*^sDSK*aFb@@Blc;#{h2}I?rBDqMMc#+>ln?a>*HVO!(71v9{;n7br4wTCOQ}P zByHK{V|zw-oNKyWG;dtGwP*vb3%xyaLAZPuZsVK(&H1sG?np~_c$YiuI2@hX6E5g^ zclP|3sxMZ5c^M2oHlJHdSDfZv&b{9Gy7M*XTgU%!=xalfnfpg~eg`%xmwa{6Eqmqd z^2JwHTwW0?Umq!7537%vFWA2$yf#M4H#O$>ZdoAv1JiBvj=efsYC6$qq$~&fvf*jm8dBYoa zN#A2Xjs)2E4&*s=*u=jBMm_tf->HYN#PysAGFzu{3oc^v_P}rnP?D?^xFnCyJ%kv+ z-V>}(wY$vSgQ0*+vCid^h&PO7kQS_%h)T?e8LmXR2BNf9{5?ynFk;^A1_fZ|t8F6| z-E3f#EhCl@n`9*VGm@DUl8KNE7Lt_|l7$cx3$Z4JSP{ag*+@=ONDe|QEKP1wNG?J$ zDTL7#f%H4 zPg*R7Q+XlGn*0GJqv4+Pj2K4pUda|GhNtpJ@)0k^{4|n(lz8At4{LjVhhc-^`3=8j zI$^BNasMmE<48|H4vc8bfJWG1BXvEuYQ|A-l1Je{ii27$SsQEIjDA(benwIop*O@v=Q5CO_hr@3UL~NEi715FtEhx zkLp(jJ#dFA)lIju+y{#T78F=Cpfs6Kz!qK0P9yb#VL&9m8>|R5BdsEu7zZbPjw%ms zg`s0h6?zK0fz+}zPbRakahkZzI|uA3)4_}`o(46QcK`qEy?b<2S9&j4C6%64sDw%- zBp#w9BqRYUUNT_uu=VCCzzDF7u~eu82!uqRDj_2m-45M-BXT>_(CNfe&60_@3T+UDM?`HN3PFW z6i4Tr{odcVzxUUpN66zccV&_w;-L^!$$Fy}nh%ofC;>^KOf|GOGEgH112+MZX$+rc zN+Mbe5yep*KOyfSHcWj=AzK^5&Y+VHmh=5#zpqLEvmWxKUh+P`2aSkddc3jc>&kxe z_XYcttU86ikFJDbYiiveb+ZVmqF7^!Q*53aOOF_F4AK8=A5ic>!gOLTpr{J;BOZDq z5;8UR$ir6#6il9$o}O)kIDPwrP1>>HQ)J%=ZI;|PZ9K?_RR~w(BW1yk1Va72!f9EN zkYcHOfxhdH3=H+2gf#E;+3@k9!6b>En2OE5z(@dEJtoicvwh#!t>$#8t?7kyp;62Hr!`GCiU-}F(LHlBh0Igfgp+&v|(toajQ)9lM|bYRYVL{l2XbkF`8|J z2DvwU$Q;*%AtWPmiI9;RPb?N8Dbiq*M0o;X`cjZ0bFE;QkjoP5fEQ#JX>tY5wQ7!V z2m+Z?YBLpslaN^AHef1#qmARAYT))iZD&259tyzpGIGb$hZY3qA8t^ zEJOwAbP|QBk1(O=<^GDGywFSA7yk4 zorR+SKjicdkp^(kJcGtUvk+>U45gjL#2~+?O9lN3tB{M9eQH{=7D+l^UL^Tw1ji_2< zLd`^}QB%q=_vr=t(cVTMnWcbf0=u9^3TP)yhaKpJ&VB6%iKf7DZFGPr z{pspDcpN7%MuSbtHzi*aC6yWx7g$r&BZjIRUo<`(J^D$ix_QtWxZ)?Q(4gNntX;$IFt2#LYSjk(^;qM#WRGS!ez^}Bb4EK)-)OU)gIV-=t=wXm z%FxiD1Y0GrL@cZ^1AHwDV*#{zuAU-e*5)XPi)tBl8qNxl#k({HY zeMmdfAB4n2_LA1`CGZt$;uxwN*bQjYggVu|Z2+vX6}EPD?P+7#H9_W?8fc+yMU*nt zERfVu7#*sbJ4phXiqify@V9Z?WA$LNK^Ppff!+{tjRn=aO|O*2N~6k@4T-Z+p`TOH zw&*v*$0LB|6SVDhh%sh?=RVm-@&OOwJ03=*8)N7ue5dWl8|?tSt`sn>?`ey#Z#cL> zh>3=nREVSxoi{SI%lMx~4%U8vyShBBo$4iVk4Ex4?FDMVK>)11LVtgoe*T_*F5sum zt;n6EK!X)B`mc3SZLGgcDn*^v4$=>ardYcyr%8yiP|-e8F0RV)@YylZ#KMom;?-}F zMCvnC_79}ld-!su&ErKH6Q}3O`k1qFqH@_-$Hnb2*WxK>;gy^iEJ+tv;Yml#wQ$N= zb`9dI+KKv&V;#}rx|nO(l+*qFkr)z}msjGW_6xhGoV7nfsr3`F;|0pwCN>! zv?1ntcFJ3Ku`A)Ni+SrHA9|RXQ<6V5ui}&X)mIiI%IfZw)&1!8#QKid`i=?jq6tsg zKRWRNJb>LL|2PMC|7^=C%pY_7Q=!dMezo=O9dGTp6~0q7Ueqy`1Ha#;^<$3j7F;N} zIP&J`rBNvHCMdPZ!!nflB1DqZ^Ubc7T>D1__LgkNNA3-{ugf*$O?+j}oO&WNv7lsOWg!yMHX^!$dsIlOvweA zxV04BbwX+zj2<$XlFKAhI*frP%aj;v4fGdMk{)wmfCYTXh;V157TFjj%F@Q44WnpqX%s_aOE-HEfVF#vwE7W(?*o)e@Q!PP$AP%?8Yo1C3^l z^Xw6bXFC3LGQQ7TF$S-PDCEJvAyB}#MsoyHO}d>m<6eY$*&w7Xm?E%kLRO$x#1C7r zReI211yfRG2DTK8+-m=NNo%H_(8lB*pwoLVKfHHA3~51xLiD6z=IBG8e$1yGHbn0b zaP*%JnEkq~`>4iT`1N63Ai9==B%2i^5e~3* z70{|j%U6xBX&(2qkXqfhKVEVmT6kb$#g@d1*4Ty>;le<4(hP(bnns6gSFz@fqh+ zN?MBSAC=l$3LPJnZNU9k3Mce@M6|`o(~Kfg0BM*T^q^$t;R&cjlh`%j06yc~7MY ze_gm3V{d%L#n3LLtK~OD|6(E&OtAK4xfqQI)W_jU;OR@WOE=>Xv_l~AlDHEsh?>)w z-%9?1*P*jvN&JQB-GG_DfEMT1o4?ou8ghsz4f1w@4bi#<6F>#F9 zBR)^E7nxW9@?ZES*}wkZxRLg+Sr+<>EUv$p*7`KV&^1_Do<=f*8N!YocBPpn9YD6> z0u0%{m7W2%w>KTqt~3YQ4{Q6=94ie3(*fitI)JQz3los61K0yjLdgTW}~_`HZ*+t^pHjl!4UQ_O|~=vWU=3cWlz7NuO?_Y$S znT@MnKR!`pYz9T}E9C|(RqYaKeI>7=wM;9oO5S*K-l)){B71=@n3kL=$hp)hH(4pp zH0ZCU;&5nLS!iJ9Iby~<$+~V*Hc}ty()|^6fD^DFJP4B>M+vk4HcE5J5rWt)skT&Z zCn=x}Si!;=Lv>QpyHX_gqCBy|Yi!7=70nk%vQO#I0+nGm>=I8F<4z98z`H zZe2s2s=IdU9u9d)wdJ8UuCq?{eQGp5?`0b` zVG1S3t`pLmPCUWE=6VNbJzcYE%^9Zng6sH+rqQKOnibw%cvlRAb90Of*81mF}g^|J&6P|{wdhhCy(xzY%q`IWkXc>b?TA9vl~+U)$#-p ztbxHs7#o(I;JYci85xMDTEysO5%XFLE1^2E>tNL+HmqsZXVEpoieGfi%*{0V%uZfy zlqOiw%;883_Xh@&A6r}gixG$>d@RGTZq6U7akdCK|6*~u>gFk?SF6E?anq|mr#lL4!i}(Y;0|F-5SRiTBg{4Fr9XI^fE+wN zOZkMgzo8;K>FeC1+R!QF)6pjL4^U7P9y(Df!yC$<(RoY=HZno~K^C+^n zN0B}mOQj9cqS2giX@!?1}E}P3%1t+j}ap_e^Z>ndqL8Xz^>GWoFDPLd=r6 zMMy7J|6G!(n6u(0JY`lraF<2ruliBlxO>w?!}dhOfmp+Vc*Bc{hQV0FV7%e<#hhsA zs(Xd25ep`|aLtce#^-K$(C~bsVOy+WTXcI*ydjWi7>PBE#2e0vPd_d3MVAc5OHM}% zPYZ_}3Jf!Nb7`t>$AgK^qp{ATiO!)|=TLOl>1grSO#NNCIpJ@P`J2hKZCT8< zTvRl%W#|3cUAO06pZjjvjj}&maIbb3eNq*3RV&tS7&VkobG=uW{pH5Q#+|W^JEI4? zqsIri%v3vTl9}c{g7MquKlj?|I_(b~WCItX*g)somUpbN|8Mp4I+i>B+OZP%f4$b; zvC8q+4V!V_s|&L5A&ZC0#hG8nA6%RXkqLWc{;`U6d;(5U$rnmPnw)$I5g61|c2%Tf zM~+4aS+barB_rTO*OG-SJNp7>^pLYWUVw4jfpW9b|B%n1uBk!1?K9jfo0a9rn_`t9 zgTx9S-7u63r%NC_ih`~?n3%{B3W};Lu=t0nd#Lr1Yn-|1Jr8MM!ts#zF4^s{6EPtf zM%o1!pLDXp@Qm|3%+n1_bBI<`7x!neFGP|I_Q#uqB1i(pQAD}T?fLG>3nvo=<*|bD zM8UFH!LsWO@2$-X8EKJ%t%VP!0ueZM2aib$%(2&S&xR=}Tg%-g+ ztt;nlfs6q7U2G-o68%sP4()q%_j~x6%Q}p>1 zeO{~u`VldFpbyatjF0{n?0-0F1tfVo-qkvmzN0pRRCH!ZETp znRvrPY84qOBD^V3!c`T$gSny$--;kxGN>b~#fdj8$QBGB)Hl9}gZgstHlLIXGxje>=^rZ*ahd8{rZ{-I!esW&E~z+jhP~oh&?)MI`pMFr6TRZ9 zpgdC>^CEfZa~|F@wa%a$!7Q!zo&G+egh|8N&x;hIbRkL?uo1hVMzSu=-bXy9wzow* zDD6RMH!IzwjMrlXtd!%eRK{Bv@ys>|W|GR%lctBP50T=e9u}jA#pvPOlpYq((8Hog z@niO|I86^(A0i8rdbkihT!6{MEqSfI2qH%%K0sg3Y*(bwRjZ`mTb zk&?)~$bzGeR+~@)i<-3m8m<@LVio=3-uPd9d9EU&IMM@OY>4D))j@Z}cgCibKvhit z7ey*gkXRt;3YLpn?6$#$%IYr`&w=SGPOMEThCkJkkrLC)RYywFw&xS|qP@9kYF569 z%uA|yUfP-~W>K^9O=Lk*%?r}jTse!Hm2bk73yob7*&g=s61K;@rdG2eUc9NIH=rph zBW0$yo=6#jDP#;fBW0HGR~f8kb(We+WkpIOmBFR#O{LbD1_OXZOukM410-K4ZFSOA zfcY`OTvMp3izf13W!w}R1|b)rX>6yK7_ zBGahWL>9e~9n6R<2`;0#9$Xe#bb@Y@t~XSCw_NNbK-HoX&n10|KLr*LwMNR5+AP=G zT%osFK4Y8pN}J^~w8?6XEYYe#EjOk1F3oH%x#>?ob1-39e4=@_bs^`@%80$+9`Wf$ zD<;bOTvfPD)D)?*-q|--iN26Q?ZvF`e1c#5cXmQD@?Y?8JN{KO3CZffrG=>yk~YLz zQrTUDYb8kt<9la{%F5VX7N3D)b3#m#8tc_ilaVAmU7!u*{$b(oc<|1k&S^s}WTZpM z7sAfj*4Wd-z1m>_gJ7v6u;o((-N#{Fe54P#SCH-wwlYsQG>DSFj0VBugBl`cH9#md z$_^K?t(?`$j^y{0SJM_G{| zu&1YG_pV+0JGXVcgayX~J(zF@W#;i8MYOJAWGPhA1yXKQW0H=X1~;M>|4BHAA31^W?mgHz2tW}+)K(#+p$h%J-IPdbPiM!S}B4-qy0ab9MuybxfUgCbuH-C*S!pXMl@`5KWo#rkW?hylspO=L`cqLU{p|23Y!)@}P*b{}Ya zp{aRi+w7;$v~86=sYrM-+?sfsB3E9A)fm!z)L@t)UV|9Q-8w!r}|*+ zZ!AEH{TVx7hff`WDjc{~1mt9*VA%AaG=hqvFO2S>X;1EyY>sIfjD~dQc=?*p;dy#F+w`hA@#@%K%2QWO+Qn=VcUuJ)jVgZkR91hIwC97%m) zFA42J_dws7z5%1R2b6a^>6LktijJ#Q_*fM(_>Znkp<&V`%m#3H$wrk3wiuLrJWYFg zEu;aIpHJT|g8XBL_lKcNV7ZOEkM<9MFfc~i!k@RZ$JV11bue-TGy_s)QXT1rswgjv zX42Ae{A(8FJza&Nvj~89Y8qHlD(OSH@5~+SJ~{x~CS&OP zSod4FjZHhfvz}&i?S$5dI%9e-bk|70K&Zj|t#KO5uwvZ^m=86N(TknzZ|jz2DMYWO zQb`Lz(Zvy`j3c1a$R8Te&iV$x4-LZ;SGRT(`Zzf!wCN4}Xl9>GAJK=DCmV^m`%Y8l zp+R3Cf|UuaG{Lb5utA&17^?}rTVU8Pu`5{BM(pntI@dG+2I-GU(5FY?tP7@g^y6Sg z>$uha23gMffP1o&#oN$RX~3orc1R+1`>%8gS)}OYm8n4w z*#bQB+!&o2=?_xU&qrCwA$>B~@xjYKat93KUcCeQp0ohYz>!}6zQLgp94sgMlB{Ya z5v6xS>}*iCdf-GZB;wdR>7$vqkkQLiM+3=J(ysQVX^0iJJ>cE4Yj_~sU*8VnXPmc9 z!#HsvcHm@}Agn2W33a+k4ynGS>p(ND_1&;Q?{6sesNxv_@#0krr(1-Nvb4-}JB`Lz$ zfQj67$vBRi%veA*Wu78_%r9<|Ae)#BdhZ*dG~21DPvGOgF^CYEWwQi%Vs|)VWEhJ3 z9hgCj2`GhqSb#M&3f`_BDU`tQiZ1B_Lt-@tLkM!JA^R9@`$mc#(bzK#1EG+AINS^5 zq#6jOJCGWTnM}1R`qEPr>_I_@wm* zk#QcY$dj0uYJy~%4EVS2=`b)xU?4QaQZ5h52EOgcAeCcDP|@CZC<$>4VvPGW$$s&uL-( zIl9?$M?jX+H-Oee${sy{Z;CufdzEZBPtng&`ZuZM0?I2v8xd({=ojG z9eJe-9JaGIQi*GCqd=XVITF=nXwRY2Ne3wjLu4(Y$HCE_r{!A2po%4*^lxIqozNEl zrel4Bm;ZbShLgOe^*2QgX5H9Gsc@syMjt&_zsG;M3` zZra)QLYMJW`wsfatf949nu;8qFuIY!^D&bL)@Y5yU@3c5a4`%O&38mUP!l{D7lGL9cG*oS!KM*3Ck4Q0mM-oc5YK%VfYyXOR z^{-P&r(ao*FkLL?HO;X$jM=YSVt8+`4LVsw`~yYoQ*7EP=Mnc^qX0B;ZeuEHa&bc< z(7tsI-Gpm-GH?P8B|P~n^rzu1N4P=z2HMqzF*O=FeQ0F5r;+v2WM*LS>|`bcscehj z&tPyehn6Iu1t%R8lXcQbgitqUi#0Odn=EEe7o|>l&c_7JV|UOMrHsKKUm7{2k4N zH2&AVMbF6ApY3k8nKb5Qlg*)#&r*Rdj?i5UCrgt@D4h?|r_bKkI)0}N9EH*NOk2$8CC0CBcoYfOWC5fWCSW(^es&{K{)ZE&5=S;My zE?(4`aCJsqol_M{#WTwGt0DvmoyauC0$bmp!Ok5v|`GuiG-# z9`#hmTuZG!)iYMPJ!6rHit3Bm7tegJ;M0nwiHc3JicPn>;uX#G>{7v$b1u);?)Hv- zePT%+p1yXk(D&(*+QgDAu_aq>pNTJNr-!jZ-=lrYJ3HZC9Cg=B)Nj6+9i3NquW;F? z^=lIKTVwTGquXAJ*T2jj#|n{S%XbqgwN|n~^=rqUX&?7=ut4?Q@sgfsVb8?69f@^& zW9#NvF5W@p!={0nrX2QKN>aLooZ=@Hj%kwI(*8gb1_`J;z<}ZmZ?TYR{ zlGr~G+dq)lKOEaX9PK(2ts05Xe+>?kQ}vCB`pq$YxNKb9Npiwn9d*}FtlLSIuDMsZ z_S1P4(aH^fxqN(HJ8GSnzc>2A@x%*S>;*0H!t1dYUXSjLL`%=Xp>aV8ToJt`aKK!@ z%br-bJGO2&t0Pv3IpC8v;jW6hS4=#!onEZISGa~%zWy)KUi7vmNVg78}qHb=U)2& z9-0-e#7hoG3lC3KEPcE5tx{~$MwXpG^)MY@(=zU9Wh*JZUcNc8yd}20g&L}fxv)Z& zH<93AHCy^;espf!)5g9(94~n_TKMYJs*c2}U9nZW==&8hSN)W8@wJhd)6c$NGv1KA zRi^5j67?Oi`VJ~U`P)8q7Jw+Ym3Mm+_FVMPP;}+#@q(|7JHPf|-u%lAKivF-&GC74 zV_T=(wEpgzPdp1J=G9$45SzC)x?x}R;NjSY!xN>xAG&_vx_aoRrK>+Jubo&pipg6% zA1hNfA1mWslz{(ean;pBn5II(6Tz_S~FF@a;#uNfWq3Q=-O>J8b1DdVs}q$ch6YoN3KCo+^>oo#EkzhY0c^~Kuy;%&!xxfsgnPS6wXim1D8qN$C&*?g~X%ao@& zflcOF5%o0aH6AtB*lh2zCz=k&nhwXCx_P-+;g+8{moO~9B388Gde^%LZybznIS?&c z5idHJa2<@g4o-QiE_S`yeW@EcG7i3VFy?K)bs*|(zkLRG33vOLT zIqqH)&0X{GY?f`#Zu{pC&p2#zy79luHfN9h7Y|q2=DcYC#gx1KixBz1pKr3gSYyAN zVSjOf<8I~)Zu}81vcFjFhHh@lDMO@kgT6{^AlxqHHPMKWBfj+A(3H z=M&|2`mJEUOW1EU{hEk=@)Q0h5&eIKo8Q*S{tI8q`xvDk!Tb1}ear^y-HdPLp38{X z5%?}s4}6yo#v>C}z!{OucR(Z1g+O;M7U(XM1-)I|n_;K0cbOxM4XMiv6o8^g_FV?U zul2)Z0^B#4X2IQ)3WFW`Eqbg8uzL^%5zog+EyR~iiYW^TPG6&v3Z5toF0@2y-ysNl zn5wvG&o=ly4-EJzdW4S{8x2;0!y$;9R*<~{7h3A(l)5B4ByCm|IYp}CYBl28OYzGL zGPrGAa@7j5RTiNRHx2rR2Ty{s9~8o5o}h;$Cyl|ah^zr((wfbJ~51#XDe}GQIN4*mNX^ZePna}xw?o)x&jQ2qx zkSp}^o2Xy=7X9SX4@I;M(S*>xc!N{JIoP2PY=lRvIYG>&P-2P=j$Qw39|Ez4wxfz) zykUE=_?cUQ+u85+#}_}3jH^ghbdb`Qe&az2NTRMpWp}KyJK7V7S00I%^hOJNe^#>S zYU?e>`_A{AcPhq9kgI6IGk>g8JA>*>F83v*3HxFGpl<-!^ywwTsrkEEL_J;>QI2iY~ zCERUDj^xPBTkx>ZR$X`BU3d9wmvS!Ke?R}8yDpkr_t0xAY`1^$^I}`!vd=%OK&{_g z+qB63V|!DH_WuhiWZ$>}GIz^)3bB>5L z$T)s4<2!RvCJSF!_s*gA?(i1W1$ShtaTt!yk?dfW3iJYesTXh9zq15=q2$F$m*SS> zK>YS>F(;xlWMj`eYy{SD8o90?QW+x{Av>-d`f-&LIFIGEIIe~@L>CA^a112?#M#8i zBY=iDxw?)+OB{rsh&Zo$nZ%f)Z7`dqka}*h0}2fDz%ZN%xJV2JQ)eK%WvO}9+3&@IK);X}fsnnrgd4XVqS%!XnCf)tTJ``h%Mi6@E}Mq;bdt@oM70(px*!N#*` zU#Fj9s*Ieq>T(n`#c(leu@vto=kOX}A2)Pz__XH1vk-+aVDl_d81K4hO`tII)5Cy`16`k&h}^LE+C+9$k~3GdRFcj>jz^>w$ZZfuIzY>0cG#S6DL=B}71EJ+kr z#tJL1ZMt>lPW$+h9X~DH`7npdKFqfj&O_eoxwgV)`xlc%M?Rli-t~Eid`Zu*ZCQqp zC@tlVAD80pZo%RfpW|+QHr=l+ZmD*Bl(P=^A8o0??@xUB`29aAM)-}4$t;$7RNI01 zmADoMhK)#7keT++Uc_IIjBBL>GiuQ|<)AVMIR zb&?J-``JtdpJpg|s3DC{zC?MgA}n#0fuT;wzywA)lUwPJ&8l`pZZIStF7iqFEw> zhg}gF{vqgKbBNsB=j_Ui$oSd7`FVu%gZb>&sp5ZiF2WUh)yUByRc+dJMNUu?6;3zYc->nb*kU7Mt-)xj;WC2W3?DQNq4^-?*v7vmdA-0Q{ zR*1Ai+)vNw3ylx1E&-`FVqMpUnA!|+e-XrsZCkj<^bJCjCbnk4x4)|;SxF^NV!c*k z<3z8ip1}aNH%BWc7NM;Cf@q_LG3Zmn`03xQTI{di~(B8TQf56Zq3mEd#2}tDjj_*C^ZI zvjjtD4HH?*zx0zYZJqq&ixo*oDH$h;T|)@X-_@zzqQkKSX!(YH(s8{1*m3Pe9IqN3 z5 znQHz4mCn}!Bcf7b0L27yCUy>IV)aHxJt_|?9uoamgoZf%cfc++S4(2L6iqCyx_s_Z_(w}_^+A2Krg?1ZgnQoQirtdDbZVe+DaOKwV(rp*Bri#n%6)(GTc&zP{CAAla-+b+RuU!wK zp5oFscU;;r);3jE{=@k{n4c(H87o@}en02EoZF>$HpI(zCOkXGT0im3Lt98RTT5KN|eG z%|55Yelh<+$-=A4ZnfUY8ZT)dFKmC9Nsk}aBU;+SQd{vZ`xhac+P3p81+Ab83+=77 zj-SkJD#afxs|;-)x=0qnxNcJCJ~AaprIRjDMizq5h+R-@plVEk7{Ntj3Hb%FrzKql z(NTt=H5h-nkkJ>Jfn1Qe7QCboeM6hDPrIrZ|pI^ZF)&5395{s2olc_B*A2iH3gXK zQBB6^c!9GIVo<}HkkZB0lXHzS_-V-sg9DYd8^+T>I_VHMs5i*(BuPLnDoT@<+_ljZ z1k1CCAWiN|pg+(C9j6>?%Na?3c(s$=nV>ZJpd>#oFcOHC_MzdypsbEw7)K|>+`}*- z!4j8mJi$v|>?9(@Dx<;5=4-HN4B<)yHMW@zA=s!y_{n$=enqhE; zn==_hKA9(%jp5)BV916_ILdXYC|893RiE7@giD78N4U@1lQ`~GG4HBd#qZC1Z{F>? zxVJUoZY7P7_j1G4@Y}Dy_4@6qarbl4+~*!<+6vq3UwlT~+xdnjFUbi#j`tVgj^QVc z5R|}%e}^Ye1V7m=@slOinhnlUcvfrN1-_HGEyw|NoC{9W!JcG^Ck&^pU^p#1@I8E% z9;eabi_Ov;7;J;6=4=n6RszHZY09RXIR?v-z@RvMSqK)O98Lj~l?_=5134%a&Jrt7 zHw=VerqJbXrCm$VLmv~oQq$-T2vFHF!`4dkmKZ`-I6DLZZw*8<^(93#<>MwVO4+yq zSJr?J9LoC6a4G9MOj?an>5&bzQGJ?5>_ux3KGDbSD{9)nywvXEKM* zEvzKRJEUCD8t5C2e0U)u{mf`5kE0lr8+EHx9v*y32@KscGZV9AJp7w_}|yxT_3O5kyx;UaL&9dU3&Jvs@rEiSTVk+Bf19`FNb4$ zULALLM{~P@gBI=toirDfpWo87(tg)wZ>o3Pwb$d`no9aZVALmrh2B9;bXm|tBnf2~ z$*c%dh;NyCj-*eSP|r!KDVTY}sTWZGi)4sW;(vtEawt-@0_9`YBio{IFn9^WWNUZ44!Ub(d zHp8BO%&=!}VAU)sLMAz2JFP|N!U2*3Jp8&i-QYD1xcIVEA`n%26}dtB>H0?`kkkd> z(^G*$hBULr!l0?1n7%xp;|TtX;SnNX#235MM*_NNU`ThR*O4YeIN**=<#jg#7UDur zt;7W}pjSa%5_LBlG^-1E1XU+GA!HJw$ChNBJ~2LhYcR$@6qw~XBSU5z1TQi4LUXSk zYt~5JSSAaRmuce~QZKP>&7v+kX65k7FPx^`OgWMkUb_auW3<*7Gh}|Dp#idu!1)Xb zi>^Y`tI`gk%;-|q6Qb+Q9|!x7B4`MSlGr}r`g*5vOlU~;YSWegf|>eW`ybJ^wiJI( zW*yUphEGrC=*@AZ(gnN``Xn+hXN0Sw+o!(pycQ{1BwdD}_u4E&&>z}ibrbq`Xo8X>)+tz~iV=7f9mnB&t0jmRdO{lTXAf~~RK(y^S2^Cp}{W6wP(S`;nclPEtF zD?b!{r6*n3=-XP>pli#npNj-UBzt_N}0E&pKo$F1YOy-1Y{ zYlDJ^i)@8kz6cS@K3~`3g!-i=&vCQ49Je@jnJ8u_P0$YfNHq{4P?ESXH4q(Zzis<% zr+&1V6UTazQp`FP%MeA?0}Ch%#gG-TZ51W+cbq}jm=jh}IP$*bI_C(^(f`WCUx*iu znBk5{#<`qx*@F(m+s>prUAdGs=v0Vsdr*?q=W>zMGy5cME&EvqY*VrkLpBGZ2pT&s z9K8-TR{1MkZaT#isYqD~MamEqDLdG)RuEVXnTiluGn1?76)Czu7?E(mmn3N?{Q-z6a=VgD zBuCM}x5zTli-2OG#-3)uQYZ-OiSrSLo}B>DkX;BAOaHeHLq$Mn=Li)4Ckc!5Z$YDr zxE7En!0>DZ#>bA65z=qI}1j`7>QlCg6BBb@H`V^j^G1*}f&e zZLHWV386=4xSu5JELO$ZZ@8Iep25&HrU>3|5vMyv> zy$4g5Y04I2Q%_(rLDT$^jNd9i#t_*HBMZkU6je|dNVP-QV3i%5RSss-8OsH1?|`bI z>t>d?!^sUpx=6-RZl?Au7rAx9f776nKrW~{HBz?0;*uy(uJt0>C!!a3Py;ijg$Z5_3#T`9%hSScy#Qir;j}t-cC?Do(|%ev!|*ius{x`{ zN&3RgHb1FeemVPxd4HI9t9WeNCuJ2^tKP18tL9eeow{*d-}E!LXTnn&^;At1mtEO+ zwfK)-iWM)t*!F4J;%jTKhOalhHFEvTTi>`9j@4|6FWEd^2A88L&%DbeSG`fs(x_`G ztddBf#DulqtZS-8zL%z@jz4R}-G6s`MSG9dJW26Nn?(Chcp>)04tl`$)L+r(v>UV- z-7y1X$)t#l;O=ICN0|fpK3HP856mCEM%&=Du?S~o*6^neGFR!2 zIa&TS9^T025W)-t2~585NJ9=8O6f40r!VHnH=uG3n@Y0DOwjDH8J)mgT^`Ti*g;Rf zO^q@gb*?Ua3~9IN1=CU+B1jjTeFfB6#rNpTpWtJ! z_s)nR{p5 z-Lmnj9nr4+(F3o>y1K_pdd3TTNY5OwKb%K;=6qY_R$b5ht)^$eZr4H^v z87#E3&t(n5QXKL~n^hvI6BhE+6H;c%YocG2wrGovEHJMQ=#ccIFPU{cmlMh1a@T#r z;yP=DEU^o8tx_D*o2*sZLu*3(p^(-w&X7X-gL&fi*IZSo8cCBhDfu6uO1{C;NL(8oDhaZLGdJ6&QpGkcc<}HbTayl^yLG0_WM+dy;qp#3LCzD{ZAn z*Uz~Ewz-+C7-4!RsiK2?Zl$QwcEWtuunF>IqCWQ84_GL2R|xEiyP)`^zds723!z)S^< zDp^8eCVZZuauQ67#pjiSYZn8>+`-(Dcup;)x!s-&IjD^)D|D5UJf{=3`<9q~xA>{Ws8SPnMT4Pkx1jNMt<~W*F%r_YunI7IrkC?-(Dnxj1(;`59*?SzI zaT2%$odU;%=+uBEGA9E((A@YK=RFY6U~k8yPKp7qsV)>lbj~vnTFBx`wp12moTNSY ztf!|PQKt}UoN@e22GnmDSkMlWA<6X*5tAHKr>hjqJ1;OWLdb^;kWe)b+GxxzgQP~E z$>YMT*fz^inxr3#;N{F;qa%P`ng2nDT#QQhTA?YUW!5nW%_$kSu%QZbCDXi7@TCB& zhF8rbVqrs@%Z7fo20#Yul)l%PYmCW2g}~03KHXMQHZe@VH7 z^@}{r2orz$wZ8=&)d@ErI{Sll`8>W0BhVQw{pTP;cn0t+9FQr{0les~7f)ChE+0WVSL;%iKiy{^0R4ucnjjUWZ-!bM-U`S>-u61Kabn?hh*^{}Vl-7gC3iIq{bKfmqb7y0C zB{OGZ_AL`*NM~begLA-nvW&3akq@Q_j`yG;2FL&JQd?e467W3}^FDJc`2Ml?j>WxO z67DT<(c9c~-`#xMeku2IfLjgTFGQr4=4fs+fU@wpFDBj1pNA??>G@}y>g@m4-c;%M z%Us;ubu4JAa@<|)p!=#U{91$Fe?`$>E70=^(6i+JW&@6u3OKGx0mtBMz;UGS$Z_~% zJ{f2fl`*@*RIchNLY!#%u>tNNp9c$g6IIUuZUJnsP6TBmH;1~M$sE0yb_9Pb@K(U# zO;pOxTEsDcg$Cq+K#KzOSg~}Vmn({o7Id&YW#aE&5a7Lp7CGQm+48EB0IwnDZMfC- z{=xU)-Op_sCYsytyE|_0jTTm3%;BD@S66et*!zVW?zuanxg7+7TL6I_5(3u}1g;js;DOeq8|0kBTbYEK3limRo?xkF_A%#4M0waYyS%E(V>5zQt?(09*55|iKa$W3T zqO*F48-P=oAP{xmdnUk;=Mj}4mQ<%|g<6#<+f&3MU;!1Wh^!;Y>fkt3@%WM@P^8c? zCf_aNxK3{%K=d}Jiy>P=#A4VB^g=5J_Qqh}WaG1|5XYyPE&LZIkRWl;uYidaVy>sh zy%Hs2Eb)^j@fZimByCAF9s?u+6b4WB=nSsO^xIUcPfniP%fJ3iujn%~90WkJ5h=Fu z+RtzZXn%*FPVN7|@1t^|^F#w&s~`oZutR6G>VKi?87E3isP^~tC!L=mQV`Hy(dkz0 zAMr*;=d~8bx?x%!x+IR#e}Zn}De|G4W8TfTgC8FI;Mkq;$1ldc2NLcBAcx%^$#psz z*J&#}2(^pOc2*MGiHK>X&o)=uKbmWA_BlQ(a^qeex#+!(m_>HvR>~t6#}~axx}H{a z9q2|_sI$Y{>BvRf7VN8{bIDZI`R}05bcz3ACXjJr4u7Wp8pe3mV&*gGQ4NQ=M~zs7>&&IJ!iL6%w%o$a#A346M#187=+LBm`UY zw9~S*+(QKiR2s*SCnCQ4)tc(a=}E&L%l9Vk7^d2oYztalERa|YX$8rgZU)1MG{ALS z2IB7IF~UgZ1&a^qq^!M(2kaFDUWP2prPtg|lnob@F{5TCOZ$)z&od|oe>{eh2>(oG z!$=yT6DG5HQEstJ8a)FiP3Gv;j?Urqy#8ks;h}$pPq|9DHpxbLP0R~t;rG|Sw?6LO zm~d|d)|l%-EZ&m&KeuJ%byH}XlKF{}rLhtonx-zc9Fe_Z%bVjhEpZly%vJQ=T^Dv; zfr~M7(<`|Xj_!YDeE#8|x?X*lMO7d;Xkp3NoQHF4g`0F^QkU|A-k zqb!&Pr{S>?|oP? z@VT$H&wmVx(vg06kk=V7(H}G_B3)4mD5w>gJj%X=WXy_Dp=syanTg(&W{u9KXIKbm z;ZsjmJC+Xa?A*dnCuCK|$ylVrkJ1>2N!%H98FPP2N`DdQ9zi;2{ zxSjo+0a2*R5JdeI{`id#1pEt&Gs&7_Rpu3N$^n*fYowm}RY2&k)vj+hdtyrz29iDi zPi>RlJdNsD!g~_2D(jk-VwGQ!zD#%CNwZ240_90T`A=@$%t=Y z1oj<$Rs{A{HXM(=%!2z?Xgs{H`c@C|3zKX{cGFo6C$^3F&+rrkwjnJPcL4kek=o3x zmS{%I2RE+PC^GJ-Zbz#$px9OG0e!C%W}%3czd%6Wvij?RTiG}I<7FEzY{#*_*NEqP zI8k{#R(U+ye!;KkD+QM)55sb5wAMEEJP|4sx}cb{)M- z3fT*W!dQ3_dP9A7i8@N=ta`ZKWl2mxW6TTR#1Geh04AU%;clUDy^g$<2)Aw(t{0Ie zTM@3ekizw9|1-K{+CkD9Gm7?}9&MOGLlU8-RdHnCb9{9yol|g!^nYfS3({dUv$T~{04-uTwWTYK*puD|DQkLDs^ z7mJrY>2Ci#mjfG%Mf?hAu@WD$x8R~?QNGgHy#DPwp-n8Ff`<6Cd1NSZ^)z}a$ z9EFLo*ezD@I6W((z@=UZjHhPcB=iqibS)JYEk%M#1D)1!Z4d&6qZ4S?SV~T)*T4Xz z#I~ZTq3g@y54FoPp%1YoOqj#8Sh`lwj5rKVN0%e0cw;V|(TwDU)}7%|17+wzYbNuJ z#o&qr6Xwt(4CvnoYc><&_?YlUv&0+85eC-Byz6f}KFs+b=g$1NcW1)Alj7GbfFsxP zx0c^(9d|z)&3%^e1x5AKBW4v-#H=F6`wN?j?b?`nd=v3Unhqu^_!FFSLhQywZQ0~X z5X>MkTb_~$!b)UdpuTBmSk*s%g z!5|2RY?BZVA&IS=J*>3x+QKy7S~_Gzas*Ma&ldKIAz9ZD$w6outOZ^BY)fom>5@`q z(=zS0mu%npy%F1MnJ?K!NR09d!-%9ZPbWXp5+Ab`rSzQ|I?*5M zhF65x^Pn9dD4304#YE3ckIf`x&O*efLl4571Q29O;->{~3hEiNjzBUQWJ?ahj+&;Cb7<0(n_D;<%~6U^ zSZ$9u8Y%Py8DWEzhFd)oGw2d2y?tdxALTTWV+n{O>&c%byrYr?HFk_4 zo7Of1#cGTTwE^_?BgQ%D)VB$RCuUzy=3ti$1bX{;CQUw>~HKm7+fsYqADDO{*I=6Ei)KFrMU z>?kBE7xG3h${o-MPt?&@eOVYxf&u^Jy|6OnM zCfmP(YvLT3rrBGZj=L+H=HQQyHs!VCX8t5A1NT44vD1C71NV~P#`GI;aw%iR(?d+z1# z(W5#(*OX_!YqvM$IPPX-4dK4IQK*jNs$+UxDDW7Cj_CUv=A*O<1xP}A=&eJyzIMOx*?aD-(cG=XChtWCCHGcctk%#}L#(pT@qRAuJ}if` z$lXN_+}^Fs!msry|K}Ln(>&$VpXiSU@+QIBH)a5DIq@6@9$TO`TacFR@og{*QI^;@ zdI!}YmA|?8A-$k2X}H2$RgWG|U`5yC;+MzJR!UKW=o!Z>64g<67&Rr{Cu7r8yrMa= zD^t-(K0TGVBngdpEz!v6f@!eG%Y;PQ0kxcOS(l_5dp73PqeMqr_D2sMiF&}n7|q>C=p!hkY|kJX{reP`{`NxL!Ij4eJlh{W+f9}tlW>MbQo-J{ z-2=dt1CzOwmWRCcS=gs;@_uKAN0V6y@&IS#L3B>i8)W>78Q?NHbX`X_XW2=uy^ROj zFn(Ye&8!EB;Ug(zKnwGVO9=~?(a(JPSwKI`%4s3pQB$FO{Lp&wOUKWG*%Rx>AyeRI z>$k6=f1iOZ)Tef#EzkA&XC#I@pW(oyXhvUHidBoge3@Zu*^J#rdqnUA8zT9Zi zRsVRSd7BobN-jul^3tc1~Li}o~9N`ImIs2azLr2R6IBSM=foU zY@`3d48)4JYa5kPlz=4ZLaAlS2s4eZ#R!pAa*-$$%zlTMG+Y$1=|nldSAQ|*Ic!}s z->6i|(m`%G+Y2E^)`={jZNG zyOpggvc~`DO9AVPvOh4=T}mBpwGPv$)s_mCuhhD1At=s~35W~tca z3cpbn_*;Vq|iNr=h4aq!6>vR0%y0$r6&rXz{Q;li#lBDDdAt))A?wOmxJ3W*VJZX7Dh)t6( z$r0Qbal-e7LDFtx4o|&(J(Mg{unq@?`g{9YL{1G%(x9md`1}TjVcr2sncRMn?o&hs z;iNUQ4pd|>)cgxDMChkPIsFtxMSPtoiZUN?#-B$J)EiANjzQZ(&~kvmB#CIb0NE`Y*nKH zW87+i!ASS{*U@!FK))>L+y)s){c7TcKPBWI!UN}XQz)r_kq_;{l_ zOT;ZcOIx4pTrv)$IkdoI(~Q$VNnDq2aRSV!rDDvzq53x?|0klYvi3~x>0#3jTrK2V zI7R@Cry6@spKW9-RX@;=u=+g9PtOWEO?rAv;MrqdOQj+`Z-ohJ^&0pFW3n2xar1d3 zpruV78|Xk!4-j{FIAkg&0jrJR5YR;*7_mKRkw6DrcINyNsL`^fZ|=WQ5LzR@7aOF@I3m?=275%bu3AzjFERb zIpg(X8FiR<)~xi9jA~4yCV7ftOfK(&b%(jj#ym5-jn2_;8q;bV)mUgcqUGfIlh5NI z&lZ5A*f@}D>u6QPNiJy!KhEmfIzKF(aKzH_kMBs|reyk_ES9~b@IbmCaB^X{@t7SD z-O9EfU8?*cdrk)nxvsUzEze{uqdVYg92n>i`k0tiC*k;~9CxpfRj5QB4G7S1Ob~s{ z)@O9N34Uck(Y6Y&elBy9;>*$J1oM{|q)`8;g{^W!RWfK@dJnB)vt~@C!8f$ zYGTfcPuwL}8m}I^d1idUx(UzxH#c3{bZt}2v+_aZibUla{`wBhO3KXb5}hmuT7M%j+L*z;%jpLqm4@wqCeOu!t z+oFZrrm9yZs@KJ;*9n(uXGxTjpe>jv?1=`BCjwe5pd|vY#{#cMdm_=oa~PDT0E3!S z0OK=P*|nUQv*rP+K6UezaZe+wdRM%pGg{a=Rnw5DX^ho0qUzl-SJf0ob}Z(sR{Xb} zg;!91@dICV!nZNz+jzSz?rR>~Ik9*-${>jTLMqdkSkMq#(D0)ZiFNIJ?n~>?2i`ir|;Is+?7|4N0;*H*%vSAiWYWFEm=Oc_2SDhmybT_xY~93xtMzy zD=NNldi3YcWyov)-EUm@MwA+4d*DU$9;kmNv0_VX#g_Pr=V=er#$0tjb9yG~R?}bA zG1t;5Z}Y`2HBxGG%uA71k!LmL?fdu`exk1i?|J(Y?!Gk2w4=heeS6;aI{SZg+PBv@ z{-bLl?t1|&@*)+)H_2o1=^Ed>qqmu2dSmuCgS6W0Z0Og!EuX4Xv6m)&$V3AI?{@N(l&U9)S9ojkb?D|r`0=q2E39Q;sm(@g zdbV`_rEuBg%4_~?{~Q!CY+IHlsiil@yc=(~e%SFrhe(w^(Z2n@d&ix*-_N?-s%I~* zxL>&Go_j|$cLyn_ku-hMz2o!GeCQEe#%joA%ttO`HTJ(+oX)ld-x?OIbWlD`+ZG`! zPJuC#2j|QX#bnJ3bo$1vFe_-qZw;NnUfh&iyVsMKVIHizqii%GRbfVkHYWHw1 zSa_8=6*MwBSG9a$<2gx)r4^9OiNP&Nh-F>Oi#$&6kGwZ>CpYfhmT+&Q5~Aa6e??XMG5g$wP=3va#VoL>}cH2#kb5-WvW_PtUI1FSK>H z?b^M48xY%3#LpT=FL*`~;_(K9{6pRm$e)q4Q~~AL>kbK&(>b|Kk0d4h&q6oI@fm$M zYaceoA{tmXjpTYdfhne+e9VaHh8Bo~%dAe4G9eNfe8xh329BcBYxf|QY5Sgz6}~;4 z9c)26wzcy@ki%pC^;DJ=>4d(g%PIrP3kWEiWOdvmrKDs_4iV&0`G9?m&U$7Lltpc~!O)&nu=$6a1}QHzHc zHy?n^rHu|4jfiR_@{<;h8Z%y$htOnZ|EXgvkBAb&)xtvVS@dPJjGvGe4gM~jlsC{6 zJ1PIE%WiWQCkpCf1$Eb};{~h6GCx7Okd4pZU)pqwPREfy9f>Y&LaLCZO;)Kw3`5d8 z4Ig`=U9Uv@PDZ`Y#=Qdx_dq)DwPi8Svg-}EisPPjQP;XpJ*Ah!*Bjp5cw^)3u5nLu z)Ybg?&*$1|npud&Q{b0rV$LsY$+Z88r+Jg(y-m2gTW@c%JMQ|Mit&fF%{m3Fe42E< z)nSa7D{4A*lVu5F#bwA?ahZXyTTt+=>3!4M81a>!f`2lo|51qVCrNorWWfN|K>ubt z4*3;fU`c-e5`5S=8ksKZnC#k;Ji5PG z3W+YLb8@id_S8g*Q6(ezf6}FwV=V~AUw!ry!aC%7%IWilq;Pd>Vg-7<*4u3#Zv9~E z#|NSXYvKi6iQKMxxm{m;Mn;?Gn`}+__PZJOrd-F}%xv6CvK()1|MDefe}F?GnY;z_ zCfwDO$V`m3;FJZ?Ka$8)NX4fkD`RBQ^jy6Wj()9jEdAHKY<~O~Nxad1l#J z6XupzttX;mGipGj1*e-woGvTFSzLH8T1m`www8TpW^37_|4d-B8$~(TBnMbp8S}2Z z<#<2my_~prL&CiQ2X5Q8`|j;`?B91t-gfT&!j1Rb+oQSLiM@Rm;-Z2DPMpjAA;j1? z+l>eL3M;G2Hk4hi}Q#`6l4UZjVoUFacEE=Dd)Z!Bw%g))1McaxSIJExkvJxZ;|DALBif2l`h3`#vBp)qglDWX3 zJCbkJEAd|SpkO{8S$M;}gH%5TyXIHg%noCI`6YygTA3jiKgs1tQq^x&pbh(_Vjt#latRBl2jFJ5MX8fLoB$t-W#|61+ zbcmY4KIACJyBdQSR*oZskyo<0q@K!32@+~jZYjSh2nDRDm2Zru_>wpJ_7CDzJ0$jU z3*QJUB-KZo#7xkW@PHSVd!9yNZdK0@$E)+}dA}8ldD@Q5T>&y%7zzeLJg5fWiL?><6}Ak6kia17|{g$n#fj-_zDXdK?QOK7A(^aEO!u0adoncswDW9~uk? zFxNdjFYMmg*1fG|cjrDVFrMgE>bj~Xq-+m`*!nU{u2kbYa@IG5U7^POqcO~|$WO{f zo9AB>go!wLA%ehG={dr;clx_n#QNBbxAe%+!(g*Ic%PVeXjl2C1 zDwZZHHpMD7-F_urvHfE9#WUY4m|C_DH{XaA)=0C;s+FQEPWSgwL;1v_3OreNp>xW+ z+H6+18Wy8Gdq>Q>@6OVwci+eDxJ$VA3D&UdR`L4_-diy4-aO`*a(l*{4|8mVUBb4o zWpk^~{*&kIt>un?Z(EFeChEat+lVue(E$D$eNae+uLe8Ty3*a7`}537(Y0ycnloEc6wHu_GV zMRI~cMSx8hOqiX8e4Bl*%b66o?Z{9##00{PzSS#yOF+;LBKI9L9AP*=r2wcvP*-}9 zHHP(ws4x&b)jz1eHuFg5jE>XC@PL5T3SVK`46IDI>}{>Q+br+uj2fnuJsL-xENU8u zVgCTS*24aQ$bGRNiAtxx`DS1Ty>+E9qUb|PEgw6Elh4b?Hh-X*G0_UL@h9R8nBEFv z8k*-6!sttiXI7qLyN1rFgD_I`h+XqbqIhQ1sF*T_3QmW-0oizUbR;@GxAr@YFxF+i6AGZb4aww-DB$M1NJFPODRd6$s(F>GjwQ7Z}Sf* ztH++2%#&SV^1I0bA}kGP;szS559IyAiJcz0yMjurqB2c-EPzrNa9F(heIkSIqcU#5 zfx3}`x9-}(ad$oZLZSbv#{JAYNZ~2AJvDS;V6B{;B zZ2ga4jIBN})-mOppKw)xLb_V>Q`fSGIr!{hev*iKL(IG3cJYVvKA3mMAAPAi>fI3c z_9War&^IkCAIqAU>!s>z$C@5^kk0S=T+lAd-&;QJ*)rBT;hOv1ofmdqE*^K4Pb{e! zYyIwy3p*}5ewg!voO>=GHCKz~3cX{lhi+S802B-zujiYcEfw~U=Ga>nJ3cCCD#9PV zm_vDy(DR$5t$MoQhu_iLOflWID*=q`NcJRSj{zpI!|9tF#F?erm_(D8($o zn9_+zbD>lzFqaS!gUwG9ge-_+OAqS@jpTqS+EyE!66_WOvV1P*s^I!_*i|O<-XiZONp_;AFBHVp1&B8Bh~|fr6SKOIH(^ z^L^whxj104t>)c;(HX}`xq)k#{A7&OL{dc!W~i`a){}0LnJPJ;HufA;_qv}>Bg8F$ zlm5_f*f-dRzXy*=%mDCYN>7H{^lhQzG&mc>f4h&`Q1H^P9K9J5S~-ZB(A#VcNKF%$ ziX>i_?_xt4u-K`+gokxbE)b$D zI9dmN&_Te;$e=THXW%4Gl!#s=BPC&`${JzKNvP){p9P|%=zlljQ1?Sh4!P}Q#z-&M zp%a)28c&b!*o|(Qh#yfA@4`P4KKlZ9MH6;~CEc+MZ|J z-P6YJ_vQuc?v8shue%BnRH;Bhy4|z%uYdiDNQv8IUeEiVbHA-hpFnu&WM*1%E~oBy z_j~TS=bn4cxvrAemqcOTIlCd^o)s&Y32r32Sw3gGRakkU>h<0mg^O+#S4V0>qs99o zzJ0OW`mx-mXl~QxrgxUVz5EYW{vh{JFe1nSliAsAcpN;E&(@xrL99t~<7MODSdhd@ z%cAbGJN{+Kq8mdYHtOH~0Yo>uBOOlx9P{k9Ag)hq5}P&EYnI9H&5+kDvA;Ld3phz) zqZ7~1Os7@0)LykTFnI`_)@tBTDtXy}N2G{HCr9K{tFIC%;1rD9Jzc!bcj;%tWIfOz z{d^eq<|x|GDeg$7x_g}FF_+qCNb{4MrPB~XX}v?Bid6liu4{Pz$)xkdA@O(}gt(l_ zPkx5={_1qoJBv~k)=U`HXV9vtsk?>Zsh!GXrstCSE@2;$r(Og}nl{RQ zq7PYu*QGqA;7v@5rKwLMR7Z2F;n8^QYilodytVVv&MQzXtu~%RR#p>LOcN(LP5HG4 z#yR9aBOE%}A1_d~ShdLhE?hN*`}O6C{Dwevxz5|9a0mIr_9Q;SWpFl0oQv7%sjO6o zZKoZE=+$z`ItEB_g#W^6Z`w7nBPn=<9YY`-r|n5~LkThLK%8Xx`j{2hLd;*vAB4Wv ze2Z1A9Rwu(4V8PtNh-rET!m76hOQLv44puOQwhkLQ17pre(VeN{tC$lYM+vNq+lnZ ztU;bEO;(MkAt-V11hIZ(m!u*%E;qsZh3i6SUT_02=Eh3IVYhdZf2Wjm>f%IFQd1FL zdQ2MyRSfv{O z(J_>lakX%W)Rin34IS$yebX0;(X^qBP_3fN_nyPgs01Ks{qdqssY1i})LZiY#-X;9 zq)co;9E`=+z!r}w$+Qy5`)F4vtjO3=@kkN*`rm()y-fbMGq^fdIfzVgoS{QZ+zCHV zG=lwcJ3(=8tGdjAi95w7)A1$^)57cqT->vGMQ1mZE^O(_0R-{1p8kXVbX!VUt-G;xXS8W23uTXtdXGljNAI}G`D4uc z#x zmoKjg*x&P|1J>CV467lM`87XPkYlV=reH@e#{PeAwqTHkz*xVZjIu&1gJ({O@UZDI z6g9A1K9dWt>5yIOf$j$LGp4&K!!tGIWmK}Hy%y&b2Nx@(vtdwz*$EBIJf~^ssyw&B`%_)f2`z7+5)9kXxk}>?W5LI8<1r6D}+E+i<`joeJ5+ z_9xlG;#i}LXz?C_gXohNxc; zDG)$)fh7UB>Yd6jmL`i(9czEq(iJRX<8(yqhAKOLb}PKv9_Gh>`x|>gy>zCYe8XhO zajZnICUudAkkH@^v>v(>Wapx51t-gDCaVJz56FifqDjd^2~Oo09gE;>LkzV+b*QB+fNAdjGNw-BxAUxq;Alv4;G zpf_asPO7vMg@}FYBqe%{f;I}CrC=cfSd|eg9CvU%#)cD@2jfoiX#@ZIU5W?w_S3x^ z^TZlgJV-lVj>;9QwSAp7zduDv!5VLqrQ-5eOI|J+3)Dpebz_01XrL+P&V6C+*|o8n zx|{yl=f8L^^iuenaG*FlR=q5iA4p_M#S6wIM{(9ilEarZ;+$|xxn;5T&EM<3)*aa% zitO(iZ9j0my*qNG`(}R6l_lS5e`WuLS-;!;hrXM>#na6!YIe_0U&qA1_zktz_@PB#yDF83gjUWC^{W~L{G$~_RnNG_=>S2u zu_D=qCC%o0@>~d4e~OMNWcwetuW8=ird$Hp4=j>Y>%c5gednOktr<@mG1mx*<|6SK zDdCpfxnr&hcqEOuX5lUDTi&9V>R+rsS9U&h!9EsT7!59rR4j^k7Dt?mmE*{hH0H$C ze1*pRGU^sL(AH!3=~$&VsApVNST;*KPs62V*hcC^{g~H>s99%}xL6LflBTSSu)>0= zG8m>|TR4r{61G#Qm81Q88nR>5!G>}Sv0+@;iMUL<6=z61*d!m(SubuH2VqxO_w9u| z{D6~TtY_VKcp`($`c1dSGO{MkE07HzVm2r{M5^qmY><^U4a-GB-N{I8!dc>m7^{<% zYMy8&jhas2KBR|+UB~C5Rbz4O{OhYWlS~`5tDG#A`UfAlOHQIc>zT?}7-U&bTyQwq3yLlo>4Yo zjTY686)lYxsS13fMa^U0X86hW6r4N${FgvQap_%9Y<6lqFY2Fnx$sKC+ZCEp&>e5V zn71nGt$KaIg@KFfU;EPKf#|H2qt&ZMy{l1FSrxo(XGWdHv5Fc%uBfv#R$c)pE9xwX zm60!Q{#so5YW>Ug7YG)vD4bS$7b9-$gVV-@~X592ynNes5OQq5OgZmG045Ti6am1+}d>nqtuC?|GZ4*0j&O*0gYj zWvyw$b|vSm`36){(v3s>^J(EUn8Mo?_ptM9+G*G6tg|*HZ^Q<@DCciDPiOYJhBMCE zI6h5rjHDqxlj6f!VOMu%PuBAlvIN-O?dowqAC#p`=ysj4g|mBI10|y0*k0stwl*GQ zNFB~PN+>0t1b)E49gouuo85b*nfLdnal?5!`*aRk08?(oZ9KpSBas}v)SM9sEz9{0 z=WzBBvc^jJ3wsO!M60A}r=9i;dm#L9?6)0;cwi6KI*e&7v257!P21P<;59V&w1aEP zowBAp%bN0r^H7u5RFikuYlY9lUbUwD)83H^)MX2Mr>raAvM%4S4|VxXb@_+=mUa2n zx(ZJFxmUg^Yw}yxR5)CSnu<&{6%7|z)>Nd{6gXWp669VLOj%c%G8@W9JKsP^jH`GXagk00(j(aCu`kvBU+) z4e0hCyki9CL)-(0DbOLNJN4y8QsOeWr+iGJBy5PyU1`)C(_hP8T34Z%y5)M8C@=lt zJ(%8s+5@vrarQhwriJjCKJRAaE;`A(&ZI0GvwUykQkajV+KPbxh zWNjCDSHVDhf1eU=Y^Lei*mtm5To6E(Fx@^0*~LS2q9+vYB1>meM`&~=cSGy-s^D%h z2h*PuVki0jQCTHst*5IlStKZorc~|4MtUR?leHci4QSk{?ylZiwf4Hx!5-ozS(KxW zcz>gLlBOxQWMr{;$jsV#fuY5rjRFuwQJul@%X2!j{vK&t^fKCF1~ogRE59TM&RFGwB+=r@Q) zUk^;-!@|b`5CR!?bhM;C?~}C7P%4Qa&E@unV7sjqn)Jq=`Ee<|l+Xdtu+MF9xb**N z$HvTE8v<_&pB4w`^hJbh@7@k&5XZO%!c;tGp<@Zo+oH5Nt6>Zeo*ig{HI?j+L(2_W zls-R%JA3!?IMT5lULIf)b{MW|!g%x!bFZ9$!ZA{`hr0Vwv4M0dMNyy2OGfvk(n(sN zE^weOI&t7|H*i94I^7f)#p)DSEjXEMPL>Ue^rm7-x8Ae?eqylz=|7P&2iAPw39)8` zZa!~MywB?0oce0C8B;{B>IM7uvm10MtRFgz`z9_*TpD8?TJGHJEl96I+i>*=&6Y+R zpf=h>EyhPHJC$hcPt$lG{7c-U|%87BqVO0L=~hheyW*76B!D=F&{ zm76lvC?U7`rwR{CXPswZ$e!d)UoxK(NE_42IwcGb{~E_fhVsfBJa}I}Y^LU<#%c3Xsh$&L8Af>oc*ahg4Q^3Z(Lk`J4^lbg&&f!~>Nxyi21m!>I zr*^JBLO)-|fW|Yldj1(ETWIO<=fG^y*q|Y=HSVNP*m-|fO7tx6T(?G_W+5>w78V z#fdAi@ zuaOl+@@rzgz$@D?6#nkhQD5D;whsdp5Tl&9sJwRS^1|q>rK8o$ZUmN}OTPo#$-)aW zFV2YM&yBd}CITq=-Z)u9ex=#DCLmvP$!iMj*WAr+{P-vQ|6K83VU*iIsQNWRzGO^S zzK%Ezb2$-X?*FY}uJQuqc`(-gfUvgiK3K~en~t=tDM(vgdv5ThXTI^w#qh|w2O{m0 zp-+djMdhzoUpRPi-)l!N*FGnaO!-wkD|I#>MS`K~`^@ISu3mTt zP*$IzksvXfp!3&#`>r~_)p7nA_**@7>C~8iMZ~`%>f84*3*5g_StBdQF#*<{Uz*%` zc$Z1-{G^WNYaK-g$^LG0ovaYjYkhQ39}j<;4t|9?2xTa(gC$@5V9|}z#>;J2ePgBV zk<#{P$rsh$6&B0N|G=8C?p-_e&ZbW-mcVJ*CY`kn%V*Q9Se;3IE!O&~oF^QX#bnyW zWM)uD_xFUA-@!N0Us^V_gNqG(+B5oFDKlC!{K49nAG^5r%EIricz4BE>Dox?+GxqJ z+UN30Iqt*z?A_#551Nf|LB)vPpEL+`3&8ljnFhhYZ;Wf|6ic~{hkmLRkp0w{Y#21~^nB<|+mp&;fnDC=Y!w)OmV4NZ9oANgaXKJ)z5;$X1 z{tmg45XVJ`bE0eCp}xMO%086$sgUP|-lEV>X=MhGJASs`Ww&P^0pCX;Q9@*|2Q&2Yh>Ge^#| zp>gFzDOG)?p3pHd2rfvgx(*6qSlna!(Md_D3piOA;}rLpesGe1LrLs}hw)tV5b{T! z0_uI-rJ@8!mvPGpQK)Gr#USmYmNN^+XNGG0+zUYfof@Y2dlY|6jN)0w5kgZ)F=EE) zruFwwdzCW6pU5uV*}p?dJegJ;*?DJULUd&iacN@3I$j4fF9 z&dRq}p4~vt6L0tsuICQCa%il4ZnS*v4cEL|{*qS)$0`;?D;8XCzv{nHvG#_4-AFrm zsOx%V*H~F&w5;)lYwj&y@he?pB5y)c3mC(plftt$5>+rUPp!}nfmjC7rK7x zDY{i&bK%L$uF>+9=Uji~+xJ21U#$DHb&(xUN4~IkbYtj-Z{J8;tZB*3!lf5$gy)wF zzL&Ejg-b`)A^5A3FGf0cjdeU7#p6MHjz)U=Mmvt(DET6u8Q%QV&GOw>PMtsX>a#CD zd+}7XVtJ%|_sA9mAC?S9cJ3bA*%{s08QFV0^32fa&Qmu^hVPqc+)lJHSo0m{YtBgB zqgSg&gKg0ID$5z!g!9{qb@I)Mb(d={*uRtUTE<1+YuS;CbrE+d!Vf_w_8%PEe>A%P zXr!BK+kfgt;V=ehb^FcYwU?KiU-IhmmzQ5S5iM!N`^O_25Zv+kN7_EDnRD^zmHDGJ zt9~YBXM3Z$!E=stC-3B!p5GJAuaD#}i1|uCEU1nJs$#`evC4V$UsY4AtTt9$KH+f| zdM6|&o~L#pZ=xJta?bTXf9g)I|86HfI3TZIWdGyh#en}L*SCJD{ZDEt0spDPw|oT7ADajmCe={hkId;ftLiy1j8u*6UhKcY^l~nCLUZoH=Kl|xYQxl zXw!3cQ;PsqiM}T6)5^pfbjdb&)AozOV>wyU$BiRjNc`Q9sBTs+0G*QD<*-VPNGBvt zi;+Uvjh#cBmV$zcr;8**ZgEZ!zrI5pz#~X6^kh;WRAJQ@-#dkG7moUujd_-h*gw=2 zR5YJB4k>rJ?h+>-N-52G_CG3Z&X>W}vlk3jD}WBj{8`y+ScxK$8@pTTAB2V`^YYZi2QzLc zH9}c0otKm&^fxFXbxF113X%LN>zE0vWBMf)l<>s7A9u-+*!AJ!2-;n}loYm&nn8h> zN%EcY8M(JIR++UXYnH|?UDfxy4%vCA3!Ubx1d-Z2B4Vv-L!#HNUPD^k4nC`0 z&?aADB;REcF(60nVhON=MR;mz1Usav)hT$l>o`>DOmm~%eCloZWF`RAA(}7U!c4T` zGqEsh?^E_24u`vX^)}LMkVG9i4V;USdcF`A=d9mVP|Z(2k;3Za#3 z;u}EtlC-|I!z_(&Q3T<$hng%1-!@@r4kZ`dz^iU(fP^8~#B_D{k?mz4eqv)*DdBot zhtmBg#nVkUeKY*Os?QRv$4RSq0ESgvJ^Ns}v{z^|gKVla$izW(P}%q|1bsnoguxzBp0WfcotH$A*ecdykgGLsFu4Y zW?C;x`9q+Mas_aKA8~>x4(c{qS88ckMqk*n3n&LcGLO zwDqU*;8Yl>ZqrB%u|2eQ-8}_8L8Sj>U})o zejMJ##pn8{r~YE=4bOc2u3=s@Fb@)@9g)Di(Ll>seoMsNa>tW5l9_NwzE;h(Rr9Ro zCiz;O+&s^IZFUA=?V?dZV-*q~E7WY=td-V2`Ly{8oh3T(S*0F!+=p7Pb&OQ%pA`c% zB?W<9#?e|d!)2Tx!f6_<_%iG^&SVd#oiTsaZ&UF#?YZn>`8o4fU6WS*nueM)wHAgm zjFOF;-LP}mCd^#Jnfg8O6t+D_bhB5jOhKiFZ7{mU-R_%NZ;(V2f1p-LuFRQI*_lOy z7zW!-DvPF4Dt(bKho%uGT>kfg8j-ag;Y zI*Y0n%4D4!6BDY4&53mf^}Mw6U_a2bu+%20??xCjk=lfmCjFYE=34C^iw&0h(`^hy zzk!F{-6ypH3mpXutM6;ct?VC!!*J{+>gGv`31aNw&azK|cQ!sG6MFN$j6*mW8q)!p z(1FY{P56{V|7pJWBx4nQCz%0d#ru+MTio9jQqU08#yWZ$qTw^`&$JOi6^hpn2^k2& zQzQduV(%;C?aO~MeDnEK&D!&5@f|pZ} z^z*_&^8QIqF889>Wtxa5qXu*C)DkZ%u*~f`-vx zFKe3W&3MqZZlLb3Xk%x*VcR1Wd3YXEDBw`zdX;T6+N-(qR9O%+)7Pjh#r`)`(IPza zkV7lH27L^snqoEt(Q4d0RJCak$R@rEA6g;-uv)|1p=xs}>@rBCA&Y%I(M$~z>?C~M z@w-PLirw(6KMjJkH%C@XF&q-|_11mv@hq&5xGN zA1hmNy=(=uIon3P+avDnc<1HZn&%N!8Yx>n>U|{Qegsh?tIqF=l)47b2@1&){mtu&yBly@}T#G z$d_Y9#pC+I@ES zSoW-F_NjWD0C3+`spUXA?Qi-QB`{S} z^QW#SD30pK5v;o@+z;TgM5PLRY$#PPOP)fZsjIKOi`XRy7$CgGwv9(i)Vtdt-Q=ct zQ!%YTOZ%SBz-!DrgY}u_VIk?R`Eb}kdSdMK^``McVAoXHby7dEN?9}7)WZjGUY|sS zNhVKBH_UY#G+}e!KzrX{Z+KFp&B=Ak>0sA0#HP}@jX6*4tY_}Rg9IVknWq^l51abJ z+c4#mhb*af=9S3bA`e#*VPJKcr0bp{q7allRZ~S={*YP?ZeG}PiASx4wJyM}3oqk@ z#h5v9E9B)WxjaohL!%FqzZ@p|(2DGWJ}gc#lwKY6uf8(y-4pMg_`oyj-!3$r22BVzCF`=)}HK9$l5=;yI&|<4@*N6p#p=PYOj{~cJ1Um8Svruss64o0j zqw}fOXwqS|*|boT&#ZLNOP&+4ROx^=owXX6YOVGgi&e2ali|0>Xdi~lX02ZG{ zXjyL6mu2cD?juqEBUkO;%ea;?>R&hJS%()AH*US@dHm`Zzva4+cd_Pj_?@F~AHA8o z=DO$ci1Tq;p6lg%f9ZMrV`TxF2Js|a&cxka&(K+m--GIpd(>YlyVuX|k@VF}D;Z){ zv8`tz_vg2o$#TQW{vXdLW}yWse^aEikRWQd=BgADRwAGcnJR67H&NK$XC8s>Q|h0V z546C?v>+4Ae7aISoR0iiYJRd-$ufC>$+EhP*60*U3UEnTbdVU%Kv{Tv@dcNuESIS) z*R;xVaam3


    o$qK0nM!;bDLnW8jQ~P!lRb3ELekoT`&1lF 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 AEdT%j literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/http.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/http.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d65ebb5913311b4c50fd154d88731504663c5efe GIT binary patch literal 116102 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 KT%04I#Qz_SFtUvR literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/integrations.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/integrations.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c690ed62929323cfade76d15ae37dbfb02315362 GIT binary patch literal 16226 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

    ?{OTS8Mq@SdJN#9A| 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Ν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 B;I9Ax literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/bin/libopus-0.x86.dll b/venv/lib/python3.12/site-packages/discord/bin/libopus-0.x86.dll new file mode 100644 index 0000000000000000000000000000000000000000..ee71317fa6291e8a015b57b5b42a968b49ceb7fd GIT binary patch literal 366080 zcmeFae|%K+o$o)%nZO7mCu+25O*K~B#SU#_liMX7s0lCuki-uu0e`~Cj)qEymZ+wZfMI{`imRxdT{k4#cLn_qd$E3+utw#?zeyNgFk90{>}r% z4@ZAcy!r>l3-4S}{QW<=|A8-Ge)+VS*`iCnR`e$gwGVer{{PCY4|Uzg^H*+ttm^}P zeYER4T-VQetZR+FKHBw!zCP6Thx+{^U5{~XsC}gKCa$e>9_{*-zCPR))mOXIy{^^I z%U6H*L8Z*R@nd*67V#|rftdsS!uV8k(gL5;1+c(=E7?{+IZVucP{;o&Xx zU)2?-LnnmRYOPQ0p|vVJ+vtkN3UkcXf=U%GFQ{BV zDC6k>PY3FQeP-*SM#F6FQ{h==hriP7=nV8|`D<=ZF1|4}PbRWy|CowCMal0AC8w1h zvb|T*#G&v1zd=t;OsFozvlJP%j2mJ_Qbp@HAFX(+gB%lNK$Hi z1`jGcAn)=ZwtlI?y-?WP89L0+_K&OZell619-*gjk}y&Kpb;8YVZU8eS-RJ%J7$GP z%fsX5=BI_!p^;aFCkNy6D|BMW zP@xl*eVsIbN`eO(|00oWxF!>w`=IbuCYsDdk2#0(ay;>Fno^*`BPvu>nM314g|JGn z$J})Ie`GRDtelWD->NQ_$+ampk;&Y<>TdPRx~}~f{xSc|j*xG+9_yXSnmiH0sqxFr z))BMg&DEU`BNv$_XUyhQb+OEW6mwCFcO?9^aSFo0mwyGyowPSmmRd~?sSb9Zn=^-mT z9tclZ;RzKk>VIIOyn3SP2E@sbL3zr*r93>m-eB$rKWfZXAI%T;H-4zek=g!{3j55C)9SVo=JXY+x@dmtjA1axDSEu`Y`pVh<6|p2m^j_^d1=4O zw=2Brz@q-MX2(8r=U(GTFgD(Ja_Gjf#1o~Rl!?jQ)qC&G&^=zwd+^QRa7Pdd7C(f+Ip@zcvcy9D66)UpKLJ0Uw-~=8-iCY?8V-h>M&Ii~6VgExj7y+5brLa7n$gUbN|ouIIu#-&*zvey)2~h*r>;BnMXNvmd|PM zAF9RB!ACuHZ6ZpV&v}YHp7nWcIjm1lsRLu@nLhTajL}n?Or4nlW9gM3IM6t)^r$>_ z-G1Ydc+BT9Hx1Fe1t)(gJv!?(?dzbGZt}@nxKqc?ops~QT~d1L+zjSN;#G2%N9HuF zN*rzaR`7VNMs=kIXN;Xj(9}4Op37w5qV173nYMvF5$FEN6z3K0RCHFn8@5JV7qYO& zlN(s1c_>nz3o|{~)3ih#kH==_m_NA^sTGgS_LvDDcWO`HxP{)ZE=Rp(?tDw=VpY#J zTkeB2!2$Cp|3cI36*=b4e*1}>zOyIa;dyL;)#IN^j}HBVl+*A$t7~r4e^q;)3UsO- zm_o`3`|Qdb+go85_^j$#4S_%^cx3%mw*T(scBK(nCc`rCpFEzSdZTN3#9o}yDFI2j zYq`AK@^jkOOUD=-ri<;rE!Y>kqOGR7x_azG($w3jq3eh80)6(%9OLakPjFy8%Fo>t zJ~YMlewGq5(OGUizy3Q2{r-&7L#m54VeGVSUue8x&dD#y`0ojH*^6@_Km}y$I}_;3 zL}%OH&qQ=Hp87{&oqRr5U8RS{POBaSlC&@XZ}}7+^Frv-(}6nY=0X)3PbAI6JfUj1 zSg(jGRMH{5ghJy=#0c?sS8W2aF! zHQ%&MAY&5A=q*gROmsLCJt4C$6CHH^5(`VdJcYy+;uJv~O`6ivCr^sF3Kc@3&9BKV zio!_X9VE{6_Iec6+Vi$|TA*)IO)=}Oh1Z{7-RUYVJS{pO|F@iI@5v2(D^>JDe+b4j zIe9-xZo|H->lj5L_@+C1o4yRI#MhO1qBp7P!qUCz(1=hraj5Bf){lDSy|aF70CnTe z%HY1nk)dg1A`3ZWY%c9tDvut8M&sRu$U0T$i{F~xG&}x8aemY9t;want1{6MY1TKP zE9y|Z+dpK=^UY9#W)6vN_DC5iW5?5>ajD?i(_?SmIO6m?>ypYVbh`dz7pjTYEotyY z9xBcBzbCvi$x0QPh2EkRvvu56Pdd`(PE4@>3kr(aG2%*^v=#Mj@9^JStrBaoUxmk4St|>yh|gM_KdGka^{w!~Ji8??zx1E2(8LOuss>xguV_n`f%f4z zvmP*zb_E_a3MW|6;f8OkXue&vV-Cwp;A0VRYwW27K~ zYbABWF1uCh3sSamRQ0McxBPmQYu}b@^w(RJn!EoU2|`{XB$WoybHTcr)TOHPEwezx}{5S?|LWrN3~lyWj9!qQYwW`1u6F6rr!p%xY_B9mQ5` zoVjdmpY)t+k)jUBqNx^N72zVO=QSnrKpW5=Ph z?XA5QX;1_Me`I!`sf1B7{IVWLQ7n9R(c;A3CKHZ7f9mJdu444+N5Sd|(|!r6-W)3s zeF6Q-?6?!j6fQP9rs^hzXa4xd`J24?s5%?N)6LeoUpHUxOT9P6>^NxbYd#~~-!xU5 zk3-irpAoY$HuV*`44L)j>*4A3sduN;8wau4;Lr|nn55233!I5(u5bEIX{K~9)-264 zJFY^~_r<$%)xrL=XoS`^@jc#PXlCOtnf^3wemtE^hpkwVw0TpFtl44I-qAoRHJFQn zl)na(Yh%P|T&G7Mt8O*FmqDhd-t%HQuHL7OX0Z&!YBqQ7OP%CitY#V^kMc?z&aHbB z8Poc;(cY7{lkbALvY+wBoQMzm`_5X`eg<4~_>Y8> z;elFp95%Q8Ygxfu{zDAbDEMl^F4{#Vk4l*xe_(dx+y1WxK3=_7WbcI;S#O!fxzz_g zmFB~={{BQxG%dp%9;bFyH%h(2x2fFtP!6gE)me3;(LcTS?p2rYrnH*&*3%yt1$)A5 zJ)-9>jk?l)cBZtaKImW6m{$?(Z2Yx~76$h;U5ml+nAveeh4W$Fhm5}9+p%f)sy(aj zuIn;8jt2L{uGX*adh9&r!$ao-WN6A&dl(@xW`sVpv$_!DWig6Hfw8Yvm2Ff7TU2N8 zO$`4%I3>*1;}AWOT<#4Xms zAE+4p!)xQ)4*kTE8`tuKxn@_eR^BxgRTM_v*>Civ&d#W}B3gV5X1jTTA@uzJw0u-i zzv$#$wXS^h;a1Y}vAf|9?YXX4JZf$hen8i$8)fuVe|9{Oj;EWxj0Ee;%12W=81)%F z74^!02PM~A(~SP$9%hm-!zeOL*dXoILJUqDjlMc`H}dhD47)w|YY0f>ni%pUA`d7% zpylKFN%@$Ae5|(+k@0`eiDJ`^%SRW)Qlug@#Aa5Z38T|4TfkM-`HfEHjkB6uh6G~~a)xsI2e;2B z_X*bCdTUC2Pj0Y!u^JE|TlP+cmb$8WPyc(OHCo$xcoUtLPRLct zxBb^z_BtM9fmBBjGrcp=Rc=em&21^$ z9~NyKW^w-J9yl+&RK3&xzB;VBtZn0D2_&Qx+dJP%Ji|@mbi;ypdmDG2hOaAKqS@gI zr27YlzU20U!k8jvO9`Xp_D51KzB_pXFG`d4T#rgSB~)oWci1iXvTVUoQzc~BZ0|}d zA@9gIRoa%eo_m2u=j`3?!;A9pui1wNc^J$-td)m;c}Q&FR%z;4iJ5YrknzMOw-QBi z6PjZs@^$)4{IwE3eJ{go?efU|uC4O-xb>VSAA+vLN)+f!de{@QP0P)(*eC+2!!p z_O7)OBiyJ&i~MEPxK1>N)4g4UEfPV67FzaPl7e~? zG~@+RR%oG$RRqph?Y*SicQPl6bp~ng`fsanB=AQ3jM0?08|A|z3yM46{7)Gvbuc(C z`W&j$t#~s0lh290>t;>fyYHI(>4cOo`G&6Ht1B)2JjAq+bfI#VhoD8n9JQ^2RP0OL zf&TY`oiTrKhfvN;Jf-s{<*O)+rw1uI#o8e^Zl37l?p#u93sqvBeAIDQ3G14-M4b&l zsjVdS{|YKqdGRRd$Q*&k*-~y`Oq~gg8>ee*?;l4n8zauctF^Qj8PHIq>}SZt z%f};13k_L)BW@0*g^%ssAw9D6TjkGjn`7C9d>35lZ@eYmF2e_pk8@GmWYFAkwe)?% z6e}TVxF@$A<~lS*>8si${1iMMy;5n(Gd6H-^2W~WRMYH=`P=f25GYn+M6Zaq_mDql zJx(Xn5`m?(s1s4KZGbnBWKsVh3kH54P3b_Vxjl8;jmRRQre$~Y*Dkw)4_tlvu0`h; zGa7HMA62^~htm9dhm|-c54wn|;3+KFZBLT`A3xmxp6#D%*iu^%N9fYVca+Xtno&C* zl#hB*GpzPOZjEjC%SSIytGLXTXY=KyS7nU;>1SB*PpTa<)m#D$U9Q^i;^|KJI~f&K zJ;!Q4L0Us~@NF~kZ$biB*r|j}9Hm>34wXq?8|L8}_=pwsKdE*ZN|yx!cwzmYv6sUr z^UoW2YU-^eTJLcv-2FaV)-D+vk(5{aq?+wK;q2Q;NQt`b4P3MQ=dM<}l2S(nx~wX@ z#T6N9ZZj5KyHG7S#uPf}I-X7{Tlcav!c8Y9MdaBTe)WlO#aBPGgW+?k(mkfh)XYMXx#HZXK$S!FRQ>S|A@@1J_!ef2ok<6|MZmfj#z)pDho7p9z zD&lN~BJu9oRze0SxI=h2D%$U5O0P`FFQqxHHlr)4)Ri!|benXRu_Kx2(rfqL*y9$Q ztu&*>uUl_M4@$(DCDga2B5G8j6vCF{@=~hP)*IN@=mX8|jU!BW<_u z$J=%4xojugRU{!qu-otB&1Jd=yCt6DGW)6L>@rV{+t19d7s%)=!Xcov7_Ol|FG^CG zBxx~&f5%-zgt}Quse1`A&0M{8v+Hy|A;DSj=Cy!33I=zkS5^=DQQj z<&I3BOKGC2ZgDtr+_~)b+}ycK25ftly}Y`B3@+A%e1W-Q?$rFQG(9gJH04c5UB-F0 zb|aJNbze&y%q?{CBk6@(TlOOYP{vrM7gg78f0_|8cWRE;1B$L{>~RNJhIA?4+Swr$ zPPN--@_`=APYz=PFP#nFHDq9gG?`s%CFKXCxB?*FT_RIP7~LJihHDHh$!j3~7RfuG zy!cL-I#dxzoZzq8CcI^AllzF3SV%U;2><%>h_!8kMCWp;p#6Dyu}kvmPMms9x6s}t z{Aahzv^w>iYS$eoyOkCS)4Ai}?Ej8#^NXY?-SQe|H%amCnUibhM$Ne|Ne0${|AXZ* z!l$2F9JEb zS1kUHDd6%y4*sRTh4*W-voqoxz|g2wdZi&vh~x?+HOZ;J$=;K!rdc`5ivQnnG{Pdw z&YF|UH3yrU{z8wT%vO7su)NDMS!Qv&WbYEzc14uSGoN5{Vel-=JcW41?HyRqhxnY zyTmN=TRA5Q&SA8a@F4X}a+SM20zjD_NV)emaE(hi%3q04-K(^OpRQ#TJv&S(t|Y}@ zzx2Yg(@V0;Ef=_Jtyiycs^_GKcmKC))hpresCrVSe~n(sTGw;(M-rY$Y!Wi~?B@z$ z0WrF@=l1?PkS(78AGr2+e0Vml5(%~!Dx7I2uzb$vWJ46S>hVHzE7o&9dMGY}6d{_J zqXw+H!|^jY(a&e1Gc(bGHAH0m;t_crYm}I1*3K7CxA|81FCLH!vvFfWQh=krk zaA(HpuAHbhky)2Vg-zG17%{QSBFk%?sjIZ;v|Ih zsc~=oJ=1)7V-N0n^W`7Pg%48i=1%YF>!f0wM*v1DrH1e^yw^_)q3RCPv@pTkQBlA8 z-?yTL(wk)}98x0A?raK`AIOA81a4%Up5EJcj&CdQ zUlCHEsD?JFI$9{CslYP;bj7MZruzHO>aszj3|iHP0ir;!+FwZ@4+|PaS3{&|P~JqG zdAxCxGtp6^m6>R9q=peAm_|U&=ll;?RuRdYi6bz+&Wj2wktwP3TFMX)8}+KL<^AY( zQNJ@|SQi(Mjd+@VU;7LD&KpN-R9YP%oagU%rjI*spVS?We}5z=`Ys)y8!~RVJDcX> zzI#>V{E#o}?%RT=+kClW0Gh9$jvD7_zJ?q1aE({?b@3r2KcY!K6H&j8_g0S@8%OG{73*BAR5Z&{O59`!W<$0|wvn_08m z8MS35_=l!1caB(c>r*4~MaARdT+@Eb_xzydIH9SbxI#yG<@7uf{YFjSqpn@;N_3 ziGie$iI}LWMh4B!LbGP^Sus+E%kY|9IK9^StN<9o6E2`5O}^>#b|_%PQ*go2@>T65|PPc5ZzRfVm~P^(s{#sKOOJpOiatPhO+zDhz}M z1@ll{hz#iLJ7a|lf_+$vDWuF)nO6lvmw{TyQ~Rvy0%#uS6Phn7hH_Agi1W8I(Guu! z35B%GE?&M&W^Ao zFXmz^zMNye?DfTy{$Q`UxsVi@Bb!ZbXz88I-M%3!R&0B}#X!hnd8NRfdgAZq7|H2C zJZ6!@j%qJ9FqSo*+GQBfaI_sNhybGaR%E$Mz#8W--j=Qp${Yk?3Y4v>{Ac1rYxwFs znO05aZe%#&_)N_6i0Pz7vKTS1Cb)z)ERY z$y>Qd&EQJ{!JY#O!N+t09Oi~9B zHt_jmc%Jp5I1`2MCTe8}Yn(q7&EyUkZDt@mY7hV!7CyMbT`6Vx5k35Rx6l#vd>@65*EsW}&~PDz_MPb;oE{p^svd437YYasU)n4j7L(uq4}oc3 z_}&T?((6EI)Sx-zpJ39oV-U>#-|FbkD3b$mKgF#cuwcLR^86DLTy?wIj_`$dyIX2ol~K|TeqJQSR}q1KkI9}68-F~5f{jr z&t8)09|W)U4UeiSYPc!$=?IuN!<_F4VEy7R^~LlylT5t?OMuXWC>)Y|C1t4fpEl@nR$M}IBRV&>tY=~-Pv zqR@JQ3cmdF#B_eu$IkXs|RLRuar_QO~>^Ir`#2_^umQQZ-Y!LX{waNG( zb7G?2SUByxMsEsIpes>UPzq+&sQELA+09lD7ZUFS z!R7nye4xjQPB0|1<7a&9eHVHeorNh>eGGtYcmP3A>&7ceGoU&W zL~l=Pf=y7+I#6!}d;unhW|tlXP-=Ut)W>c>(d=kkmm2^u9Ge}__{`1!Ro9(n;S!X! z;A=yJsA!8p|FAl4m+;~|51K?QXTdz#5)#XqKW_uy#B!=C5mtT32`hR6s5ZE4+^KQL z8yso6-1dI1^iXOrZ)_|FeL7S^gUVh+QX0u1sDVNA=}sfLq;&6%ZwAx0_geF5+}j6? zzS6zHH1~F8=Egk$&yCKUD3cDwWdbw_v|B_^gXhdmpJfJs%mC32Il!${8UVwEB*6pb zreOq7JXY+vw_yblR}>-^VPEN?z)BW)Ks)Bn<71~-xe+Y+Mjx07bc-V8i=WAj=EXa` zLsJubqelEgZ~W{vO}@0=1T%#9BYyTuv2j@}hoxh_v8aQRYvh2V%*p$6=wbUSSV%!N z2{t@8ekKx|zN$^4GnzwDxZr0=f`o2TX|nmu1`=19PrF>44Z^bi$%;G-*t+y|=}{Iy zIJ@af2psiR;2_8ik;W6+BfbQ{!@_)E0gUus9MeZ6VE!H-AglAi8i%E~>^|FD z0{@d?*a(gEqjWAhFRS8EPV||{bp$j?5^3kFb$*F0k9m=OksV99FrM|WSbX^YntBy2 zu18GWT%R}{oeB6IsSw;}wls*%Cpg~R$g<_m6V9z-EjE3PjO z6-BQOo{L^VgUUlQqnDK)D&2c>I??F?ywD%g)j6UL%ZVOdFi z&D>etCZZNempaRajZTJ5gkIavW2k7baiyPR?+kr%ZJb)x+Re3}l;= zeLf)%PJCC?F@L`KWN^~eAS&3I`dmIacwGrS+bAOXf!AZ1}z74B8|X~SDS&!uIXrlo(LOUgF6 zSX0^677}vmIs6RN0tKpjGXP=Z-#>;OHDD%IA&#@8Kt73~Rhq0-O+Mg7cd)LB_X4?2 zri}3hmWH~ckZ64+RIThLe*bJO}ZAD~2M0o1D+75I3sqgjr=$p6U8#pj-YABjl zaXpsTjCq4!W>eXXZDM)x9Z?0j$ogB?H7{95mMiCNc$Ev9F)v^dc`u9cr-~PO-8@`G zhD-5JfdBlUMWDwD0TBWsn9Ds5sg*u!M}%9o(#x(nDxy4V#w*ssbHtY~dp zDUW6C)akKyEaU-oZikeKC%1hmR~Gk#UoxSIcN%Y6E%pf*oE=gvwrDk#L0w|wpi1c6 zZve=UuXF>j$?US_sSmvIzifPjsl(XBP%gmQYyjh+|Nz? zT%Kt^O)KH^#8$55m2=F5l7yqtlFUOh?S!-g=VkIUOoASeKJvLH2TNW$F_TBZ=~|0R zhOT0tm1Ro?H@&`IY~Rb~$rk3=H0fa(?}ny#NP^Wa4=N$VfJDyPKQKIPB~)xZCp~oT z~x@y=J<+H&y#^!^+1fHFCxJaO zvI()tlo;_+hOooXWm#(i|F=7euNTT9Z%cdAiN$2mY>*IGm%Zf~)^m2SxcH-7d%0IP z9up)rjz7x9iT|p6mkghoC=~goiJw_J)1}>m(!Di>cqtMOl7|?HP{-+m_R5wN*_Dyf zCKWpwjUG!UX6t*YU2=e1Z3WAgG*~>{l?AzkmL5Pbu`-CW7PDlN&bug{DQrrsgphGf zp_9 z;HLat45g&G%hnXuvOy^|=rww=2L`8F+hi`RSYAWyI)Ae_Khq1t;YD)_LWW1X#!>#e zXIeYvNRj7IKTcci_j6xv3-304C0p?hVIsGG-rMVgy#R}Q>w_b>5=O*M0xIJcV0P?b z?{LSyU=KNZ5_=~R$EoexOZVE|&@ja$lIy-D6=kcKeQ6b2%+~+Y@@>B^J>EWxIy_Bx zDSgu>HjdH^!^WY4AGsW#w#%wq{=jo;KZ?IJiOGTQinh;(`pN$B99MWSc*lqqX*tm3E^qAtC+ub*;-e~CRWOm_eocfDJ^~jZsOc0m7b@~X<^0w zQF<~5dmF!?dIAhKVFBjxI5H|QVs=Pq^kUs+$Bg-;fvgq3quXEo*UJ{t=65|K64X;u zS#I@&WwtVDQ1hnc=qVomd#N-hy2FteAp~G{gPU5dNuu6lXPf^?mGd7c39Q!w&W^tA60r-$ zD|qrZ<z8f^bVPRBV(L|BsJXEE=VgpUEV(T>KnvzRS(-fc^OFXNY^%4= z$>gtOD`8~*a_8%tg*l#u@U8$xPH-#%fgL^SqR($2yQ@Fr!|%OhsNLC0>6gT-^ipiE z=hy=OO8pT#Ef%QS3EAt6@}!LcghjrXNr1HVe8&t1#qR1_)}o1^UXB}IBIYgK(#t|{ zn=oT+p-W=*aX_ys?6p?5@G^TOis@6?KdKq_qind>74)*X9xWO`w=OzjRZWPw$o$Y_ zxl2A&JC@4ld*pLVr(_>-@<;GY z5{!$b*|S`)GUnzNAe7ps*Tg$BcG0Wxt_fFC0Zy`HJ7i{y*>Q^snjJ;+l`R!3fAeHx z73#idpYZ&fhTC-XQPXBS@HT0wUJ$xm!4)6!x&@N~y;V2DnpUB79r#V+CsA;8_jGIA zR=O<+x^3O`h}5o^URRz~x{JBH8oR2Ex#_^TWO6xQmb(h8vh3s=BBAu+P4HVCwAy6` zsk{Bw4jH20ImFHz!Bi92b9o+`7CaZ5VztY?(y~A=WX@GzLEhLAQrUa5O$3&)*V50x zy`K|W+5Q?3N%GmQ3jVtM7o7?& zpJjHb0k+NQep|bQd958HQHRW-sgoLr?y9v-`c1j5?c3Mx&Qagl#_S}S?yso~rX_siXXa#=~S>~Ky0F&r1s}M`UQz+ZI zJe80SGml8D?U8)qw=y|1dcCp}qMT=T$xvpruFVVSTxOR{Oy?XpMwJj|j(3+;SPRPR z=LYydJVhD>vT8O}UPOUt`{M)ybkY969P`!GruE?Q!lQy}fnPm>`{G1eD||X}QK72! zsymqljnt(U;0ME}UnqWt1vrM}AdFtjE35ix?JV75|Im+yj3mSzl1?=6jT8fzL|YJX zy8u&h5L?u$eo3P3p=XVhc!^)bC{G+(_gVGWOxIt$r++XQ+R~6O5%}P~rhmsU|H-#G zpF(3n`rm7g<)1@4wYGha8q6mb@kX{Du@9d+wP@z+G8D{E7NHd@Ro#nN*XY!8mc`SP zG*)r*~?6uP4DnC2k0cq=pupfAJ%U=n!vO1rQ1Lo#G z<-RmozMzcFC-GR3$67Ea`nl!HY^@JOoR&3+bA8XiV=)s3%ZY-+=>;^ix9LU|8&pT^ zf;-W_rg3P@qWa)R#99upL39x+Y(=oE@dF)p1q5MW<%G7YWku?t0y)Yi_IzOE4iLri zpvKZ6@%nlyj6GIm!O$%rJEAwOF_$@`Xv~zLgXkOh7;uXFK{n@9KIA)yH|j};2*CrW z3NdHol9Y>?K;2?HcRo(^pR{nhCTE%RS6UAT>e2Avnkhv89Gh;c5xdHZ+p@?xD3u;~ z1qBIrMG^arjm|Yj4IT|=7jMk=I~eyDP|t|wu$Mm_yJ}7DgGDR6`87@++J`1o5|>oP z>ZAuQXBD@?o9KkuUMZcY+ws`Ar|I|XDkGR)fBhO`nRB_@O}w|bDLBF4Le8N)%;4(7 zs#D|V6T&U7Ja<37Tt4poL#b46tR~n35Sdz<@WRWLfzxSyR^xY=k_OosXQDHA6%h-=&5{NrW^=*`!gKjd%2O>@h;`vY`)$Sky0%0W|=7eYPR25q!tyZ=<|V8 zJZYpuFG!bzd)8mIChx&QhO^fBnx-s#{{qBwoZm+zbwgZyR}dNsJI>*MWr_)5^PRoC zwjO9pePGlQy<+X-SdQnNQx9+r9b*a54Yk5sX{%|AC{xvKxS?$C5B2#%&mf8u>lj~G zerR#UO0yWd(7PCSe4rPX=m}0wDB;ui*%ArI+TQ=p1LbcFrW(z3XyfEN!>Zm0IE<68X*H>+m8iI3kW4A0@;rx`gtxzM*om@579!s2t91T|oq8sB$pAp-rcjD0v zwl$L4GYy&cq@*yN;)DP43A{D*5N3HZZG~Gbb|!R66=8; z=v%O6>Vtkw-#6Wg)xc2Rt9epPG(Yvhlv;~}OJ2PnGP~=q7L{?Cn(Png*-~jyXZO?GAvhL1P59z<{|+0OQBV_1Ibm0wEH?&*x-41h!sG z1k3RZoRo>SaW`7y+{^5dVb{Y$Nj=Oh_sxI*nN<9Ay!$~Fd$IJiM!@WsRn;!ii|Ivu zW795K!~smmdioD@X6o(`(F~r_>%NeiN@^`}MYcxXDO54@pWlJO^$g znrHjhX;Y()eT+q!M~dwgvoeo>bl3{gC9_LL7s*a%1Ds)#(aJefuw`-`evtQ>=nL)= zt>H0ravAiXv*7NWH6G{6v@FT@#ACyrN3W2Xmin%qX_j6L&GuRmFDkr!e&9~Qa*Y`K zz?#b1>e2=BNI}l@=jE%J@piq0Hk8oF%p;(@j%A|HW}+`aK{w}qN~5_n1ER}^SN@aK zKSxz>Ah`Y+EI3Zt8B_=QPPTcrc($DS`Bi)CPyL+IZ0+n>uJsN+Kb(oaC`Ij(bxyZo zkZ$P`w|J!~WlVl>X>=iIKy~o~fFB#0 zt?+ANGY<}Zk^CSOUQ)3E*WYsm2%far%Fgv(;5wadb}^V?o@WKVGh)SF;|MkFZno+O zuXW2JjuuVGJguTH1^NOXz3SN_WE$O4nqj+lz15ft#$YA?@0p?zl8%bKrs|R^)GdWp z_m)?W#9*C4)%D2&dIRB+$s+P6izxYxB6{tz%Z%gpTu@QZ#+@7*=r+tu$e{#sFk93g725LD*c16f-(W@{1Zr0}Ee^S&#ZnVG%*ASIFI4hXD&aeD zSNc;U-jlJP%jc^Ls`OPiAV4mv(mD!@KE1~CV3JV4gAxF6Uf3ve#IF|Pu=h2mTpgGI zgtyuDCRWn4PXz?{UL#M@_%A7?K3mE_Jd!dt*U&{P3|2VShbiY+`9@2=`#>62}etOBR=fAXk654 z_looD>ml8Q3ru}bT<6RipL0EWCTVtPJo4c8SpFU?VGQgid%0!e-GIW`Cij9>WSjm2 zqxZTdjgrE$;%64y&$ba-$~8+`Upzc(w~G zN0Xb7?c1|3QjTfF+lhuemS=X+rC23}N><&V1Xx2eIfu+loFawLV2+tM&dW@+3{az} zX&QlBKnDTA{o)naT_0hHtdLdhc5mM}#$a;<^T{#s86fs#i7+?cLr+y~*shs_9TWqI zq0cYKMCT}jvQ8K&gnH)DG9=&Va_85LWEPNMvF!T~je2eGHk#uxdiXy6{qY<=kK%c= zVk3&)0A9}e|E0VIUcjrDwC03hN6?9d+R zo$b9BXfrO{Eo37Y9`6<))faA#j;c2mfBe@F!cg-k`p)!?6Kq(bonR*=Y7UqOC>gE` zVRo@5N9@`;w46>;@CjwmU;6!6Sp)#-KRt1ggyWpna-q9?BR!@xx6@tpP)@1zUJD#l z4kQR6C&!IsIyA}~l*Vqcc&qnoebZ$Ftp^ArEU#Tw)-%BpeKfSFa9dd*+j5D z6>;w)D2}`YXSmL*O03u@uoNpg!e)}qNs1u^A2=e1r5<1^TXmq?PT1ZVs-RF68r35p zBV%=SG=R1tXQOOU1z*L1%z2cZR?S3~0=TK!)F6)JgW4gxSiEUW zEwCWq1sz7lWBE>s$6b$A3r7ifN;86z`n3!P<<}K#H`pn0nD}GCD^mCc+8(}i01jU= z0K@+gkp(~BvCoiG1)wQwx?G0xHK74>KyEoWSFloxXga5n7^i}<{Kg*+-Cuf|KChxp zcG0cC_&`q#tAc;}M3aUuZ4w|D%@h8`|51DDtd9@rVX$fKrA##??jzX&6Cz7jBFy7MV-|2xrK@^G;!YX9Sc6wpUAh1}L zI$&_{5q9XGp=Mpm!BYw^kpdSr0M=vnJJifOfD&Q;MCQAxw;1JxMi7GIQ_Lq*q-AC% zBH#0Hmad#8)$$Wk0BNX7?^9!s=UY=slb|}pD_P4@rKab(O4I_MTIR!f$eA^B#c%0 zK>6ye+Vhpl&>4e(iu{cq+?!r7hlb(QyPM{)vWdq}yBpY2pep8CIfC`brtjB0AnCI% zq_YRWeDc3#Us#KaCHuV3{64^viiR8K9TWm3UXs^t(bk0`inB#j3oJScWmc)m*%sTs z)0MNygbJDG3VoIMzUAQSIqx%{%idW4DFok5r!*X^`HZCL~%{+JkMD`9aCQw^ubW! zybX*-tRT-bMMAgJ;z^0Jo2?+WCUCd1w){1N6@OsvRF0($7hzrHyZJqre04op6skFt$9@|?P;d}%h=4Q8-XL@CWKsq-yekIIfpn~T&?j}sTTiTHt z6zQ@3snX6srv{y@M=tdM(Cc84z(bh=O=gAWl*dY%>eYb8JF~$7%$GD_9ZgvGzt;q} z^6gJ4#6(x=zQ8`rMQS>Nd0W!>b6HX9=1?ni+y1(=>yr%{;heX&&wBG&1ovVqJCA)q z+Sb#dlREa)tB;5yTj4qNedhz?wa!Xj;{pUv(8T%OdxqF06w*ohIH@n42bM!5R>JF4 zH~Glv-=6#Ag*i{6RN!jmqN-;}44(sFIpD7jwD`1ms=_@1kaN5cE~TgMaeMy`b?sj8Z(!p}hI8&=*gjx`2a5E706Q9PU|UmsJ9q5M_?|y5I!>ChzQFRb!`> zAT^Lz2FJI}K^LSr1mscbL6+T#vKV};5p3u9&{uG_1vD?n#tPO5kh?qg7@Yz+xBq8 z>j1A*CfZEhb~mU3p4QwHyAFUD8|GRXxKT|-oUphvmamo|?p$hpXdvLs92w$|SH>e6WM4<41c(+>R19eT6q|O_1yt0uJ#SoJQXKV$nNM#5~i{ELefp2u)w0Z#JbqGI~Wm#}THkgcv@Blm${0Y1d8h1j%L;5mk=aA*dJ(+I3^%hseq zsk}3=$I{*|rp+r`^eXPKU-`qY+TIQLm&Mn>9#4&v1njDzd30K7Xw&L(`Jg`&IBRLw zrnJr`C_)mq^~=k*#b38j(Y zQ9^ClcB1u#x2Ot<{_(s;ge zj0BVu4jw&i`&X)vfP2S*wuD*Gd?-)&)dtaXKF1GIJX9Y%LoH|O*;t&bkdK2^!I8!f z%#Jt4Fs9OO|Cu@*ZEyWZ>f*HPT*CcH^!%;N(!(5Ewvb_nexHF@V`7f?MWhLS82$co z9q4Wfs_vO|XpnoDk#O1m$@Tq?BK1{aY6OXf9TH?Q zTPyPG<9~c5SsqPWW*Y9UV$SpTMXm?^5dg;Uy}s9?)>{H(E_o#l8E(49b5 zHGM%`649c#Mg)1HSH+(w@I)_?TygC33KEVV(O)-A z8Jh7g1OGC>c_S2nY+>XEG)}$EU0>LGg@bCC%MC~eoXx>d_xfuHV4SaOobvRxm*I`{F(y}Z5`x}u;`=%oowR$ zCHdFjZhD>*0SS0-cMeNJ?t>c%*JXA|^r*(Uf%ybY);Awuz)xR&f@Y)1UmHoBGDkjK7I2_oC!7nU&u1N?78PQFN-rq-D@hhiToln^*0 z0LOlU2x7>>YS|#V#E%I+1jF6yugHeRLmONq`p^~WP!F|nu8J)5Ez;tIW+ros3c z@~S4_B`Y@IT&a^v$V<4*@$wYc@gHKjn;QJ_^S;KZdP_bH=Ok{HV>#~Pc?2n;xi>GP zI2|-)Gt6MaBbi5u)IObg6c-wiB>FX8t2bwkIE|mhdVF-TPRFmeg?Jafvk~W|zm!Fx zf}8{t+jQKDcO%ZyW~fp94DM?=C$#CaoNStUcUpblnXLS%&+#vi(}2gM$~wHEMSQO- zB!ZRMC4(WwRvHF_@Q0|7N1fs{x);EQw(QC}s(hC{UhO+M{hx2zkAytk>Dd1N}P5YVBEfPWklA*}~ zBsRWT4%coSq1~^@8EpZM`UV3`zohj7(x3K<;FkF1FHUO7f>JP>f5NO{)*E~3ttaK< zc8K}EOlYMg~pz#b#cjekBVkad?t zB=c^>c~xQ>(X2o|4a*W_KA08B*!Rfe`4ymK##o}#8f*6pNT|?kA1Xj}aP&wWKj4-I z(ZYGu(QYtCtg=1JoU$tE0X{w6qom=}6#G8uG#VluGtmtguGEkGY!g_@h_m8Zm~jtc z8aGm4Pq{W@8n4v~(bbwK3v(O&>ahx-PDAGV?4Ba$C%Lp?)QTQXWE#HJ=0U%BYE0`6 za7uhUf{%tI`5_iyGFv7Q9*$Pr2IQEi9!;6mUxeT>Rvir ze!){6)IaPH8_kLzcQ!b$=g^_hOBhtqP3X`3fE1f3@g)E5K8|J2{R4vPC=AnxC z$%tKfS0wWg$ECF}#t;~t=9r*Yq8o)DnKQ$}jxRk9(Si0I;_OU~TKuM0 zLmX4@gDLFMfI{at0EJzb015-Bc`sOX&qL%o!KHwPhn4rAO4C?(*ml334@b3Qnca!M!XLm7cK9|m_eIvD>A1@Gb8IU+pY?NYJ>$46b)a7wTV93{>OjZvQYyJTYjt&hF6RBOq99E*-8bf`h-kTet}KGxNq>I zR5NAh>kixAb%Hb0=R+~f+1gWH{9SJx%>Be&bbHf;zV!CYZK=!>$H`_44$07^E0_x za=>#fwOZ1Z{Ig8e?pFnpNS~~_-Yi7co~xZHXhzP`c~TN;7x?HCD#e(vPMP*D5#iNI zyX?m*+!EMlA&>OlfGw^jk=_34twcT5_{8zwflnNC@ri>aG(oV7;1dT0_4WqqDyLAy zx^V_D5Z)0L-2hP67I25sJ0yYyC9#nDT4^$Pd>Lm#(4itHQ=vQJ{B*9gZa-uS@>?t@ z1sh_YlelxzmlN(b`Zy`PdjA3qVML*MF>zGY^_nf+G~sq=Ag3VNtvtLc)F_Dh;Xbo68|7%j5#R5Eequ~H1hi8v^=fB zr6hQ8O~?gD%wbjdOO?6>bIF+1jd zi(fihfc#2}uU|X!4PCZ)7e&=Xr0pRX03z)|1}Q^tvj;+*1V1(?yrwtn5+D%2g2Q5n zV`!T+1Eo(KBQE@^dPLhGm^<57k9&8?T9R^qB+I@%M>Lahe7E%~@;Nk35HaU+)DCF_ zhvDPY%cGn1;y6Dfha6l8s`DEscvgu6n|8rsz4b>zoU-Th;#MdQVCmFHdCry|MSX4k z;qT;+{k=H*GA}!nn>ssX&DE;&!KF-HeH`|K#WIPV-~S64sbTRb6sRtK^i7a+)uXt< zr*RJ2X8CleAb14C{2SS)DN3h`ie3F|pc*ICpfucGR6-Me!j4bPpzCiJu@DWR-`GDo zL1Jc?Zj9bp0UC2H4TGuH!Bnql8;rG*br=mz^H>GIMG%$}rym%)qBNhzCWn&Znuh0O9$ zp-dHG`l}IfsBYEEU?12NIP_!-AH{dS#^3u@f9wjk$FJPSbN^YR zf9Q%P(@kpIB1z!1mEL$^H+x1nVtRE_{Kfp(tkK){i`k-8_cY}(3lqz^Cj`- z)v5b1zb_mWcwn(Av@dl9S3_t=K?d@|Q|Q75Bhj*Ra!3_359NeN)^~ zI7sxv9;O(xR*eGtv+s?EUNJ_iV8gg5YYLP)452s@m#fETvP+9`Ze1d(dIJd zXSFZhxis_G!pvifGi-m?#1|bfaE=yZdbm~ip>FMRR~Wk+fmu~2y=R>z zRd!8|Gkd$pKz^UD;WNbcni_J~A<7A=Lw_ZmYXF zkQxM4SB?8-yn=0uleM6KJ)QNJtGbO1{JicnI8Lr)=|1;KWPLpLVy?(wVnvk?*1KC; zIc(v3N{1M&%C-Egc5FOH!_2Salwcz-Yw`DZqQB?v=msZxJp_^{qjSP*c;uO!N4UjU zANs1=QOGO84zrXk0m;d2@V^}~u6IoCkixJI62)ANF01`Mt~vrMhLiXw#X;T#_-P~1 zZ@t}6L&pPpM|MEBWfK4W8xV3`n5x_EZebjO9N(WqYFUS1zuWKAUrx*+;70i zf1|iX#&LqMpKP**`!AyHB0Qp3$J@nO?csR3kS|@)!0f~8!+oZrLCgq_y;ci~tjeX% z!aoq^^v0hM)VK>FXRMHKAYbg~dQnC%VD*YlA-uA1W5GLq0;&Dlw_GOY*p><)q>J;! z(S&assB2=B+CK&NmhVvr_({o6l=5h{lyOm}pKRkhW~4x){)Su8I{#9V?)0fem(+m* zsjJYC?}d1Qt#ABK*4_s`s`}3R&E!mAfRQums8Q3JEwl|Cx{FP=f)m>$Fi8*w0wD=o z8|d9zvPSD&R7S970yt7VJse7J+iluw+r9T`w|$=VdGOh)gjP)^$&(C!3JJ+#kW`~) z>%nAgfGn9{nmq6C@63dt?cKev=lXhKX3m`RJHJ2Q-}m?Z`}rDM+{PA9DyF-uG?%AH zf+W}*Ma%C5c6XI7<5bKrO3S-S3*^&GXtMAYF=8rv1Tz~|G zzt$|9o`7&-ftV(V1#h0<;Xe`;&UoQHU`FCl+A}>(O}$szs*xP6br+yBH?dPoP}fmxj;Sx&`S1AydUmQ2Y?<8;|8y*Tr^$ zUk8|PKC!KM@3FNcBVQ(rK2jqgfsqa3%Jb<5#J-FXNx?Vafgx%*M@r*OihXjf79}p` zs`t@rxc?55-k}TPc??$h8U}dNRwF-!B}zIrzJ4;Gp-!9wJNzWsrhqCd=7@D98y?HJ zKH~tsi8DsfrJPrqL;^Yf#^VwggTFCJ0}M=VQiVX3frXjcLL`Gf}{LmPGOpe`1L~{ z5PJu>9;v{V{}m<*hwczeY$MVwDOVaQ1HY4hSokE!dDD?Rt9W@OarKCr1=WP9zqf(8 zrAR8F?^Tm3ZrhSZc#oEpxb4UZWxMp6krB(Q+Aq>BNU)%Egj(M@4gaSEj1j{cQ3$({ zPpQesO<^YiRp|YWU@nxV1I)eO5xW-w=8JL5?bvR1b%k=|jYMEz$sjt?1FIw~IV5;A zOzTbNYbHe%!Gb(#lut@l58i2_z))QRU91oBW_J?^FENS-VC7hS)G6sH#WYM~*6 zpra}e?NNQb;lBwVN^_r7eL>-FWZUJ`2wK!GMTgNz43(6tC(LXouaZQD+)QYej5ZJT z)!Tz_5Cs6rq7;A92;zX*fh_7X0avG@Irr`O!r3C7MXJ{lykN= z=eJqQ#ozi?e>lgkd>^h@<)O9~kkpyKMXkuqj69%T^9Er^W@IT)%$t!|>jKoSJO)uB z!V6pzR&(XHKyD?=nO@Q7?ir2o5Q-!ekX9r^m}kXTZ=c0Wlm$XsdMh)mt5v^*pY1XbnR$9vI^DM7wURGrSsNr&nE{nZQe!_fh$|}f= zPi0aGD$^X7*$j`>nVZV_OQ>WnN;#1NK)4Yc7%Hqo^HT+272aDWrrKq>z|HcNWpyERGsU9uw}jTJb;4f-xQYWo$BHPFCs;}kw-Iz% zP(duI)_Na?eyGv`&70xZv5}%#!D(_>nwPpl{jwCe&2nnA%cOVybQtpMG`5Y|Ka@{o zb~*Le%t<*8NqezBC${5S;g0#2@nh9-`Y0|_%UPHQn3Ti-=N+swiT_=fRTtZ%EzXI-FOfc%SCf37XGpg7!dm3gt<>a4?eHfUy-1hL4!9uuU8xrc$;h z1_2e8{&_Qb5Y=8ke2c8s;hgQnat0DuQk&2#JiHO7n50@~mlAG@s~5Fq5CfnYIZ=$9 z1AK32kW!irzht;CzQ-U1$uc@*|7SiM+W_SSwiW&1O-V7p{F)sY4fHb}Ro^tQY9ZNq zs}@WN`x%x_MotLVi{$ed3ErdTDJ|j&beTz50tu}sunl@s8HSyiV)#a69265u zgwXQOS0bKE`i1>hS28n{F_5VRrXX-lemIuQ^wEgSdl&-<-?C zY$0%FVQiZX_kSm1j!zQfqyj-3z6GmiLw$}i--t%BXrW8r|5Np;91G(Q`GjO37H$rl zu_YvNmHh$RfpiIH1$kuhiG_v!r3Cf>Vu6%{?XZfcwDth!R013bcNFnw+7Ni+R=8-s zn(aD63r;i^Iby z3+$>;DNT1%aU8$t?DjU{gl}2kB+-}`6}!E_9I!^a*seG-oq7a37#k*T-u-o2dpu#j z-a-#DRz!yyVXy-hnsXvj-8xLV6v^kVtwB;tb!Ku z!4^22dyHrYXFWe4`Y8Vj4lcb#&k~cGb4)OWbhycSMlSKIGblNnnYosN+t^=s|4N9q zNdU~|0@&Bomfw2sq8`+frdAkNIcVD5Jy+_C8zsKrp%E7^jx?Fkj^TnO=)Z5E$(XOr zgPLVRj|Y-%A@-D!OH@K<6}7os3^4A*c5nf=5O0HOUBvExVUgms_m^uhyXoGn7(eoD^k&mA_j@puCt;;0bi|n)TrU%=u%gWdzXCR;$ zN1$FxBLDB)DC;X~{<4f6bDTnHQWz<6v)LIOkKQH5h3UGULj2ub4dcUexyI2pQKacj zAyHnLBQ?Y?GruNr_g8>B87|UWPT_|lytP1do(%a-;W-X!$TD-S!p!)zHhdc*n2ML5 z36|$RtMIY-yKXf(UNt$NR+B?)9#Nqg>Ef6axxYg@hOfhN--2xt>im=x?g5Iy7<6{}~MlbT{GQQZt}3LLWv4>lvV zWL)}3n00s+K_-31^|R9)Klu(v?p47%mEts`PhM79!)=Z>>4n3^iOKx!se(1(^o+QY(aRDq)Kl~ae`r+es!HbQHCGJEwJ4ML8YwH&FIqEsW zbzSgE!>8qY8{henH9g$My$v^{Z<1%mg{4ZFq(9a_FUdJKkjSKeOJyWH)eV7VZGnHp zlAqO|ew%|pe`yc43m@4@oA{%Wkml=8e}`Wf-Byx~2**>&Q?ZG!>Q6s$_4;z>I_im! z+lmXW{kl|r4f*aFt5Vk`a_da`vRSk$l@b-joHW;5?>4u)%?gk84LQQ_ z>cL53tzWlt$^?)(&PmFfE%!=M5Z%>W!EW;lD6hgQTPsSSf!!9A$5f)4eyGe1ry;aD zm8#axb658(`D)qJx2iKL$yb|8l8oFR{V;t4uk?yUI38 zcve^0SGdNXugV_*PiARka1(r0D`OU|oyk4}m_~p4P5DKl8ptBpN_972r6iJaiy#IR ztCX=+GMZn1TCCly{D8CaFE}et^UwTH8bRlj+%( ze@bPj)uyN>wN7d3Sf-Xok_dM^fNpg}%>1#gU0_50OpQ$?&>`sXVu)$495-f(+t@2U zsF{_G%-uSZ?FK=zTfkCKA&&rUq1g7{}wE8tN$-pkhNgJ9Qiocle(~A-h6ZV zIokPK{(YN&*YSKie^2u-kI#4UZ-mdP-FdEgne*mp?s@WG*1S3M=Fan^_)7YZvfor( z)vpj82zv0s#{AVaM(xW8Du2}#QU`Nnr3n6OTy@5#+61*Pte?yL)p|c9@2?7@!1~uH z=_oDkuL>uWyiYa?dLCTIU5u25MXgPme1axd(d1NgGe4VWHL7&5J6fId-ur|kg~uIf zsZDR$5hd}a14K)tyCyOx7I4JNk4PsM3Dd4Kc0>~hR5V;h8^NiDm(ALjt#wnRReVC? z?Kg#i$frZ>Lt2>C!_~p#0OCY_>!^S1K%If@Z-k#$0VEh=ISku@d-@ubsS%~pY8Boq z_Pbl8^26aBp@cm40#kyHT=hcgBkt|hi+CT!M(S2j5J0}3MAiuO9FaSzv|YsS09I)| zMpZMgZinbBi3h}C(i1EMKv{)4v{Oa&gHdCx()WLjBaQAvvs8cux(I&W<3CtUsH&8; z8K1~MsxlFIm*B}v=KsciU|{Cx`tW)yun|CI5lti;O0eihE%z(Zxm4Oy$Zwa)^JJ!f zOUdLN5*|!g+cQ8-pt)G?6=ae?9XfAvM!vgWWQoe@9WM^pcYpynP_7WwR+ z`3$d|@DMFgz6iBR-8sB4mEKBw*wA6M1u-l|A3s}^CrzUfp9>BBw)Xjf@bmVS*Tuvv z?c?Qq^@q3OBrdyOg@jn{Jyf^}jWuSyT0mL_mM_5jW64{ip1qx7s~MhaUWg?ZMdvtQ zDNXVVhYu^Kq(Sgbdlkf1|e$E7xXT3XBpb z*N*tnd5^S$8LO?1$P3X5k19zG?HPSj6lW(La-DV&^_40s7>h1Hjs=E9$hi!hi&iPc zMu+5Vs!zfCVHVDotX&@sq7+M64X6rp3!y2HhM$}OLS49o!T=qRbXL`2eP6sQz_VaU z1w~P~hxkaC6o`5;wcaDp>I-Js{jns#RLyGANf9c$KLzsv2wTO*4YqY2pDFh9%RBO+ zpgObcYv%gx)Q>Z3?iaMP4I5aA3P|@y1JxThD(b}ndcyt&0V!m+2+@Uz3>k%k0#_xE z7CnoP-0E7&j&hH1L8G>=-kgc&ETQc@STGMV=tHR7N8~pQ*&~MBo=eTzFQC#e9m(9f2)M*dm2`y=!WE}rZ@NMhn4k;*Qy)pF zvb;~C8c{8fR96UhNV0vwtw21VZ&LcM$`;}Jr((-i94he|9T4GK@u#&{&m*=&-jR%4 zb}$Smkf^Q!{sF;Ka$Na?RRux2zV#05284pBZ31UfbOO7y4@k3Ofa^B4jjE*UwcD{q z6>JaS*jU{AJ7qeomz$I=tokfk3}> z{2aajDDL*wMV(SG^kp0yV3YI{C*dS|Z`NDByg4)Qdhgp>RV&(i?>m6UKng5g1;Lit z@2d5}A$1yS+)bR0H7EyUM+jzpiFP5_+b}G2EZW0>qdlZdsXF?@jPjtN*}yu8rUmn6 z$AidcJL=>;xTa3j*uVUpEb(F$vLIEAD$I7u5JUp1+s&xhl_iAE#Vo@Kdq!CROQXDZ) zsr%CJ1XIp_5qM^iaGfE4!i@H%;!#oV8T@SBNd_;$=Oh3A_|tt>uSFLeDx+tBAV7e= z^TnbG)()y7u407w9{IeMsP7z{{f74^3@G9k064RAydS=rh|EFSG~7R-b1Mno3gR5w z{|O;#3XENbJBbywigiySBQopp@%~g^2euW723mxq4%4!PUYJ75O)liV^8%C^>eF8( zz9TeBEmBGl{Xm>~efd`cl*)>Z>8~PMrhgG!0al%YgxwGzu(IExG4xr+rN6rWqQuq$ zD;+)|U!-Ylzw#XsB8l-Z(rRsR!;4nqQ4@nS_7lsCduT8?5!H<7p!R04AE~Av2qi>? z&jrXf3BN48iA!fVWAsB)qAvrX*r}2UTWLt+x%SvYHZjoI5d@VHCvBAx#6taLhGSZ|n>9?KluLAWVo78)(78m= zaZXr`ZYjbT#e|B1Et{}Z%YP>UAOy@}7!JNpxGTZg2A(*7K7&O4#dJEvFFkUZ(6v#s zV7Zun3;F+`{;CRVHakf#X8HQLl>d6*b^Xwr{Ni+#o_1=r-2`b$7bRC4sACG{L~SiR zBxW&PMJP!=FenJE!L#z7Ro|bCwN35%yjj~Jro2SpQh0*M_yNpx3|QRLoP+61!* zM(l=HsV6S&Q67$)4jp3noOn_Lpd$LoB94fI#o14||3Vhkg> z-NQ%D0TpzICj|HMtH@#*Kj@h#9-mkd8EUM;{CT)LK7o;r#gU<4Uo_o2>#))#5GFZ1 z#K?Jtgu{~9#BN}guuEl7e-H?2Cvl6a=m!Z|#j6ez)y@VZLk+LS-x2?IWbg;$(QdL? zf}M?==-Cu!jtm-Pn4Ktb;e@KCxY;Pd3;KSqa7-xb+}^1Kt?NH&N5#z8ag+6pyWk7= z9AF`KQf9l$B`fma<=d<6iGWDn?iPu4iP@id{8lg@TELXTv6xYmlkr*K<`tQb-+{kz z8F+eful*Tr$IwrPd-R_Hcx~w!?v>A(=4(i+v!1H3f5iPbO}U>SFSFg+Ch;nc2ogH= zN4ATzUvjV6FFE+_L)mD@Xi9~*n_YIEJPEp8hvWuf-X4AoQu??!cN4h7dzo^bf-!5!@If?kRWS}1@mO})9=w%B0%6pqCgOadzPZ7I`^yD~p*4~kcJC(KL zV(cM5iu3x+2!WkBW(V2iADF%IcjuPH-gfOkE1si@gUr*C;2Y$n@%|t;!fn=8OXi;IM)(2VLnw&iB;A}zfEb($ zR^>$hmL#{#hP6mX<)|GnUX|37Ov?up-QUL8hn4Z=cUYf|5Dh81b&cbk=S=`*L8|N_b&c^NwBw()7R{@w)M?W*SjYi z>XK)38{QEeJtL!t@Y4L&VjlMN7CsHzX-rz~J7+)keCn|o77qX3JMs+AUL{EcTtV6M zA?HywY!|yKEdfWLsW9)bLeFAVG-?mp%do_Xa&u09>M-L$RIS}FwN(C#d^ru%tZE`W zV3Xzj31HKy`8Mw)oqf~3XNwdYVOG^&@*FSghsIUiIB-ZlFl+Zqm_VdS;*3vP{>KHk z`n;P41-7~!-yKjXg|g((#zAw{T*d7;75-T+RoH)*$F}TVNuBB1{X__>Bw+JcPZCs= z{L3&nW9>c98f2nJngq>JBr0sw*4leusNYS2&Gj4MrzBo+h1q59c=1^$N*aUfVRCqZ zTRB8GdsVQ3bP-N%}do8Tu6%hM=uvd+usl^H#V7bKk#0c@L( z+vRmAeH&mKp=XTfK@+WJKJwK9Gx|*M4Sjz#%v2#Ze#`+J2XBudqyuLn=zm!8dMM34j2)J^OX#l=?J^=Sh9w)LWUUJ|(Tth#)`P8*4!6f{rMpC0qJF z4;z}aC8W7D<{fPJ3QT0y*Gbst)vv2=W3CA_!xrTcC6Wc!);uuyU3A9!VQ0k0>!~8 z;(Cje@xe@5CTDQVx+#qlep4A7xd#E-Rb>Z5CmN7RiTwcBJ$k$NG2LYWa{v3Za6g=E z9X~*4E?_1F{qi>Yj~K!LVxhrIA@6=hQVgmeY@SYwXohB9HK6aW75=d8;Ps?UxIEf_*du z<$N(kIj<3qk|LcoLa7(TzBwQ?^;-T>#XnQOkBbbXZh7DAMNK#=jni-^KFynm?Zot& z$ZzdApMouyejtKNMF*?=4@fTuUWTWM3!x*nt$Qv@DoZ8lC&(qJ012+QW=f1$M?lO2 zt!R1P@Ta4GvV>@bZ5eBmju^gdArz=rj#a03po%>NyzEKs`#Mr1Oe$*So8s*7Uzpem@oi6ioQO*WB@>J9tv% z`J4=#U6J#v$8O>zrGVGIRoqo>dXEH;@4PVVGrdm+k3TlgT>Io?IakKHH{#>5v#a&P zJ?1fRIl^9?-QInw@q#0KS}U*d9|>OCIY0RNqjLgpVE$b#3CX_TMfJjCfwO7(^h56p zoK?5XY8=8OK=fGt1xiRBI_aW3d6j>?!a8DHGSY9|!F)=BG8wlrTuM6@hD3Y|o?@ix zeWwCvtw&uw@9*$h-p?!1F3_XBzCt|Tm$~8G%wSFm2}r;IA({D{?Z+*5ev@%`K9P&l zMhOwUtpsmt;ucRY1oJP#n3w7I5x@Z$5cvkD%r}U~c+;wJ1ut@`lS^$lzs|rr)GT=| z`7<5ynC^p``v-{3e!CKv1CmcgO|_lJu7I`h78QTam?Q)}>?6YEMkWyxF2?C% zmnkL1UQ2aSBdh|NjZB&aO(ds^VMKN&J{1U%=%%?^!-ul{!E!G{bknr(cbsX zGx7JlvG+VH3cmLgb9wvGK-c(LVuiN`;#&d|*^rW;Ss!t4vP7WCR_EY=Y|QPogUQ>^ zjh_o9AGs|+o?*4om}^w$*cDI>nxaWM0}Ys5=VI`hi=rROPBUwK=6Wx+i-T3(NB^?Y z-0H42cY5GI!Ap-WH0PG0-R<<~FS)ao$?F&gl3ce&rF$O&$DKk7A^y}~<7jqNgn)7T&uylL#p z>-k{3SAR(o8@WP)kr8IUR_BoW zuOB!jeYHIx->QUsH1d-It10yyQqCZo6!h6cT@};r&J%q7>kQVLPD)wPgp%(NS6|hX7tAa}DHxn=AOKo8F zKA`7W^Bp@(#5GT4{ECPDgi&D;=^(PLw3ESdxAQLcQReH<#y&i zOR}p-@Cx*kAU3@lQKQz=Yn$tGNqw>kUARaPA<5b?yB4$s=VVw9;$|-#SKOxEY-kL(6pIO0(L% zqT2JwLfM#fcsjK$c_sNtrJnJ#!L~f*T@%z+Gy@Tb8`UBOx-ScIiN<5qq^JKll zFigpUNF8BUdVkM?XlKPzr@yoke^ys@pxafQtG`sqvTCv|Uz4Njps+Tzj|u#HNptR# zAIKS=`9X+y)_>}KoDW{ir6J#+IvoCt2Cg0seA&}g?4%DC=kkr;7Rw)XykNDSl?JKk z*RyvQhO|8yDR}gX+{)^-JQ#oP7L5NqvEvblTFg%z3?7L4lR~N2&^G%hvle2VA#SEv zk@qt0TYZ(jXKe=_N#D;svh@^w>n|OHxQ8_e+pNfqe8lB+`6EDi}5AdV-kL~$2`?*uPDjcNyRp=weFVqJGYGY_6{!k zQts9T?OTkJT<+VtrK?0y8J|;Y$oxVmB93~@Tab3vdjfH-%pK_2P@$dKXh$(!L#f72 zxVw6W`-QmjPdnuG!5aOQc5_`$kvbdyLB*_Y_0C0z+h4XWYr=F(PW1s0Hn=Mn8ulO>U(qkrLM8WNK3_v!`15_-d}#T`PGbb>?4&rTN-EdCvbkI zw=?WNfWt;@<^MtGn%c^|B*aT($IAfz>(%Qs{of!?SN*^jkPGB^sE)Pf)tKA+vFmP5 z;$AFInibSCG8N2shEQ%DnoJ3nxH(-Pw;~|_S;eM-Ni^OQ*=60oLmyiK@GcT2wV+Q42 zepku`a8_O$o>U#_la3r3=gqVh=%Ev&t$p# z>Do*ob|NzX_dHtP^TKZxtr8SbKk=z=!+%m#%z_85%=}z`LH!o)bFmfHYDu~uxCqpn zc2c#uR+EjfHgj^x4lT)2x*Fz?S3KaNXp_EggK)KwN5i!EP&Sz^Xy6`w-)BBVFBJ~G zlp!g~;ay!rgtNZyo5D@O#cOr5_pG8^b32hT=H|h`NfY>oilmqz%SQuewQ@|xe$1*? z&KJz>0HtZ$v5ECj{)jCR_A?>nQ1{2p%|n6B;L!EU#tr)stSamPt;iO;8&vgjHW}o; zYfO5o_7odE8HuF`8^Xk1s%R6wnGFyYAYa&jB0lqq5uG$2D}Xq}#~T?C`|95~v@gDX zzhf}1!fN$D7!t9YMHF$yq;L6uBj2TF0MOb{KbGp%@`fs6L;6$kd7JKbr#(2hI3=kL z6FyXBdY3CyD&;mAWy>mRTrOTeDItGKYZXFI;CcZ#82ZC?BGCf66!^qf4)G}TG^h{* z?wDL9^-6Io5WeY1iCD?8>L$%i3+aLBU8r0$*!r-0Lh(32$p69GG>TzVUMW3D2qf&` z)3e{rZ_c~ZFSgZ-IUhUJOSMiqrIG+7ld~TX5#dtKyIcR=ch7#S43%vbvYmaV2JG}r zYh@x*<4(PvaoZBmE8~_IGHBe+B?#N_;`umXIw5bmcoBQHN#tQG3TA*}k-%32Xy3hr zDI?}{AzO>B8BJ>Ah_nVvQicXQgf(N;3T|wcthCSzE-_~gXrbp_x43o^DF9V=5ErCO z?o=iSumbM8i5cJxZN{oExS0kEv_+@@=FWGt-Pl8YF19Izrtdq?K?wm15ki5r-CD1d zjHGy3C|lq6HGWJ{tUBP}$9qSfh00`$A)#VQC@^ZD)erofkU)o~IamEPX-GcYY}Fx}99txqE_6U<0LzHL5I-3>(1+GoXa zny233#qXXlYMaR-b4r6--XbFBrT94$TKfw)onc9oo#j>ggPjq0-LS+_>wvi#wSR9! zewx}3_qxp;H@eMC(|@B8e$L_iqiMzkQ6VMOe2dEW^Jq9vL=(~IguoOC1E}y zxaK!FhpOtvf{%2ANa{EA!>~?zaz;DqydAW|Lx=`)Ch=NcDW?!85HYg67@>)XH+kX9 znw&-iobed^+48Oz)sRwpc>UIJ`XxWqgAtNaKhy)>&PkWDSAs8HsZk|FIs(X(-nx)33!g3b;RG=Kx~( zBwFK2FMxG}+Q_nKRRaOoMmH(nOw>kzFU9vktRuwJ!4cItUrC=(-NyKhqu;KA0EkBPdF1FCUZ^^H_QZ{&~Q}u z;;aCfHx*5kOv!r}aAh0e{q-)6`#Ve?hvHs6V>u8*Go-J>V%Z9a{7`Y3xFM`1!B@9euh`e|*;^_IK?laTbo? zNjHbmox>MABto9k$oKANr`4a92ld0})QZ#}m-i42>U;}#OKTK~3lDIrdb7<_9I9)x z;c&Q32kL7lRp(F2#NJY0^<5b%B5Zy5piE+YG$}tji|x#xnzs7zGxD=mbwYc+zH0xq zbNrMuwOZA4NS-Vp5nVE9)hm$651*;OC=)XH4oC`0JG1^a9*b- ztp2pLz$5e~zzTM&+3KlR#TlG2A}JW2z#B>?K*(Vn7^4+Lo=5zmDt^Spalk3CPneeR zxZ8~WLVKk_K69Xinl%N(Y}|^OHulg@2?PCm;g8`CBl-(G!}`7z)B*$MO1!TGMJc>t zDN=b#drj*?UQptPz?n4Z`+iJb`)qEm>}SZ=*ZQADnI=RGnSnwUW|^lP&ofCI;z?U^ zN8{sYd5A-)>I9~@-`vrU10xk^A>kO@4E6+@`vl=`>>z$3G_Pz~FQ6gf+uLmT<1=9( z#O4B9fmi-8Qp6vg0{2>TVAE3pqhCcP(t9X#BZwqFptV6DN& zxaxZY)_rdCqOt0GgC%vb6|Ts?5V!RGg&ZT#h#*MD!Ca!m4=o{lWrGJwks#wS7I`Lkq~I5hfAQdRXES_f`1dOR-sj&e^;PU0v5}>-*NggkSP)p> ze(_LvttW^^PtDLDou9cDDu$Y$-5;5s?|f)}8h*+As7N&C=a;kRXVtk`^E3Cttof-? z^HZ6cpRbLj=jYn%i&LzNR9P~>&PIE86>#w=8Pgfh&~^W+d8o4k9~~PXRGk~;G2(p z97G6$l5o_#CchEIy7L|Lc;HyidF_J5SpqzbH#2zlQTO;8pKbXB zD#Vo&k&XyfA?C}qS}TzzT6eLCn{qYso_aARdXQy$lI2d2I9Uc@JA>FM{UPc#>3Ylw z#f3YZ%qP6XYb+f07LA`-G^(A!$SO&{_jQH*I-Mf&4qs=LxAuJE{psoS97BJkh_ zamQw<9t-qLcYWI<=qTs}6Z+nGRjzC)Y$>2Z$e4f+d*@>+v47@5pe;*+jPIG^e?UOX zpCZTK8uo}=$(2Fs2}!e$&BGiAxKG?njK}4P9gE>F{Kk+ZW5QE={%_bu;{@w&=$IQ|3 zH{>)TBYTdS=$$6r{$%gF_$*TwuBZ#DGsp;46o*8z>E`kO*lJ2w{+Ab1)^e^|OR)6B zeJe{TR)&a&7;}(c)cW*ah1f!7R%+r@ChwOt3=n#y+b{<8fhcl*hq44WD?ow?KS&#j z(m)v^)HQt{6o7JmT-pI!%l$OlR{~vgWeKsMQ}C2;gS%BVsXevrs6w-e-=TkX+^eVz z{S|5i^h~h01tq<|3y$w}Yi)t4p7$gqe#9|YJM_sBL;=auoI5$y<}%#KzzImk?jmdD zRF7Rm5nd8_BuaX^XUg(E%>Vq4pj1W(T^yw5TNW1zccSW{{)sCkX#%X2?7?u*Uk=O7 z1$xW!?-hkK?CD7&_aJ#-ezV*$!SItbuDw!Sd_WR`a>#lxixs71@cHb{CXFxpasT3jwBsIT18B*BnU?3mXg-{;UH^oHY_ zWBXuD(H6>`>!W<(dT7#En?z9;9gl{1LfHVsN+4g*=WJO?zImiEWw4ku+~^azsd8-y z&@PPUkicNEr1TK6MdlZibyDBIf|W$yXSz_A%nV`EAi7Rg*rS}4lE{SfwI9(1ta1VP z_o!*|!un-GM zeurJjoX}RgSX3KySoYXMUXRG{SH#NcDWOBm5Z#vCt5!VT z?yZ6@SnL*f9Y|3Mpic$?w%Xq+#zhL>Bn;>Ymh5z@Kd2o z;v44?cXFd5M3QctA?2w3jc$RBIa_bZHjmRKI*C3`AQT@uMZ*vRQs26i`H6{@jZiGs zY@%lgZbfM)#Epi`?4de=`9;&0J`Pgtk;Y2`GRDp0Dv<;gs!Kb{#xSSQnkCEd zG`^@7p#qZH@I8^CNt7e=&auEkjxb~)X&A^Dl@x5Og8jS;M;`4ufz|!6NPXX52s5Ez z1@<7OCz_3TXif#9q;bFwupA7q9Dg22qB)Y>Ch-ZG(uPaDO!fdeC=U7a+{hb^Dw*40 zr*8d=Okg_(@6bp9vxOvoO9mwNyyezo9(mObkbuxO1y9Bl`NK}t-)6dCFKQhB~s};#=1#Kykso;zI^gub+r2w2ViEPI@{@`tdk%U z4k_C^SF8Ardyfen)R+QnLc%wN0YEQr%IqY>kplsWyQ$0a7ON+j$qtIO`&T;b8sE~J z`r!$(N1Q2yYEC#L%w+e)r+pe$EoZ`dr<>Hlh{p*j1T)PEev4m0ix(BX*(_crT0Dhq zjKX$fQ#-^)F6uyLi4Ycr8>{+)XY~CNFH*U|UW0C^k_0GeMQS6Am9pOzD;34+aX%o|$!|FMu=ykW)(Pi{v&Fh%$8yHb@A?zQ6#i6Kk z(83-iF+AMC-8{jna~|gk10;hv{U+wVW8Qr6gVah<5>a3m8o0Ox|IAyo`RdUoG{&>kI4CO7tt>t zUs3D94^+KaKUAH|;XtwFwjG}=2IHdPU)cV8NxpFVh@V!8=X1I;=n8y0zZLyq=9+NI zt!C#;;9=^eye~E~D<4(F9t=lPW}Aalau52HJp|zkw;4GmRYUp2sgZ*2)E^`xqCEE2 zT!QywokWH(ulB6k1F{Ns34f!1rrR2&Bh?#uIp#8=Gu%hg4ccI*4{>VpEc1PwP)B`WM3#A7T&3^bOf%^ou( zujnsNeWWc48AAk++vIDb??eHy%l0TAP+>`}%pH{tuY9u)fJ z$aGhfV2$Wal6-ka^05Z<&#kES>j&;+&~i%;scwQ{w;h{?jL5AL+az-;H9c7Gdk33n zgL%U=oR&6iO#Nuu%&THY91aY(M{z9r4L^b(%X|}1AQMjM9i#|h%dk$7+7QqHdwGO2 zN$GdMGNTF51P{Xr18W4A><7HA#v^mOWh|QX7 zL@!JlA0NJf<0^emHs`EC+85(Q7Hna(Uj2|LIh$pIu1H-M?FxwLQOB+q3;8lvGG82r z3PnUp7S9#|)q2gstD-rj_aOxe-TMTa=!B_}-wy+U^Am%2o9TXr;)_!8dla;TQMQ}_ zC!Xim@i&5Jc4wJ*K?pbSlROf+%UtP()Xphv_*)4fa(~mQ&g~#2$b%SY`Un=kM2nYr zT;lk7_6j3NDXne5(#DeW^=I4HSml=&ot1W7D^&n0mHL378C2JkRSv8Psq0k*!_0wCNr(F&9ioih}PzyPymW$XiY<8K~t zgVsce;?WBG mWgHvh!`A3ES)wkt8s%%6;iC9iR>O!EECcp>_kE%0={X9y+^Me9C z)KuRuAmV1|BKTRNUG#%s?Oc%@X)VzN8be0o7XCFIlde3E+O>L+o$sF(A!685D#QY^0DN@s&X5RaBp1ZKR!nlaFS=U|HI z&v3Jp|76oO_IL@$^_g$PKOne*_heHSOyC|;sBT@MmxYTVJ=?LOr1F?>-IG$CPZ6{H)XNo+5HO$R^ckL$!n}P2|4?`A zy#-W+zDof?po)OcPXBf=<84C*6*GGSgtlU&d1+ zp(Go6sr3lDv=wd!IZLXn+BNom{7w1iU?dLbVjD&56}27ufh=`0Hk;vupzowaxYZdX z8g;pUA~P%Qg3QL-(OmF}NV!{;gTyucThGbFb7mmMpYBPDq=1-cL|!2BNJ>YA%gN?o z{Vy8g*Yx0rBlC6_$;2Fa>_-n=4@84ayNLT)IR&0DS9`Cx0D+0NHk^_?zR>dqkvowW zIFzt#c%0Kq*RXS;~>>?NghNNdwZV^g4$NGPj9nC=EdXhp={oyAyr zp7Khe0XgG}z*JYYNCy~hkV)9TP=rIY{jjeH2$*WAP>i@fQSeKl%7FmYh+Ag>>(D6M1D(KJ&sAsE z@UlQ};1U`Y`z8PM%rjD|;hKkn7xW*u-7Bd+X81YEU1L&mS=;_z4rm4A<=X#Yj-<}( zFVEsf!2N^-UNRegjY*0?AI|M0wrN(6?>*DPXkIooJ{z^q@dY|%!gAz$bg(CB6*e-1 zM(7u2TwUr{=sT)DH^=(|>DP7zm3}8^OKv6!IZ73yG0TPyG#m|c~DctuT( z{eR&wWqQ;!Q1VkC(9Rm36;*=`t62$aCzjzdP&%&qbIIH$-*zs*92|MTzocNRC5UoB zp{BGO?r)a_s|Fi;VIsnLT47hFzX|5PaYKbrX6Si)6JjNEt4hIh2FWf8{ZyRj5kaSj z_UE6bla_nSI1unBf@tgece6o6l2}NYCNzxDAhnX)hp#u?FN*est&^e^QoXxdky7ZVdP}nYlwc`BfApVYT3`Z3?y36}KDD_=RxeB@Y6-L)`}4%Q7It3+%{*ALvUB0Zl+8z!T@72r-h{lT8ybAK(aso@(* z7^&D`pHvkfF}C?Y@gc55aKf75X0<~wQK>}zK_F>_o8d8OdIAhB#Zqf3g`cv$y~e5+ zM`ORwER9WR4R1fHe?cOxI0-SYZoU4;Tp#){#j}-`D0DL9xy|{)sd~wwc|E>NC2IRA8C#R@{;^!5W zP&sKilIz<(RQO2*!F1s#`K$^*p}sU5_$8Hv+5<(@VZ2|7w2@sGpKwd1c(I2by;{OU zs&_!zq*Z%Y9+7l=v&5siSW3BZ%v0XrsJ_2McyS^a@=^P?#Pe!K0y<|HaZnWsRtCd9 zgp80EZ1)^}|6FcODJjgy-jODTah2ss5g4;-sfb~PHC>?-{Fp)QpeU6_Av<4yWU52Q zsP(>LPGi=JaKY|*DeJMw6e_U9oI~U{W~%(t@weuo;7~qE;&78(TSZ!27}mjPC^#k# zBB+hyAcP^cT&alIih}jeo z8XUQ!0(3hhzPA^}OA{FjM*Y!Gp}K-0rC}k=sWZW?Fx_Q!_$pQN;$^_<*NSc*CdK1M z(eeGv0l`bef0ekTT2Z&FcEp7vq-ro&wN&4K3+oY|TF6Zf=#;{3O)yxqDo=FxBC&v! zlJZP=dR)lg%0q$K?Tf`@hBDSo255yPMVp$$QorB$m3q)oI|Az*4&x^l> z2^b+AovfUqandjf3A%~(ibR~57mx5YN}=u#mZ)@9WG!&4$mk4jN?+aBeMu}umm zf)ZM7U;n*K$;F99hcYPk21w7hd3-uj4&I;?OpN3`-~!7LxHiB*A8g%}^(D&Dz=j7w zTT&G#v%&sE$nw}ta#C~@!k%N%fs7p-wjOh(B5>-tMr^6{{Il=UkE_?{!(#i}T$AGu zqZDZfy7e>3ZJOEjpOT)FhDHbIO11qcDxn%6$x<_27#EbXY z^X0(~Ds@3t_GfvA3@Msty(p8UDnTw&?T|Y+9a$=kP?98%;xdal&K_+2OxCj5to}?L$lurDbKtc6@aOkSRAtYHRGX#8zm4N_4n`q3*`Da9Gv86=_0dz4SAt+x`cT z=hg5-OSPFf`L=gVkC+7p>$zXy#4`=C0=Sj zjB+e@DL7i{D;>$dQBE4Lf&s}4?dQcPKTZcIF7rl^WFzb0OjKg!I4R`MC_BdtFB9*x zd$l-^Is+=W2)wsnWehM&sPL2W^5w!l2)P#c_%03ar+&DA3)#XqT>=kG7!mi2mU{@7 zQfRr}GG(pW*B5(l5AH;aQ&-3wn2Ur~HH0lY0Jj;j$ToBl6?wf;m8)D09O$F>WE_-& zJI(TEcupW($OhVX`tjR99FE@96u@dYUqb-p@c2pFy^9b;a@jn@sN<`}7xl{eoWOd2 zu@(o4bH}G+$&W`r5ld!AucHiGqelsFJOH+TbV2OOG+Cg>Py@(CE+TtZf&s2We><)J z02pS~a41KE_2~_NfqU}p@rq=%C=BuyWCj3$YgD*@;Jld6VzI9xV%~;&aM(mU`lc=FYsD6 z;{NaEE71!+D+r36^j+)Lu9p~^gn%W=A4!R9D~ey48=vx+t66QLBD1yQpeL?Z6v6An z)_W*C2*?f@G43O@UIu{#qs#RDXCyKo-NhA}4Az3}7nkpNQbR>f{o_TmkuV&igravZ zV7sUcA|~MDtTFpJRdq|5r*Vfzas%VAYNADu5Q1U&w-{ey%RRc)$cGjFIg!U5u_Bs% zP@UAB54g1UIZv3^n`0p{|biq6F?A^*tC8@XEAAfhgc<<(YmSC+6FgA;O5jYb( zKOM%8(Mba?Zy8^i0KS&;eF?{TWNE{*kQ*HqfQrc2N|mOJ$Aaf1Y3Cy-85w0HV)7x36`hQ}zm;pKCt_)59*#(BtpS2OnL=JRg63 z?+1H_<%{yzrH_G5hF${yLqg&i$f->0Wb`XZkPAi^>-%>yuu=eD>9dSuztmIRdfygd z|7tz`W@s_oA>~C$875FO@Rz3WAmotq6M?L7%2;f@w_+)+&reP?X$}b1&7XS{AT>lJU3a#?J2{U0FM(t$hWQ z!5j%6l#PhgmB2&<%tet{0x?t0tuq!-a*?F%O+Ol0Njv}}4%X)C`?F*r)Dm3g?6_}s zVZ0Q@sr7(W=gsV|NoRjWBN*zf!f#L(G7!n;z(HWdo<+Ulzlwd)6J4{y|Aj~?L8&e| z`ajReg*8yWTMfAh-k|mkj)PL|xWt$0?4LT9l-c2Bh?cpOkwIO=gOFT_4-kIP@SmK` zF{w6((9nlB2Ysf$$Rl2EkJcb_R+E_16#HUE;}^jM5_{Y9T_T?R!>_LGk0O4>uV%W_ zn^Ya7OTkEPLn7UWU-Hhh??|Rd&CfOQB6*k}TOs>OqLGcNmsh6(#}^T_(a%0(!wR$t zLeOR@azeU!?STGlYk6$YgAqH_jB-dQN#t|Lh-hFh?fEX`jAVo6h1{+h7`{1xO<5rS zuRg{>J7g97NVVT-kAEFWgJOlP_P?e+b=dEuKK0pWwQ(7+LvQ4F$)HQ$WJ@7^q7O{;0I zcaTIp%Hsw{;U=AgUl{HcP=Hy?tvgb;Vt9{?@Xy8_#Gk_W)Ewh3?%;9EWvQFGr4W=W zk`+KJp@dbEA|Ye<3eYirQD|ZhjjB#_Dv7sfb>3>p{fYXtIF>qM`o~ZgyMnmHa7i5? zx0s>(%~O{Dn|r}L{GXPn;0 z3C|@3^(8N&8J~*SXN3$onTcof202{4*J~_N8s`@6U&{=-uaDkLp-X-*BqxlWg0ZpC zD(FP!3ZHPi(BA90j5(Q_PEqgfr^Ow{XfPFCY+N8E+X>SNj}DUn3D9qxpbR#F1Vn{S zuwytUy{25YelNpBZ#h8*?7)(+-zt#cLJ9Oib8F>q?U-8G4!K109` zmn`CK`b#;8Z8ULK0$XH=wS~R!Fx?pXgT;AVp*SB6`j-vg!te(G7k zc#QL?g>YaXXpPzt(r+b+IGl$NrpRX#n}J9gnSS8W#KT zlct3C5#JE%k5A0e<_Eo*QOeYfWJD;689W6agSHo)66thAbr@B`of%B96WEG_+F5`D z$smdRle5-RK={IHxD+pB0}E*8fp72}5(257qFh&rs)K!Yk`bVtpimg0?)cU z_(1Jt_rrQi&U~PyL!$vfVCn*UfhB?`VXv1^!%={j-U##yM+vRc-W2miL9^v<#fWfSTzU(~L3YVc{u3Eg0}_RDO=qF)v*IWm@iIyQBE<8{I4SM(nds8l8K z;S34$2?n79|HL=84|KDM-SajPdv5B9HqHx1zp5Yj9zQ`)!>lq{qP8JKC$y2a~bwtzE>>=+c4122D~m11zzX->R_o_&f03g;wEuC zXK8QB)J6tmQJ7xIa(lKl_Ryfad{GyM_)_L_0LBqyyWWbE`urh;20EpBu_)E4h0v9T zP8bFfnjy=pL(AFI>(ne@IV~`K#4O;|Hb@f*5CmN1Evlg2_GTp?Nu?UZYu~UK7(@Ib zKm7a!wz&wO9&u+D7{1{J{K-Gv#c-Lyuopw=JgVesAsAy`+VHq9RMfas-ui%Rhw$9# zJEg5BUUDYycKNdIpM-xF(y-wI(l1=tCFIANuqX0hKLRtJr;a!8cIR|cfL9kxs`qkO z`bJ4U#sJgQhG#bU|c$M$|V)O&orRA674%_*5=KendzH?X8{vG z4vhuQy1WPFW(?xqC85P#p(5#!1twmoJP=wXN_J?ie2DlNs(PR0z1;{eSH0ZilDE2` zpaAElxljuiN$5eG6I4IoV{Ax)X0#&U&KLP!|FKlHC1-!3NF28ZUjubh(!aL2!=U#mkxn zZznL<>=o(g3RPfn_PTD7(7dXO{G&)oypI>B-$fEOZ)3sn=6gA@RvN4Z6h-Ao&a(X_ zV&{pBF}XM$mJ%xt;NscnTGrW&u3Ew(vlG__kd2!p&e?s7wULN>yEmDClsPa;Cc9SM zqJo8DU!QbQQ&<6uti5>>dw*ywB^axCxY?&y>iqItH6DwB$jeFgqSzAcSGRN8p|njB zCMMRt2V7W+JoY%hq5tyPhuzF$*WmX;j7G!c3W7&d97{aTcn(PIns&rk&Ar2VRmnkoS`ojCT;uV zMnVq;#JpKkX%9XJyN_T@LAB!RpE>VkfZ5d#@PoI;{&QYT54@E&c0w`jS=&Zu-uu(P zo%P<7`XloF1}E^EDi#=DM7+97Hc}{u4fK?N;Z>SB`+gzTGN}|K-Wo89YVe9^WE{5= zV3=(`eM}ODxFJ~|^2!~R{GuO95|3{`$Zujd2xX(JB`PI?WWugaJ#a|u>}C9b`A;6N zu}>UT?l4+a(QJXP3i}9`us_5){4f}r!seE$BoB!$Hs4g9aD+C?{Y0=WdSj`z&ZXkD zPHD%3#~L_pCKXc~H~R@@`Z9ATcs|jOkujrzF)D%{FjB0o>*`02Tw(Vvh-Fx{|D_|Ykj!{jJw))(lP zrQ}!#Xp}uzk6+K zXaR+pRuNv>?HprhE?x;57W4rxMgQcb_#y;uy$)EHOaVX;=Y&r`G+`Z3KTAY2Z>uxP z39`+8{Q1;&P0hy!dW;0Qd!D1$h)rCA(8e#YUrb~=wd?6&{yFqnf)S1`SY{OwcXz7c zvRpmA?=lgB-)mbb*o~75j#+-STS#vdI1-O2O~+95;|`=O^o>F!`Dc`E810#Y6+}o? zr54kK1ZiqVrS$NFM@fL&Xjh1fswH7Hx=4x4R%FGDV+YS~btao(;RnO#2A0_G$b1m_ zk35SOa+{c)UhRy8Q+qK678hZmYj}ro&(@`9=wVj8F3LO(e8P$BPkc=>B9w}YQ^UTI zuX3OwrFa4W3jwV>61ae|8S{Pw`?!lVQNw*RAIwoHb(J*^c0?!0>*#}_fwHbl$TI^Q z6y7#0C7Hnw8WPMq_W3AtO;`X`eW>3?%q=4CTihz3kw>MzqkCPk)=do2zj3=Lp*_2E zRbFkKF-I*}{%HnSDm7mI?N_qe+_RB5bo)t+v?_^`kX6pMWJP?+XFtS6L^V8bNubLR z>N%{CIneTKO#&(~R}Bg=#wG4>i1p_E+!aFbXLR4^4yiN38B9=!1Vy%ZnQq7*1?~n2 z&xPO`rusMuGgwx}0`BjZDC7N*^9l-b9K!W0?ih?WD>+#k7psu-kvel8PEGb2PPYWx zE?FlVY0RacmpUq9SCk{3ske$T#-9*lMQ9A+%SX`)s?HDcV@6YvOrnJK(_BWKK*Zqv zW-}n45XI7)boiRi82i-BIrKtc*3DYgD1N#->%ahqpp^bO)C;OMZpx!VWKJ=laG%s| z5fCYQi3d=2U_Z5sQKxNYoX|!bi$JG@2N8iK9EPZ&_J$uZpCZUJZd{xs!)Z{9dp)(~ zsz$|;8A(d08Oy++WJJ^MZ;@X?pGg?{I6FgTL;UXDxG77`wJRni*fzgr631iBWbjhM zzsxTBQc?e*Ge!1W2#6-gDK{z=NHDu+dH8+m^{%-kGR?xkI(z0N3|5+(4x zKeGKCdzLx@;5I7q*nD%xYVn9l@O|Uo%H&170Q7_=9sYaRzf77wyl$$FqU=2r*k}V% zGpv#PE(z(Ffytp>!_$=5rmWxe~T15-$t;s?VIp-U~N{X<|txo zrFPkNaZO#|kVwV{VO5;L&WU@$9>TP*T8Ee8CL&+hi5hn@sCi?3yd3u!Q#O;}{d1%V z1{zOah}k#I{;IOQXJ1eeDXml)if*8GDu5LecPYt@k~m()8m=1s>ih1{LEKH zh&eVxR4i*9K!LEMYdSx}uZylqXtJ&<#MB3EXRFeKDj3J;$2!h4o z4bo%{C5b9#sy3{XW6UY|fpTwE`~i>JfgiHAFgFZ!Qu9On!9<3!hm@rPJiSr?)QDp2mpltP5&0njS!@gmba+>KSOw}AB|B6|R$qV` z!^Oh9DF{zkpo*9xQwYXu6Xhhyg5{Lzu+}5F!JtmernIFfx;btgG_jw=IeeUh#>&WABcPgJk&pTG9 zKXfc5LGi<}i~9EXLO#Un^v15>McsNv7Lo?VtFr~>EH(YG!N#Q!MAE7O8l22-ruSjA zF}nC+`EU08R;vk~nO~6{nBoc=w#p=I8dyPWZp?9XOy)Q> z!5gnm@Vy_N;JF{2V9vp7=lI6d1n-RAwGv-p833swd9 zUW9hLxpba?7bTpjnb(RkRQw0*PI_KDl-#c8!Mh$3{>8`N@<+b@R?j=bAO21K7W%e@ zzU7NOL+pGw&egxRxq6&0ZU2+G_m8ity7Rr0oD(==MH zw)NiUdH#8Ly~x>X?X}mB?^^4-zU%u_McT+uo)HH}9}6rK{z?Bm8q-dVs?;c;ctUyCmvc_l-6+IDX#|1=LL7l$7? z{6EqKCKq-pzh|&~|3LXJioPFRkXLDLzJw;T;AqGztG2Nn1P{l591EFrt+kEAd8!L_Y_xWf5;X6yR}&U={z#yf+S7VcXr z?yQp~;LJ>2?JTk^UgRT7nDlvzyyC2Z{4b^RrM0n$Xqfk-wUhqjiu5a0fXSNd@G{a_ z7vqD;A}PgWYWYv;NfM>Qx;Ja;aYRE z#h6{hGGyA8-hPFAP3XQ0 zSq>L{KkP0=Rr*i_IjIS9DTk8YeyrJ~$wxtmd+0No>~-%A1#pUJ+Z(LXax@fV3RMAH ztNmJr+f>-5>h!hlKCoN3px6r4vMQWFGyi9`suIgurFvVdsz}#5P>s~D)m@DQ<~QU% z9`j*DEI5L<23;KFs)J7M!;yoMs1M55VHdNZ-eCjQ4aXZl3h)ZBZ+~6xPtUof7!y-t zR{&=7aoLxbLf#%WSntu5Hv$VWuJ6or@$h&rkjx3!HCV1;FH{5iiCk;qAzZYfKOJty zD_D*>gl;wWdGu-tm!sJTZ^s6Ia83jtx}O=6!Y6)ju{6eJRHMqVIXRg)J-5?h2bq^S zD@SZ`jY>t*x3LayZYCcQ}H=gS^DVK`7wdByx2d>LqsNB&|~e7C+@o+{5Xm#^r4;a zU@2c=s<9}LW~mJBO+C<`+LO{m8bU#Q?3Hxr3P{{oZ;oiHk|(?R%I3LVsZDgabymSM zmV-Kf-96;FTOa0cax_foaC7!E&j)k8s*bW!H@31jTIg@HSWXP2LGx_})e>4ot^= zwDxE*wQqvkO{ZITFGZ!Zif7Ua9`W`FD?VH&T>{uiTyhFop0c=j+&6WX&Z3+oixhoa zd#xid7d~>Auh*!zuUWf$`?eMJvhsYbZ&a~!QKI_eZ}UF&TND^S9Y6N30pZzV6jTtVYuo zev-L-gdAV~y2{wa13lVdm68CxKW%4SPa0>fzYp3u3+Xh#*CUrnSj{;6hO>DP4)x5g zehtquIGMGEKv$rYDf?r<$`o7k+7Lib;!l8<_spo?mojai`aKi($5V5`_e|Zu_d}C& zLHkTzdV0>;3pMI^*o+UgFC!+QBTcL2g`Z#{#USo*>ANlZE7?5nWMjg+CzaiL zHk&ZoXU^i-!a4xf-V6m27xFUFAw{1Sih+(`S2bW>8ae8F^rX8d-jZKV>)+G-+W(ZLzX}9o^E4nVrwGZc(T3M; zv89D-3SEnFP^=BF$NOl8d0HsXbXW!!x*wSthu@C0Ay&wppZq88vSnWENt9+gO6Mm> zvIqV&LVQ*gfe^>hE(mebpGAm2umwMf5Kj!FdjmM}#97>k;z!7O6?_WT+L^P)I(@Z9 zo&>?fwk1DpFS^*wnBBKHKu|u}q`p!~=#+G<)YyVQzAfAH0m_XqI(~dzHlqn{vHS63 zf$4v@AK8raKV>rp?);RU7?}Sl+c0qFr|iMN{0lbV5LWg#VBpT7-Dk13j~xBo7nsl1 zyKw6gIYaobm3K*2)fK5`mSsltca;+%5KMRUcdQN~;T?8b zdLpkwR(plLH{uqTSlu6);?T@M%Z>K(M*)yjEZHWx>a@ISjHh_z^&FBrK3F z5HNp-rTvME5}Mjb=h25InBRm54$?T_T73u1DE$btaxQqmkuc;?2Y{TEPWQZ^{M7Jq zMPnA4KxmScSL8>>RunSIi&b5D@&6OVBOh0}mk)2xFc)d(}Sc31fC~=VR+qW&?szfZEQ>0!lufPys=RnFhWnEbAzwnzSX@G@q}SQh%xj`2fR0OK?t+K_W>NDyq{I}VaP5lgbaU5mDb-XN*N>p96@VLNgA3+q~YpuSM3daKM1+ue$59y0x=o| zf5y?#zHA8kxq%M@-_3EqixLu@FYGh$8u7yon_rXKsigv=H&6b=b+vS_W;5YY>XT*I zH1AU8pj#fos~Xo)daWBN4W37tv%B?!T!N9DXY=Q^_Fo2>CkIid0_SiNuh(3jr3$yb zlVxbt(kR9f{7`VfNn+n+#a(@Yj{+ad!QLY|W}XOU8My!He!AsB6=}u>bZ8_9V(n7W zh;WcNQX({B&8@&euJ4jHm4lbz3;5DWR53VN*U~Zn!%tm+3y#9DK>8WH*4YzeMMQBB z(~!D2zys?K5XwI>S7{v--bS=l`sX5^_=4zXu6bn|(b+Kb13oE}&&7^uei}=m*DHU^ zEG^=~SY}6_E=S6jZTs~LWtWxTDfTjC1^%U^&JgqEogp)62VCGCcwjHK7;t|VHGyG( zwNH%0ihzR>awqM;_W>&)-5XjzU)jtCqt|?BDt2;Zy=N!hHK+)eNVXQ?mo{4$0!~U? zbXfZLQ>rfG?7FpZG`@zvbn9`%S`}ZowdOW{#@yPnke_RA&8Xt%@>^%Tz|W<()}S;M zuEXvp!xZKD-(Bv1$2-0Y*S)EC^Kxp>*-G&hz`a8L`ed*VI>DPV!>t}e4 zM&x>?B7>_=1EyXXaOc-s?tD=`#*!6SRpeoI)ibW*GN)&1MX2#9;q8TcoaJL4cT+IRVboFa z%0Kv3!3&CYCY(u7>iU;(Ci7IYY(j=>Yj<`Q>P@(=g0solIm1tU!zNTsMk3a!@2cP@V4f zGl4yP@j@~1G-x}3O#?7rWtlF_e6X&N&L;1@gYIwH$P|RPJFE25e9&&%=1y%|Y$00l z&nnj8gPl4;x)nI%4uO!|14ZkR=Cj+fCqt7ZZ_>7?b=g+O|F{ORg4}_6Ge);{uub zFX86(e@Ui*q3Sp{?Ky&Tih0Se`=witbJZU9az7)K5H!|-vf1#*yU>$dan7uNfI`Se zCdp+Yo;nK$=*K1dzOrh|rEuVCTmR;-uDL~gp!^%!47Pg3mhk?a!Bc|$+FzIbTV?^U ze!Ek+1Rg6*e*f#5w@z>M7}sSuCrLlQmF1NZR6&W)A%Ui2i1O{Uh)x6u=rtdOC<^s*imyIfUi1dzLO+K zpa^8GM6F+>6oXI~jL+s~BDa{^lOFg$`qU6;?0dGr0OV}?q-yu`_WHmgTe9Z(5p_i5 z4iM`Z9M?yIkIa06+@*(kN=dm6^a$&-GPOAtCG{r$srZQ&<15<|U=9(Hkt{8Dw8 z`D2Oj6xhFP!l#w06`Xn~Shv68W|$)xHK{v3tvn?!-JkZ3o*JDlDPQTsMO#soWd5r0 zc#!!Qy8&A7S)j#gdDfjimcEP5de?5#UW)X*d4I&v_3v=o)QhaBb6l7L2hcr#(+B)=*g8N58IP14ZPa;!mWD51j4# z<$Tw*&K}ZbPnG*eHsWaixaOpu;vdrk_$|+pV)7@Ha1Mi7DPPIvX! zzW4oC(8_*$MQwXMA_$Z+`2KME{k{E9_jhgZwp9x7+SKBe^e)Bo&hUA%NeLwn6F!Mk z#&+`8ekXI)$$!4MlbXMhkTiF993RCI*dGs=MGuF7r$U-4I z%j|DFT=JK>XHK-98)nY6elVJws0`m1?uoXA*JnYpMQe}f^Yy2JY_#^Mo*UlhxpsLz z+^vkt;fbOGk{Qm9M&6;(pA#S9{Gc!+yz1XcMr+kl^&Dq;0hS(!5Q^+qZc(mVl&4}9 zxDXhqp+6UK0>0zmyJn<&;m}I;ER&!JS9uxXF5FY~4g2AEzcw}9A3~VThq5bx-m{gf z0=}Y)8GK{gA7>t&Z0^i=TC)?=@6`)0xDEbwq?@wtqmxy)%2j>UwxwKCgH?x1Pj_{t9=MFJ7RbeFSzSZUl=V}owPO5~^|Sbm zkB$DMlh+kjnbmeRv{dInv36Jj3Zdj8w6YiOL3h6WKS5-;ug5Ma#{RCzHm%5C%P6~v zvi*|}wQ`80a|dxxu1l=$ zB!wgqG;n`nwfbklO3RRgV1D0y<&u3rwynvf% z@gw+3x9J?SQe!N~dq&kA6Z;b@$I_DiC035-=~oAs>w?0>$^sHvB#D)I>8>PJ=BJB# zbB85XP9mX}Py7@8#6#IoZR)pQ+xj-uR^!(;^3T>5@@r$uWt>=KYYPn3MrOLUKhrmL z;?MPM6t&R-r!QDlJTTacyZ6byeX_Q6-!QGoII)L6OL|_XpMHC)$>|$bHN}UblGbU1 zKltzLRyo0u(}O3$(XU;g6Z%cX5h+~swGVMk#NC|#{?~bfUkgA!sI>1>U-g?+o%U4q zo1KWxt^c9UBEMPn-v3Ztaevyw3UFU8q#5(_82+N&nT3+V+HpMNt8>}mOv zTG>l+#V{J&uG+6YGat?i3>tVR827IW@=bWvYc%1U9Z`|zoXx8UJ7>pLjBw6Qt;lW` zFTng*t1sM)Gdu2kA zud4B0KBvBl?8Zqvx%H)t#I@r|)MxOle;7{M&PNZ2SKUTmL7(**Aau7rX#a-z`_LFV zR_fO0@a)yg$wz5&b1809TO`ph&UK6P%#SrRxBg*z<h?D0JW~FDByWd5pkPJz4gm<*aqV>1X;{*{ z&)qR$gM6Nc#ASiq?*OKHEd=eX{AQ4>FVF6@8>1^o&u7#E=Uo-nhPs=b#j{CwF?zUdj&DhkBml{ttGqk_5ef( zR>ihHzk1|5cp7|`nqjO{t$(Ecvl<*aR$(D~!P}GTR0V38aJcuBGQHWkEJvCBol0J@ zk*+Q54!{Y>L2X=Q4jrdV|7KN%kFjJSZIo+U2abC6_Dio`qb*Io_7is9-U)nMuflG< z03|PhLjXGcRex+lsKP!8UkrfUY0?JBGCt((_KII^5<4c~Blaoh?J(A*JwcJPIov_} zL-CxQ6V?TDo0kHi)OAjO4jIoVL;B~b5jzXl^W4OM6<5PRr>) zTQmWBOCaebhfQ=0sr0FYXkKK7Jb zuVVhUrb8|<`TS}aV$mPx>&1fJ_$8vW?HIqZic!F`BBxRN${r!95sktO_7rp1>1O2CzW|bO z`g2wF95S?d@$RX4@H4dSQekzC230~E@1YD3uvZ^sT_@^iktr0$g)UJaBq7Y!ULWF# zPb|}ujO6M&?Ol(Fcbf!ICdC3G*84{SSJqSQNuk#ZS-SEsD>H{@0Iu1hA-b^|WKI|+ z+>-qMS6G-kRiFEuw5+_~SAj(Guavz-)9F6A342?r%t+ovCeMXDyU#77aB?a+;U@Dd zKoM?o4%(k5UgZZi)q^i_NUk-9lquJ6fMeos)|9j%t9Tec$TkFegZEf)P&w1ezw(y6 zDi#}G+}nD5WNn++Y%am&xUg}D%RtW|H9}WNo`Ip%b6VYDI88$mPO(@XqG^3Q9iz9O zYgCmlaK-kyYQ6HE)ab1g@Zr4GNlDF{7PKt5nvb7zV{6PxA3B?-{M0Vtbuns4D~Y^f z;?H!QaAOTcW~CMYkxkypF2&1H>==4)CA*T}ngPhLvm(f6(BW7!-~1V8YcUMBwY37! zn%EvikQoN^4yBig`13s=V~dUo*-$m=mK%zZ4*$LPcFnZBox@SVZp z=d^*pjWz#AQU^L@&P(H`^_^UFo)8UwxI?7mnKxVCLu`fE4CZWGn&AWsuLld1S%JPt zN8o(jz7@Bec|)e;HELnS;q&;>I$Aw4dVa;Vcu>wWM-RV~`fRj^pniI~8o^DL`5jM} zIcLXI4dd}V+wwO6R>8l&JOx9!RS_1lX}7vQ8c@p)JD`qK_6`jQ#>X9p-?I*VkJPo; z0+ufj!APvx7Fc*-E>@S@Pal5A4*Dq@$M_7YjUc=u(DmH1!!LfQVRmD5o5FDYMqC9* zn^nS5pJydbwC5hI|^hN@01gWwXoADCfmXCI`-IUL)*TD{0+p z1*&lStUR0UzZBT-<}}U(SD=&$z!r3-vguT2hV!zOa^U9HR6S#6tj~3`DrPt@YvX6d zqctyU)nrwCncK{xUo^27Ak-NOh@%i3l9934T^4E<4b1~ViJvhmg+kom`qYS;DpYCf z{t*h;1lPlR=T7!8wZww|3bX^OeoS)<_rNeihAo}n!c*dreqUC)W9T1Ajr>N zZ|V+nwYQ>|(CcDf!Rem{ys^=fGsj%X*I_)OD2K#UnkR=(^w2f4R{IDD+MUAfxavUU zjPr*qr>Ze4{w1?gc%`=W@97`72L411rbwm9(M4>a1#+S8f9KbN;dbPp_oEqX+ETOf zCtaCV@Rx;wFP3##stngOD+iN6=6RAdgA#RL; zH(KAxLL(U4GeA1{VkFnz_=mt!}xLHLun(DD+AZ;n-I z{gfj78@(WR-phNP*bz|KH15>9Oc6>fPm&lGZvFaqkyy zk_yL@WHR>0_58g5yi3okaJ>!EHzk|pCooGuI4n)^?h>ZJMJyC4-9GVGo8cKqp)zqXWb(Yxhu_?UuEB$yV8vN$J5C)U;oK;GA;2qkWQxMA!*^sNLum* zAhhr-7|)hcZ+$L3J^YZ=`xxl+gIEJ`!+V%tzxW0n!hOhH-2v(6AZ<{;PVv@8f`1Wp zhXuIlF?aR&Z%N|w%-ki_B`HlHAW||on0%Au$ibR$cK%5r$Zwb=nKVcrp1Gtcc<=Zk zBDu?yoVE{pO*QryJ>h0#lz@>?JkJViH!nQr0~5iknSIO`VX!}|#LUlB9!nKbhqSM4 zvco17+}9gCu`^wnGl5{a3tHb&yq#=JwPGMqe zpq_A2j7NZb@w>?B{(O3;9>u$}?>T2q0Z&I;a zwb6~QiTXrT!_L!u8Bc$?TT~Zvj_1C`@8JFM^_xKb+#l_IG-rr-6(<_T=W0uz#(EkX zSaHdO3gh(xPt>Opj&QsF;nCwp1q8@7tM36%JG)j_@RM1A8;~*b`IHNz^0LRcAp7>Y zgp3Pgix_B0E>m@}kim;tL3vsKW_=Amu&gx6F)613{l8T6;ig*Ax262*T*jkX@-Ent zc$h)e62CETfvIrbS|*K16q9J}Z%>KmKC4V_u+;kc@2Qs6`Z}@Np8V7gBbOsQv08Tl z{WI&;n7pH`w#QAYe@=RnpuFc20%Ns32$P2k>9hrl_1K*2)hj=M$;2C6#jS(vT)8#5 z?oGfPm&=>))Kd9sk+sg=N$f~7!|8Qbi)0Y{7mEt-!Q|k4%)Ie}`Is~`AH-YA7`*!F zjLmg+)jy!F$1h(RdT0VPetGh*(beV4p&%w^fbd1deKUd{vtyyP@;(7sf zX()cxL!l@1@lAfwHT9dxPfZ9nwR*vS?fwzIy~~p$dABsway;;mE?eb(nPd;~#X0pe z>=)KA;gp|gnAM*%lulQBm_ln-U9U>%+VrR`K|HA+>lPPovVG|~yA+kLEbW%rx%esm zxxT5F#trfmm>4QbFdF3e2TGHd&jxVolqDWk!NlJzjuvHA-G|3TLLC(qEDh1$`)$v1 zkeB4qk$ek^*?t~gRnZ9w#V;>S=YQGHM^ZIDNJn+kobJ~jZZ66q+}3kWlSUP^fUdN4 z^)2=RowYf*re61~nkGv!hU+ee#1N35qtuC zUb0^dPUPzhHUkeop@+uU9>4pbh0L1zF3P2bx7%N)v0m`exVVa!yY&K1vXQcIv4F># zdR<*7{)%mojQtmX2VBgsvG{4u(0-7n9P?k5n^K?uGE{J zTblgh7hom%>&UJvUnL|lMY&QGA<9_)HeD{g>4o!3lXrbpV42`FSw=y)u8>)6w-X&S z^|sg##<2Y<%wl_st2kruUno~m#p=hY3(0@=-#JYd>r{+;=x(TVzoqiz^RM^!Uyz~N zl24Mygbc2yskH15E4*Mhxw)9?RK(Dli#I8dbTF=DPbGy?qR~vN||EUZS}YC zSlAzKYPd~P=iNPGrWafj=mzZw>YT-7FWf{2kY)Eq`<755#T)WP0l(WIG*C-Pe3rAupwp8CPT=O#l z%#FR2rWY~p^X|)n;K$=ya~sSzTO0!6rPi}qf&F+)s@gS^*iNr=7^bK22V(&JE+*vh zuW0siPb{^~Xi4a@vovFVa+|oNmPrPa(@x;GB-8)7vb7NN+wH1nB@P{LT9d!L;gf5U z^*ArQox=-vPqAK3OZ@D{KaYNV)0oHM-1oo?YwG5S%X$x~@RNJIg5PpbWuzwJ@51R1 z#y^XTDR0sBO{J9ba$4|SrGWOm8|8qBI#H%->fzN+NnlhoT?Dr>p}{g-qizj1RpkWw zxFI(U58$?`t2zg-l6leAs>@AlY9#)Ei4seIu{Jyh66Gj2aNZ66vY2j18a3j22%f2YLqDn2u1S`eEUa}QfM!7>4TxzB^G3!~G5=(ElaM$NZA3%zl@=O~-_ zkYhEWsv5OKtYdkg6i(9O*E>5^G%J4P601=wM!4%uP(#ylDn=yg^r#k`ooX!uE<@cv z@e6`tKL3FyZ;LRAnTC6#irb`Gj7#^tcqlPUJfYN=Q8A8(6UDG1>8qdjc{Gm0bw8xz zXiR2Wj;v6iNh(GhqlGb?_3v=!=O=QkN{CbijdXU1<#IHlz1pSPt(0Cnyi zNbekXEfTsrdBweAglqIE)w+&AW~PO{DD~@G3pas?R-c9R#>cSd2u#FF4X>KRU~mQ+ zu0stDG2q|i<-E%L6C-zT?R)5xe)W#p+Vz5=~Bl$5q$HnVZa3)#|(P-s+ zgKys8&A?=ajHgQ7>G?&qdo*fnQb}v<9hLvh*fmA3I83U&owl*xKvzFj;3_JtTO67) zGryw53`em$KGGeQn%4Lgz;)uwjKxwo4|8ax`*XuW*6BW=YdWWds})b{a1Xu1y0HjV z(`dNz-~B$(^z_<5zW^k~254j&SJxk+W+{1)snre1X53(A$vdea*9bqcq*i&pb`xI#mSJrc91s z>DjF`@cK=riWkOqq3%_rD!aBkqDm`<@6ghdGtqfVGnbrE|L^we418RctS5+C|2Ex& zIMdUYE=#$UdUcgFHc}u#c98f4u!VRx4TWtVBL4WJ zK3p13>5Rs$wO!ijMfLq)R{Xnl{S{x7yIJg?oL!C}l37s@Znlfq#}g#(W_@BdO3zY7 z#;&I{n97pp|IUJd5QTOBoe>+mUZ?DGa+refs$Y^dgniO8`u(69EOT~StQ0SCc0NG; zneiFE?8tfHN-Hr+K5{eYFpXt$63z?Pq~%A>W}ZeQoRedyoqq|Zn+zsC!+bx;Ha8=} zFU}5`Ef&5nCS30xI_}!t!f}1e#Fo@#IuNe2TiM@VyBsYU_SRg0nx5mbWdBd?*iPsm z#zhFK+1#dYx{hAesY?9udv@*FstFP4qvQ@h7lti7Li7%c@$?B>kfXRz{qUyp7sVgK z(@e38iK8|Z@nL|fmq3#jeVr?|)61xs6ZI^!0)0bdCmJNK2knYfRLG>#`#g(FU1A0> zLBq`M@oM38#aQlTV>q2iL4%o9Th%gs5-FB9!4lJ{zx5|9(vFZ+O?;7H4)Ia&#a205 z$cpoFLtE-KKklV>d$xrO>QAp;Z}kfnrC#!Zc29wiPWy)!`)k$T z)5i80;MBHiU%IyII6(3DoIj%InQ+56t@W*TBiyDtA3(aLf2&63FU0;WqSk3xAolFy z?cb`oK_C4&)&-u+)QNngrFO3}YAxw3|AoO%n9acalj~o&*{HT9`*e7r{Dv;DJyyj- zFt@;hL6dIQ4Xvz&>#t!g^paBn)aTHIzc8lw3*t)SsmI3ALbU$Eih^K-7C!u+`Gbq- zRJwHRPn2fb`nRgyvgAAC_@W(r>DFmnP&*e^Eis&3Uj7=?6446v9GyVsX?4Tj049L# z`<+1>)u1c-QPmP3ii3+ItF*j-t5AOOZCFVIM_{fK%|c7UCoc9)2~}SYxuf=v61r_J z2D*!}%PoptiuYRER;>kqkY2H4JCc>E_fa>_Kf-k`O9x^hTvwxq-IgS%pj}OpvBLve zrJkeX67!OK>517ogO_;x+#q6uTL%Ie`#5D}^>njAFv4GmjXylppOKZ_sWE1Q|K*es z)p^DOlRmHGKDI8aC_19@qjZhd1Sc#0HQ##2Nrn=2k5H+!wQ!uBu&073kc35pqB6`X zTO$0TBOa3`mTPjRKZ|H?#&2SS+mpR|yk~S%*7?((IbwjevhN_T+EP~w2&HGj6=mtwLj{2%o(>#3x%CA}nz7#{299TJFtP!cD_=h%c6!@BOj{ zMU3>PT(X9~?#Zg!y+fQgKP%P9TNIYlTr+CG0XOw_eFL^n(=gTso;-Jmf#$cjgM0#n z%Da-Tt5X`Kg@QF92bbClewFKhxso#fbh;p6S-Yl-h3Wa`G zRum&L!W1tN_Ki0>&4OGoekDU64ba4+WAtCA7F7}JsF}>>&I8VNZolR%!H~wWirBXvJQ7s;mDDS2oja znRQ&7l3WtGVyewJf@y4TcS#o~_7Xv0)=SNdc{hhk?@l&TaIq=A7TR;WG~gDyem|Ou z3+VSRR83Ry7@8N$j-2)6Xr?AG6I0gPWfJjAq`7n9rWqrH6kJR}AVUw3{Oyg}qLu$< zS#$!wM7Yom0yxexA59?%np zLPrP}ZP4TJNgQPG=GO?4OIi^7CWL%5()_Dm^gIXiXCF2eY5DR!hk}8;L($h(jCAku zjupW!s!S1UD%*FDz3m7`_?&+|9+>m5$D;cwGpFttSHfWB`-9|Fc-xids58*b#Rhxz zKQ5egapCi}upul;>=+!O5lEEX;5CEQ1==gF=?_rXvt!lmuBoeOFSqi{iD}xNi9(EK zoNu>q7Jgov3>}DlT|GN_T;VQkX)2^{B#+_-5eK>ET_s~jiRzFM-j-W^3(>*7;!!Nb z$XT=Si1mNrObutO2%1d9rQ0&t=-9gykCNWPdqi5t)Xpqyi5|v>Eq#iIBVi*ZjYZQhO6x_J4I}!rK9F2N7*99 zvnWJl@Au3?b)eC{4V8jjOmKKjW|TEr@~>Fb2Bqz&?g$mbaEDERW8Hg|uK7`aWxe`Ge~< z+;rA_#M_$&`fCoF#M02=9?L-DvdRwrIz76JF4di0@s_k-;+;4kWL#n~0k*I4+AP>L z-FAgIvq!~4`a5Pr-r_nr8#Tk~np6e8&CJ^%NV)y-7y9GR_s3rX**DXe|q#Ffu>X=#EuDPHh81^r- z5LgD7wMrdj?pSaqzT{@+BS6SV%(S?O=I-+x8Nv+lOB02sG*qufH6?0h!J!loilTFa zmG7j+W2yEcQOCn|otFwSd4Ocizv>a|*%uG`YQ?->|4Z^Fo}Thpu=@Mho5VvtC@edq ztba=j@L$rW7O9Ki28;p2_r>jSsD#AkLKF(dlU|cu1h8F6Yi|LDBeav@x-B&4?6l}CT=(AudPn`q zR)>cG=6Cw+Lo5bD2v7;%PT8UfufBDlhZcY+;^j^Es|d6ghnpLwKa1=u+`RH68#T}& zPb6#g7_}c)?q_Z!e_~#4;V42R{dqA8Y*qf8A>bLBv1N2X43ZeC@&hx*&MnEkk$6eN zQE^K++A;d)IAzebX%wC=0Ko$MO;!J`=V+q|Hyt%Qd)Y1uYyug01wrYu zxbPo7UUX?U)LE(@&s)|^7t0Ct@XYG##OvMtFa$7;Js5v}@)k8f6kV;!oN2Xt zwDoC7n5wh#=gcuWr&Y-*JJs9pI$1+-LRX#gwv3-d!IEz8i5~#~H;zZvV{m-c#qheL zz{7Mb`RKpG!iS-IMhsp04A=2_{)(Y{Gh642{c++E$GaI-th;}kMG+;Z zvJ3NB4T->^z#f!nR$cQExX3gKknvI{zhj9*ILuc z_qH$uFNGHP5n+VBgG*JG$|BrW&8~cX$yQyj^}2H}iOl$Sxsy4Kw=&hvF8jBIziI0- zXD`p5Gv{-v>+WkU2Uo>ASedSKfWHu36Vvu%&ZP8HyRB}-8YfOh!kNKe8scey1cZw_ zK*jy%&r#am8%l-RSLKgm?^#?Dzt8V8DrwmoqZcgH5X+Ktk*N-IcqXO?)odg9wMPnILN{)zFv?P$|mTV#N(WYXI5r${#E(f5Q$a!vJ%!m9z`$cA3%$~7H)V2gy64M zB0&oa{ey+O8g*_1xqewdb%baMlueN3&Q4Kl+)J1x2~d|!QEFI1Jl6~}3?t1a?qsEv^TW7_H*P{yZB}aRvF^u;w#~@DUSAT)m8q%3Jll{Dx-g?D~66+E)|*f zh1i}Im-b__65n+q`5&5K9m%pI&^a<)XmQ=&NnM% zQR@~Ln3XcNcZp;ijCgO_ST-RtVaU z7Fo9*1I5$+5Aq3SC?l08sE$uyCB#2FC7u^A;3!%&?*xY)y-BvPH~U{=dbtyyhTZ?6vi^7hmvt6B)+*|+a=sG+s42`}mRP64;z zmd~I^oqZEz6HZ=M;KQskyHP)-$uBWcaQAidM|mmwak$~TEQt#T$oP;iP zz@v;fH%)W&Puh`O2F9S{{gWD#-{$d)YKiIJxTND1o>)FKzb0q+*G5)l^|jWVrK_9O z)qQN*zK+kqat^HthLOeJKcy-!{`GLvNZhaZ zDIUZX-EUKd6yqOB&R~($ax`46&MMbDB5MydJ3Y5oUec)kq_VPb;*`Gz z3NBO=93EUd63G8=;l3?k;b`H$V`lVxxZx$x_(hH!(klk|6E-Oxs%etZIMm4lOu>?R zEmH`$!2I&3&NQ`k?&>S@M5=Lf{S>h` zy8TPq>;v{G__A}ShmxOFlif?Fw!Rlif?`lMWTA$l?bSCeotg{|WCW*753RUu=>y4+ zv^MY5TBcyMqiV|12U6q6|26scQ(N+VzU}x#$uM~@DX&8xzZF{K-Wj^jh5)kiHi7@4 z84$ip;n4(3llyYBG9LOSmoU#7!AiQmjjSQ-R~=}X8Oco0YnfX=3#n)_wp}va4`ym( zjKTPLQ0nI6kI+N*vXN1ie3+WpOBU|=Fbxy%JNo)Qw6Ug_8`JSCgSQ_*gsDan;^!6S5?bLSDv z(hg&we)XdJ1A8uZ8RU;QA6z*VGbih!SKLeDslpk+pAu#-dBYWN#?0zl9KnW1MlksU zx~YLaQ6a~0UpoLm;U`VdPBf`9%DItpV`w+$hukw=Rkv^1$ioLyBb&!iVn+{)5NA#8 z&U-6%)Q}N582KIdoJFng49EM*lFlvUfv%Rc+6OF7+HuUpATDT6IKHlbc{VX&7VfF- zw+I!7RIu<#)0snfxjiwQ2CVA-%WCEDJMfX^yAgj+a^HA2rR|dcXTLdYSP$0rYhzW7 z#D?eo*0aOC;5GMApA2ka33S|_PBUKOdokjCJRL{5*Lo+ZV!jR$uk5@x6RxY+i^Oze zW;u_Uy%Ct$;W~2mFlL3M%mMfz01SD!!&PFKO{CutZX?``N)0cDH;Xp2FWKfD#Njwo zJ<0nnlYa^;LYB=kBzJtq>Hr_)EW-wo3{@IMTAEy7XBEtZWDN)}#b36Jzn^%16pkMwKvCbmTImJML? zy*sgRCHCqmcOfxk;rv+6#trgF*>8etq1Lkq>Cj$%2{Er*Dak1iL%ZQn<=f^p=RDlZ zu5&kh9C!_;>7D(D&kcHD3$MG1omqRXZ$%a->dX4^W@SPQU=-#D2X4dQ`zhA$nX}nV z{orVbrHB6!T5`cDVa`}DH2x{)+z4Ob8m>zKYjHbHNz>;93FglW{@6?)Ry(dB-p(}b zT|IQjyvgyKLl__ha65b+w46c;#S^aa2Yqvo00g!dsbYxPOxzWe^mqkXSp8n*P0uv1 ziRs;|3Jq+?UMjCWFV}8-Rh4!DH&SEAD_ttvD~3s@m`f-EFgyi44bC&KY@Bu&enK}L zb~B@|ha02`D6m73eE4N(EKom=HuWQ>Z?8bvk&@l!1W`tYR~>puLR_Vj3TkQvOyZW~keo^bQ)GAzX5p{&!5;s{&o^t6GrY}5w~)PHZ?OtP;7 zhkV2Es_w{nR$pEJic-+4IdtZYCK{`GnMPI|#)=yg?kl71E5;$H{T$qqj}*g~J)W8p zZL7ZQ!i;gzb~w1*WTi`7?eveSx)f68&|yugBpJO_ElO=-3w{fb7wEP}1bUsQ3$%>! z%S?o*JG`8=M4Do~L!3`tX>JBy-#!WX)(Z#{Rt=Ir6XE6%GKWMrDxBVEfzn^r%R zRn3{sx#a60L2E9(`O;dEESQlE67&0;guz%VCw+`H)kbn zd;$W0F$96vfIxw1)tc1!H4Wz&{=up-{_w8>ej5HIcKGI8Duid)K1P3*2;ckE*KXC{ zOQ^E+*t@UT?+?5Elf!PWy2`GP)Tnf&!<+1|vmzfdVog+Ua?yV<>~6E)Y0q@J81_N7 zziEf2&!{0?x9_p|ce5GrWB-+?UyQI&E8%AJNSO0z?0C2#TfBn>CwKBeVSh=^Y*R&G zvXkt!^&3zo(QXg^@K)`#72|K!Cae6sxr8mI4aV;Jwb^s#gVwjRYR_qBRSvl@Ayit+ zz^QNd^TR{(N_O_deV}KAmf&HcMQ=m_vGPj_FxYAN4b8zj1Kk`I?hJ1ewr6){1)yD( zdPY&A_gB724R|@grZ{*fjxN$Aaq~0`|2TcfX1!5yg{c}Lo_x%mZfDI7{+A?^mAIZ0mQ{3e3-o#HtGy%dI-&yMd z#b3Z!x6>^PQtnB=+%x*A>P;6_036~43>E|>{aACi>@Z9|KQauKvu-R~9!?W+96F8k3h zTJ%#K{Ka1T8~R03znQ-{$RA_B+_%njWS&fyDKSNgH6E8T)oE=6kO&crEaay}ep zzMG%SdfI9MuwEA_@?iZR{FQw1a`o*+jxmcDbr*EZDg*1M z)X0Q=&gB^?&ppJl_w`jQ0YB+pgPA%CX6$yz`o|S;EP{!C&EM;xt@Uk)!ER$Kz^zgs zz;PIuPB;R$qHYsmS9TiPusOq~Bd%JhXM>@+Th(}J@*JHdgwQi&PqG=JbR><-pJGc? z&o)o1q&H*tMp(g5+UQyM>j*r#6>C{+g0@cPC(>Z;YP{g6$bKB<%-FiA*qs|B{P#g) z$Ln{YeCepAIokU3lkdR9E1y5{baE+30O=dL(hH!k@NrsIVh+B{$w-(Z4w_6HVlV@n z&_iwcxk_?|0-fg)f7bmZ@m4+~3`Daa-jTL$1;0#doRJS4_-@Yk5Fo%vgx9y5EwFT6&` z>abA$s~Le7l9^}~4mamHt-tpr5zc$gJiJ3?XY9DRuwOJYxMMCtyA@~#5yh|vHI)#$ zH8&O!2a!m0y|foym|JNEC^FmM2Zk0G#nWh!JKLsm+)bc@SvnspVs{}^ip^7UAKD`X zzRY6DhqvE}k~y&vowojEcX65Xsx#e^=ZSH#t>Vg)I56o(wX^m3h}J$pSDo!77pJn9 z2b`A0nDfr%;+J;CVZCm{6+np>m5ui^m$%?YBD{S%;eg>5fr8C+RwUjbg?kT-nZ6 z2sp%HRkU{-AZ3-^8kWbBPQOcy*!f*j{XAhAq25bQHq!+zhb80P-7oMGPbIGRFc025 zY{;JHfx)kN!e{JxB`?76BgoCd{784?sJrz^737BL8=S`Sy!Z>O!41!lZQ|qHtsCt_ zf%|j?55&Ub?|^&(Cczcq?Ux7MgeURz8ol1IS%0^R0j7J;5jw_{fC?MDV5948(pwvL zlQrf|U1sWJPYHK&bi(dqvMx`xBVcq$-Xb(ebd8q=Wkjf zgaxSnx73L6w#sX>*%H@c2O&6^rv*yKb}`r7Q`cbX1f)ov?H57kU))E~I2GKWselx^ z)@%^a?WMgv+)N0AcE6(mPvzJdGqyHxr%2ah2Vwz_J1RU7hMW70omEy4l@n3w`t;{@ z`n*`Kxh%xF;QLeMPXH`GJ2fr=ScB$*xr%PpstPxJi@(OMFibdBe9t_s$pf9A$szn{xYFyt{MPOzRf2=MMoUTa{tk8}{0OFrVU<|9G&8)tQn0 z`f#9wfW^qG)}pMCyGE5*dDV#@@&T-{$_<;4>NUW=xFNiK&VrMR&5Q-7gicO+)6jOA z!`=3fTe+dZt=O;$Y5YMB))XU0E{#8Hn|(tU`~@^$C+>>^=|^}I{&}mvxXu3PYkYWc;%}m_VXUH8 zoA5LZH=@m+N_1y~Hi6k%!Mo_es^R9~P90aqo`=*s+_b;Ut(J^sLnV}f_0wOngw=1S zJD6By$3tR;yXt9Wni(55xig+_u+Rv+3Op8`OsslZ1K{h7z;Dcqe|y25@!J>p-OTT1 zeqZAEC4L+EZ9Ji1QvRg+UaS1M#(*LN9!iaVr|05D$v%w19gBUKVCU_nuOU3vo#1;&@&7$994NV$Cv>l*z6Q|T1jCKRsZs5n&^2zYe_mCcL zx_ubMHl|Y+K(S5fl$H({J)P2xiIX6m63Ywpo=(B%l~Edf;yn2bJ}^sOaE=F9es>2t z=Jjt~#f#)uxrd3P<6~|jsGZN^2*}9C!Sj8|U%h+bF~E6Rds4Ua3-Ny*R}P)3zO^z( zY?)gZ()`56lwy@EB5GE*Dkkt?$h~XCSPPw;pT}nJ>bx=ipEsd^x_5d(VYHA zLl_}av^*JLAcFMXd|w57zAbsF*^3MsD`Lvb!^GeFORL}=yH0V*}pz#X% ztCY|b7jNyR&3T>oiN@hF@r(+8H*xHG!PZ#;(h96a?i_rbWvWLQI+t{0=K+Wd>QrWAxVdJM#j+ z@C_}lOdjW8cCqJ~OqjAAx*&yLw2MD5ojXbe2jrZ|%x7@2g5Cs^Iv|B&b9abBib!^2 zNglfbGZoR%`6n&5OyjRS+fz)?bRT0~+cmv3v)rr8p%AJoKU$>qrG&qH&F&D-YlCan zAg^Z-I9(u~e88@KT$xOVeJ~#zHtnwDYp3{%o{#gM>j5evo-O;K>-dFxUspFvPmdii zry}5VBG%1+tpfUMQNc!O&wP^mF7W9Mdm}$3HJi zY&F>MIj|vkhM(UTX^rlw3Zle!2LAF)Sn1KKlhvreC*i{rCmqJU!JY|jC$Ne@{^nvG z5X3s58}Y6y^Lg&KNTWyUh7x;sv733~U3wSoM$5Y7lno6MNhtRfawooOwMgaK^v)vO zlOC-64`fd8=jl|l`X9jgH=fXtMIPUXmM2O*??w++Th`4T5j1O8{0D6SsYp+N@M;A5 z+g{Wc-j4YYG)X(O#fQ=k?el^+M_;ebXI(?z5oxg(GbrRxiK;O;U`vgUCUA2pp39-s z7t_(BXi=(Y8tn&|PHUJbfh^p^0=QS^9?@HennVhd7 z{GbniUgiTxknJ=#LkAczrwfSCQ z=Gs>}Pt?3MJiM)IvDv>E47OO2F$qAK^WAWBc~*Ga$Ft2r%$k|j);}O6>VgqU;3edL zfdy!2=8Pa_hW(Oh`jVXm?l){+O6HlMo}omiN22WXQI10R7CMrN*=b8RLtv+q7~ z7vx2|!VM3zE${n;?#1B#%jaB)otlD<;kwu8yeTP=43Q1h2jAbzyF?0KC}ZUX_C<(* zl;oC+_E@(hsf>5c5BS6@%EVQtHsAK(Ftn(<&WE?%GYV%vZx3J0gfv5#urEPi;PbA& zh`i%Q&`*?@Y+D{6&QVFeon=cOwWSMjZ+n#Z(h5sCSiToE59b8(i{9l=YV$6DRtNW_`_mC(yvx%E; zj&$3WtQl6ir9MUx*mF^RS{%Xehnv5{>}CF`PvnpGk3Q<*8p3xYuy?ZE=&4-mi<$^P zOK(^{%`=wa82FDzbaC?#yw!b!pt77bi=Qv>4<`+Ih%;O{P5T^exV5L?FPqvVf5T0) zKVyC-$M~r3@&5X*v*o5qdZYnl-?PAqzW!D0$l7V6*Tl%%4XiSfZ=jKY^LF>a_O z8tZ*uGO7pPP3~3()*-LD55kH+~TW!rI1Druk1I@v3tmx=M8cA+jhreyNO zmYS;bIM1Dgmw_8g#@$#lA#(OcZuwY(aaMG@Rh_0}oH^I^!KGD4TYsNzf|;fxP*vc( z)z|t~7z*yvj)c=oBl-ty-I4=qXMLsyHOwDKM52-UEl@okhqR39+Tx4)w@FjMtWzfm z&ub$LL^>l2PL}$kgT4oGoQmw9R~~4SE-8553zp(P>@5yXi9_@KW>w)uV~yp~J}NcP z5R?1klltR@C>0*Z1j4F$=i#&Pe;_qaw=dmn8{D9zvwvFwnlSy_PST_P_>unj)c#4C zreuQsJ6?Zdx&842xWNxM6@CV#RGcc}`S3X6Vl=*aItI`1=e9Sh!r5C%H?cX0jTte` ziH)7$<)E^h4@@#k^0@nEB9gHaqDhN&3j^t9Zeo+oj5WQe!4A%wJTs&tQ%t9cV;^V* z2yXJF<-f@;1Pr*`MvXXwt4V2cJB0v|_h8E)W%1ZipR%y)b%x}3B?TykC1O$s$S5-_ zwQwS_@g_bsTMEtPt$oA1moXNUO1T$YsRgl8tBEpRu-2L>&5~^6SP*RP{j^3MUaQ59 zmWNq5$Lx{77|X<`RlgiY$HsZVd$IH;KA(npbfYzID&%LE{6Y1FaV0CB@WNwQSGn=2 zzP)CDymU#c{Gkip+13~OO0|-7XqSr&Ucw0jfu580ih-3=h0wJSgD5cSShMJqDJT61 zUV~?WXbQoL2)4%J8av#~DF*}WLWjX1XTkvsoyuwQiwh4xIAw?39K6hP496F(~a-)4Dj4*)6SfAO2E-MYE2KoklYmlxOaVHN^DN`!pBX;N+g`) z+{%@lCo@DI;d8b_>Q^svny9ds7gg9`l;y{nsg66z0r3>!`qy@`o5B>sy@Fq}SMX)6 z<2RzQIhD^EW)UBM+u?lVqSDb~wjHN$cwl#aPdjkX{GJil5|6!MP(MuI$&xovRYN!%T%I!2E>nB;KYste+8mACV3cN`H$`TJ;JhwPFeVF zB;izz-O%xMEHX2FDT^EvbNp1?KcJH2vogA3e}35-_#l3@VP>X9AfLGi=i?u)cR z0^7ikt>?qeJ9Lp)iz>uz4<)}n0Zn*TDod&ixrHWvl7~tEVqS}MIykqZ<8Ekim+s~TT2wHF> zU}xV52iJRabAZ+Mrq|@NaTBR;aPK+_t0BFKwRJ7t-a6%}8Bi>nyd`MCJMQB2*>;O~caNPX`V~-~o1VxrOzPUuR-C zzW6Fj6(@MC>s^G&XoYuj20JP)eI*deq1K*D3R~X`cJ-j`=)CL$BkRnYLir1iw7wI> z18(3=V5{)jC7u4H%E_=Qohnz_I3FI4OypDJ!p8_5owLl#xrN&ZC{sr3`CwraY=pHC zVR#302>w+2L#cOdN-L6-MQ84&mBNQU-ZBdd+#ClfZNGijZ;=^#vBPI(T7+U^v*6PE z7)&9;li`LM*hlwyn{_R>^N8 zNKT{Eh=-dVh{yM3K7^%u240`^@zSY*bQ(_$V6ozN{r4va-XHhV$$|7SKRtlgij#g? zdlbBfY9G$3k8x`<#is(2Eo)voL6-IrxiHVFTL-zG2T-A&RVVo;^_<@GNj)F)^WW98 z`azlFJjZf%8^n7GDqg+ex;KO-38h|r1lsX>0s--Jt%Yz=zJ>nR3!o6M0+WWD@8I@v z%#^a+KY{F#Cl5hXBcZuWl#hx#>@a<(lHBW$+6Ox60~bPpbf=&8p~Nc4vDp6*3uIb{ z9l@UaSoPEP`lHbfn5J{Zj*RC{|M}ejRBNl&)L>v2OJ4f-e-7(0CN^Ha9fE6E3>*h$ z(i+@{atseq%>!CW3O-@g8zVyYXyvhGK92E^BNJtg`$nBqLSbx$T)xh3N!wkc3Ze0-#>VmJkc0))iI zqyvN;r$QTP-cGB%k%3po+m&=-jF4}Su|Yz{n+4-PvHblYA>(Gb@iCmEe=bVMnE%&N zLNt$#J>5GaKNPVFklh7i+>%hVvuc+4U(CG^cvaPz=$&v*;D`rKw5g36HEm;uPMG^) zNn32NO@ISYiN-$xYK=O#n$eEV)yh%C1c-+aHk*x13oZ6S;m(6IOox8bE0&;0&H;vm zfEt9+v&jiY%jluWI8hl1m?ro4zH6WS0a|CC=YG%giBHbjYp=cjzUy7@`>yxTe&-cI z%yih9`g04SllU5-!CTR2L5GX25kP5jD89x-Z%Ok@thuOV<`-+#H3y=#lSW1E^OiI+ z_q;_53oL;=**kgZ`$RjZk)>*J#_gXIEeNdgh3IWARKsTTMnF4 zjvTc6Q-5&?He(+S-z&h!sW;x`sXQ>b9YX#3=cJf%$!b@2Iy+=Otw?v>o}hfnmfl_R z72n?GX%K@@_MN`zxD3MqTZ2rvHSLt$Ak$_|>xFCtpo|y(r42$mIxn9(izN7&Q;<|* z_a1Z>uBqEE)8YI?`lZU{?1V*Qn&IL?6WX$OFkPF`3w6u!dt6w^9s9i3Od5kl+W1Bi&gx;BPZkw zY5y2niOkwD$i1=A*dHk4gC?LO_HWckc&CibcX~yM5dgd-bCF84iU8nS)&sHBYnn7X z)dMZ5-8?pKk`6u4o%#(ANLIM9|I~T_?l~N0(45xQs>oTbpmk52r2;?-KX9U^fEc__@fLW!FxS;OqVyA;NsHQm9Gz9qFd{ z8S+m-)rliG`oM|)_yZ?IKyZ<8T-b4?g#=3$Tm`pw5*AaqKsmw^gRQ3}1o)5mX9{4= z8LFQrCCfV-`B7ce-((B8e789)N=zB{F9fOx-Slu}$615@nHVe7wmtNb z4oK|FbGG`HOaR^S3S~5%fd%kOIIi%T)v%%$Dx&a$5cyz=Ybt6hIv-t z0x?X3$U;O6lc=y8REnWun4^ecplfhDBeIy%3Je)l7W2Q}pz%sH)pBixEZ_*!S_5BZ zy>-oWXJ2*4kU(Z&hpZX#i(&(j76dBd^f=Oa``pxhU<9vAZ;qfnWfDPr)DCpK~9s2v3>bbJa`>79=vMDGu)H!36Ev=NO>n9(j=p?6)aJd zCuUedU0guXz=M4WxAlHBDH0`hafPqunl7<`1-wvxX?v($!Ruq6%T>sVsNllorC$N9 z+T}&|5^j(XBD`^ZDv-yu%>f9W5|na8#BvBY{Cc?O>y;_>mxM=!-GZUSVa><& zp8|jTfxj08{;(EKgWz}UH7^PX8nQqT^G~5HcWkST1 zpPJ=C-O?9FfLwQREg(mPfdNq)$BH3fcqoIwm&m*mN`-hRFKz--6;(Sg3+@JCt2hfG zrS*&)0(R6dTOTLZ&&W|=M|E~))b&}c<4xkb3|T#KhiEy{&oBvyv-=w zE9a!dk*)1aeMzcXrhD>GVYtYy%vTv3NW+uAIsRp$inh!M*ovH-XJFoml!xh|xzD%5 z6;|aok++@3z}}8baZtcR0U*5IDb2S>hMF!CzSQGEw-`~0ULuF0oe1xG(|pr5Pw?|X z?H0h1cbU);GkI-z(!m_VrHU+NFpKIb6oxZRXO;IFw#klcwWq}g&p%J&HK z7 zj@M+pBFqZ1lH1{?wgU7>LR9tzX$U|0X?$RO{LJ|12iP6J=OPl)lX0s}fTiB?(N6LR zhG67{CZn*W@QrAAGm@uW(i7RL!0P>C1zRer6ydw=$UNDwOVDpwCqhtcX)F!hW``%) zmFp3&;JpN|zyuu?82%miqC)g9C?3{qeC`GR7$uEWpF9tzIm|caE+%%M!#~cF> zEUkHFF+BJ%&+zKm3*EWF3QA^D>36QXWBsKL zxFQrh!G5gU-vbk5haa>E$CY8PTqdWm9oZDxahU5BF}YME!qtP_Z|aVp9UpxUshm{o z1LzQkNtC$q9^Vn-bym`$T|U+mDfxnNSS_{IUMlEyN!P`v->g4e%LT6>(DH7%Vvc~M zeI<5qh3y{3CO5h}0A3RLc%sn7P7uNPqA{;{^6}3^FkYMWips~0iaz9P3pdItB0uYi z$bVnAM@8hVizXwXh8__Sd9kx-8xn0h(&Foda8?1`CPQg=ovdC!Ywt&~9h=j-gjm*c$%~ zBU>z$5BN~^8e8nvUh3NmjmXs(YLF)=7VpXd@J_?Nz-4mxD0zEr0Q!_QJn+ptUCOiM>NrpVOrsqfZPKiFU1-<_ha(GoGL-n&T$g|5Id_@RbJG1P$ z)1O(FNW^2`5$h5={P5%f9}#u#C)*CMw~z6OJqgt-^kcqhmv83~j>e}B(&4=&(fAaY z!4H{jWgma7)C6??Zd!QR2SVRXntJD4jYX%zruY z-%;&+jcFp3GL1QpH(#k?eP6})q_GLZ<0Y&Zg+ko90NqO z-J7O=?P-4Jw`SYo5=Y=jd9MuA(X zUWoaeIzgx53W7mwD@L@yHl7$-d6Vc0R^4ycb|Sa9(kW_C&I#_QwzIBTMgoT+9&`TH zd43+%4)QPch)gcXzlgCSEr*MS-6u@?|G|Aik-1MO`v2-aq3DA536tbL0Rr^%?h|s) zyH6+@d7n@~_&x3u5Vf1D^#8XuDaKZb80=Z96+1;PKPblC%VUl;B zP;~x%LP7dI0byCV0HR5b^lQ@h2}NmYX)xyaBL#Y&0RLKa4qajSwzyidNa<2@@1*nuE|p!;x1OsI@&p^EW67 z0V`7Z66+S!Bw%g=#j1r+a{z3D9dGTFQIYECP8C*0s_Z&NJw1hyzQXWS!gu4jq)Z#+ zLr=cL?Lu%Ho-MYen+u%VT)sp<--e=P(9}m&=u_{H)=oei{zJj;h<{H53Ryac2r|`x z4Y8RG)yK60oTdbwM2$n^jhp_5nkxKOz%D~A^N*H649xqL+cIDSLrrV+cd$6DPJvcC zG$)oRirrUsO-q&>Y|Y^!xlQ24(OIV`H9X0l?EHY)y#u>^67=2_yCew(cSJA3s=Arj8th)0rI7DAn&K?c!S-fgJN6q{j>}3*> zg$Rq*ve{%bFI&T3vAS$twr()BnN$wB&C52CLYS6e>F4SS?n-smm#yB-9^w@?5(CRh zD2F2&&0K@8Ih2D3{nDgGO!PXelafi&W~B zGQQ!?p;2T@;pOwcfqrcCE?!#Ed-N~H|D>z+?~nBF-{{{T>)$8%Yrm359k#}DL&-3$ z>-cZKq0N0*LxGXDiPB^FF3}<*m;fqMd*Lr(c%pD?PTuznJmD8@V9^45_S&UHyT*=Q zb^|UfaA{oygUunj-TqQq$_bFdByJaokK6Ez7=U5}_{a6E5%yr}isI;FY~Jm~kv1$i ziR+C@WF-XsQM;;Tnp5;DGm+stNY8xxwYNucP!L*qzsz-H8{xW0%oUsF1tcm`TT4WD z-#?j*`I6y;msF&FPNrSC1XoYCBjw?zZ7qM~tgX?k?H6USan8)&Blu!QZ~bC!8o2b1 z#+IO${laNy<`M{>b@3a&+Tu+2qZ*(pyCS^V5nU>?PJg2UfOuO*3B4t1;@O0D1j}>& z7CZLxmPih-7MT!I9Eagtvb!!FnU_c2gOB|IvHOb!EZ;ik610f3L>x+zGX*cTZ)XFC5Pih#@2?; zDx;pmT~OsdZ26-Sj#}t9D|>E4+MkS3+StPp{V|FfUlj`qm=wImbbZNF+K}|c zV*m3+ls4WtA{SEw1NgSvEkB&sL|Ta1I|Vj;wfpQknKiU0AQz4^2(h zq3RQSAVQQj)VY-6@xG~fE4nj>ues6Q$6rp$n?|t$_|s(X5znQG>DXgctpxqph$@;3 z!)=~tc7*3p{L!6)U%0hx3$2pay@V2hRR^gcK}OUbYN`_;6AAe=gi>307HA7KJtxp6 zSDDj#5i36w-Y(M8P}6S&GDA(403qUX`%)u4ty&E@#CtEdtJXw27e~WwIFtZAtshPv z+2xIZ6{{h#KGit_39Z&;>L)i-F3}r}xNdd&d5d`#xwO9DY@RozpJ_k@pxe^V2^iqY zL%5cP=@a93TG%S-%_hA`((6rno22n;UmuX^@vkV=Ic*a_W+_0n#dR`sp_NDE4P`1={z&bI{Aa;WF-Wj{;g~(Q8`@B z_l%IOOw$@_ttW#^HfHsqmS+VFL@V^6m?RmL4?M2miE?7hj_jLhMfO>GZkkIh_Ga;K z1eQW84~sFELKxF!xI^WphCm0k*65y?Tk#80=ZeN*`Nz!^U&m7Ry*=W>Q8gmlbg_&tGGr2h-^?A!A(s6TEmk?o@L z;7F$doKREMhinQFG!6qBBs$)D&&)OJ&pau7%*-**E7Q-O06h&)Gd%(Nn)G{5fS!gQ zJg_M|txvy4DN5ig4R1!EZiLGT#OqCwPD-+VgfsCae8&K0=2Hg8RmpDdJ~Ql_auwVV zgoRJ|-a!<5Q_f(<`|_AQ_?VK%;Nau$EjUcj9l)Q=r|flMSfdHGzQ(QfHH#qeHtm#KDF(Ky4747VcWJcB=hNRSWlHM)C`w zqE9;y2Ocr2s>OhIu}chM*%OtGPSFZ;C0p6%G>X_n6lS)AHm&7y0#;kwgp43IBfYh< zE!dBWfK?H6o)>z4Q0S1oc@&bQNW`D<`-fg=R{Xh8H6zBk$q>z9yJzZ8<{ zNdGW3%RL$l24RJtxKZ~|;qGhr%y^LOL1F4 z!@bwnW-ls6c8InrUMGSJ_|6EZRWHr=iP0gEBQ;oUg3%UGoMjaqm55 znrYNbbDH_!m-V_$9c0dJ4$BFVv0~M0Y-lWMtYtHpOH6x0_3BmOmx5A-K@VPE^NYUF zD!CN52k=e1^e2)!$mJ*jQD7ZW8_Jo+U)V4%VoL8q_4ytjTYK8w`gflGokKmomg4dN z(Hg^jM2RX7taJQJoZvLO6sM?q?v~zVEmLC9F1@GPTBgT__5vfgW_!jn$ioAMW3!jZ z88!>1p?C&;TUiZ^!dAhiXiZ)Jh7gFZ-&7(=h2?%^@f|=EcMRnd=5R$hSI+00`Z9tkN-VVm z$RnrzPM)CBN!_QZqoLiaAJ!DtGkI7>iM$_oE0sB(mrAQDWq(6xvcG4tRyS6HvkUiE zq<$*niX@|{$tZRe;4J|4FE!+A8;EH51Sj0Ws)-|keZ*f$?Y$n@l<03o7&AP@^*tj958!;Y|gLJ3n8?e&FLCZN1S zyM0Vgo=%TVfCw(3&@H+VpZbDEcjtth;7@(60ADb(q*~lmSmQA%i}q#_ku*GE7K)|+ za_>F3a0Z$FAmTraa#%b?Yzz9&fA*esKf#vjuDgyCILih4Eu#ZlOAnVm8RJ8%+_M zeiJz)=07ZdrkFYatJ~(J{+v(oA`1@JipfL~kZLs%8 zMW<%ytC8Q#O})hHuDj6`^osunJLgXne~Z^$e=$^i4&g8UMDcI)T7)$^AB8S{@8I&Y zF>kDJ8f54dsmd3m)3}0TN2Ogs>n3475mR#W@}NX95?|oI0*#_7Mrn~8hL#Evs2eDO zrkGz)H_-Xt_|2;uSn^$dbLs|SRs05dhD;3A7YSQZm0kCl7SE~sOp6EWK9l01dhvn| zz`SifCkRvgY_PCx@&Qu~9)%{yj-2%hZzTMiQ*^t1M9b8DCJj;I$k`Q3FB7qkIiyU# z=!e&k_A6Asm9Y%(A*I+X8Ie92QY52Z}(b z#sfM1@A?xzI~q@mC$I6fp6;?%2{=fO2~cD$6F7r1@j({^Nfy7e2xsdAhGFlnh5f`Q zw5Cd|Wdg`2-=>L>)68EdXM?oYtohtaQp@7vwn#x^30-PlmP={LZC;i`3gDt=6QqW< zQZ$H9>hBe|M84cuGgz9HIYo-yn2IOp=!q3Vuvu zN|NIp{|^Y))=a(GKapNY+XY&$^oRewUUXdwYG@e%Firn?0ankko1^jZM>^#iy*%g0 z2TqP+1yMZ-m4uqwMRzSnId4^!Lw>r~`dK!$dOS%E7Zp%&Z`6KmnphR0xHL?~2VcAJ zlR5Ifrqg_;USCJ-4cQ>2^{hrE7Qrt8mv!j^B?2lq2`%U`my)v>aXb-9*Ro> zDv@vTEyic1$WgBrRoJngqY6vS&_Dj0P!%?w$LE0ey&Q?NlfJ?D$S*zV@qkJUE4=hNG&u zEp;0(gj;|6GosXqn&+zH6zRIMNlMO5m*X8pzh;U$xBj8=pMLeLU!8t8x<6>|L38ME zN=~8S@%QfOwQoUVEo&O>gqptiUH$pyRQA3x9FC&q@i!rINBjd~nkVVE3P@+9Vmj}mzRu|(S zM>Onk<%mec7=5EN2^g80RZx-&y&!|7TqdqRP{69}^&PQC6Y`T>`HI1|c}=U96+y@b z{la59?5XviHER7Y8@2u*i^7srTiKXnM<40oLMs@m|7#J;aqs~mn5hy2flE;obrxU- zY5RAhB9O-s5A4j?t-v#5w?fa1-NBQ4gwZb#piU(3&>xm}r2&3|R%y_A;OHRrcM~M9 z2fK3qPj0`yDtFPndd=Boips%uR_w2xKGtbZ0h32!cK_MbHvGgyMpLOZ`xg=ChI~@xa5uLad*& zRC`yH%f_d^DDr~bm^IuCRXPX22@8=QQD z51F~T?v(}wMtd&}Ev*|(qrJJIr6)LJqP?hcaM5`&TsmTl@@?0b=Y>}NLAa~%cJw3T zVy;ysP|U4uzCF94%s0DXhE>jL-24@|Y;tCkgZy_1$qJHFEprJqyWvirrdZ``AUUnd zbs)J=)8kiTk1#LP^mLwY_A^CR`D*SXntpHvnRk;h$tquo9RmuiEXZNjY%`=G zLhE*uIiF10Oqoog>-LekfJ~~#Wt5a0E1byeXKKi#rliRXh^K&+&n#hj$>+PHCV#Y5 z-bVgXlTWEbCg0CZ8TrEWQl6)MCZFgEG4f@Ze0YTyPbkRK1NcPX8bM%R@PwRCLKcUY z82Rcto-=vYOG3?(eIYq=Z#Rf;cwDWIMgq&@O7p#u|MI-lJa0*VJ>tHA_uhShxliD^ z*OWh%E{~=nt%bYO&z{CK%Auw=C(L`1`fBfz=GmwdQ{PeZ+?IZS$UL{CpZA&PSo(RF zd2UQU=a3MrfvchxW=EgG>qzU&=%e`eQjKrWsU%lxE>cit!<1hx>7^#UMbe(!bd#h- zw9N>&O1jsiMWI`LddSEnoih1-l0IS5osv$Pv?xF0e?seNlk_2zZjtmpla5Jxmq|B@ zmxHX&^>VPiTD+m+QEZ#9JfA(w7A|HBubc+&>Cq4{(MbKm?CY+}X(yZm zt+Bz`yp!0jY&O}_MI_l`IV7i$WMge(`(HMEBlE6qDjWGy;FvwOT{kk-)RmCI{%SOU z&HmcOu9-n5`zvNL*(dwR1eM7CYB8DYuR~;lO=N$ynM}HRluYo7Y%X-7Whb(^l4OEj zp5c9`$z(5`Aafp>B>PMz+bTuo-RV7ras*omhqG*}9>IGGw}`{V;#Nrt=5aW^QNCTD z4tnnz4fV0hdyJXKecoe>c@$G9Ih@+e<5BN1VIGs-BX>1I$ei#VJ-R04J$9S7J>H|a z&nRCf)tZYC+*8w4UPBs5a=Ru8cVg}fsd<;AMGu|yK1l;kl0GD9xzQkfRMH8PPD;Ad zq)$lNP*de8Nq3w49=X^4JPHbu!%$GYzA%s>gk3Sfw{kTE1nvpqO4rI+vqjIERh&YE z?2*-II*t!#j!v-%{FUtv`pl^0{}yQZRtsdd%R>Ds0CLR@8w z&Ihkc$6K{q?S&J>IXmvtY8Wy4#S050mh8eA$bzs}Rg+^n2plOjswagS7!kC>pxtTt z2HXW(3L2i4XP&pEpL5Og_VhDbMbLU0%}&cU&w`)ydsao>r_u7XiRM{wsG@lfZ4aXH zL+1S;n)lFtB3(Xd-VYuV-m%e_e(xPCgU5__?40sQZ*{tq9&GxI+M51&y{UXt`gu7C zI*&vvfIo_Zf_PV&tZkAu=R8cz3-69%8l0)qKnjhU;LMyNRbR&&#P~wIY-B(d?EE|OVb+^2A(v=bhj(t) z3?GgYC2Oo?{r!k6RH86@xplM@`PnVJGS5V(;(7Mq^C*43Dg7MM$1?LMyyp1N<28L% zJqB6AO%_*mhgN=>9gh=Ev}54MMBLh2_%@Cg(+t{9oI-y^l<{D~b{ZyZr(wc&3KIqm za`IQg;1OGBTCNtEmd6iI`TPW}X$8&$$w5}(?^XV<1K(Q~6heA{n(Qq1wxgvizUYz7w$u7Fd7?hY<3W zOQeCI*N^>Ic>U1Cxg915>=ObqA{zQfkq61pG;v;!bEL;$MoNB~80_)bKO5O&R`5U3 zV;FzL4>K+iv3m(iP|Omnv{=yec06?Q2RscE2$}U#5j(RjHp8&+1)<+Y`=0k_|0s}^ z_y>PB4CxnJ`nl?j!9c35o1N(L2`7H2?AMkcIG_ z1k(80(05z@UfX+Kze9a4Scn>eSRS?DIiX#mL10Ix%_3Xb%eNDTzRfn@KE$`Uh2mR! zEZuz*MF#CJ-yXviC?8f^w~XTBublVs#E~5~pH+((EF4(JSEKpr>qB38-TidG3{$!* zioUM+b&H+fV-EKV_jm`Nv*rG1k7vr4G%hA+=Xd!jZG3QT2D?mOvZc%8`RdPxy6mmY zbZHZh4Q7^FQ19Du;Jih>@ZtmpNBc(?2a@K(Lp}7*GSuupK2-UVPG5S#p|0ZVVPH5o z)EsYhF1z6B%+s&T>YVzoug>M#RviQrU-D+U23&)(zk7x6es^ct8e=tPQdGqAQ20 z&~1X?YEJ4+jCO?lrF$&J-iB2;K{(8l$9=#8d<_?!s|!RoYXsDO`VROktMu- zHTN zGcqXLDuqu{*zZVTxtZ}hF;W-4Zz<=ZOFdf81*`&=e_08ku(^0Q&YO$hSoB>K!WY_r zXdhbV^|1w4p>{N_y4YQG33?3EM%lq-*6d||u6Cb#UoMiW`l_wF@o!kO%s;F6OwAtq zOmTU3?Hw9VNh<20DwMM#!Rq1}H}x+nipKjF*uO8c3}N#g3`b#(L!u~BhFKO(rS z_zaB&udr|Gv&Kqe%<4(IiscAO?aZll_cI)a+0&)!M9r^9%z=(y;t`_4w5XCLyo1p3 zH##gvc^|4X;6bLKmpEzr>pxwPtNLRs)#L@Ky}TmwrW_}a8NEEPRiW_ zHAK{*@bFtL+WS%9!AFUK$9;Y3Z<+)}1;MvgrU5nHN4tmJcTpi%UWoMh>Q26*Po1f6 z%V(kp(fC)@)zun^<@AS#QFYggTLiq^(H4qoofAp%UGLxVU1}5`@sOdF%cdQz6m;Ut}T~HMd2dKVyYGX7QaM%5_RJ9f{DZUr9w^c1n^W!x0;$XO z1oO5o@6ArtDGcqNIZCI|2`(X>MTnWXsgrvZ>*+MECfb@eV^EQA@P=ZU-n5bPs+P@n zp76<(y-A-_S6aHZ&}J zM+|#J*H<)e#niBn=ymvUG6N5yUE_U^eiofZ8| zV&ERU_sH3M>^&6muA>dSDv0J1S8+(!^b<78gtawsNO~($?~#GMw&;Q2Rqhx~jIxj0 zdnI&4LU6;u!q<-=?>Si5s!?{u?nbnX1f=GoTgH9~rWQRjFz};s1Cc)Hh>DbiC?nD! z6#WeuCE_wcZDYEEH)O<6>>!~}A;Dn;yv%p#7sR1HfA=t77i zDn9&~Rh5^jzMcsJ;~td2T~#?pIt#IQ=@GlV{_NC^yu=&0WQxpCDs9GVgw*KssdovS z5~SD$ZK9Da(kUD?_XoM%i@r}Ckxt*?_APlqiKY#q^T)Yb z*dKxsFrT8W#g^M97rB^{!9RbCRz&6qa>yh=A-)g&Auxq4P8hgVO&wlH_nL9-mui;O zAq4LP`MceY>_U8qCfj}@U7Qd{Mf7oIzw-nV&s+MP#iN{HS*U5WNVIwnpAqBK9S1=6 zQwU}v;Gz|PX(}P?y`_5oehqj*+-iFi_zx>44 zLHxyG(&J3ekyj}~OX6OxB2`E}jcn6fT0AXob*7g2&eRQvLQG9oll+Lo&HaT$nND08 zyLJnJmbJ}~h8yuU6Wrm}1~lv@58|3ftWtW{J=8M~4GJ8OEE%2gqc7kUvEq)p{cWgm z;LtL4KpY8_W7RFkptyf4x2|)3p0NaU@rjc&*RJX={KP^J1&32js7ti4k=R>U&HX65 z5NlrSSqK-jR9poB?}7*xUqT=e;Ct`QUrlt4Ej(s@-~Wo_1M8t3kAe*L7t%NGBiNnT zR*9<;L8u~5b>$BJE#EOQHmOyvYZMu|QuYqvX{s z&2gh-eZ!i@B@un<1R?GplX>#E>A}UtEuociIr~R@A)r+A5G^-~zIAnR+oCUPYoB29 zU6J!}7%jIK)?vk_fMT&`+s zdj68{WkjxsF7#*C=G@Xe&Cl40V4I2ONJ&}W2<>MZ4)nc;RHu*CYtaVToOMOe@Ssp1Vp4EM5Gwd0e>Q{?LjjZhc_>LtcICb-bf^C zDTk3apnbTXXwi}F@pri^Y?Od-zoQ!}DUIRs43k~FDB*lWFfFcMI6Vh^+(U-9d_8=K z3GVy4xa=Vy0jMv@#1b~z6V#gN!-8Jjtzq^>=2=R9>j(>0wEz164BZ%Fd zm_}k$g9&B1i0ysg7`BRPq7dvva^B(5mxzBhX8PgJu+D*(!flbKoAa5`&3VP>=A`gn zV@I~D)2Fs-D_1UX>HS{xK2p&~dNbwHslG&H!64Pz1ZFfimBB%Nc{h{G*dz!vmmD}w~z@SlQWfx%$3PntC!pT`Ep5mrH1;2oh zn`xNUhbt)wW7{;w*TbpQd5uf}n&>ZZ*{v6az47-ik|81)d!2j3lwP?+(zlh{WueTa zXQS9f@0V-B&v5`*nbfE{J~}7k=JAmesMPs%981 z(3unbXJ%1?6A5&l(fbSbD5!8$wL&Bjz5LYzlOF-F(BQ=402T#q`+?jDCVLtW=eK4p z;IbGE44H^+Dsxw(94=wfuvQVK$kz{0>O9kpx0!0Xa3=ZzQ1=0IjimZwnP!DL2qi^+ zfIi0+J3?lkZW9VJ;G?4Wz?fNw2kM|(1t`)2k$$PZdvD2mE&>htxnM` zL;e7TMu1%Cb8?hO5RzsX@Z=ic$&J641|E<)GpMfe%-wdVDMZlk|BTB}0*(pM)2wt) z13ED*H|!|)cU+{u=jl#`Te29KrmwIQEx+Owh(n!USgO!~e|u2iZ7`wEP{ApU-cDzXg9r#w}No|4OX;~x%{%|XIV9kCG;(dmF!B{Z=v0-jdLn1D^H*F zSY{-Q%WoOAB0lQCsQ8NVfj@`#>sgM000e%3D>=*mx6?p3>Zl+j`?b{n^~@1sgtRzC z=x3HjLW0T8E$2y=n@A!U z#rWEe{N8u0IMRm?X4d^MepJRGoO)7>*<(jizC?Zd{4a!F-J3Se3r1T9%GlpK^J%B> zFq-Mpd`jU@ZohHzr(bQkzN&B0SJdC_pKPl*l2a?u2A}j=f%w1o9$^mxR<5U<%lNQ& zlY1BY$%pIuQ_v`wzrU`6v^a6wK`G8Hnbxfj%ZUo>syA!V=GlYt9Q@PV+G7_z<9jmu zsVwC~C%-Ao?c&p)IyrikX(#Y?GiLV^hSGII@kg~|)F*S-H#lt7cgv2wV!Q9@OGBoM zmKV=HP#CcYL<<%a0&2kFGGK@`e5swVBB|7+f0K#JkS!qjErck9Yat5!%mPUDmeikJ zNq-`Zj{oTjXHfyROaU&CFD27P%_tH>r4rqCqF*_)^YYG~o)nE4sO?2y&oe=l*3!kybBKAek_7Ze*-7=h-ZN~UO1LWWj7Fw8HXG! zglq%P0lMf78)rhCls)QZi5y>#IMm``m7r4D><8cL_)92m5ho^v2;(4V&?ojHTn%l5 zi+yjf4K5zB4W{?tLWao!cka_|@I9G;$gat;=>Gd;dcrKN6=|_&T-8m7#}}Rv614p2;+>-*FGU>({j#5K z{zpWsYH$yg#la@}X}-#s?=Z5Iu0S($1$~wwL3Z~N@vJ2ZP3}d!+xJ}bJ)bCBjH*cO z{u;ia{3YuiinZV?hN`2nCD=Q@&pIJ_=t&(Xg_H!wm=n(VegVQ&p_Ht;2eGj!yrT?) zsPN_zj?2R7GYBIC0*{}?h@->_-i9|*1R=tnOrOdt`{hnHIN0_Vve6xX6H4X9iO8tK zXX+0u_8;!=np$^8_`lks_`BJ+rLLu8)Q}}yJOC@JEyApiOf{wwGi5^V5yTVn`34|B zQ7}K&Gh(nRw6_2(A<5wPo1`fESL);z3+~qVyCNAiy`Y>pQ`rTcb)K8Y=$xl!tNqKJ zFC8j09*x3Aa!@I9K;IY*^W?DWNOX95Hzbo4B zulX&8P7kaeq{rtzI7p9kJc8x|I1jVR_#3p!vaPZlt1Qr8=cYol%Gou8)zPaSicNgaH zQzoL8=8}1Jw_M53!{Vr>xnx4d{qi%>{7f=GMe-w8VS}{EpnPuz0ba0Dumc!EiaL0i zUlS?2%;cP~%YvHIX_tW=vymNwra0Hqi2y>8>#K@Ft3Cus?aG4FaFY`tYgJ7=KN|NH zw#^ZCys}`fZ*OS#W0|4dPeInjEMf}(7Qo+4B-rq-!tf-pNN6{gC3&IUrGJ2wgh9c0 zRW7^A0(J? zYbXc9rkXlPsx~y=rR_>PZ|1AFSGIBLuG zofe{$A zv#im0mUt;I?e11aPQbRb_)ki*C@(whoCz&;DF6X|W^z&3+>9KjFOo-=9iSCzJ$N0~|`ss&ei2fOBJZD7&<$I`mkluR8P}vFcEN8@G^=51Pa4!37zi z2^cv)(&{y@gdIi zPveCti4aR(uJ;iwr(9G=Yd1#+e2@EmA9al;YEG}O$72N$H_ytf+-}uwwt&WM(E+Hk zcL6)R6scL#HnG}(5y2vq*Dhz~RJ=MusQ@3F z3uJz5?6quH<&AGIS zr~w0qKihsmT4k5eD!YVM`KHn;LPbNa#DrX7%JGUBTDeNrCL9|^u>`Na5XJJX<3h3Q zf?}CS%C23f6br^l+(jFTr9ml{Tkl60SUBs!!nqHhL#`;Tk}RBcANfAuLTQpPG|3WZ zk{j#>pHX)XjOksAM2BA?PR$z_oVI;~vBPtSA>NJV6u=+wIioZh; zTnqHcOo4Xn5B%&0Ayl>rp|Tvi1C<-TaIc|L(nNsb>);T+7D-O--1<*LOTQ&YdDTQ? za~`<}62bSWFV^)9GBA#h{22^dT4)l^vp*|qnV_&tDKtyw*TkOjc6EmldwvA_&d!iJyrZx&HI!W=OEhdzk^U{ zS0;R@i&Ae%-2NZTIve6Quar_`hG{J8L%=_j6Cbe;_hxATlvM#d#7w ziY^94AL9GWPT}e3z6ri}ILlraV_4?CHuoMTq^R(n+pS+n6RA-XWH7;dRnS8Td3$@R zo6C{GT!y6ZlZ{Yn@`2|H_cVul8Arz9UVOJB3KS8r8lb;Pra+b`=w@>SPJNq@M;fpo zd)-5AOBlR}0AsOoA#Xxhj|VRk19DWM=$UKR_Srx7Bg{sqSp(}a>{Bs0=TpRT55>x$ zna$V!%k0MjnPGH})d)TKUFcD{pr9@915+CP(ZLTQ0bios!~|$W7+ZmV%seKfJ@Lzf+u?hm9)` ztA46JO|@2=u?=A5uYZ`xEp3`@%u*>H}xl8()vwXDe)5(FfY1B zbtLR319ko4;v#}VY!2`wPP%gWJ^b0>-mVF}6U=i3?_kf;uMdA_9wvQ7gp}nsPOrXvpU?TNlE&claB3t(Mv-?{AQ{YcIC6 z*vac4La>6C@8YHw!~$8{dG&{4fHL26btPSFEzxWudvQ|=!5Vy1seeHE6C>0E!pu~aH52+SAiFzsC&R~bl>w(lvd5I3YR?xoW0-qO1iCKMK z3Ge%a0zxVvJ=T6WPXwaBmQMJc#l0d)nH7+OQs32mmU;nJbmiTww;A7qG7D@)PG%g_ z$V^wH*8h*pjDaUHs2AV@a%@N73&^ow5)dmSAYWcxT;{xP|D-<*4BY1HG2ny?;|7_Q zkswve%-I`co^hlUeO1;4kd?7J%VaYfC^Nv~D*O;FQ{hGRAD{9$rT^X8A@Bm+*slt} z_kkYVsdlCmnJjW7yl2_fg&7b{F=coI!7Ji}QSclt@ z=t#H<`6sg&U*fQN_oI$uZag{e(ck#96LEJ>a$FCeCH5R2Y(Sb#Bu(Lfn>FKq<0@vf zo0ZQ8?grU09a&|hkGHx9j>kLdrGLj;`CM1=_?g77rOe5dGNYg0PKRkH$F$?Fm2XX3 zUF2z-UY_&=)co4fp$wI;Kkn zn0@|I4TE&uE5nz~+cmlX$>(Lk+zk_TN#t+xd08jZhO4AT`-V-DW774S)}54iUR&89 zqjSv?DgsEj0+OYXpc`{L4Zs8b1_%|N+{=?K!)H*QOeHd~_6=LLIZfAVdPH-wyUcJ5 zzA@WUnu`xMHx@WI4IXearx_@=mF|gt7;rCl51ikDVb#W5e;}a)GKT{QX3ueU;w0U` zLsQ$4mCu$+9_XkS$|t!8+UJvwtQN3AvWp#+7jh4>k@g%vd;FxE$Cj9&Jy(<^j{$wu znU_aFk`&`~sXHr(Jhbv(M6FHF&7GVM8TML1z3x&yqK3~O^Sso#Tiy-FaIwUj1~rVO zFFF}r!C}*KkZEoTle*3i#djL+^_NXpWTD} z-6!Y5Q0EeQpbpRJsF&`_*D@CUx|P3s^y?9aF?oaMqtw_@FI|%_rQgH8l<&PS6M7(y zJa--h#)kJGnYEmp)agj(i0O8A2*f1EEdl!AEZ54`vy>(W*CA5s$ePESj($3ITh6Hfe>c(9whzgZQ=Q0i*yM8<08&cKDS>D)5USZrR+S?9U zD&)@ap0@i(OlJFxgCl^l{TwofdC*zhEAu%tCx%E!jyrcA%pQauQK)rCP7>#R8Yi<& zK#hWQx&UBBKAdgxTbgJEIVSX2@Qw)4%1U&*t;ra)iXud_j5-HzgjRlWknpv2Zf%`s zd{DBHA)Z{*DaRipG_bp-p%Vfa90??Nbi%7rQNkk?WZRq7G*m%q`V%A9G@%@@IhhQ& zrZVOWoi2-O8XZ30W|Zz4C!1cnbRi~xN)1f7>zzq}0dujYAs=2gjeK+_A{UcCr_sI4 z#Xgh?gIZP0tEBIUCSvZ)#t|8YZHo!UEudF2*XC2*Mdp+vPcVzSH<{H25DH#}EC{W5 zMiASc#QX04#J?Wb^~zfK9U*d(*Txj;hjrqz!TP>z(c%D$s$Mxj2|Ue5bM42i&XOSn}E)8IvA8a#9S^EJJ8S zn)iCG@Mju+z(98Tjn0t1NgPQNYu}}bdm5pMv$T!Dlg2xZhP7~+0co!?(*UQIj7lca zSvKV}fbFE&--%yKW3M18%&>csS?grR&Lqrvyg`o?MGfgG)4ek`ec5wkhCAAW*Po(b zIUE?G`^ypvPigW>nocUYZ#pJ60Pyfqp*d7c?~>yZOkpzXQ96?P?m3kvUzO9RBWsJy z@*kgpWQ*C6!}~Lm=5duX7K9O`eM62XUs7sNBlI0_O|PwY+YzEMxMMIV-y8_hvzLZe_RAW$lMe`l$ob%|U7)8# zOjhC~aJK=IFs5BdKw^qt)(s5EDle2W3ARcdS=Z|LJ#Hjv&yM9~^ z`Mj2fj=z`q-MNEZKMu3i0m#GXnX=HzCqZiH>DNtUiVEu{@b`~S$rg6&86e~{G8tx$&H?*FR_p#u@yTKlRxdq$`%%L=}S6;OJ9LL8|9bk-Y~}4`QRD z${s{d5}gm*N$9SS&AXoDa*e%2JyGFUKZmZpF@?KU_Gy@tm@nzO!_@+p<8>$eJf# z>(q6P>qwmJ0ZD}EqLA3Ddqo;p#5>b~ z5?;d|A-qaQyf4Ax7h-6r2o%qG#MjWFREfv}@9aVl~oyxZM_DDREE;5kqW2qdfg3 zBvweR635Jlg08Mt*H?sOFoIaS$K+Wm+(ZO*09xn(dq$s4nd=*pP=Yn%-L=}ytR<{D zys7?rdFI^Iz9bH$2QWsVPxK;_%>RK$5x z1lM^$Bkz*qRu7hQ>m^5yL|Mf2V!BJ8mF;%?wZu^~f1^8+?q2s0|5Q?M+H==vDX+}J zG+OqEF9U|UlMHu+uuE5}wIeH+9wnJ;Lp+wwzl7ugBoKzcT=<2q(Ml60c8lk3vq0WR z2a*4VVB!v{w5QZVIl|HGPc z=S_(A=S033eRTr+J!AgYniW9_dhNP`d&|qB{g*DjB)aRRB&(G%f6OiE&Wprg)Z($G zxQxne$RI0uZ6iyOrl~}blzJa+yWyQlj?2*XlNC1eZlL^}Z8r4U{khca*3aexBk)0B z`Cj5#zvSxum3il`l@jho&2LR!8=#pX(aEKzkW%DYM1&*;fjE`PofCfrOs$m;Pe!Iw zFPux_#=bP;qZMlhc$XvZE)rIGM0T!z;y*7xPxAxk<>zaD@Vxv2&CfnBe}d-coR>e5 z{AetYxG^^x&zH9{h$t!$D~ovJ8rJO!_{q966S?p)yrZGVoR{WNWak9N&iM*0?hiKSV%WR@2< zh_xYh2J&NRmiv9b+fb87O~YY9FMd1LZeuiV!_@QM%G7nNP4bpIh_&}=sr8iVSeqd| z3nx3)PLf2!-RFHOWA0cxPe0kEpHxUrRt2+=d<~)JzK*O6(nzll9seD)w&ZgT&`?&R zqz`e7oDkVkp0=>$ycPs|cC1~lEtH)1R*uAuwX69nT`$v8o1`BqQF9yaJMW7e?Qw;c zjLF+pu7ARv9$~4SRmAx&FJ5DF?n%6U{PzMUDt>NQdR~PSwZa8j;f(X%mg(Cirh^;W zwA5xwb!<4H>HE+7Le738`*R!iNy&QoiU|y#NY=|o9J>dPziZ@e#}7dd#(CL#{C7e; zZqiDZpI7M=?Z$)pw(PvOLZWo6eN^9Wk+%&Go>xY3dP9rk>#E8MOQ%xYmW|UT?oN)A z<&_R4$I0Rz?~*PVoRqIkD8p*FxOa_`Ku5iR7DI|99RVGK4h5806i*U)z}<8Fb>QTm zIUP6ZnuSj!4l(T4O_t0O9XWpRIP`_7K>Ha^QtR^q!yQ=<3a}xb7bs6Yzm2~gStXh$ zz-W{d+FDJs9MP)$v3i0@{O!}@_B)c z!PW#@jQFyXw{F#H8NmD8$nljdMDlrAtmCgSAQin1Z%YZasx=+;GPL7+Io1$+Si(^))@qhe33~ilY$42|GuNXLQ)5G15~Z= zFyOaWnrh<(tJXRQh@{-AO`%nzAex4sq8yE_6!dvFBf9t9D_wJ&BkvBl4V`q7_TuhF zNx9}?$$NKV@SUW*gVlSN8hj@yPy57s*FE@7Ql3P~d)G7gPExL+cD;9}2H#1_qldkB zy@T&0<$((VQ5i!YIeHXqloUu4HZqoYex4k88y3i40jI?Cq9Nd_(_Dp>gof~QtCq0- z^7?*xUA5F41n$Q5+KymZcVmsF1zEcr@0RpIcjHveQwnqACQS=|b2l#0bPtQuigj^De#xmi?D z`wMCy8e+_(i6Wi6b{+f6-jE=t!l}=N46SghV(xT*^4e_PJh<*vKCWtUr)MXxT~3Bu zb;uAM$!k~ZW1BlYkjzR+8&yZ$2B8j<*LLb-B6S8`E3Z~(#{^!@d2lNgrv7pqNvD3D zwEAF7a^9e%Tfd$RVu#sECA&W;aJ7j012~od>xUNtOIa-U2f=2aaPiLbQ~6|2wK4fk z#O7(AQt0EQdjCbdNCh6;@-2ywr271Lp>;}w6{%VRL89(4WCTKa)cmz*G!~S2N_UMY zqWXQgp6=dmRa9!Wf0@gu3io1Q`qb!X?0$ZY+T!1!!kHaEJI1r36?5`~nalDhOzb-T zMtcJ_UxYg^B~g3YS|!z3=FJ&VYl^QodFk4Qv>>k!XD=FG{LcLG)1B$-#m~rB6UFaD zGH?p5`m15>wOm8Xmjj2JTXe)4>D3Spt%7lpbKe-p+tc-sz4e$%bW zcEj0jrToQnhfJ&(r%%s}cKz^l`<3mq@Jku*{3`n(iqY=U>l%6TzDi%mhV1oxhfKp% zc7PU-?->A|57;ZOJ4$)GB%gQ1aa6L`_HGccFKr~S83~4+eDp+i+0b_Nm3!+nXpx#W!;fqT-#gI#^>!cr_CQfo4j@c z@afU0PhZT{Iz zhoRf!R-v#+l{D%uos`f~_qy!6SVv{5BdZrUmnPh-rKCjIm*rLly2gOaDgz=PFam|r z$VJS{0k^V;SFLVU4|5{ppvo4iOqBPyRi`?#Qgj#w97Y#b0R_dAKRoSTdEl!pX856{ zZ!s0lw9M%5e|Y-Xm2ZBvt@vj$Eup2m$wx(YSQmR-CIY+@Oa2>&Fce_`%I^dmK{zdSeQl)4ZZJ6nk0iO)&k|+lqK9xWaF*j$Zo5H^%ZJ?8M&v4&Qr*G+Hp;?`D zHVl!L3+fd<;G9YiRo@6~%Ny2yY{+SsDf^kQ9WoTu2PX3)_1#1<93-9%!HA%umVv{) zo4C#x+*(6pF^zG`88Pqtu?Re=i7p*Xi;;l3QUi}&|J0Ev?fQEl$4sbj4Z|eJBK%T@ zxk?yTuj5$@J-KpwxX**?gU8>Kxj6x$A#@be0yN3U67TA1ZKi~=A8_x@b??m^VUuL= z8>p?y*u9x&l{PQ_8XFRi2Ml=em0~FyyP^9Jq(jk|1pC9gw;1E$9Ba7EoP3W-6OpjO zIVdy-t?O`2VX&)pn;+@M)fkW!whh|%R@=c*PRXchtE^w_m3!{-`jOTeR{UBNt<4uz z@N5&M-TiR#n;lsbUKZ*16#k+@k3JX)UyM5oei3-{SCBH^DFS#R!1pPUju1BWYbQhd#1BxE@|g@D2b zq*tIjGtxa+01(jk<|Wx3;bda0_@+6Ye&tT{NB3ZFC)Jzpo#+VVIli~e5?5o;XPR(7G>bhP5^(h4_+OPN_YuaTC;CV}{!DPfa!TS6 z)%Qclh}e^V+!o){k@&&AgLJ_Nc$>hH&z2CV!?#9gmFPo?38;7-P#0D}7W0hqbx>S- z;I;Zq47;%(8IabhI>l^%0d*)WbrY$!Jn0nO<@gmCdSWe4BuiT~{p%*|LhAXnD{WV_z$hs!6 z$0kbK8Mu(Z-zV;Z@f(j7r}${en~v?WubD#*d$U>M$LO;_X5^GpS|U@t$A@bO%=DPU zZ~4j-nS=|K36!b39DF)S)CB+xJ$AMa$c6=jDqQ@P^(0?QWQU(6o* zz+4?wy&d6RlvJz4rAHWeu(7kqlSo`+u+q%-?U{z-4Yd7-mu}Va0y~-R<%q_LkJKEd zX4K;GuSSctr_wXrV-fGN3nxkWkrnr{(!&Df2|i(2>2P4tf7h-Oc3Av#V1)y9#vENY z`Av4jH`4ZR7lWO!iN$LgU7CF}Mzyck#WPA!C_WRa&MfOMe!He!)auLGD!5)*V5W?o z=SE&+#?C=!#vVlG3ma&`Pjl_3gZ3TZC_zItcRF(d&Xa$zeWBfcO!5NloY8mn%Hxax zR=?)C&phJ_N}sPVk3ME3T|&?RhChwek9h_m6LUt?n768wFp1q*yv)6Q?!e>zIjK3Q z19W6P3eAm&)5!;_Pw%G)eEE6FnO>BH|1t6r_XNIYW=%X{(=>j@C)jB&Gr9M8hFjE1mgtK z7gJ*)9x4MT-(W=lhqm{DkE%Ko{wJ9U1Q@vyqDGC1ib@^bQbQFSQiCxN!Qh0H#I6Ev z*X9MZySU6KU6MdL8Oil>fv(cxuJ+GXcin2MTa7?9Boo+7Ko|LAD-r*IOWPZV+Mtw# z5Hr8;bIzUoLA$?w-_QHPCv)#T_uS{4^PK0L^E}Ua&hu#AW>y#)V$CEGFHas+sLT+k z##|$!bFi}nip*NsGD*F+@Z|fu*|kL*N4@W;(0jDIzJz@}P4UG_p?c{z)im@)ROa1p z!-1-n#t-eG)~&4A(7vSbjCSt*F19Y1t5r%FD?xT=mTC1o{7u1bp~y-zc9JQw%37IY6?4)? zwwcVPI*A9_k(Xh{~< zJ@X-moaV@O3a1QWQk{_V*IArTXp;8g3$v=SGGxZOc}Ty$jo0ZBF;%0zAjNSoc6E~F zpuM44z{q-5-uaZY{g5rc`o2@)LCE^s3d~5deo}p^fzM&u{&#JPA!iZ8)!9vX81zwEf25ynUn7tJqsx%i{7z^=jVU$2nq;ydG^HX53Jy7$ zOfrlnl0%jnS`0EW2+64TA2N@-bYX00;-S;A)l{LUI%}t%`T}u16=It5ai^nEi!rCL z@xn|(NkG$-)TxlltIaZJb*jlMJ?o##Jg9611n*tK?Za-mLYl$!&+dnM^PaqU5B~6- zw3Lo%j9A*s+s>zk01J2e-sVH3Vq*yzvm(5!&1@O=HW#+OCLkp|4}WK?TIw2)SUv<}dV=fp;SFn>SpM(s z{0~+mg)1d3GP;Cr)bcZ@(+Lh3>o<~s#lznB4%toe^1Z{>85+-`^64`$pLn+Z&%2$6 zt{A3eOLK?r`B#4xoN;acjM|*K`J7l~t;wx)=QqwPAFd0)sCawe!SENqV^k-{mc5ZY zPDLL^GG27@-LjL1GCMB{zFzYoCtc@=f2rF3U~Nv#&c&Z+;FY}SXN_ge*USNHEII-$ zRxo=DBY{#t;YBa;S*vCJR}GezL*~Qh>Xl!w#A^L#?f-(_E>#-AY^U|||I0i89BEo_ znZ_vX1B3N_{m?0@suF)=jwJwF#w)FXecKp+#Hr3~EO%YyD-iO1 zN%o`J4ZFW{IpUqtBpR>mj(2&ZN4*C>?DqMeV%C*M2s-pGYo-}r6+sd#p{ zWJu|_Xy@RUxbcWwMh$dK^rOB&84htW<(zgp7&;Yni_@iK4VIE_TDpGAIX9S}isW%> zmpMkB)Uj-_kH8uFSq!!6?@7_xe0_d8QR0vdH_6A0hTBHotZ2E^=$*ZOm+qqWqS$JwGdaZ-O`4iksAMKbk6}ifK!kW zdxZqM9NP)&3=Z032dFY`e3ig@FI98>tDMQGS@Y=l#`e}^f+oQXY9ji@0F)2RN37qUVVuAx}rzpYk3M%dj5Mp;m z+K~fq2g-(L<#n5N1}{R8%7;1Q+V*#S`rO3b)t^4sWvVLWS5;IZkW2lXm(g2W5(3EB zIy%rM@}$$TJemptSa|1&4$b7&r^bzyIP-x(McW8*0Ku$EY2Utc|te26dX z+gTLnhAJwN4V)aQW0?dR5?qd{rj?CvL5Dj&|tI95Gtm z`F#pAx`d-P*8hyoU>e}uy0QL;+#^_LBlb0Xk9)-3TydPyAbIe)X}oZd2CZUmcfZJR zckzq$gt}iLzrKx~i{53I5pC*lO*7HsS&t@|U@12h~j6F5a%GxeMQRl~j0g)iJ)Tl-wkv-o<8NaAI`6iZ^$Z(^;2Qg`;Jw?BZ zyNiy_3|8dbhkhd#Z5iQ95AD7cvF$?dUbFzmEc6{N~dWzrI5&Q5XVfcLic_=m_X>+E7Lv2J*@^P_lJ#R)X`R)h*Y!ebHs zo4x81hj)Q8f-`dSQ5`r+MHI$jBUz4CPq8 zrqes(ZTMSh)i!Q*{ji%E3r|K{KSN37?eo54oe-Dlf29V7KiE?n65ViIHLJ~@rW6Zy zZnQIVB*^7ykbgbP`x~hAgXG0%>Eqtyc)4UIM~mhh4otRd7NOyY1Vv=;T&T8Tlo2Mx z22pZI<73(4{Pw#UCT@&lS20Yq`VX~`cHIFGsgbxgJJIQjg6hsi$2;+}e)`aUyo-Kt zM5zxQImgSW(q2$u+D|Y`E1Xj_Z4A9{!)@C>16s;BZ`5O234*BExX10O*`#si(4<%@A_OW*9I31v)}^}kk_-+3 zy^CI4wzE1NEGgu8;OWjqj@rF{_nZ(zQ&bhbLOtnY#bg$|@KJD}cBl@HUhu!$))-dER!>7ySXuu(~zugTSJvGmZ5LZlqplR~L03n&h^$6_qv=awsCd z!A`?&m28x=lX9>t#XJ1#_Dn@hQe5tLlRn7d4Kyu(;1_IV3cl27EKO*#S9gr|xhId* z9@Y^yrxqTOS>?#Pmn@~7G_d5Dbo@9(f_H_!x|8P*eKegk_Vl{>Q4`EX-nT{9{s{BS zVT6^}g*e|gBi+Fsqv6{y_A=*m^>Y?Ss??p_gDT-&#gF+3MpAP#OT(k*uI=kb`%;o) zyt0QltS)PZ>#-W5f8EX!-R3UOWRdqwrR>1qnU3ih#qFY<+ou0CD`%JsLj^w%zt36Z zShRCF8{Ue)!rzT>S1xb$FZga?iyhud@l#*m?`X{hd_UZ6&m$ZO6z-HE&p4B5zBPOm zy!_?Di$yL@J?yUtIU8^}!*a)Jyg_D=U^lLJx^cWN4hCDDdj-UyK~`gCBWa&KS2Xgx?b9 zMvL-bHZs=SZOtx9l)ORZJcBQ+%9*f#wXJx8Oq4t?uVM!x%dFX`myH()(P(UVk~F-y zr{yhN6#M4RA_K1pr}0N?XV-(24s%XO2DpP?;H*zX`??}l6l?Z0lZYlUiMhQXL^00H zuZ!)3L#HyJVR1?h5ln3^0-Xy#*o)7Y1a=Y?(yx`y^TLSs<>pzV9PRALnvy zq!al_PLZo17c!N2W|X}V{+cy=CQ9f^FfzjQO{P$0R2g3V_HZ3JoQ1B}!ft z&d$x}<2(%hr}3aV#%Z32AYc0;(QsHd!`JA~CQ%<;QwI}Jvoy6_H#N=>Cl_rEo~g@b zxOC-F2(y^_Dtun-aO7OLtY88Ig@iSq4(PzTp8#HCoJxv;rL=ajDO7)2>Si=tK$T*L z!E6L?HT88fRgK4s6UQz6(gzgeTb2+6J<(Ig3^KMhYnym6iq^h?FPKT;a%=Wfb9Qb$ zM`LK}S8)|sSVl)j#>18-X6F}O#wOW;B$IXi_47$r!D)WX?snFZzmPYCtxQhTS;eam zS+kVe6Ar^HJR%!f+CO0Gq3i6DmvNn~Xe6Y(YChf?T42x4VT#%1ymn#$kpbXX;gXurHTzZBtveSElXuJyGi zC7W(TWcG3lfo=;)z1f2yfTYpzG@10<!n+K@gugL<#d3!K! zJlQt)%7fNB=E7}XQbu+K2UKFg;kj2Xd^bo$&tt}uMDAI%%VZiZIeER%iF9W4$hkUJ zsC7upb$Sk7x#-0n=8|0(xAyG2vSc3<@CQWPw%))u{?%YWz6)RS#iac^juS%HR@w82 z3is5zAjZ|b3`OY_t>Urv7$d1FS&vG5poxXPIrYJWMO zL~Dk)MER%PelZ%3 zfz7TcKO!GiCrS=cziYsUO!El|{V7v0`^TRjNsEp!c?fw&<_NaJY-@w4QL2_-9fq#9 zQ!cuUn8c7yMY^fWahsANxyv(Ey>8Li9JuSfNESeBpZsQrvS3xYfY~fxI*LLO8Dbd9-X<}%-MITBoW9Kls)+T+EPg83WFjw1yvJZ|ButD6=O>bNLCUMoaLABP=Sv4QQY3|UKW2Bir~Af|C*r!X5y^S$jbf3 z(0%F_X8D$Vikk{ZWNQC*q2X)G_8sg?X4&&H4}PdHqX)~~pmpm3ad=2ML>3Zkw)pQ- zzM}WTpVYT`)>58?a{pXJm<$NGmZgvjpAi)1u42L8LRKoF;g=PsMo3+8wzsLEJkAtrCAxmg(eIy=Z63wvb)=Zn}Jn{${FzVKn{?*GCPM$72#Djk01SC$2quZ$azY)At&Ww`K{e zVU{#jIlo5L1x?^2xymuSQmIp;eW}QLvt+I8u(KYw!d-6C*2W>bvt}&%GNJ2=a;5erJsy(SEZ6h zO0^USbM|!nHk-4j(ZA;GsdWDGjB@4ybAAzc!{YvaXkRwy&Lv+jIUt3ul@oPq4YDvqex{35uk*;5f- z$~MsrXxhFZ>w~@UNjvveYbS9WRcl~hX#tQ2>z*l9|I;UfRj(5?s!c|tWsH}=wVS-K zGLIK&xWSV3HO~pkta!R*54bfd!1*>Z0A(d~83{p-M)~G6{8d*_u(vmOrsmgXU8z<# zDu&={7Ycmz;2zTiH!VFFw7jN`ueD>$@TB^I)^{F5r=n&GtCTOkE?QiJ56>9 zeV90lrd7o&L!wqq%Bt$d7=t&9eb#vI``*3L-m8su_drQR34gaHGbc4U_97R6qDgMJ ziWefUWw?;s!l1Tf zPfr&^dqaFTvY3ArDw$1K=5+GH97b-#CN&_n>~j8srEz$oa_25e5CO7Rwb+_H8P~PC z^{UR{#Vi~{fXZ_0dYO(3ISlK0_*Oy(&Yz+`ly--|V$Cic%3PAel=tu@p{09ONgw}V zL`l-yk?bW(m%V6bXz80O)9w+OT3~I{odNw;tj^4-=WjoM%lUKo`wB>($KR#=E#|L= zzn}2u8T+|^8JT0fV|`hYK1#hDojqn4^}g{&*RdNiJi}6yz9u`hf-SEcR3XkCPz|^m z-1XwU%<}eZj+# z&55Qm!sDZ<%yaKb#P*g!gN>x$sZe$Crw5JL8!;DDIO8tL zVD9e^Ilok2%c>Jo+dJsp=Y;@}DE5V*BH);-S>5`hts&Fv-B~UX!&gr=vFuryXRgk1 zzMC#RQYK3uBW@B!%5ZCq1Vc+F!9i3x?&jhHa=VLMqBkSTK=bfJ--4$QQ zxWy+pO}l%El2_Ed(hsTqQ+Cl<1uu*{S?n2Ri2z+FKap#;iIBZ$C#xcBV&t6Yk(_fp zB`_0?Z_!RSx6YwEUHA7Xk8f~c9PDb9LA{rCyjCml*!(qK8OvU6B#YAki*~Z{8XoPc z0Z|jyj#k<&*_q``z>!-<0t2GJEAv;eK~p=5&Rc@SB@i=d1rS$dBqv3Cf!G4sd6Kzk zWQhwc3T`qQul#*R^!K+wEjg77oR^O3HJY{KZG3z$zJJe!!48!b^+p@n2iq4tp1Vyp zU2#@ENw^gHuuAqopP&c{FZjC9pN0BN+(@%dJt$_NWjO)jb>;{5nzhGOWRyvIKhtO- z;Mz=#M0aC`P~MP{`*GlRWNJHJB3 zF9}7qsz|3O>w&vF$~ z(NtFLQrmw@1*-4qS|Z`lG&II7J9`p4DZa$^-){SDsR6sE0ipr%lJQu3f$eW1(c^wi zgnR9FKK-Hku1u6f>N^6MpEVn(_Lj@oEI1&&BGM%c8P*#SKdRUZvCr7*n@3Pv`gmV; zuonebuNVV$5iV1ryYA6(vy5g!weB;T<6EMwpWqD*&dOJ?J2{pVd+xC<2uua71t~EG z&Jk1Tsmx~B6#kP`U6i^KO|MsCS>9H`hF2>h;=$gGk{rCr9~DZGyV?th|5riSj28|N zVcm-(`~iu?F5}gkC^(=JmZVcOB@WUfY zaIhbDF7viA(=g`odLP)itXsU^rO7$RZWKP0*!65;m-)Rr3EV)SB!YM>z8ftT5yU9V z_WcJl0=lNUiS?&5_?o!ua-l!tXC0n!$7f0Q_WVs*IZx0J`8{VK*eZ(v0So!Yqf~Hc zF=otI!%kc7t@WoLCudE!?cZc2D!qH`Y5!m%1C-@Q`$k933;3E&ZUhhx!h5|wTkexL zG2X3dP1$@F@NJeP;{~5BkC zFB-*`(&I+UT^Reb^~Hc=W{RKAlqfR$iA?{(>pXb(t4uH8*j^s!V{KUf33-i{RecuC zXETp5S}RWRVLX+o@(DO%+uwzhe<}^-V}Ur3=_TNv1`7;A)&P(wTbYDpZ7C%S(-imd z)YuHx&2J-)#pVis0U0mCY9GXO8!f%ogupvGEThEid=vQ>VNyKrx7qonkdPJf1wN6O zUo=!_U>a~UOw$>%K{27tIbNtT@kA(bG67BjQf4Px+6enGx1be$;v(6K-_lxoWxF}i zEQZMizw#J2i?fMY&8$;+0Bjo@_Vc^I`So3h94oU4_u=f})@V6}l-}#?kbBB$k)1H%I&hw!fx#SxIgbb5rNDW(1fMHO-8x+X$R}_Gk zzF&dww&%e~df#M!e3$=;f;Q?KXhVr0vps{2xJ(jeml(K2nD%cW5J@1;@^akvPu;eW zrAzLOmWuHKVkcv=-xAj|ma(;sIKktS1Xn8_zXc|eS%6_(sAA;eTMOVagPb*AV6-Zy zjIgy-hm77k`-l~+bN1n4ec%kG0HZ6SD`)zYP5(c!x2-I`|6D%V zszg0Nybxo97&VA_h_OL2@6=qvrGJvH`EMXn?>>f`ox6$M)M2$(R_Y^bFG(Y6pFLFj z?86d*nnN9K?K7zB=UV`wsM^bU4cFdZf}9v&^i`Sp%tiUZgKLzh@?lw|TDlFgXJ`8q z(jhzD34(nz$~phH@&D&rz>JM`y&iM}zkDhOV-~U$r0Tv5l1|mtp8XZk z+~{5ow(wDgju!K&lC7eB1Ccw2P@fY#SXZRaMr_6If%=I-wX8By*%G-_D(@ z${!0T|GJ`Jdky9100S)K1mCIo4+R+hGkSdTkn)Pg5%EJ-5Hw1?EFE%eN!r#67Z`1M zoCHtg=4guyt`x%FI*}-4HZNmgEs7uU%F?^>$CB7>`)=nP5UcXl& zijZT^L+6l~a~rpw;0fc&R(0fTUFa5A!tucqk+BH{Tl87ziNLqju9a8%m-q^>gX~=p zt;cv_&WduF5Ye$zIbY@60TB~ot*hptRXd4h*7f5LU9(_W`zCrJmexIZ#l zIA>U#v?d|l7_N%Gv(pSBhH)%$dC(r?03(31DbRXfM&u#kWa^QV+ zda&Ot%j2k={gCj!a0%X8;w*~BT&+)mxCIM?_FNcNE^S83LRoJx*lfA20A9pUf=~xH z(QoG=_sk!N{JT{)MFm(8D{MC6jSb&bNR>&%S~MAXjAaIBR3Yv+hY!#BZb zS(GaSU)f?U^annXlZtS@1jfq`>`%)F{;7(U1A4YMAtpq}sVT4lIEQkBeKpSueY)$o z$h$<Cv*BwI5}!<$&{t-qxd8WB0)8W}>4W=$Pyq z3y-d4voFE1Wc?ED5FR53c3;u4c6Wd4(af=XT910q%J0J4Jt}ke7rh=vEs9>4)w5Gu zWnN2d6=MxFKhAHFxf#rC&rLN^^gX;{`GAbZobu&ph4RochRUm)5KW5iDjJlv1+b#O zoDuVDHgUgH2xk}V;Q6^dyWkb>gPXk2leU|Ru7C8r$L=2Nn1z^9cveS zNx^^%9$3S?ZG{4h(cu_Y8eO=I>UpLvj znm@~;da$=`2wIz1bK5oJvpi$zi;raHRJr&f9K71xHZeg{_iFj9Q{gsrzYWY?83`L}PvG7%A+?@=IYvm)bXY zCkNVenz%R6cVhpm@17pKll=&tCRXb5FA?+T8}5z_z7>zN@(=#gY!(-GdU4Cri<|PN zmxzA-76GMpaW-U6k)0r8gNG|BrN{-$Yee{q3hhN)Q>5RcC*#zdHIAs@IFNjUGU``9 z;LT<|v&9Qv#Gi=0>{cN;#wre*>d}hiThV8MV>Y2VPGRXq7%jQ8V`2iN_jJph!tn$6 zi4qSPkY9B5bz>7HQaF(keh$v-UzGf#WP(jmS3uE1*gPcF(-4c#e1v3eR{I` zaJW7~nU~4g)-FqR13~OXEAfdAYA@bl1xpa{l;Bz4S6qh(oEBE4HMXq;AW4chL2zCTStk%CgoE)<_P++v|MuV*#EM>|Jx2 z{*bTqM>@MROJ~4B>Qx0_HI_l8&>cG!`5V0J0yf&s@jf9POO+zdFE)7+(c4@)F&gfd zo>*Oz#~fkAFpcwA(Z}IhL@~Qlwd(1vJzS%&9sysT@C6!0?;Q#`Z*GH^b$i#R!3tYW zyHerrfel@vmT@v7MnYAC0z6%^w>Q`-_MakuU>h_l&Co-PhIc+C{eed+eh;g0H$3It za~cm|nChO{9S-^u^6Qc)$kR2RM?Ilub(TDjC2z^I9P0udoiX_pcg)WFNAbpu{pZku zu5V$Dg;9a?-XEw@R2pTKy%;_1U*p%96P0fAtI^Zr(+Q#sPEL-V&PgZSDG3vawR(Dj z@uSu((V&Cx3IG9y!>t5;>fc|>0Z(;-c0pkW7HiX1IgMKL)Wo5cC2T%{$cCUKZq zRpI;_niWe;@aUV`P3y@eJgYnw2FfVFCfrnMe=t#Cb_p_f}YpGhqk9vE$P&e+0cU|V) zqpJ`d$f#YIP#;MbTbA(0R#Z6V*zQQyc0t+j*-ZMCe9&1WYnv#MtY)coG< z=RE)?eaW(3d~NmkLN&Q_~h#tPy{GTy}Bwlb)9JSkA8R z65GY(STX&mkITKAN#U(vcQ7UZjHlw!)l)sTzf1^B=P)fH$?&z?)>3_)6hOD;n^8Qa z?!4`iPq%jHi)gdV6rS)Tof``MGZ}S{Fy<8{-$1zWQrrJ0it${v4SLF2aRDfKAtn<) zV(bhxR%*{Z3%SYh#8M&$BTr#nH8^}DfiOu_vQE#(va6tV)iV^d&jTSui{y{K`l1vc zHqI)5Q_%`MlQb&vgCRH+@H5xAYot(8+6F>G!!|*#- zml6509lH*oOv$oVr<&fN?#{a3qvuqanPxSIC+!KghbKl~eV$U_rlPCAjt$CpNS6uz zSLMuhkqK&+_wSg*Qnjs!pXAsbM_6aJdAPU6>n^ph4ILT)9lGDlvVGQkpH<}h!gp_B z-DMSJf8o1B)_lKJgn0J_FyFQ2=U7EKU-<5bH9yxX!e;ghzB^{k&$Ej1zVMx6&Cj=r z^3(4ug%26Z$d||Mvg6jQe(NjPNsOQI*wbLD#usQ$W_sIas7|Q$&y99*x>eSOHNUR! zQ(LN8zmm1nRN2kPWEJ7_E8!KnQzUx9jMaBVCe-&ywz{#2sAQ3QOWj#kgY-?jE}M0U zH%v<}ttF*?KuyKj=1VHI-BJLpj{1}WdTD*Luy$K+Mr@o=DBxZ|XQ ziEqsnnnsi*H_-7d6#YNA#4eQNn=nZVyk$XwQ`Cc@J7QSYA3w&KCZexM#ClbX*j7sd z3)Bl31hy{gki7$)q}VKyHFwFR^6BCQ-XN5g;gc)G+&k8 z$Ae>6xztHbxu)u$f>tdob^1)B+^pxSda$p5!9u*DF|R1Pr6; z^aP%#2~A2@76-|5^l{!NG|_9MxVHb3HDFDF7wnJ?XFdJPo!KOXCa2Y(RyM*{TPJji z%Dv{29cL|oIybDBd_~PcgkFPGNNyctdxqja>R3VK<4BF2d%MbGZkG93j+pyg1>X!M z^cWjn08D+efK*@1_3n0oTDB~X@xJt#7)%T#0C;3VkGslvT}a7Gdwwp^hi46sg-28X ztR7)TM9PDmjh;@0CzzH&coY9CqKyjvObjaNNBo9u_)evO!%iKbcw*PCe%gW{ed;5PsLRszB8*r$4OnX~H zR#eU$1>joSvp&37WQ$^U`L=e0pI!c;DLQiQ@|n)j-vJt{XkYwyc#E`@YQb8OZ9TS% zrUyP@GjCbP+Yn5AAZJ;-x;c&4EpOb6N``nZW_jaf;YIJ$ZP`*qJGz!PmYRxz%SvT7 z>#;4G2k&l|dBmWdPSK+ga7w~QHL$GvUl9zH$AX@Z*j>d{ftFw3#jJh880Re8^R|5X ziMd&5hl-(o>nSPUXgO$X{gh;cpUv{dv=0eXw!Dp5^o@M^ITBc36CdPj^p7ZXX1lsD`J(HNI)i>CXw8aO;o8I~XwZS`jhg_29)DMX9c5T)U zxkP_105h!3LN}J`wQBPwduCPS8B29~bSGYS6t3Dbqd%A0X6ULLv5d26dU-J( zkC%rkozC|t_SF}me7eLeo-A^`U^c*JIJ*ER;sax&1LN!Rm07*oG}zx4ko8R~uKKS9t z7h`n$%$1W7@~99^Y*-D3&_Ok<3UCW64n@eh{fy~3JC(AsApsePzo=)%XtpB8vMoag$N-WVJFKJg#7efO0h=&7X z)o|3xP>r-gVcEj|LXl3wS+?({5O|&>lw>ui`O_XIe^V#~x6Iv^lTHIuV{i9AzHl z(Do(hnF1ZUzS0!?!IZhOC=!mgALlxh9{DCBO}eipW?`O@Nq;V+{7-|Nn`Iv(y(eka ztEGHaSna>MbWPUy$Cr6OvC3Bj+Uw)HpnsU+3VS9U^gN$=-%PETwxBY#!nahWlI5QA za_97i>1nZwV;wKaHuA+q4|Q|ZcsuID3E1>Qhc*)`^Ug5w{78R%Bw=)GHs#gshkvTPd`=4b$|MNHW zWrt>Lr87{j*owG!g zeu}Ys@g4f;>j1t|LQ5y0X{>a1^MX+jRmyNr_*=t<-8Gtn4irxgxurZwW66_jrn+!GIpbwJHJBBroEKNt6zVhjt6oGmd3V9aS`o?}60-q{oQ8CVU5~ zJR|l??u@O`FzLS%c(~IFw$)rZqv9UJ{=Ry*`W{ju6B0_~Qe5YFW9#aBEKs5ui|Sw> zn+xhqrZ=U`MJ!t;)F*n>9;o#oTgt+jTC;r2>T>rh$!#`?Ac7)AF)abL1_$02$6SiR z!d`nT@xNse6sASZ^iK)WH5aYyvqsr>`>bYJo-y*keDVuTJQ9}Dex*%JC}B0er7v2Nwla>9JsxfAl1NJl`*-7<{n8Z-E zwBV!o=b)0(Ys+=#T2INW9_X}ZHf}PuKAdTcw{6t8`$OX&&DWwL{a&*XjlX6|nMDB`r0LYl+3)c78t`zz4EVb*{FFnVYU-lhiTLt-p@8kBSd?LuOMe ziB7$0t}pqOgi=OOG^)TM&4*qnl1~Os=#S@DhMe~=kixTF3~?AwYutsE3tu9e?n|#` z%64^Q=W2*UN9?}Q82K(VfY8GvlUV!`g zDG%vW?^*}{t8mNNW+VQG?X@V1AB&B;T44w-&sz`5U@(=2Nb zUPz3_1_VGm_AIqcaz;tKP5CkfOU( zbcF9<7B5wBs+>dk|HMEr(~b#eH?o>(=Z@|wQRUqKnrgi)l~v9U`I2L|>CRUKD()!$ zB%OP^(EmY&OVMO`!Z*4|4PQTONxeM1&gPx9wpKYs3c6nlwrWAGa;_uICCy4ft&Dt) z!769ptF)S9m6Oe8Aviei##_X$Q8V90gP4eW ze8~3A2stP864X_xz^En}4aGw+jo6Lysam~tS9ht4^tD!W_H+&FxuI2A%g#v*S*tsg9@Q~57TE!ldEHjZ5}^P* z@2aUZE*iRG>_Z1vV7Ihy|0+$_`jwX{R_HEGI0nUDLVeVJ)WzqKL1h0OOG_jOMcbWieID|%+K55CC9tprP*I) zm#5iZ&F>Bx^fhK$dd63SG1@G8UTiVMP)hA)M@H#cN2`ua#f-Td<(A@3&6i|X(zKrB zHxX6)eT)jD;joMi*+@Uf-AFeYI@E9xu?G&~RUT5&Qp&N^FFt#W4Qg`gz0}zFJ>I4f zc3LCpzm*R(CS0r;;LE4%7ms9(-Iu&Jy@~L7M2+2_9OEBF_RQ9?`$R+-7&LWka|Ht} zFLb>J^(RzC<-{1KC+eQt^pdIVFZ41N=(wF}LWE!rI?+o{(&QEZc-jR>+6WElMeVZ5 zgddrdUIs4U>{{IfZQr?e=FOhSs5?nnb5gH!MX(d@SdPsFVr6K7^U!QCt^A6`B!aQk z-ZfP&-O<#Ak?Hzi-QTIBQZ3lVc+Aa5sEyXcsVy+Q*Ji{-238VZ*CX6n?a@@unu2I; zUPidsmAF6UBXw{w{)}NMry}ClZJ9Z=LHA#=A{KgO4 zqJQ-Fe4um7GTRePT$p@QFKXxLy~8zG+eI6r1t0`iXV$M-=9F?C)xTv+L1W_@=Z(6H zf^odY94ZQSKa5*7alt!AZ-FQ|tTN(;yTF~>Gxq{>(C+hP zh*c~hH=TJdGbi(T{Wpf|c>dBxt75OMPDB0=&kJAWp102u6aPF+XbZ)hBYZ`nn9GDO zE)>H;IftK%82YV|=kSZw5$7A!5$CK9VI1U$^A*_b4m*o~{4FLhbr!!qeitLl8yD|D zA?I0^tYJs;1^mb(`54p6sr)CQZS3m7@bFXlck(sG4W7zRx8Aj{ePGBq6w6StU$4Yo z@^!Q9@j`K3V{9BxtBi*CM{ue+UNcn zXMVynL@HQG?m~&@w&s#;axtS%j{yF>`{}ZID~>$olbv&7vz?u3T^fEQN49J)1LjgW zQ-O^!vtosl>sKUajvA`;*VCVt>RU~ zTbMPJ!>)IA4aU0f3m~h32GyUI&C$q(i&6K9a%T`VZ~TWwO?{W>b$U7%U%b2is8|fu z$3@?Riep}`i^ZR~SzSEOkXl3q`0$FCeDPIY;50b;|FPe+a0V&aZ2Cxd1J`ZaBpMmCoT-Z6HfJ z7$BriVtXnXk;^njxrJ=?^s2rvz$o&2W(a z)#f5ZkI~iS7$LHx<4~I8T{AzUp+rFmvr9T`;Qmt@jxMP{@+kYN;e|akGShgKN!I=0 znaYPU*|T~jVEVe>dL@hXtiqT}{MQa;6U?`fMH`n7hn1Di1j6KOP`J3zl*`P*N9FR> zLQ5`xQMg_%*A&V*q41w!yh)a{6O%C?oJHv4hB7ms zH~duP)xJ#Ld;hGwAGGQQ5NFD#4YfnwGtSi(qNT&UWGjYN9Cb#2Gw4I@ap(Jhu}ikN zR&Q0#_gmTWWqW7THcyeL*_1*>DeaceS(bq2Bb%Dn-)_AJb#AUD? z?ICfsAKly&+|OvZbXT$T=z0P5+NCu!$h%l&9-LnjEgCNzd{Yx<_|oXB!kM3)??-OF z#R;(N@wfzPx~VMW(gVbOptoe{FL&;KPxU~0np@)LEbP0M8g2XsV1)0zehOK`Ux_+Y zcs(hA2`#-=J~!1CqjUa9AQuf47g{RcN4+&42ya0QCtH-XMJ5;%%ty)6S)Sk_IS*8!ptQ&%^0%{^xo#5r$gEd0bLR86g1>$IEqE<6=N0~9J2G=#;_oo`Q=2n$ ze#qZm{<`@)m-GVu{+hpqJb#D3pX}6she+$^&nw^YcX_ckn0qE^Zsa9}9cz`sXQ7%xh_Lnt8o)ka<=9 zdA_{oY~~ez9CXjHBk2148mAH}stU!4N;tnz`L{Z+P`07M;|qml36EAgn~_=$(~5H| z#cZ#Dsn*OkT0+<}G6}OCxyv48tns?@{A=mD!C2#4$8~bm?>x3!>edezJe;xSs2W># zRnEc#%pE1YA?E@0J)=N715)SiIP)idd*=9rAs4?rOIBbmlO<2)Xm3KFH>|X`s)QfO z4wb2n^*T%L8A#c8W}EB8)>cd%E>+O|jIr2DjIq>Kc_GddRQ`&}R0QDJ<`Ta-CnqsS z?FA?1n2mavg?0T&C)$>H0ELU+$2L^A-*#MJS+T z@!h8V2T`1}x|1EChp$u2kv!keGnlrNO`tjF0asIGyzuGrnaT({p$^sp10O&*6G^O- zm0upsbNMvAeR@ zy+)=`Vx8zYq}mB}=vg%233cRIP4CY%Agj)KKy-EMTFC?vYw!AtwfCgq=P{M|C@0xd zk@GaRej$Rm=+CrT&3Z)epy#a1tPS!~;syIKzItedoK@*zx8cMRuX20C+2O5 z5Y&NiMB2d-B;%(nN8DRf;@`q9&nUf84!u`dHw4>jFXM=1v<)u@_RO>e63&%^Z-&Pd z-74qTnX-m~QbOPmJQ4fEWd<-Sfmu)mz)P*w*>;8BTPraCi8|q`?QD2=57tcp4#E5H z>sKbIm;Ia1!5aZi!7IrYKPxM;y(@f}KJnd}FIm&YO9F-wcljU99fuovnwPbOI;9E*E=<1kxRP-J4OyspP@ePDZUW{PoEU+&~SzCYEmcQ<=Puhp9(+@q`F=&@PIW5 zfMBchW4Fbu8WMpmM~6)4c`qHz(WRe~e1;Sn4hgP>G#>u4RhCy#1x<@PfP8-O@lfvC zBUR%{u&3I@Ndv2W z4k)BQ81zFlI5Pi>yU)rmCIDyWuRkvH;Mpn_ydQ6p)3zlIa;mmutyMAw&!RGSm`z`2 z8WXQ8X7hdAi8F;SF&){l6+DHOHX|WcItNK{RfJjG>WSv(l4Hn37!MM-Y{k90?R$zU zc$~dWfO*6Zft%l2zdX~7ts=kE_#z5%4o%)8536|)f8MdXc#l-Cn}DX*Dj!~PjD zfp5hAmS1b(7LEzVB-fmblE(x4ELCM)1?oZp$|Hn@T>#;UKm|TW-Lt{%JaG(#P>%Qz zQ2Qz?=c&r3aGBzv)CI@MeHWDSW zGI~N7C#TzqLs;CRu7|DRvT1=c@T|0Hven_j#0g1woK>D695aaxDKMf6N6e03_)2sJOy1a3v@##E#swQy|(XDtu7xu%dS@{T}omWWSY z_d_<4q>D?|V_BkmS=pbap%J)Z7_6(^4>1J`3m$;@o8-+-%kYW>hJT-Nc5NOXQ5%px z2Nx^B)5dy>71|mvT~IfL^Rg(k-Kt_qj~@aR%B{jVpAm_x7OZlHw5}CS z=La%meFcYcyttFKNP|Ib3k>RtM4|kn+DJsR_a&GvjE%>EWHfw}6#Kj4cQx93p|S2k9`Uuh3A2UM> zDxJ%ICgiKwSpiL8H+$L+iThC7|CO;!(^L(oX4%1czM5Z2-_RpyBTM`8H&)yA|H)(cTQcw0(MYBxsv|8`&Du&X&Ci_OI9$b0K5Z*jHBfEaOm10pD4qsU z1-DHw7p{DelbXsWIr@{q8fC(&hyCy(S^}l@f^L)otBQjazS^&G{Edb{S<_%<4%A%< zv!#MR)n*YW3v4T~g9&FAQw`^heg_K7sfum{lZu&B<@@N!srxf?TJ~k;Jk9kAo;|+L z{mbz9GJQVpASwd4$nTNNy;2vXRCr`ML z(Qf3KhZ{Rc&?6ErXU4|uk{izy^9T)K7MK-2j&z<6x8knoRS>J;;!J7mf2{TrdKEf|CC;Pj;utpa0C`C>#g~SuNN;H zEv_8tjy65>>0XfjRg*`7F0I$OR!WOx%j5=1S>x^R>%tgnc*J}t8`!Fd;-Mn4Yd&HQ zYt!=;y_wG*$p*2z2RW|al(M|xj#J>5wVM;++sKuhW+qE=Y=5Kcel0^gQ_1fv$v?}P ziX@G2rjkG8OeG)pYq}_L{*RNntRlSG4R;<#7zQF&eVh?_Lc5Q{6`8PwX?oZ7$Lp9d zrH~=2h;$vPDZY_Pt1bMj2~(+{Xr|I7YVaxiqjF=D_QZn3#{9kX#a|0^nC+mQV-laD z3)K0w6PL5{cfY0ci|jr;|F+kzgkpETa5fKV##X!w?H;C%ifxRAc@$-~KC;X~@~9(o2V>i;6JhY$H9@B+yc?^CNP?c6e12hGiEdB7%6GO}3{IoI~77jm*mUWt8}TxXQzr^8Fl5jYAm(zDa`Glt4D z50HgHbq9_%gtrax=-k4C8M}j9T73VgYn>frO(SQQ8M~J^k%H7KGDW1C1iNlCZd|@9 z)g%?FsKT&F@SJLrb~}H_k-oalj@9r~a5#-0VbMd*ix`RvSEjI^iGPysPXe%2=d14% zl?B#bwtVKw{z~vyt+sPBa7`}GU-vCb$N^pNzGMzw?jqw<^0IxN4}BbXFq<3r8f5{3 z?^t|LHg9_`mHPBKOC=|-N;L^^J0_{R@+h3jE>smj^P|63QuB4g&L>$7wtS%XPqXy? zsZR195>fhtXtNN41YFu7t*K8*Q;gW#GWc~rx^C-KQ!I?D?#9}b&LWIVNxl`6I@>#h z#_)jplvI(~c|$!q9mOwNs;7dB6{jsdm3sLpsgRz2l?^gxI_pdY$C)pu2OkmQ7Cejh z(T}Ld{kC+~4Z1om(l6C?73`?J%%v?$5n9x_K~9-TAdWysPp6&x=(3&SzyTkjv$l)s zhqxWIuc4Tl{F(NxQHMl?Bw3#}OdzAVFuzN#%XZ3<3qXxlrVq*7WjjS11^2&?1I2i0 zknPm+rO!ewRnB*hP=Z1TZ2eyj5SV)51Y+tq>l%@9a~SuL(bQ)799GPrz$Eb+pzb7N9RW} zct~-vJr!>)sV12~tX@q~X0tRq)g+yYe4s`Kl1GyazSL$tfK>jNN>M`y`J!qlZ%Aje znq`1;C<1;Ge#;$`X7krc#UNQaRdv_31-tK8^nI;&vy4`6v-}bh*Iq+RncK>qwHIU> zTW=kZ`vbG0r_ZbTFG~SQKImLdYjpK>d)z@WSQji=hw5!L-=QirWkiJ{m*2lx+DbKa z`J1Y(Oo~)RtK$BcP?HlS4bHmuQogW#+s&A?CNe<<0J=hr@U(i~g z`V5reho>men;x)%U?&lk6hNg#RO1t-O`i-vuBIgCGZ|{TaLzx4iG#tFYPyYNLD8^| zMnR(Iz{n(-4rQ>psMA2Uyd*%T(TGN|&<<%(T-K8_ zJe2m%l0|~Jv=VA{Wo9&C`KSj1iE@g)i}W z6g0i81s9{#`>dY@WsEi%QsyxBGt+@9EW3)*u@+73aP~>-ABW^eW8GSsFepPlBy978 z$dKP2k|Do|40$8tJmj3j*YGeI63s??kG@Q?` z{atMW^krk+-%8>uYx6!-^5n^*t~`0RfsO>*vCdz%M~ri<)5@iK@3I5R7U%8Sb8)V3 zJ|att+Q)-w#^6p2blkKd8OzGXalR;Qh0n#!D8IrZXU~}Jt9v^*Tja={A~r4Rx9?U$ zY7!x}%DLz;Ei3D`XZ}b9Gb9oezN&jO;EuA3_&PWnIdV{_g154Ah&?GAx8myrd6>#; zd3ZiTtLUAA^Up4-8zU_d;j5gVzoW*J(7IYd7M_%H%LqHwt0ZD24$t@1ygJmZC5WYu z2-}oyztkaH+SyCNmU^|s-J=w-PxE#h?jHpQ!RA$^^Q?-?;|n<(k!zQY67(>p)vM3a zufn`i+g})%hy*^H#{7sCVi0d$`x{#RuA(u{Z#$(OY598<8R3?tDT{iMzwux0S9lwe zzZK$;Z07_keYLj^O17e=KTvm#NEQ10XmIbKbSt}aN{E@cE-l?oAC#Q5D^eMX$nvrz zhOdb_=YCF_M((b1rmM;#Xs4xdCFn~#PpWoqWr`iqP7(5xnS42LNOhO1X80cYpb=^2 zLVpoWRV_U!Eo~jv($qgd=r#NqA7th%&wBM7o0(^w- zTaFu}e;uZLqEgg{u0>=mMT~R>_{(HG?Gqb5eyLf*oU>pcVPQ|1&vkM3I5sa5hL# z>JO9+Ka}@QhwyGF8~U9c+~E}#AFu=xN7+!9U3VMEN8eE4e48@{i2k9jq26TbM>v0P)SrcPitrt>H?ZL2t!X2+>Bz{-8xXS$DMyvcnvu>zNDsd;2vI*@QCV6SrCMrXZApL z;%@`rk8X~I=r7Q5L=>>G@$bY=rXmQ=juN(q_fbR9HAKc-hy zRiLi0qJMuy6}7rXtI61{e-o~{%-CV*O_WLTLywr z}mIUy2P8F*y+dC$af3#5}8~*330vQX)n&mkUZB* z9$X+TiVkEO8|6$38Lhp@ZDv`HRWFz%%vQbN62;(Xw1O8hQQ6zXZRVqh2N{jN3ni4x zr&KgLFv?gjibg9FJ#ML4FBR+(MI%8y`Hfr+Y}O06ilW^51<4X$uF;n#uHSpRWJ65? zy2oCZ&j$XBUma|>(rN6~J+zk|Ld8fYjZrzDBM*QHLd~Kp{ng6OshKI1=sugHlbP0N zzCjU}84%;Ey1Yk6XSQa>rS|HLO6LrzL+g-2TFEkjw9(#pqd$)<-d0|IEGFLrnRS$l z(SsIGu${w@V8N6Pa;=`0J4P)jgMBSG^mqMn z*-Rg?pNU#Yu>?2|ZcsOQ;`g2%MfETV0dkAFyN*FP1qw&i!ZR3FC&$gF*7KzIA9=$F z2cG(sT|855?xE~b_p;sOZd?BQ5-d}?wY$AmFX(@Pzz<-&X_JEXB)^4{z6RGoPxD|^ za}`?A6% z(Y{gPA_;19enPdBHIvNJT5deaFGu^bBlqZ68jifuuw^GwWx{!?AW80Z*&2wHt#eA* z`fK4^b=p0HX^&HJ`F8td{MgMkyx8X193_bvRRNTZI3PG#!8@4 zQ5aSS>gXOxjQyBjj+dg2RF6Ud>XTA#M49(>u875icaPm6Ii3>IF`J*|7ipB=igKsy zUn%n`shQfNXO|S0#P`V~(z@V1wOJ^M{aKa8_F>c6B;{2~2B~GLNy^cgoej^3)l;b* z%O+|0*F{jgpUrue!f3Npn*Cadx@~Qix?AdOsP&Y*u$sgC+HJ)QwJW(8!{fo|; zicGa`%@3$!S1iA&CTVQy@1|8%mOKB*Y+%_!lMFG&V;G+rf-JN~1g(+L>;D0Mj}+1R ze{gGXAEQ@g2<}4|>ab`2Ah4&PRrGpN1u02+g0R)8bEIz)muDZ@9BftxKTm3#L;3yd3Cc?Ke(vRsL~h< zEkAGhd8sBrj#F_Cwro{bqlU8QzS|;3Xo~+ZS{@w03$(gLZy<>2NFYqSL zN)tq-6>nmjrRVTa;C4V;@bM{#Z8QML=EHR20h8z@&#`>e= z)DxASx>8LtjiILbXTj*>+zY#|#!->?sZx1P;7@uJH z_&2uRQL@k2`gn<8y*jwRmhoF{-cj-|MbX~#h!{O9~%RqQ@w2P=UP%KeWH=DPp-4U&ZSv3-F}c!JydRyF(Te+)C*|sQjbo`LQ}92i!%w zG9rJH9k}1ZsNyIM47vO5?tq8)uDrkXT1{MX7z$^UR!rCeW+}V;kp1908lJIr?tr~u zRP~oi`|XED@ziG*$y2Yfb$%b$KAC6U(Vv2x=9#7W zX6YoebaJ&>I;A+;dabF741Qp&mqpWlW+oL7HG<_S#pH|`YOpL21&4+nH z{`wB>1Cl(FjJbt(9$yd_ay!}#Pax7C=&{;yMKzCIMC%g-N}{mA{oB5d_>rt97KBiM zF8l}dSqH4%85O>|`)FIRBD?ky>&H;w%M zZ@=(+NHg%5l`D0E7^p&uH|vhv$TxDcI_}!gqMO zu5E>D{#5CRIgJR}`C7<6il;spa}lz&-dYLSNEZ4TDO+Urvn_MA*a5!jqe1-m>g}=| zdWdMepJ>(Uu)cA}qlg|#r+{dq+LJx3Js6HUd4ug4OMAr5TFE_W`>XonLV3gG8|;m> zh@0oFB^c3wc6@02ZV8r5!g8P1I$_Mutz9rG$~z)EvR^?f6=<`%jaTMo$fndQw+<9n z$B$-LkLzH@W-c%2VD@AxKYt+jK}{#{t=j*Owzq+=s=5-sZ*p%SLhu9)7BwoZu|uD0 zTWiolFV^r8z>jD!0)C;LsWN~%V2pvh~m-KNI`=-S;fVJPW*v9Jr^J($f>ScXQjiGK1x6z5eC-X{;PtxqSw@8@o z4?hBh-E0Vp3p)cB$sD&&LD>lX=uOHMP1N0d~G^Idf} zVW*pHKCVs}tHGWD!3N5#J_*2y-2_Sc2LZiRx;hA0oTuI+VY>g`VIaps4VhiC5$p;l zfSpiWiPld@|~OoGa`ix%Fte1aN9Z7GJ3Nk=ogM&=^4n+u56qOb}A_|k^_ zJ~HL4rx-eslVIE=_8o<9-Ro~ir|EuSw>jPAvU@j|5&k^wO8>1+ry%q1-1*lstv|ap z_U1=}%G?|>nX$y+U_#oR^8;_Zm{pxiNvh>kX6{t~B4lz_k74_j`3O z5EU!FhaM9pF3{HakO9M|TQTYf-Z-5gIX@7QA0CanzWklfu@Id+sa|?c=gkt$c&^2EX>aSnB^#dk=qi{;auyGP7D5VRK9;zmzV#DTh;) zP*L^si;T7~*lx5}!Iq#Wg-#A@+1MoTU_0SzS+?_$%3K?O6`A_IX$bshtPedXpdYwb zfVwiBD(h#_(NSl^Q%EY2(zxCZDiS4!ME?KodW9EY%m{Y|Kbbn+pZ_Cq zK?cvLh0KsD+1lCs`;nQ95#f||;As8Ep|T;lO8qNA|Jv88Va&bskt-wJEC!Gn@PMGQ z-~XWh@Z0tZVR2^s`%US}3m-T$_OGSCL_}^Y?bq^B|J!sx4I<}XCJLP>VWj=qN%Led zeqeiH+i|}?>$C0Xx4wjWhiX^Oy0r(&Jwwz0Ux`1jF=1J8&rqw#K`V1&RiQxilBWmG zmUG^WB?J6x_3V-DE*?q6$?T^GTs!b*-O;~=er>Lj2`0+H@X0D}H`7BzwsKxwCK(r< zRF?NQqz~R=5ovg#QXxOI|BtIHCShz+gV{{=R0=H zzM4Y)Z@enN2{C{fjZH-%N)4o`MEWCwo}y5?iyCOQ9|dXOr@yiInf%t|N`drPNPv44 zCF*WMe*02_K%RkPR=@WmJ3T6-t&lye*(IMcb&w=S8XPalE$2VynS8OfUJ8Zc=j(4amt{l0oBGPwn^1Rs-3V z9qgb%$;<^8NL*c~`Yy%_5xZB)wQ#?5^8EE$&zOm}ry{rsG!>uVSJV=5+Ud+1lQTJ5 zP{elgM@o-1GLag3TTwL)X%N#Nb9p9)H$KIuQUbY{e1!R}ue!{@oeF)gaOCB&ikX*)8s0h5C7&?*_~$`gU|t4Ss3G2ecnaDOkqtuFKc zAdb#VrBE0Hz>%3g`tFJ^S4lCsXvMAnwx{)L^2@3otCZp zhs}1EEJT*z)2Z^62%%?SK_X&U*n`tJqDn!UV*=H^U$H}L8xbgn%+Dk6b);k7`Qa_> zG{nn$R+b5xEvS9TkbvCu+KYXZzJvY|;-@lC7~Nq%ra)AEFCcNJrgM^f2aOS>N;_z>b%OZ!7u4?)-iaw!M9D< zEVqoOyo>R73L%t8(V(}97!icQIany9R_9gDbh{*XtCurAT#`rOd2o1XT17U;&kXF6 z@>u!a*zCT#9;e8@`Y2HYQoK!7K;mnxCbQ33cQSDrcH5@M5sow zW^)K*p_0FFb1X3;dEtf;OxfVpGX{SB!&06tC#ax?DW8@tI)*fcBAlXH_OT2 zzC!Pzb_wbJSF6~$z7#v%;dsJQ*@&e{YI81`Z9bdJmSJ|b9kA`$u;u^Ywd%;+Z+Y?2 zQe^F&6vZCl))YyZ;yxH8LGzKIFZ(f&68qR+Qz+6`STe|Z$u=ItL@s8vJh(L#@*Dq| z{CZ3I1=Cl38?HUK-h6Zb3cOmW>lW8rLlR2F5_R53)=th z<5Ei926B{kYoz^=cbsKH?IBI%3D>jyQY92Hvr^=3CNA}%j-b^A8-!w>FDd&Yap{QT z$u1b%B-t}7zJ)lH8?)0JH8stzuge=J@wV%3BSdy91`oWJ=rDQXND?pRnkpsTOzyk1fj{f4Hh)oo!S~N6cKrWw0=C=WGPRYGr@K- z19y7ZEz7$|o3k{`IGgx#o)i+syOUd26EGpsd-?5??^f5ymu&|!s%u8^>G()nMbaqL z?MNbTKp-pMX`(l3x*ZuO{vC!7b&j{~pxPN`Ru_@g+my$<4a0$4Q(U^rP0{g}ikfu5 zcnAa=MNMoahPY&OH?1Jgn92fY+0Y!OjW%|JtRqAV-e}%!kQFEoGBl>Sv(@!RamV<@ zx_a=4$0{+=5psw*0rAEGwN^lFYRV;3{*B>X?&|xvCESnqElCOuiZ#IHl%*1EL-$rk zHQb1(j}-O7EDyKxfV~F4PTf73Mq6Tzw|&Iu=61fv=KSG#Z3hasCJvt0*^U^He6A;x zj=iM%QyT27+v$3b$>-~u*@)PY&?n##k&WclDQM@PTl=7-c#mkhPWiO_-Kit0l@uzD z=(R9Gep_T4VM4sji;Sf;vbGWD@etD_1kl%DBF;0|zb|(aIb~eTikfyV66)wx;!f;j z6L4NV#a?8z6;iaK3ECTMl@pm%AABF7J=byY5Bm4jqN9i>Bj_x>O&cPE)Vbem5>R)( z)AnJki9M^a?I2n&l51T)k$*_b{^NO?9h{a%`d zT=w>!jES`?409rpTm3*TACI zE)Wr>T4zBtxX)<8LfD_ObwsrGidAXwYUexOch)s^A~ulL#u7cIsY&5X10`~{Z8oz5 zEhuSiqo&E4F?L?yvfeH#7z3orlXNFJu$P`)H`FLDm_?uJcDEgz)pkJq*w=N8CyW(5 zU#*y6I?_9#znDFAWvP_4H{;IuO1sa+bhm?q%C+TCO4~u(L5hkU$)rpzOqwb)LfXm6 z7RrEmIhzEq!RSgT^y(oxv@3?lh*}`p>E+f)_nUNKNOreYsurw;`wU$5#Ok|U-45X5Y@wS8nU^fnmiic33R9;WkXOWVPW8tG79 zvbIT+r4cqc_KIMF5FgE#x~f$rDL8TUstNMBAlA;`8*OCU!Qe65ToGbFARyJwSR`dp zlsj?ADo=H^BnGy8O}I2&R}y5&%{2-7Vuvk^A05XNy<8~7oHG<6;Y~(J$5zW+Gh1%r zgSHP{PgXHNkc@S3F#_SPWLBMIynQ__x#BsqtL-BRSt;NIjdpT0IIc$$ribEMVta8O zL74oCW;qxPzr);@a|#6etNUaY9p`;qD{2CJJ#kxSJCex2Leu;PRV-*b-F7PSPE}sy z_=1smuK9wU2nHmZoDw-!b$;)&X(r|R$Z?#byq8XslmdGn>l#s+&5P!?)5)QQ`;$Xd zz4phAiyEa4F%oX9IQAtoo*3J?U;44oY`5U+0(=cs=MzIKAMjmd8rlvduLN+}ron9I z{&Nut*|bIP2ggp2KjD%Hev)lF4zSensNtPu#wrHAm0U`kd}lal1d zlfAo1DR4bk$LI5m9xT6Rm3G;b$5#F(sUj zTr3N0W_<^Db`!rPOq;63~!aoA~ z|5m9Ri)6kqdZzV8ahR;S15HaQMD;s4M%lCAj2V5WLE+nM_wV>en&K@aXRwDe^P?j& zTz!h}u#1mvf*h; zE(7+5Fxb6^X%)PsKKV-Q=qUITNK9@LHHhKC1V*3H?51LIDI#`SIJ=LYff+&prTRe_GaCG;T^}s&fDeP6XK^;XD)9!>?S8|X(u3@$>Jcwg zEBtD=c#n4v2BtkOdYJiZ;iF8!jhlBHrz}{JEpADB?|C)geHRVZ>2L+|sl|D9w>hs3 zw1^`qia#Y3b0j!(PwdflEPAq|yJ#zw!$YUP-V`*v^6>@}8;vG$8*{a(_<-OXTH-7d z%RyQrumX7C73$s*Y;cR;<+zT2xTfMm~d_ZoMkW3e5!|mMpz!VWREFn$3zpoO)vDAJI$BG;uaG{qbJ|Y+!1SpEih^Tp6Emn z3MZTCke5pf+JHaWhAnNUQ1oIINArTG%(Ok64}#c>ja@uW9OBKyhEgVqGyp}mJq!$d zUi66JKT;PJMYdNwOOuns3>t3v@^mm_z`ZE;=uxy3Gc%^WdrL;N zD^}c&SqT!B159B^prvyet~6IqR3idz<)KI?r)h5chE(wPSwl(z2=D<3;vjlIwbbt} z1wzwKUI4GjOl<{4aT*i{6cm+*1Qb1%fpUhy34b$oG*_A9xMfsLGVjThH+H^T z+2t(zFW{3FHwcUCeVHF6Ij|e>o@D1Q;_>~3yAjD?pi-HeSyAE<>j6W{9G%s9Kf`II zQZxLo-7dWu&QMa28~Vj0$jJj|Ak&9G*N?!G(htu4EKgU%D&V2z08SOat;UpJ#I%YZ z;?W!X)*rJtrJRgy+<}5Zz#F^K-Q@Gass1^WFShYD3M_G!t>R(&>;Mm*`fYEjHsu${ z?k%#0_)$J6^>e<<+qDZx-XMNuj=yALhxowMO1+{9=@lPE-tpTgX)$R6tU+k~;jv%E z9^)fC@DeFa+GKvkXUQ)+ug3!U6seE)6=JE^V=Xi^bD*=iKGt<3O!6D~bjd(lSE&qb zUM68hOQ)g_HFs7I`(0jaW1h5i!9%f)MN-j%`%>SX?@g*myzk0(TWzM;-*Y=^d5z!X}z+mL0l~mM{L8-`EEOOQ)NV_vX)q)r=Sk zeYZgL!q{dR<{=dqHZ7JL7=O5`(WJ`psm0zkYoI^SSWv`_E?)IN^;f z-V99vU5z?g@gYQO_&H^-apNr{qpGIAd-S)R-)rla#0P^kpN{3wgOvUj1ee7AjVBZ9 zpwn5|=d&nQuP1YAtxp23`nS242<_H)HWj@rs+DPX=M{V%&9lkGYVA$W(blAk@b52@=3tK`MW%D{anot( zudGuqCQG*|p2K@t*riSJ6V#w17JoN==O6w%`dur~@HR~$af3`2;wzGH{3VMZG{R6* z+~=+QdGRSnh2B4qekL5x!S4hDPb=(EFD32bH83fq4*2` zmOj=Y$?DLn=>VAIGJ_URIHpCsESjGD0rt!Ls91I-|@ljDu(HOPB8TmL8MRk-$jl zT%>d^QaTqYor{#tMM~!)rHgwLnJ{NcuYFcVScV=<6Wb*49T2??!{>{8$9+CYI_{u& z&4~Vl1t^lnwX*tY5>-jS(&n&wq&8H&7qM*{Is~y=vpNvH91-30oN`MU7na;#>GE@QG_6@fdHSn zwLg>Epll=Z&Kw08-bMip)Rc0z-I`yK!|Zc63ICxG;aBBY%kDGBgWJN#(&wGc8Qx79 z%CQP|iG>cvhf=<=Ut1oz)@5g1p!{=@iuj(&fw7ACp#Y8=CdS1=Jdku;lFcUR)-1Q8 z_(T!1k$vg5YFR=?Yg|-C=SQmf$eVPUn2X*Mtp7fMSOjN*pvXhFjYy3kmh$^e++sPI zWu}8juw2u#KK0n})HSGX$UD4M%x2qPBl6f{gr{hmhz$H{zT6R?|)tr#s`Dbdp* z^kf*Ke{14`wp4Uq^?B=yp0K?Tj@KVqMdK|}mY}sqe#m1O5AFkrZY#4gOJabP`bFPn zDXn8i=bW=sc_gr}wunvvIx`K)nWk3uMT-i<9bv_l&N@z2!^3gux@7Lb8~jOJ!L5T6 zAWcM9B1lv=0W*Ga2xNQn$pII#_v5H#8 zZ6M}z(G$raTmo}vZT(6Wb~P)9ut69yi5p;a5?BLf;{sw@qx-Nhg~5_s#B+Xitst~X zkg)b+I2d;H?XX+wxYQ4j z{6V^~42&Gf^D!gaGT`+I3DGgVFzsudf! zheG<8F;<^s(NQ^e_SX-QvxJ)PU|2r_*cjXj#IKQ?r-W`XE#{dKvD1IZ znHRxNwmkI{UW7#HRPuZAvHZHVIsCF{MBvRuL=vJpawtup7R2g?O9!3mOIW$FI_<3! zAEFOZE-L+EGiqy3pR!9+>!b~a9!pJgGp7d|pnS_HKfTKix3%Tl+B{pEsgYzT60EyZNlc|NiBT4S zUwaow_ob_O<2|*49&7}+tG@^PE#Q%_I4r$e>i_(HX7M_u-;3Y1?|Jd7Qvbl5z89hE z`@OKRP1Q>A{(n5cyw~9{Tf&J_6W2;ZQ-DLBR-xwCrGDe#-h8n)Z`G_`=xfHaxyO+^ z*XAyei(ezTYoq{Szv(*w)@(FZ?|f1uTU(c_*W?AA`>5PUJ<$? z7P3P-_X)r+w*V%&qw)e*g`%zkcgas=1|drTky3{RpX0s>C>GY~I2 z+D_X6cqu?)-+a%V@#phBb`-x2qN5IHXADfaWh-RID^?d1)4kFxbl~Ayp%hx5?M~y= zkqt-69KWN?gqGk=4?;CSeCJ|f$rck2=8=zR7{*k^M|sXEoiR5HLx}1Auq2CRS_iH? zVM7Vz5CUAlK_=BU_NgL#Wmj~zRpunmdt#tKuB{S&4qTn=J7V=+rCLJSbpIHqWSDDU zF_8P5=Kn=P-raX5fwCeJ4MWQk2Zr8J>R){~ zeS?J=S~n@yb1~ddy7S5OGE>y`oaC~Z25P44>1FP?E;FvX-<#htk6~`en{JcQ@5P?J z7a0jwSM7lfal8hd+8oB*KU+eHx(N zfA0gI!Blgp7R!JeOqyz zxDPb%jT*z)ee|G|Bk09Et(pE=GEK#UQ|LSth(lnh5a-LENQtW@8h#@9< zy}0118LZ3sTuc2>J6UazfHx;P>$aGkriG0)aWD(4s%!vz$1$g?9TlvmbqT<$GA@q63U(K#?bFY+E^FC*xQ`m5m z2p**m2p$KLvrkBC5p%E1(I9b@I%xEIE_h9~5=Z&+v+AQFanzg#kvJ+0^_Nv3GD%UM zLA)aaa1%5T>K`I{ObmJA`p$jpY5&5r1&@~?c+6A5kybq?Y>iFwxAj0#<;hj_1C*9RIfRGSQWDgOF}Q;cyWOXJJYy z94_L`^IdTWvwQY;{uBt@p;*6B2v2*|2kYx#rD}Drvf;c_8rs|6akp@{3Kniuri@el z7F~>OOz)8OJaE!d0-)~M*O)d=-P+l-ueEDVvz#HEI-OKOV#Flo?EKf0ppXNZj6k?~ zPQy+PSt3(w4)0u)C}dm5SCRH$gZ6+ZyS57(WxMcmQDnepb7%V{^`XoqO1&ii7YC5Z74B0D>58l2n1DX_ zoW14qC0drN^?EPKhR}!Fubawf^e1H$K`8&YqCYW{D-#0VcslNElu+?X#1bimx@W%V zmb~Uh*SM9dM1nULpqZRSkyfPAt)}F)qDWK4AKYo{5m(P#{~X>^igy%l3vV;iUJE1R zSxN!Zmbk?)162%|yop&mOdfYD_yWr+^cE5uRCz;|&K2}Zti)D6Cpv9tL_~j<7S*4X zr+7W8tHtZxlIL+F+;6q4`&2~q#XnQZAGv#JwR6D*Z!KQq&QcD7i4FW8}YWw`kH zSiR#GKmP;)E;iGSg{&2zvY@R;HsGoYBYPJV;2wrU=JTclqUWRJmr&HxAola~({uX@mQ`*#St zy!bV9!p_ZDeMKs|Dz#SWQ9^pa8P4sZs^ZtYB}-*F-&JagUrenLI*VVK!D}S%jOnHW zC*{}ZTwVOUy;RGk%&&VHDyZ_c*qb=j6GQ40o4;8s4faZQl%`&nQiAoV*QK1P-t84r zP05-}#-@rftzr=)W8-jSyTKt{fGr@buOKnJr<4^op%ObWnR+Jgl!B-fOt z%4>JbxWga!b@@VGkwZQdQf%7GrX*#kvWOu8w5X%tdEaQ&dSe;P>st;tm)W7@Pdk)byybMdOf$upQJ_20Zx&Yu5L zEuHD$&^Y&eFLZ~ObJI$)FxqqK#kU0RJjS)2oU>K$1+`$jb;~Y6VB-E@z2Lnv|7l!? zn&@ks)acm^(qdb3OQ)Cl|NQe_gvh#6R)U-Dj>-ycgjB{aAnmQehF69{OfF(tXqGFl&i+1yVaoa3w;JH-o4fzfO_ z3DRg<;5xUSlBJH@)~b0b&wSsT-i>c>TwGug0{i_NsO64Yyy&2y&fsp;)V!Ps9|#5aO8*(!av3P`KK;opeq#{Ka}BJKSX6#}Ed4brZs|TdP}gh+b_K zuKF|z>=u_?ReXRS7jIrSj$4Yba>7VEdcx#C!!hfd&bm(L)nj=4kS!Qn94sl&u4)S+ zP|dcD&-tNg<1I?n@?OkBqGa2SZAN9bU?+JxtV?b%oBlC&A#DoJ{Dpd`P5u_zwbFcyZE0 zgAcK)Dae<1x+MqLT2>;0EPfZctO$#X@%|JV<2{ZSZ;ZHZMuuKO&hb6iQ21`N9Tzus z1GqmVH;7q_56I1U3~-CzMbCxcHz$X%iV!c34#PIlE%_Wo1!ga^+^?Gph0{`p-lb)> z>}663gxhDij+hcW+QrUy!imoXd;(o!!8Z~)ryGbc#T6(VZ}wy`DT;@q*REHKL#^+R&a4P%azIF)G5+I-VRE6xVexC@o+<-w5u6M z2@pt}hRpJ22=21pMwn_0_yroE(No0Wk?r_}%6Ho<8*rX9uUnceWhCW}Tb^HlvT*pBnBG}SL}Yc_{1#LH#sy3`YT+Ln^nj*j{(?9bXs&4HDh)bJc%CR8J$g~07Yk0DL~X4 zdDnLMoU~utM+(>H1h6|5t_-G7eK2f0b*w}$Gd#0PpelN;j~;^b3*(rsNzL6(N`pJS zCkILgI^wA(CYoKSa-E^~PC@UrR9z4`20%Li==<<(cC{S@pdA3T_vtdsEi=ttp5>hr zO9?>t@^A`(?#2>uy_{ph4W+nZ$@cH=!r%<=-QUAfgjIpLWyvAT_;Fa19cw_Zf*=^b z#DRl%hpb7gY#J3%+og$#jParPrwcv+>r=v6>yZrJFLcRuFjywL|61i8hcQ{DAo<>N zs^|%C{4BJ2x&1jyZFij$;-cLIwGHC-&q-~|^aQ9f+B5w=sCO&DjYbH&oYjMc6QAJh zJr5sJOr7|rKz^qx68BQtr-6JskZ%L>EkOP~mgG)Ugu{%-puVTe&{NAa@9-?|oLG-Q z{v94p1Nr^E=w^zdn?q@I12XHU&(@1?4xIzv_|nMF;+qrDw>+r;J!*n&XKcXHw$B+}0jlAsY|@ z1UlbO97be-fen;JgU;Yn0zVn=DZ$QgbMSb$1pVFx=Q`UDMXC66ob87`U>fdkJ8&6_t?B92sR}RG*n*63$+SON&?+ zbg0?*2-{S!KHTiCZkB^g>^^yp-Ni4qvF_r9l;k}X_*6Io!6LV|g-oqoNZC0_r06j$ zsh@G@Zu%9!{!i+9c#Ay8T`YukY~w`A0i7Uh5k28_u=BXow2`eR5MC)~e4`!?Ag|1F zsm^HLMGb)>akB?CkR}Ccv$!@vjUNC#vq`?iT#{e(t7epW3j0zozJ`=iensHS&G^~(SOpa3^UK_2+%YSl`t((dA6AL+`tuxxRhwDpXehJdFUVtPA zTF78zB0vl_nN2hTwFYVT++6c7!fpbQfPhZrCO*i53Ty~&6@PRLO@lXToY{$Wu^g`0 z!k`Sr#w@*w%4%u$7Auxal+Jz;%~^jRL8;B!B0vu|cGayb==g7p9^RNBbGF`qG7nYF zY0w)g!Bc>%Jxsz0l%4`e^jNw9KbkB4jfniVx-SX1t;dcrMn=Y2wujx1GbWi))!{Al zg$lmRM)}kmRTS=NO~F7-soPcS0mJ`!LdNm>QtKtu3(ejy^g|ewI=0Oliev zQl^Y`4a-i6)4SxioK0JlKWnWZy288qY#_E^1F_RIi486i zIv{Pxp)=cl?n%o{tt>~j*wDK4a5>9JM|S@2G86*~7%d?dnV>>L}gc&ihee%+;8=Z<7afDDB;Xejk>K=5l<8-$K^HbZ2| zx?{3Anw)1^Pr>CZ3Ir-YufzqLxS&hfuC&>*x>|y*Zr(b){3c=_WQhL7U(31Z6jSWR ziu0O6>$q9KAs}=CJx|pt?ka{oCB4Si-5(&CbhffY({Pa)QFZt1?`=*6?ZhqhQ%ny| z^Ka&kG4dVps%vzWP4reJx&~o^@RyH=_&^?qB78(YtavMV;oRYKhro!H@BM$7s8}wh zYxbH+u68z}oEH51bOW*)K}`U6PV=WM7sVBW-qyV$oJeaU{Bk^Krfc>{m@gJL`_D^? zVg{5B#ims8^46-qH;RPBvSVc{XipY<-}$IUP@&2DrQNwO@)deZv!uN@XeoFyX?P+_ z$czQXQ{;($tgXu;kH{w#ubH*7Jz8&wc2CBabK-CgJIJD@0QSw|z2WeHL@GPIk2 zCd&G^azy(=TE!EL%Z+?n_&cQ6Z5+T(t$2umGq zVhK#nHAS(^O$dOPQAm9J$1h$C$5pE1T^Fit6sBl%07wAScv7aBNE2qEJ5h`y>wHt8NO1@sNZGXiC$ggCQ=pdXeAeZzq;1F;2u z7@3bOa$V|TbB2n`F|Y-ajzYdu5dp|-PLDh$4mdP;QR1yzS#H6T{vZEH2!*;1({z<` z=oo^I^cM%5Qoi!{Xa>$N=;Pd|bFewM6PkOgc{UqG4YM|fU)Oe>F-)Y%nUlG5PNwM^ zOd)Cn*9E)6dv)bVy1P-n*7YNgtuoe=gF9Psb)BBaF)et*BLXMAZ|!1XyNiS-P1kL~ zt}Vb*!T)vLeYM&~{N=hIJG<_0{r|2z-ESc+`kG;sU~ElI{`20K_qD*1Z)q4jD9J`3 z7-m8?q+t%>a!i0}o)yrA^~8_}cCgCkH0xNTa_2ND@Yl+x95_zqP6}>o?KunPznI@w zYr4MKBzP~aWDxtLOuMe9qJB(Apol7!rGk6B`g|051>T>@HCRcRNdW7P5kU9Wo)?Y|n_W7Yh{yeD|J|!&B zhkP%u83JtDyOZ37ohd=zsqB?;whKU|pa5?5Lob^k5aSw@oVzzfj$i2DS zE9yok18WG1Eji$9hMRO0orW94E@B^656))CyCV;rupq;Pmbv2(nTg9n?s%U|wmbeP zmmGI|2bWxTJp8evQrLDg?Op96{73jPJ2GJ3<=u>tkE!e!XM2mDma|mk@!mt~PfV4V zBG;W6le5PoRyjPxffXyeKOc?tIvP1T8Zc^;7uDGTIU!?_9v8PVJtUO}{Eku7Q=9_} z>0L~++?j{q-g-I6{oWmevg$Iith8b&?5=u80RWvaCsF6PLu`~VLE0P$;-V0#_>38t zUir7e^@1bIp6&*p&ifAI^PLQ5^S1COlVE0Uro_OQs9!Y|rWIZsOi9ZvUjE%q-C*Zc z6bzg?hbz%siGwyc-dvfhlv#2x9)M+I#2-)tjFecC*a+5sBi*%@%OO#d^>L6W!#L8o3Z0YI6N6QW5g-U-B+6iU6IZCs;-O2W_z+>3$0-eE?_t79B01-)EMTSfx!HX?-HYmcXP%b{(w3 zlqoF>!n!~$9`43Nvdu~u;(*>M*8vs$3rS9<7D z|KGnxJ5KN+9uOr5)%~9uVttfJjR@4f;?&(b9SgM3bkP!B@E3I`Lep=CL%iFpmJy!Q zn9ZC)CzX4Diqz1(J|rodL?_I@o|M+pa~g#q;Jzd+a#t7di)?g;zjYGXOGYi)@;q$qQtZWCost$LP;+!iSG7kl z*lAjc4rX+e`Bx~Hz}%73r~A_`<`76q$J~)KX84nN$_jiZliEka>=HJ+tGXZOW>Icw z`%rRtGPvi=(Z@DcU6eHE*ja}~wY8hZ9lsDxaHhLVQ|Ir6Wh{OWtR1hsfh#lW3Ojqk zn?_R&Dm6`xaE}$mbnfe~RC58xzb|n76Yg;XN67>5Fpnws*gjomkAliQKG4fO-aQhd9olIVx~Vojy7S7dQy*r{)qgPr|OJfE3tbWz1N$-)aoOEylC zul}%5=?#25dJ9;+>#9idt$V~LA(Wm3+ z7;w3jcyEVr!S%`d92U0Uay5nQDXiZxLEhKMyf&wf|A!VaOwDlNhskFcFpU3*Z$KEdoP@ub7){3+4axK~7C(6$}tNe^f14P32TeDhPT==PXTdr3& zpm)ECeIrnnja~aJH#BdOun-oVd{*lCD5d(iR=XGLm|8`&mE#0s3R(w|;zEdTi4s=F(E~I)G=((c1B@z8J8~FCO@&ff+Tt>(i(O-CR4!rQ+%i}!RLwZGWwXzwg zR8A0rXhq0s59`jy;#a}kE0X6kvN^#Uf)6?^MtInL#RS8zB2Mlh=difspQ zXqGGk$zJ&9$z#*l797z(_f>){hLW}=oryt_x<Ua}K z0vcWiq{xno*xURAor*PBH$r*os( zt-d7^Oa0eB^ESse$rfuTWvnX{{hKE3?O>YGq`cq}oWnpv(J#a{3HAt7UF?+(OkQlW zK?zWFMo-#m=&&0|<&-Ka1a$b|RY!kjCn}$ikFXd`s|mo-E;M z2@$wsg-G@9H0n!^xQi{l{Lamp7K_30QqBEE3B{~6vcup&VZtG%kILtjpfO6!T1=6y zrLYL4m;QC(ig$Toy~@>XGCpUdb&;L8;rYZSiN9XoZVog2*Ew+83RWCU0y}YYMsrYB>~yQE8Km z9t?~pX8~86LXfzeNY{eA$Vt2worDv95>EI@IN@FF(p@%>_dt)UJ6xoFK{owT3KEwD zZmr;6n3e-vi{P|r1SVD@nz_c@yP6!_EM!Bv(yZ>FUhkg;PR`~`?~cJ=ke$pp~Qhz^Y3+Y^@RJPzuN(`J!Gpw~pME5Y~84Ve2wf!-Hl)+A~ zCl;EvPn^3-jFPk+(>sOC8!6OXEyp?0eJhhaXOt@jMLE0x3SnJbmi7;h%?@5n;66*C z>PNAUGorq1JQwn1{~hMDx-z&7Jgnq<0i~Xs?zGx8Xw;7+i`fo2A__H~eOrv~FTFcU z@-w@N)%Y-*v~Wc>mgfAQqTUslsv$1%acc6VPw*sL5FMkJFZ-c#XoD?8?9;sHi`WHF zb2WLZ{>It7Sf*pJF`~!n1s4&oQ(xHylRi^oMkj0Enh;DfI7N7RmF&=)_zD^~qg&)!FH>>{F=N!mVRG8S$!zjUv-vjgT!?+Gh`yqF=@068Ws0{Kss{ zlkB+>UHJ=!N17@xF-^&fB2BFGCf2*AV?1Cn!zNjw!M$$inQ^x9_>1{PSj&JlnVhU- zVZl!`+$PKdeWAP^6xkwS9@wV~-{{%dbCmoKG<}fku-i`TInVSb-umntoom+bRSbWvR?^hc3zW#%FjhiDadZ^||Ns ze0Mg-M)_^Isum&oe`(%*bed76zb}idUo;=kdGHfI?t!{w_vmaNqq3!{uOg3ue`C;x zONdu(bq|T|H!Nat!k&Y*inu+|%oTgh$u~BG!@|#s7J+iqpTs;z*~xk%B95tkcw|rN zIjLl$Xi78Nno*y%c9TMVcC$87K@#D)JF^Qm3w*!x`}zAcGrP>ve-T|`lQ1j(<#}$D zsDq+IeYMdpI;*JH0kh&_@##OvY`O9nqQH*i7rmQPZ9S7(doUQ>ww~FtKr9BK$Odkf zhvWdOlO{fl@}KfTPl--3uKv8S*W!w8Tzqdu_9C(&fBdGnKie)6GS21V`0TW-BkQE_ zBk^P#>5@BL7^+|+V zd(2KN42~UMV5Pxrr{*+?j2Ln7x@~%RMSr&=Eel@MBkijgvRN)jrj8hLF6yzSA)Dnw zV)BXq(FRbp0u;;PAyiGJm06H8m=1r0@+y9tQ02uzPtJJv8awc!K;7aj9l>lycZc0x z+`p^=V5R=8U+uNnPTLnRt|z^)-s+i)%OGoFtbQ_JRsD)Wo;G596MJ*SLIQnVW@2Jt zBcTEpFXhu476K6G$Ms88`Gwi-Y=#ipEc!g6#H%VgX|D(v=ZJt3#aq#GtwzgrPV-wk zWPZlPcg@4~*XsFrPQ%~RNg4CzIZZoZKiS(Yqu`+GEtQ0~g?EN`J%E4<(&c`4Nd?uZ z8n~{{{4>l{R%*Vee-~i;HWQxyYFZ2L{*Zs+<&1do2t-W}31d&zN(HaflhLI>O?lp7 z^qWzgCa}iH8KrkjE%R@<3eMfwCy^Fx%#_@0-uc)*;^4fvBZy|~%vT^C;qJc)!`Vlb zVL)t42y+E=u!Z5jTO<*9R)b01FhX^cD+|m_G{A8vl^6YyXmM9PDq+}5vcs(s3V_>- z344ZOU*l%li{WK5ODDR?8zf=R@g-lU>0LMml?4Eo=^&oJ_ zih2n}XN1m2ma1ybgm8Spd#Jq+-yO>5`*YyCKeIO^+EYok>kVh+aavyR1yQ?A$AEnF zTA3)sx3uQg|CBCLRp=xLJ1*d#cB|hS&8J+1d>t3rRrRsmh48eXwueGf{Eh)lTTiR8 zp*@3Hy4VaC8sQ3)C~OoZV8;^!R!)Y0QC%1FHp@XAL51fgL3$NW)gvwKh@?qA2vL{^>C?T7_O~pb1eg zBarAiU*x5se-i$I95lu#;mpy>9*}7B=wzCwgy;SmQ+d?$m_d7qS zpK{f~QyGD*XEGUji7NVbWsW!YpI8w#9Jd6P%2ELkQ^#zvan`0@a`u!|dC4I_dS;0u zdJ;#9h(&}Nn_&hZjhKomtS*Sctzm-0W>$V4dkCvPz6@xcH3PR-`N@gQ35; z>yMLH)s2wlMULGj^h59V9#nd&e{JXSuVo(N$i51em81yGEySL%)Z=I7@oJ%N)ATnq zpG+0j17xB=-OgtKEFUtfiM=zFPmP2K77Nv^4Lm`{NM6IK;bdp~UltY^PapxY1QY8! zoZ8jaS5}qmokq`?P$J5|G_UDml=)GH&h?@XWSVlWw=56N#=;^XWNx z+*!I?rqmdt3luLlL3PNjq0LlF?yfGEzE5RA1q zVhrv+@m})*an3%YGOX)wB6IPx>yM(TCV$4<2XSu2KzYS0CB(?;UvclMlAC`A+~V2I zz|vFwU5Qe4BS|Ny@xc&bhsvf+7f~W|RmH@Vuf}yQ z0^xOCsORV`6zyrGJBeV$>Xq)Tt5G2h6L9Fnc_q{5bYHq#R*JM&uwrUg-8MR<93qxRE`@WaM14}?>S2){5v5XZmpF% z`?CL0>(XuwUGYb$5A-T3QV}}2^iugofn)WY@QeiOLOua^^@|+iJuxDgw_$_;jXOfe zSfmC@Yx+$rl~zh9PsYS^S*F8-#EAZVjlnPuxy=T4zN5u`Ne_W#rp_x*+P{&o1-<+0Q(Hjkyt z>(xD%YngdBb~HP72wrt)nt3?nK2i`8k$4y6Rlg}Vf$b~Llpz%#EdrSdAp22z1OMh~ zy~(%HZk$&qjKILnhU%%gi&x@d?oPSlg-kB~hMx+1Pm+X8+a!tNTRz9T`Q&DtOa$5v zC&vdjkCDx<8;0(g4bHQQXAJ6WXqG9lSEQJX{^dkpH`*AZ&9hAn?u_{v{afl- ze!C8Yjm~jouk3R33XHmFhThf&y4DAE6;4pfsmQIZ=GW@?*eC|XCt zfwL1i!Tz0M0R#sp?x!F49cQs%@nqL;wPQV@0DxpX>i7eYj zFo@{5INl3@I<`p$C9~oYqfIq?y-_zS|D-N&yt-OV$LEo;Iy*j3hWbl4H8RRJG|$Zu zl;@<66?L{^jBYiMgsYKzBAT`G(sZ;Q4UdCw-`niR2=HVRUCQTPhz(MP3M&_ls9>Hf zD9RW*8EznnszhnwA$i0aeFzi8D0EcG5pOKj3Js0VBczC!)+Kv~TgS*7MZGKd-j0eB z7cV`g-;mN64VA>E^@y}7o9xG5N=K!#Iib1;>9K?|i_jt95^NHyElhKk zGsfh16*yyVA!5(Ra6nCsOiyJIVFnQ&DG#!8<>4A02;(NVW4SdAqELPxcX*wLzhyr) zPmYM4B9PBdW#K^=74mg@JZxyF)*vG<5G8;^%|x!ffqbsDaRWRYIUfrq!iWz96mQ63 z&{g;A;Z_?PtXG~SVo?xK2F{B8q!Bf zk&r%2IGGADMJ|~_;~}LcVviD-7+BaiM6YV0_N~P8k-;OLkL*;cuxzzaRRz&To9Ys~ zN@zhT8%xM>aGANYeWckzjkOf)upKq(lU`ha+umCj^|tp*$LrLT;p7}t^DVi)*LIkI z7wXy`B8KQLHf9ns_Ws}qYOJxKSRxAhs>QXw`_&VEldcNj8t5CJ3rv&oq>;b`m0y^n z+}j>&=8Rk8%Wa^KG^_{_B%OqIpr0~ng=R>vw~Q4!UyF>^Cf>8P4C{s;fe9ro0{**Rktv7Tf+RZXcJs(e7#uQ1my3)>KlVnQ7f!gF1fyFN?#w_bF5r#( zlMU%+KMxf}}{ zHgQI7o8>(I;XvLL?V9EET=p1|8M!t~2AQkQ(52~&J0xRAmL_6sveLx&s99Sux&D5R(XR!RZ1|G6VYYXNjMr!IK2C1WVG@sZ%PZ zzu=Z^c*(Eol;^#!&uRr-UofQ>Q9#jhWu@6rM5m0lN&-blzk1tPu^c*a+@Ct%vB=LR zGssPa0PL~$0JnhXu>-i5b(ZXw?&wYczO{HN9Dj_`bcc`?#e8Gn26#914PEo4-gkkE zOrm4WGN?MdE$I}lk0r(c|B;QeoOvCL~DmlJ!ehZnaH_c{f$=~7(U7`1}rcgu!hB(W<-8ZPNMhuCZbe=h_10*AW zcL7DRf_7lN+nLR&QO8Z+$n-ag^QKtDA8hJBn)YG2ex7T*vE1~F^dzeIx&o|`>J~AI z*9}}yB&bBIeRWG8R=IQ2^4{@2D`J$+N-0eyNdMAg(xpq2rXt#u(xgEdX;}D~lWm+n zy1r~W;E25SbdpZ@C2K=8SvqTzV;bQ{;z2z^`{Wb5NTp>EM3NYsShJ$@4|X50 zF=vX14RtCV;7WTb3L+&kt1PjtTVOg)Os$khB&mr*R&>6{IYbKl6q`eh5@z8+oG2Uf z3bM=-ZKiYU)HdB@&ABzojNRH`<#!ZCkZ=QKX*#6XijlH zrv2An)&RSl=F@OT;#Wy0FvmijxS*CNCU&-~u{}PPsANIgDFOp%2+zn~q=?%VTprnp zrodhfPzRHvRQtl-kHj^YxSNvneDSO_fZJ0|3pg_R5Nl+K& z;#Zjo!$svxT4D)spb|LpDnFXlX2d&}l^L{#yVi4R4}_b_(d2$2yR#kmHzd(|A)u5R zQ`&%1#Dx4y0i{sj+Y7y=RMANrQ0f%=Jy+O$2PFprE*^Fk9Y#Y9jcq}15>)Da+Ie;> zQK#0Ul_mM@_EcDp+M6y(0&xn)YdvM@7bKG3wzQ_VVu-MB>|{j2$Fh3Nwdnv)^08a3 zbSoOb5>Uz>nA}YK4Oui^WWTi)MRamkyl(5aq_Tv6CcM;aX}nuKOljcwB|uga@(zB*Fyp+~Hv4$7ub!lwJGvTG=T~Ruwp52SJENI2oBAj=Y-XiXzikFLO zjMj|Y(^aA@O*mAmIiM-`R!C4L2_@Af_M@C1$5OHos$#+}+Diym)dq@amaldOYoF&e zu{t!qZMrOR4I)(VI_UpxqTlc~j!QTh=#ifDfwEeJX1I@U(|m|gOW^g&v$pn8!GC&$ zJ94|M#CZj*`C*<~#d>3(F+0QBM-45t>1w|6bWFl;6XMqDlZU?HEjSZjYO;+lHRhHP z&a&5-qP-L_H|2aiMvtyl_gKb<#A{X#2)u#PUcLrgjZJrwRb>CW{ND)`t&vOZC%AOg zg75)t$$Wl{`i+LCw9&CT z-)9~uCkw0v;#XdlJDM=$%9XxXAotsu=EHljURe%GWyqD<1M?{>sk6P4pe@Y|4za1$ zHH`|ng$zE z?ju89T%MJCESh<&@z{|a0|SBn0GR6CT96%Xj(y++6PIosoVfeQk5GN=OC8voT1~2a z7rSBNsx0E{WXFz%_U9Db)hGabvjc|azWV)R3(Uj<4CpD+dE*o3(%rN0F?r+TSAb-% z=l1fVdHJ(C_sv?A_-4_*?%%Yx`QkKZYopv3)^Bb6-q85&Cx+YrJQqd>NaEJU_RE%V z!r3aj-oi#XFZI^{&3(Ur|H${R{@$hgvKEr#{UhHUVRppc?1~-g`b|!O2^E+R8uxv$ z&*#O!{kIl$7uKiC5_%x@*INDf7i_D)K&!vV?G;7yuJ~-Lw>D~ydD*=U?`@?P-Fvuu zu|Q@=MlWZYwB&oagPWr{>3pGnz*QOs_#}h<#&?3k_nPlr zu`jFI!uMnrmn1O8k=HnDc} z{|oY59(kAF`)>G|clo>*MD~$oIYM#|K8p``wJ&5V~%;Jvvar@x|T= z+v*pTW^X6574tApEV~-CuiMv+U46 zzH$RjO+9b$<_PA$duBsUU~ca0<&S3N`d>y{dv3rVm`!?hy;I%FH+~OFW=o1cT${0E z=Hb{w-K?o^frE&?Be=IIOCBhPkU~^gU0+_}yI6bpH}RGKcl^vAF*TGsJC`5-*JuOX zeK*plFZug}Z z3)18JdEviC8)H`~lr;AkYC=B{=Uv+1yVD_4uk6I#SZ@cvKpr%w&uST=-BQs5{x(2+ zcO&+~{sUAZ?G0*sb7r?od%r6%smzI|qRyBbq@@c67SYcWn-Z^o<%y!u`D|0fUS$-MY z>Y2JwrV_d>orM7#7Aj>TMYB`G0^H0#FNFVuVcFc4riSHkQF%A^w3IUUbN+k|JDj4k z=4Rgg)|Y-d@<&;@?vMic9X3LKFUyzT>xRqk4SD>|S~{#qFGEJ@<+5D8Waa4Ps%*V{ zImBhvGg+g#nBu@suhwhmr`K@xinD(@R-WVUc60K|n$O5*K)t;nFMm3Ur>3lt{7So< zvaZ&*vSLT4@8*W?dbmE&v~VoXvf%8qQF_I_HLHu~#DRbr@;vm5JkMSZbo~#2(pKGE zt`b@#5Ib5B8&Xe}jJbpSa!3W3bvDr5Lmiw|M6F?~SNU$4^Ka((z3xEwdm;DsY_vpX zHv0`VJ($dth0_tkid;b$OIPY#; ze;4VE{{Q|BBK9evSayLsCFCELDXC+QfvC)3T8vEoZ;T%I>|xWw-nH{jupk-=jG zr@5F@Mdaq3#|N45*}?HSk>VTmkW|(yL#{i*+w@%NVTRk zlng~$%GqJewhreP5^t*G+WPw&*JRw^=ufa84D{Prn#tk*S9vb=zx!ocO*z49>l^+1 z*zeY4G_v2eP-b=g-Qdth{~kJ4T_4pPr@p551N~AGlfNUge~cu59FIKEHGe-7fr>9y zgr*p;B(GFamTrR6*ctP2zU40&NzHf9Z1n$KKPb3$>nU+OnRyt*cWX(%J9%VHhGNErH_YLa zKzT@>Io)OBxYL}NM0c;6?3&kqbauDS&{gE*n9W*D64DXep%m*bQm7 zDc}PvSLFtXJAy;4(xvW+(M?Eg@g-EsO_F0}8MM((@_P%crPnL;tXs5=t`8`4{V8Mt z>itg*GahrVeb$v#!gJwkek5F@B-VI^4POvQ{T-ZEuh!3RbBZYmc{bzj-N zTIyMLueJ&(yI0?WU3RZlx|H4f@a-foyY~+wCi?l0O?jDz;~*l=4M{*GKHP~$f00GW z$nLMmH)YQu&m)4#c32t1V+WZg&m)+AWH)(!FSBOQ^LQj>Izt`L>ZOt1LnIeh2pZD) zhnR{68qJkCg!>nBX{O&e;SL>CnsH|F!qWw&RSOXt3yYttrUU$09+@ZCo>yXA2U9ZA z*cW99UPTv|d2&q`^Pr@?SJKMkv(lP7nDXpj+T34{%%M;VJh~fuB6o>rDtu zl&pW&wIfdc8l0UgRyG<<>AQdHB7=YQP=-#%Xf&_DWv=hs zbSkv&l!4~#J1g9Qu37vpPUCUMtkAkyfz$Gikmg!fyR*!-=_1}bDDopgN%in&AUsM#hc<_;^@jw7F>?vYQUF1OIy?}K~pG#kn{ zt~OzF;`M>u)U}!f)KD_Hx5#56f7AJ!$6vIM zY!P6?!?la8o0nLlG0<4Pn{l;^<2Emei=_?C9vzy8RWUuY!0dj}9{DqxKZ~Xy&htzhnHx%B)>% z+q}d!3^)CLHeO~LGw!Uq^ft**@VTzP>1L^u`RYGm4yiTeRmUs&T=l*@X|4qRZgTS| zPUEp+7LT%Q9(UyPShtGD#?>cXn-clEnPi(vNVaJu$u@nHWShQ2vQ6trwrSJqsxE=q z+fWGyuVeUn7 zaex`)TB!=29Q`MvRMGM#V|Snv%MVx0n-omfII^kX-9%qmREVbgcY^eG8E3^ZC|58X zH(>xlU3iobMO}z5%jR)MK96;)cx+tFhi?)`{dlY=j{1e3l=_99m*)-sZQ!<&rhPY_ zvn7*FdHg3U8d}GoPP@VXR^Z4*zF9Z~?TYicjPbz~%^D#te+NyyL$={ZtGklYR7M$pmQ~-IA4-LW)5Qp%k`i1c6G7YF=u-7DN-8O zlOnWvl?m9+G1uyObkJ|rTlpvb^@p!hfZ0=Acgx|eVYBV;z{YNzX&jtl11#7U(-;AJ z7TZ48n8ZMnJMd2TjD04EbvMSUVu~}jKt>_H%pseWq{(BJJcQ6ogwRWb&`VaEB#w0_ z`0t4Sh4A27u=cvaGNq4Ar0+@ZT;dKirO~g5TYIdxLC*L1z8bpA)j9Y*ihpl|O#Qym zn-iBne)G-$L2rXBy*>xskCu@h*eBgGEmi}qZ(;wp#2#pJuqc?{nUGAPnDqVM^^L*P z`M>Mij=#6Q9ev=RTHkcGsi9Nk-Xf2F{v1DNo#QV$NBsY7ecJ+RTek9egugoe_VPD~ z>;JBAvgrNq`u0D(zOkQ_jk=sQhn?>mU_rdeZrhjcoU3MY1i@JBFm7_{cdm=+noQL2 z)lvKR=Qbqsy!viW#1cv8AQKCuMLqjlc6Nx#oW?>&XstUvUbLdc`9Xg-dm&X#V3Y__UMTQX&JsZ*fmkXbEo0mlzYPaGZ&>N4r|| zB^$3OFN@Qktef*V+j3{}rrfZtHZNj)6!>Vs-%{P;yE2>>Jz5o>AfPTR*Ldt;oyQe~ zx}D5id)22-YFRMnollt?GE};bs<~fV`|VEu+(6d-2tqBsFOODAb^fwuII(=i!!r>*F)dyy@6do*fsa+IgufegiU0-QV!O5PYH#k#08}EmxykK!&hk${V}zW zI4@d`Z>aFm9;+L{Tz0DAAh#REfU(*!q}dt1Ul#oh_#^X(6d}5Ih{Q_dCcdlnHC)Cu zRoCfOn;h5(suxskG*L|@piy-Z5LA5$a$yCP{sNQ^u67&i?P{tHCab0kP3=49hX877 zC6i$VQ;TlFOG^3nUk%Ct%riv0&|W&e9-Kyngae&rl!}t?iuCi0)y}}cfG-mmvpEsq zvuA#=?#j^Yb)jXCxs6f5TxZ}1c8h;+xm7kj3mxh_TEaYu$;%9B#O+`IvB<7OCn6FH zz}kCr>_}29`V5LMo$?$;t|Pr!1zwLtij4Bq$ZBU~wL7vpSzSjbN8GYpr=c3bIPEU8 z(TEg9d{Z6j2@Ti|P=|3@lnM?Ntd1R~Lcl%VwEd`XG zthVYQ7i+_ZWbkAe|6+6dF8aEWBw|+?LY2D+Wac>5#AoK%*Tq*Pp=;5?#$o9v4ojcy z{GKjYX#ts=(ni})@zMV9{2C`uu{(XGFDMRauy?_O`Q z`V*9qL5KcLMpgCfNytwFSpp&Ax1rQW$CWaV>PF^BoYALtLLZ~e8~7;Vn^1Ge@8za2 z{Yf3=gVv4O(+`Cg6jw}#n7;v>(M@cRZ)|Zi-7~RtW77{6M&lmQaahp3mflmWu9C{E zpx|twv(b2KWBE}CulCcMw+R|vYNrLvBA^{p7lL?wMI{1#(=kP6iPAQ=Nmx>7P* zAlL6EUwTi4rF<)sPl+l60R4)IAte&;co6dKP7O4r1_n~s96~;7g1s7#!bpMV$agA~ zcH8dMl2Bb6kU;fDp;3~~`hKdM1P!kgF}lon^qry#)TiaYeOMHOOsmp=mdB>$a|giH zbnav$x1RxU_hCH%kkn7V#mJv}i%O<;%&4E}|1zo(-WBCn43z(gQlbLA=wQwdu|qLM zb)=dugIR`g#CI)5A6GC#VLjvCr z3O^;|HmZV-j^y-udM)29Ro}A<4(KimoW?EAi~@&0UXSfY#!_LypF3&6@aUm1pq!!$ zTWAm7<}516FZC|>-bz=Fw933#Aa&c|2!F>&3{9+YLVF_}>L-G~e_gnk)4SOns5a%^ zNjW+w>YdvmuhGqVvc&AWfxZ&|bi?0YkyzeF+G2J71+nHHBMnnLEK4%B`S;kw?w!l( zxUZE~LLIdG9vgilk%V6t*t^3D%ou~kC82pWse)4?7q4aR_RT<$dl}BMg%z03*wXTL zQSKw>Ehj5bFxI`t6}I1VjQ}?f9G7=X6_h+A#KQIELolMkWfXOy7V7rEghD1y5vfe zhlG$?AJcQ6E>+atpDcLUu-x+`<7|0IsKT!PLzo4a3>jA`(C%EVcNmxgHj@faj2J_p1;h{Nj>GE0$~>%ZV#8!rb7&;^dEinn}S@pl%}t z{jCKhod6AF-H5cB#TTnS*MBTS+`-tHR>>j%tV#q5epmavsrXo)S{CTsR2JylgiRUU zyDQ~9dekvzNAgs)CJhcm1_BdGV+eaJHHny89w4LdMxZ&%s^(4I6z5B5pQ(=6-EfuN zn|v$y!D=n1{k`^<_7j1uJAVNZu9|t|3?;3CNIT9aL01OvX37cSmw(GC1&e=@Hr(=$ zm$kam_d-Y8p_y9&s|Q^8Vzn8h!xxxIUoewCCuwewG(v&FvRX+wtSr?+Szl%?_^0Uc zS29QG@m1iSO^+mEJ}*6vokfo;G>)r<9t>ei*JZr_*XVI4oY3c^M?EP+NrPo6v5bcv zW+R9As5Ldx$ht1lvc7_7+s3QYtb8VB7qy=mr19-!+aXI-D5;W4bbX6=Qgv_gUtu=U zG_#2=4DVGh0U>;`8U2A79X10#<%JZXIjf#2lxC|=4JoISrHc4yS!zt zlY6qRhV|Gq3UvxANC&VQ^&t;T_>-=GM6$l`67~=Y^^MBW?b%2T$G_qQU5lT?T=+V zJz4FOj?^3p-(oCwmIU@iwlt_DE~CmQRxi(BFAB?eH*PD6)i==q=c~D25NgS>iFne6 z#|1V{wD^)D>n5tl0U0QpXn`yJ8cDrIlPr%|w9S>R+fv!Q`yJeT!MdKJCJdE-bF}<< zluy~tVhVStGyxID-0!GGod*rQvU4j|UzDJ>0*h|m6nfiFGh6d(vo+a7v!N3b6_#)X zLY`yy5~n4!61ll=gkeP-kYf+01hRY&Ne3D8(49X;p>KQWF8Nt#59buCcV@F0OAM`d zU~HCqV{nv_n;RUhrd%Vt^lMZuzlKXz>#BT4$cjheFm7p%3+gwDvO6t#{HquBYs|Q#`bnZ2NQyZW4D;F{;E~qhEam(s*HC1pnn-xsaZn@SQ@=_&4-U zI5JDkn@buY4x4**IT>Sw!9+tWZid?#vPL4wAk)o~Nw(Fc0<7)`z)n&e)%+_N zQT;wWm)Co&>4&)T)<`heUihytvP4*6>_Zju&^$h8Hu=V+_Z{3;F5fI5$!)W_M9>w1&u7ePM2~fVcmPUag zA||s~HG)n-<;7NqPK@0_d4qC1Vik)*7@%R+dy?-aDO-Q=F--T0&EG5n@R_rpHZ4UQ z{>!!PP*sMu5SdhGT8QMN`o{*o=NrAw8F*R&#NxBDHNvdN>`2lhLZ1Ho@=m5ufqJJ2 zbxLu0A2AU>e6}#O!e=vn&*D(!c5I;xNrYXFc0fApHfeLlv{krng`0KR%$o%gBj&G) zn;!HIzwsgIK3o1-{$tt~p`p1{zrieZHvbVK#^gV)Kbse8k38^t=P$lLX>dt>hLk&G zAcT_Kud`l1&HJI5@4`F5mVBra_jR11I-o$7ujI-@yX*w8^HWhrr0M}+?%i37%%kgNLV z)K`6rPp;|^LCv4Isy`%Hd*f7B<&jEP%`J4-_7f_?ezfwm)gRa1IY_b~8AC~FP)lFf z+_j7M!H>6}{ZZWnMZPTfIaD98zwkRc+B(|W)t4JzYxr_w zdP{hGddoE7d`B&s>h|x_d7mM#)YxccY3trp#pLF)WNE%CVHCjqf2wKm*9VUIjJ*Yc zV{W0*vZ;;-I=<^rvvWXim)qO%6-S3Pu*)YxklldO{BzermJ0zKE70N6x4LwQIeRjZ zkxhbyFH4mPb#9;Ps(&xBchS@dmAv}KADWp>PpSTk5Bg|cyGz!S_T$xmaaDg+s@vIh zD?d`Zu3O~2LBYZiUEP9-3Q48r!`S(*$0d7xdw*N|pDfb({1Xl*O@-0}4HElWyN-(+ zXlU$ci*>7ivOg6GSwRCS%J`A|rd4J9SboP;Wq?<`(dhqb zT@_%$rFB1)pMtu8{M=A?xBM)utCpX6RT=*h1@hA1X!x+Bk`4Ukq+R>+>cH0DGo>!U>Y3UaH^oB1d~6YiEiW+tD8EX4TMN7 z(qKuQs#;2Rt_;o%Uo9)VES^*$WdC74Dv@rrj+}vA$zbUpPkipSW0c4#fZlE05_mm) z1N=d7L!Vp+gfTH9Rxh4R<1t?jU&6iN#y(?b#{lyeJ&DBY2g# zU_$AHyFOesFW@9g+>-2CSLNwtzTV2y7yGY*ExJ&b=&2%qlijBz%2SR zPh`IekIJQV`|gBgi@~$re?kiPWmRs7So{u(PoFo!_XU(Y)1->Jg1U0)`O(TP8CJW9 zZAsT!I;08E0>G}TWR1vkLTXU91tvpLu#J*krj#mX?a2JK8H`%ean8%{&TL+LIqn19 z+I4apl2d$j5E!+O(y;{TH`=gzKDl>BA=%tfBi-# z=bdmDUgAcegJ{%$y!@D zbzYXwx`2bm-?P?Qb5O~hp0RJS?L=(?!K1kUmhJMdSip@wx@yFC2SbHT;ESQ}4kmwz z?Ft>V@=TWR8mXL5Qk&|4tGH5-ep+GIwFJ*>21SJ>+70{FZzQRw&ueR|9anw8|44XD ziMo`Y0rCc)yxw#?#i>dON(JcV>Gk>YPu&cUVRF(!d>ZN^Bca3?2s1wykQ~D(BT)#` zP5mXi>@xKbDK<`&gf`m4W7y^)={3#I9bTFGdlBbz@+P(qLycp}j2DuM?qv(j8=LfD za^+KL^poHGRKD_AoBL^@z4{ko%D*qKOXW4dYh;c1PhUba0<6XUzH*MDVU^J)sxL1R3=AVZoO< zux6=|nCa>FeUQGBGsFj*@vuIDsWnE?Zpw*57O)n)6KC7g|90?2Zq;edT;3O4j)(4J z{`gGKDc>JaJ##e%cUAsM^c6|P>PM{kW_B-dEF1=xXTIJ1aWGU?#-_Z$F=W~tF_NuU zUc}slb(@O6%-26#edlIw;bGU~Vz{@!o(a0Gkw)*w| z67S|kZ&cN@v>Qh1dZQ}pG|@1rk+dAY2x^QuT0gJmu#G5I$*e=g>H(&fVzuuUd3JJV zGwXsVi|EklY^9?OQ&4`GNgd3U4_a@xws6>zn={6 z{XunG|Edm*@3sg=BfMgi04#B4(zz8t5=U9iqHgMEfQ6| zZ){Xx=8IQeWZR;y9|qyi8bTBW*%!VFD1B@Ip+lXFhlTq&#t{T6x-16yg<6C$cyuxh zZ;(Cg41>BA8k(~LXZ4Gj?HT2=#*Ab=Wci-3JI_sB&Jp^PCVW-R@ z?gRZkedZR8v-d;df49}d|1HviO=&-Qnn?#7ov*jdmC{4pi_BgmrTpP`CBBoAj2HQNpH}gw=%H zNzPWuxl?lb56Ac5$&5 zelxAmmSXYVz;o@jWw^*9cZ11@ClyA&K>2GAq!HLp0U`rv5PY|qi2g?WJM6Am4H^R@-}B!fnxpWi62;eXT{!fCFwSSIB_i3R?_(ZWtZcg!ZFo~GY z2Rha{)SX|D`7^nr%+Zm6=mxEhFTU$asu2@@F#lA3e{{TmOqucEGSI2q7gzbtz+>~n z_Od_EA6FK9aE0Lb2YLSaB|+q^;C;9A60Ms_1Iq)oA*oC2k=E0#4YdtZU9Yk~s5&CH zX~y4dZGlENS6vvRO#a6E<Ftk$uQ@zMvJLHs-_84LEer;k5{C7zy?dqa z9zMc!(AnNCGfDf$9qo-Q-}b6EER4Uvo=s)UYYFYQPfchWYOe5jC)c;_2hjt<43;*rCX z`XPwS40Vhw%i5;HNfSvBe!e5#eon$uv4l|AvhEj$laeLjzX}H>{Kl@%pr_N|x^M3K z@l2H6!-&D?4mKEh+S5^9GP;^z9$FelD6ccW;1;!MiRQ;TJbh(oejt>s{o4-M?&1Ib zX?|uFD6;&fWShT}wwk}w^3C5ltMu>R<7?7vxLa^duX9H}!Pk87nS9N2Q0a5?HQgpY zny<0EDW#pw*SLv`@inV;T9dD-H1Yp?d`(K435ykc`X_lDVSQ3?1^d~2&UT9Ve0r(#rvL)9;YoVzB5=c_vibrkiHmKCAn$m^XwyB7T*71tg9agq(a<6t&- zxT(0Ky|ANAZP7&_9UPQGR~?&9bxgC=7f@XUHaH?BrV>4=0m(;2eyFAs38$DS-_nGn z%sl!(3mZL&nopFO0GrcbO&ck>I)aZueYQSW(<$N5VR_!yCeH_7mgf_#@_cqLPh0}@ z>7URs{qtb6{;Aoee;%&aKYw_JA6x=-^J9o707XE%1UN;YNf#M)2@tF~suSUlKoFOM z9yLdGfNaMI#5@5Q(vKODA&oYcITkGx@Q)LxM?wda3<>p+LAy0vsRG-@QB8C^?$}nz z0FMb})Z2(&;CC-Gwl9OCBIU$MhG}?eno16teZnHMH|Mh{iW1w(CDwBzuMbU-o;9y)*aq%Do z^c6kObR?Y^Y3e=J@OVO4P+Q3xv!LetIMc@3RZ|3YV*0(^;oewxFD${_yG^jSZ7~JD z*ozr^(p%}Y2lr&Y>KDIe1qkx+VHmz16`QuX?iJ!n+f5p>xi(Eyiq+^a-|n%YQ8`b~ zKox07J&}1H+?TG+lJ3dW(&JdaD}P*wyj>m=s+g!``xUcN9z$DmOzKQ@ae4*S<}?(a zQ6)jK(sxOUZOkzHYwZjuIx>pOmkH#h^3XQlHWfDvyi0>01didh7<><@Ad1VsE;%&} zZTD?gjZ{5`ow!^XngDb*F&Y=+Z%yCg^4lf5hM{f0<5l%%XBPwTXm+1u*D$pGcY^W^ z%Z>%N)OzRu83;Hmf`Ax-M?y(IIk(E3vDos@#7 zM*L}}+o0hy;vhB8{l=I@!Yl)tu79sdXKp?*fg3U4(DdwDg|+e5eI6zYUBRcth_g<* zEO(MMM+N^Ev;>a47HGJbyGBvnX72a*3<}=$iM30MpOYaf?f`j2e2&N$O{=NEB^ESK zRRaRg-?>8MN*&NJZPemT>xB9r~!HB+1|Wj0n^QJ(r8a2Yd*OD=L>6Blg}tIdK# z6Mx8=(V+k3%#*&G#a^T{at(K10bOHwjZxw-Zbo$&+JMuedE^-IUkK-?4m^!t^0s3azQ%#<9;K&VgQVk&)}%g6|3455^Wm4-(nY1nX3ws~>>gdUHB1ic=IEE1*{EJ1* zi^OdQPK)Pl)O$OF*+uu=}-btE}&PcFW~aQTlYK}x+kMT!u}+ffVs+`jyP~EH{_{f znz({#qAalCT{ctyMjt_OeheRyS{qtyq=y#T@sRE5ud}3K>C=t3ezeVxq0@S36)HP# zX7@&7uu@{q@}l=P93rb<6gWNLn_s*1B74tHtM7|FJ01Q}95(zJCDDRY@RGhS&^f>1 zbi!?|bID{&4r!}#OK?GI?V^k9n-@$cc1iSp!~y^BqQ)PXA>pBRD0BB*+iaaPurW2_ zbMhR(QP)k=E5qM2nszUqUL}rM-LfA{*5C?E*y%aI%MM=_=(G8!5_E(wl!&IqsSq}zXBX0sH0*Uv+1kQ=2`)BW zH6?rm=|)uEb7jD;dIHukQT?A$v}(HeQpJ+EP~FZ(N7~q>DuAZsYC!GTH8#jlu32i& z@<=7y4;-ih>fZzu{kJ&1$M~U84>UL*cvSl3Z{(e6K_*=}8nC8A>tvnfrGm@LkDGI@ zIhp-XaL|((x073pS;i|^^ouK+VdnfjiyYIfzEQ>MfXpFAcX+h=%7?-^YT>|3k^hRm zK10eg#~r&Z>BOAE#SH%AQ(%>5QI0{t;jh&6-08`jBmHb`7WPH2NS`^AFm%ko#Oq?2 zP&lcrb>m`r-=suxd$rr`_JFQd?Z$FGUDdgCMoGOnVNi$0oHqHfaU;7q0+UFb~@ z2_eN!ZA4Gy{nQ;ZZk)IJC-!8oVhv))a1qHXtg!LpC7+jLbIm1cq=e~W_v`NNf6`<^ z86|2Zt>dNdzoYy9t8)#f?!LPhjhQYRA7`;T2v%O1OX!G$LzR}Im!zm;e2gAdm}+9r z43_QQ5}U_7;>%M`x8rP4KP4Qu2npXC%Ij9%eX`D;s=CwB^)Ux-CYOJm_BZ|0J_})^e4#7&C`EQ{ z;}NKPgr|TN!v|l2>&e8jAa`Fb?%GVW^aNt^)%m)GsK^4te=4xiZrylU<_h~=m*Uoq z^9T3U=L?s&&R$Y6B7#EZsu>hTx?QPIeiRAU%&OdkPt(hdb@p(2EKhom zS?y4#F-I{ojaFIMLo`{4uyCTXQY^{YNpuGulJgNCqm#!0^faj)M_9_`hZc_+daz~ivZfP^pDi)dpr^zxG zqY&bPo23y6cq`(YvU7zdyp#oVZ`VJY*H9exF1!S`-bhNiAgf;A}PUzS#*@&s8U5!RboHf>)@HSTI{1hy@p^rf6{c zD(b18<}I*m>QIH^sS0y5RgpSJXXR=HO;Xh%gC=;uK9eMpq%U8Igex{R%jC52MvHHH zWZjMG%Q6WpzR{bh?U#JXSz^NEOA6eHf6l~wwfY7cn*J1Ae4}Vli8+Ea1f#Zx>PRQd z_vGSy)j;Rf`>b&?smT}h9#O?gY}I973#$>Ewg)p#%vV9l*N2H9>p;YRCpOR@g?&0f z1=q{|j<1y2RsMBI0k?MZaY-#Eh5iZJLx3)*npA~q3*Wrq`jTkr-_cq9V}_C~C#EF) zYPncx;lf)eW>H@zmzYw%j*Kds<)!!a3nEiK;vlvd4mPUn!x-Oabc&^>srjl++E+G| za?0FyXZVgmWIyH$$bKV+?5_}km==xxl>8`G?W8GIZ}G(&o`=Df#($U2=y$~uJuZpD z?HbWy)yO6jME?{Os9>$iOxLJ>a|q1-E?KVz#NQ`tp)PQUtbNBmjjS_CRj4vFu7hMv z)mev=HG!BRvZk2W+DvTEA*)H$^6_utuwg9ydRw#ynGS)!z;I-37?H1-FgTzW#wKjA zt0d*Ci)17uNfy(5PWJa~7>$Hz$DP1(_0abFVchf)Ie((E(si{oEw&`<#9}(<`()y( z$-9_nh>d=Vg4rp;Zms#hWh~gSSy7#VSR{3Bo(s)gAdf z)A%I<71PwG<%D4NJz^24^)*ghlgr?hygS>pmW_c<=|ydB)Jl?=p)#K(of&U!^b6HK=6=wFp0?~w`wNK*A_ki zFI@6`CCCl)h9TpH9I27`R>)|&!l)X^rz+YThWJUIB(0|%V(1Fp=5eIP3ltc*MZgvY z2?2;?XB0&}Wyo?p=qW=(9_}gQ6L4~)aG+O#c@hq;J?QU;cgtAqxXUF5_Nsth&2cj; zw$MF`88cDJ6{znZxsU^wdHq=L7v!ryX(@fb*K1&WHcX+bTjTHAr(qIRZ!4P?*;F=j z)~vFu7u>FU7C;7V_H;_?L9zK7o1%1h=6)2IC^E-RvV17tmT5b%ZZlmw#$+v3JKgIh zT0U^OI|FabM-e)+m5-tLRhPxP8{UYwaeN67;ggaPKTJsk?k-a-yjj@ za?40Oea?0hct7#nz$x)w(k=TN-vj~ff*f0#3RVYsIRjMAPkX!hmBeUbz4cg~&8#

    ss8*YJa`<&!F4OE!PF< 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 str: + return f"<{self.__class__.__name__} id={self.id} volume={self.volume}>" + + @property + def created_at(self) -> Optional[datetime.datetime]: + """Optional[:class:`datetime.datetime`]: Returns the snowflake's creation time in UTC. + Returns ``None`` if it's a default sound.""" + if self.is_default(): + return None + else: + return utils.snowflake_time(self.id) + + def is_default(self) -> bool: + """:class:`bool`: Whether it's a default sound or not.""" + # if it's smaller than the Discord Epoch it cannot be a snowflake + return self.id < utils.DISCORD_EPOCH + + +class VoiceChannelEffect: + """Represents a Discord voice channel effect. + + .. versionadded:: 2.5 + + Attributes + ------------ + channel: :class:`VoiceChannel` + The channel in which the effect is sent. + user: Optional[:class:`Member`] + The user who sent the effect. ``None`` if not found in cache. + animation: Optional[:class:`VoiceChannelEffectAnimation`] + The animation the effect has. Returns ``None`` if the effect has no animation. + emoji: Optional[:class:`PartialEmoji`] + The emoji of the effect. + sound: Optional[:class:`VoiceChannelSoundEffect`] + The sound of the effect. Returns ``None`` if it's an emoji effect. + """ + + __slots__ = ('channel', 'user', 'animation', 'emoji', 'sound') + + def __init__(self, *, state: ConnectionState, data: VoiceChannelEffectPayload, guild: Guild): + self.channel: VoiceChannel = guild.get_channel(int(data['channel_id'])) # type: ignore # will always be a VoiceChannel + self.user: Optional[Member] = guild.get_member(int(data['user_id'])) + self.animation: Optional[VoiceChannelEffectAnimation] = None + + animation_id = data.get('animation_id') + if animation_id is not None: + animation_type = try_enum(VoiceChannelEffectAnimationType, data['animation_type']) # type: ignore # cannot be None here + self.animation = VoiceChannelEffectAnimation(id=animation_id, type=animation_type) + + emoji = data.get('emoji') + self.emoji: Optional[PartialEmoji] = PartialEmoji.from_dict(emoji) if emoji is not None else None + self.sound: Optional[VoiceChannelSoundEffect] = None + + sound_id: Optional[int] = utils._get_as_snowflake(data, 'sound_id') + if sound_id is not None: + sound_volume = data.get('sound_volume') or 0.0 + self.sound = VoiceChannelSoundEffect(state=state, id=sound_id, volume=sound_volume) + + def __repr__(self) -> str: + attrs = [ + ('channel', self.channel), + ('user', self.user), + ('animation', self.animation), + ('emoji', self.emoji), + ('sound', self.sound), + ] + inner = ' '.join('%s=%r' % t for t in attrs) + return f"<{self.__class__.__name__} {inner}>" + + def is_sound(self) -> bool: + """:class:`bool`: Whether the effect is a sound or not.""" + return self.sound is not None + + +class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): + """Represents a Discord guild text channel. + + .. container:: operations + + .. describe:: x == y + + Checks if two channels are equal. + + .. describe:: x != y + + Checks if two channels are not equal. + + .. describe:: hash(x) + + Returns the channel's hash. + + .. describe:: str(x) + + Returns the channel's name. + + Attributes + ----------- + name: :class:`str` + The channel name. + guild: :class:`Guild` + The guild the channel belongs to. + id: :class:`int` + The channel ID. + category_id: Optional[:class:`int`] + The category channel ID this channel belongs to, if applicable. + topic: Optional[:class:`str`] + The channel's topic. ``None`` if it doesn't exist. + position: :class:`int` + The position in the channel list. This is a number that starts at 0. e.g. the + top channel is position 0. + last_message_id: Optional[:class:`int`] + The last message ID of the message sent to this channel. It may + *not* point to an existing or valid message. + slowmode_delay: :class:`int` + The number of seconds a member must wait between sending messages + in this channel. A value of ``0`` denotes that it is disabled. + Bots and users with :attr:`~Permissions.manage_channels` or + :attr:`~Permissions.manage_messages` bypass slowmode. + nsfw: :class:`bool` + If the channel is marked as "not safe for work" or "age restricted". + default_auto_archive_duration: :class:`int` + The default auto archive duration in minutes for threads created in this channel. + + .. versionadded:: 2.0 + default_thread_slowmode_delay: :class:`int` + The default slowmode delay in seconds for threads created in this channel. + + .. versionadded:: 2.3 + """ + + __slots__ = ( + 'name', + 'id', + 'guild', + 'topic', + '_state', + 'nsfw', + 'category_id', + 'position', + 'slowmode_delay', + '_overwrites', + '_type', + 'last_message_id', + 'default_auto_archive_duration', + 'default_thread_slowmode_delay', + ) + + def __init__(self, *, state: ConnectionState, guild: Guild, data: Union[TextChannelPayload, NewsChannelPayload]): + self._state: ConnectionState = state + self.id: int = int(data['id']) + self._type: Literal[0, 5] = data['type'] + self._update(guild, data) + + def __repr__(self) -> str: + attrs = [ + ('id', self.id), + ('name', self.name), + ('position', self.position), + ('nsfw', self.nsfw), + ('news', self.is_news()), + ('category_id', self.category_id), + ] + joined = ' '.join('%s=%r' % t for t in attrs) + return f'<{self.__class__.__name__} {joined}>' + + def _update(self, guild: Guild, data: Union[TextChannelPayload, NewsChannelPayload]) -> None: + self.guild: Guild = guild + self.name: str = data['name'] + self.category_id: Optional[int] = utils._get_as_snowflake(data, 'parent_id') + self.topic: Optional[str] = data.get('topic') + self.position: int = data['position'] + self.nsfw: bool = data.get('nsfw', False) + # Does this need coercion into `int`? No idea yet. + self.slowmode_delay: int = data.get('rate_limit_per_user', 0) + self.default_auto_archive_duration: ThreadArchiveDuration = data.get('default_auto_archive_duration', 1440) + self.default_thread_slowmode_delay: int = data.get('default_thread_rate_limit_per_user', 0) + self._type: Literal[0, 5] = data.get('type', self._type) + self.last_message_id: Optional[int] = utils._get_as_snowflake(data, 'last_message_id') + self._fill_overwrites(data) + + async def _get_channel(self) -> Self: + return self + + @property + def type(self) -> Literal[ChannelType.text, ChannelType.news]: + """:class:`ChannelType`: The channel's Discord type.""" + if self._type == 0: + return ChannelType.text + return ChannelType.news + + @property + def _sorting_bucket(self) -> int: + return ChannelType.text.value + + @property + def _scheduled_event_entity_type(self) -> Optional[EntityType]: + return None + + @utils.copy_doc(discord.abc.GuildChannel.permissions_for) + def permissions_for(self, obj: Union[Member, Role], /) -> Permissions: + base = super().permissions_for(obj) + self._apply_implicit_permissions(base) + + # text channels do not have voice related permissions + denied = Permissions.voice() + base.value &= ~denied.value + return base + + @property + def members(self) -> List[Member]: + """List[:class:`Member`]: Returns all members that can see this channel.""" + return [m for m in self.guild.members if self.permissions_for(m).read_messages] + + @property + def threads(self) -> List[Thread]: + """List[:class:`Thread`]: Returns all the threads that you can see. + + .. versionadded:: 2.0 + """ + return [thread for thread in self.guild._threads.values() if thread.parent_id == self.id] + + def is_nsfw(self) -> bool: + """:class:`bool`: Checks if the channel is NSFW.""" + return self.nsfw + + def is_news(self) -> bool: + """:class:`bool`: Checks if the channel is a news channel.""" + return self._type == ChannelType.news.value + + @property + def last_message(self) -> Optional[Message]: + """Retrieves the last message from this channel in cache. + + The message might not be valid or point to an existing message. + + .. admonition:: Reliable Fetching + :class: helpful + + For a slightly more reliable method of fetching the + last message, consider using either :meth:`history` + or :meth:`fetch_message` with the :attr:`last_message_id` + attribute. + + Returns + --------- + Optional[:class:`Message`] + The last message in this channel or ``None`` if not found. + """ + return self._state._get_message(self.last_message_id) if self.last_message_id else None + + @overload + async def edit(self) -> Optional[TextChannel]: + ... + + @overload + async def edit(self, *, position: int, reason: Optional[str] = ...) -> None: + ... + + @overload + async def edit( + self, + *, + reason: Optional[str] = ..., + name: str = ..., + topic: str = ..., + position: int = ..., + nsfw: bool = ..., + sync_permissions: bool = ..., + category: Optional[CategoryChannel] = ..., + slowmode_delay: int = ..., + default_auto_archive_duration: ThreadArchiveDuration = ..., + default_thread_slowmode_delay: int = ..., + type: ChannelType = ..., + overwrites: Mapping[OverwriteKeyT, PermissionOverwrite] = ..., + ) -> TextChannel: + ... + + async def edit(self, *, reason: Optional[str] = None, **options: Any) -> Optional[TextChannel]: + """|coro| + + Edits the channel. + + You must have :attr:`~Permissions.manage_channels` to do this. + + .. versionchanged:: 1.3 + The ``overwrites`` keyword-only parameter was added. + + .. versionchanged:: 1.4 + The ``type`` keyword-only parameter was added. + + .. versionchanged:: 2.0 + Edits are no longer in-place, the newly edited channel is returned instead. + + .. versionchanged:: 2.0 + This function will now raise :exc:`TypeError` or + :exc:`ValueError` instead of ``InvalidArgument``. + + Parameters + ---------- + name: :class:`str` + The new channel name. + topic: :class:`str` + The new channel's topic. + position: :class:`int` + The new channel's position. + nsfw: :class:`bool` + To mark the channel as NSFW or not. + sync_permissions: :class:`bool` + Whether to sync permissions with the channel's new or pre-existing + category. Defaults to ``False``. + category: Optional[:class:`CategoryChannel`] + The new category for this channel. Can be ``None`` to remove the + category. + slowmode_delay: :class:`int` + Specifies the slowmode rate limit for user in this channel, in seconds. + A value of ``0`` disables slowmode. The maximum value possible is ``21600``. + type: :class:`ChannelType` + Change the type of this text channel. Currently, only conversion between + :attr:`ChannelType.text` and :attr:`ChannelType.news` is supported. This + is only available to guilds that contain ``NEWS`` in :attr:`Guild.features`. + reason: Optional[:class:`str`] + The reason for editing this channel. Shows up on the audit log. + overwrites: :class:`Mapping` + A :class:`Mapping` of target (either a role or a member) to + :class:`PermissionOverwrite` to apply to the channel. + default_auto_archive_duration: :class:`int` + The new default auto archive duration in minutes for threads created in this channel. + Must be one of ``60``, ``1440``, ``4320``, or ``10080``. + + .. versionadded:: 2.0 + default_thread_slowmode_delay: :class:`int` + The new default slowmode delay in seconds for threads created in this channel. + + .. versionadded:: 2.3 + Raises + ------ + ValueError + The new ``position`` is less than 0 or greater than the number of channels. + TypeError + The permission overwrite information is not in proper form. + Forbidden + You do not have permissions to edit the channel. + HTTPException + Editing the channel failed. + + Returns + -------- + Optional[:class:`.TextChannel`] + The newly edited text channel. If the edit was only positional + then ``None`` is returned instead. + """ + + payload = await self._edit(options, reason=reason) + if payload is not None: + # the payload will always be the proper channel payload + return self.__class__(state=self._state, guild=self.guild, data=payload) # type: ignore + + @utils.copy_doc(discord.abc.GuildChannel.clone) + async def clone( + self, + *, + name: Optional[str] = None, + category: Optional[CategoryChannel] = None, + reason: Optional[str] = None, + ) -> TextChannel: + base: Dict[Any, Any] = { + 'topic': self.topic, + 'nsfw': self.nsfw, + 'default_auto_archive_duration': self.default_auto_archive_duration, + 'default_thread_rate_limit_per_user': self.default_thread_slowmode_delay, + } + if not self.is_news(): + base['rate_limit_per_user'] = self.slowmode_delay + return await self._clone_impl( + base, + name=name, + category=category, + reason=reason, + ) + + async def delete_messages(self, messages: Iterable[Snowflake], *, reason: Optional[str] = None) -> None: + """|coro| + + Deletes a list of messages. This is similar to :meth:`Message.delete` + except it bulk deletes multiple messages. + + As a special case, if the number of messages is 0, then nothing + is done. If the number of messages is 1 then single message + delete is done. If it's more than two, then bulk delete is used. + + You cannot bulk delete more than 100 messages or messages that + are older than 14 days old. + + You must have :attr:`~Permissions.manage_messages` to do this. + + .. versionchanged:: 2.0 + + ``messages`` parameter is now positional-only. + + The ``reason`` keyword-only parameter was added. + + Parameters + ----------- + messages: Iterable[:class:`abc.Snowflake`] + An iterable of messages denoting which ones to bulk delete. + reason: Optional[:class:`str`] + The reason for deleting the messages. Shows up on the audit log. + + Raises + ------ + ClientException + The number of messages to delete was more than 100. + Forbidden + You do not have proper permissions to delete the messages. + NotFound + If single delete, then the message was already deleted. + HTTPException + Deleting the messages failed. + """ + if not isinstance(messages, (list, tuple)): + messages = list(messages) + + if len(messages) == 0: + return # do nothing + + if len(messages) == 1: + message_id: int = messages[0].id + await self._state.http.delete_message(self.id, message_id) + return + + if len(messages) > 100: + raise ClientException('Can only bulk delete messages up to 100 messages') + + message_ids: SnowflakeList = [m.id for m in messages] + await self._state.http.delete_messages(self.id, message_ids, reason=reason) + + async def purge( + self, + *, + limit: Optional[int] = 100, + check: Callable[[Message], bool] = MISSING, + before: Optional[SnowflakeTime] = None, + after: Optional[SnowflakeTime] = None, + around: Optional[SnowflakeTime] = None, + oldest_first: Optional[bool] = None, + bulk: bool = True, + reason: Optional[str] = None, + ) -> List[Message]: + """|coro| + + Purges a list of messages that meet the criteria given by the predicate + ``check``. If a ``check`` is not provided then all messages are deleted + without discrimination. + + You must have :attr:`~Permissions.manage_messages` to + delete messages even if they are your own. + Having :attr:`~Permissions.read_message_history` is + also needed to retrieve message history. + + .. versionchanged:: 2.0 + + The ``reason`` keyword-only parameter was added. + + Examples + --------- + + Deleting bot's messages :: + + def is_me(m): + return m.author == client.user + + deleted = await channel.purge(limit=100, check=is_me) + await channel.send(f'Deleted {len(deleted)} message(s)') + + Parameters + ----------- + limit: Optional[:class:`int`] + The number of messages to search through. This is not the number + of messages that will be deleted, though it can be. + check: Callable[[:class:`Message`], :class:`bool`] + The function used to check if a message should be deleted. + It must take a :class:`Message` as its sole parameter. + before: Optional[Union[:class:`abc.Snowflake`, :class:`datetime.datetime`]] + Same as ``before`` in :meth:`history`. + after: Optional[Union[:class:`abc.Snowflake`, :class:`datetime.datetime`]] + Same as ``after`` in :meth:`history`. + around: Optional[Union[:class:`abc.Snowflake`, :class:`datetime.datetime`]] + Same as ``around`` in :meth:`history`. + oldest_first: Optional[:class:`bool`] + Same as ``oldest_first`` in :meth:`history`. + bulk: :class:`bool` + If ``True``, use bulk delete. Setting this to ``False`` is useful for mass-deleting + a bot's own messages without :attr:`Permissions.manage_messages`. When ``True``, will + fall back to single delete if messages are older than two weeks. + reason: Optional[:class:`str`] + The reason for purging the messages. Shows up on the audit log. + + Raises + ------- + Forbidden + You do not have proper permissions to do the actions required. + HTTPException + Purging the messages failed. + + Returns + -------- + List[:class:`.Message`] + The list of messages that were deleted. + """ + return await discord.abc._purge_helper( + self, + limit=limit, + check=check, + before=before, + after=after, + around=around, + oldest_first=oldest_first, + bulk=bulk, + reason=reason, + ) + + async def webhooks(self) -> List[Webhook]: + """|coro| + + Gets the list of webhooks from this channel. + + You must have :attr:`~.Permissions.manage_webhooks` to do this. + + Raises + ------- + Forbidden + You don't have permissions to get the webhooks. + + Returns + -------- + List[:class:`Webhook`] + The webhooks for this channel. + """ + + from .webhook import Webhook + + data = await self._state.http.channel_webhooks(self.id) + return [Webhook.from_state(d, state=self._state) for d in data] + + async def create_webhook(self, *, name: str, avatar: Optional[bytes] = None, reason: Optional[str] = None) -> Webhook: + """|coro| + + Creates a webhook for this channel. + + You must have :attr:`~.Permissions.manage_webhooks` to do this. + + .. versionchanged:: 1.1 + Added the ``reason`` keyword-only parameter. + + Parameters + ------------- + name: :class:`str` + The webhook's name. + avatar: Optional[:class:`bytes`] + A :term:`py:bytes-like object` representing the webhook's default avatar. + This operates similarly to :meth:`~ClientUser.edit`. + reason: Optional[:class:`str`] + The reason for creating this webhook. Shows up in the audit logs. + + Raises + ------- + HTTPException + Creating the webhook failed. + Forbidden + You do not have permissions to create a webhook. + + Returns + -------- + :class:`Webhook` + The created webhook. + """ + + from .webhook import Webhook + + if avatar is not None: + avatar = utils._bytes_to_base64_data(avatar) # type: ignore # Silence reassignment error + + data = await self._state.http.create_webhook(self.id, name=str(name), avatar=avatar, reason=reason) + return Webhook.from_state(data, state=self._state) + + async def follow(self, *, destination: TextChannel, reason: Optional[str] = None) -> Webhook: + """|coro| + + Follows a channel using a webhook. + + Only news channels can be followed. + + .. note:: + + The webhook returned will not provide a token to do webhook + actions, as Discord does not provide it. + + .. versionadded:: 1.3 + + .. versionchanged:: 2.0 + This function will now raise :exc:`TypeError` instead of + ``InvalidArgument``. + + Parameters + ----------- + destination: :class:`TextChannel` + The channel you would like to follow from. + reason: Optional[:class:`str`] + The reason for following the channel. Shows up on the destination guild's audit log. + + .. versionadded:: 1.4 + + Raises + ------- + HTTPException + Following the channel failed. + Forbidden + You do not have the permissions to create a webhook. + ClientException + The channel is not a news channel. + TypeError + The destination channel is not a text channel. + + Returns + -------- + :class:`Webhook` + The created webhook. + """ + + if not self.is_news(): + raise ClientException('The channel must be a news channel.') + + if not isinstance(destination, TextChannel): + raise TypeError(f'Expected TextChannel received {destination.__class__.__name__}') + + from .webhook import Webhook + + data = await self._state.http.follow_webhook(self.id, webhook_channel_id=destination.id, reason=reason) + return Webhook._as_follower(data, channel=destination, user=self._state.user) + + def get_partial_message(self, message_id: int, /) -> PartialMessage: + """Creates a :class:`PartialMessage` from the message ID. + + This is useful if you want to work with a message and only have its ID without + doing an unnecessary API call. + + .. versionadded:: 1.6 + + .. versionchanged:: 2.0 + + ``message_id`` parameter is now positional-only. + + Parameters + ------------ + message_id: :class:`int` + The message ID to create a partial message for. + + Returns + --------- + :class:`PartialMessage` + The partial message. + """ + + from .message import PartialMessage + + return PartialMessage(channel=self, id=message_id) + + def get_thread(self, thread_id: int, /) -> Optional[Thread]: + """Returns a thread with the given ID. + + .. note:: + + This does not always retrieve archived threads, as they are not retained in the internal + cache. Use :func:`Guild.fetch_channel` instead. + + .. versionadded:: 2.0 + + Parameters + ----------- + thread_id: :class:`int` + The ID to search for. + + Returns + -------- + Optional[:class:`Thread`] + The returned thread or ``None`` if not found. + """ + return self.guild.get_thread(thread_id) + + async def create_thread( + self, + *, + name: str, + message: Optional[Snowflake] = None, + auto_archive_duration: ThreadArchiveDuration = MISSING, + type: Optional[ChannelType] = None, + reason: Optional[str] = None, + invitable: bool = True, + slowmode_delay: Optional[int] = None, + ) -> Thread: + """|coro| + + Creates a thread in this text channel. + + To create a public thread, you must have :attr:`~discord.Permissions.create_public_threads`. + For a private thread, :attr:`~discord.Permissions.create_private_threads` is needed instead. + + .. versionadded:: 2.0 + + Parameters + ----------- + name: :class:`str` + The name of the thread. + message: Optional[:class:`abc.Snowflake`] + A snowflake representing the message to create the thread with. + If ``None`` is passed then a private thread is created. + Defaults to ``None``. + auto_archive_duration: :class:`int` + The duration in minutes before a thread is automatically hidden from the channel list. + If not provided, the channel's default auto archive duration is used. + + Must be one of ``60``, ``1440``, ``4320``, or ``10080``, if provided. + type: Optional[:class:`ChannelType`] + The type of thread to create. If a ``message`` is passed then this parameter + is ignored, as a thread created with a message is always a public thread. + By default this creates a private thread if this is ``None``. + reason: :class:`str` + The reason for creating a new thread. Shows up on the audit log. + invitable: :class:`bool` + Whether non-moderators can add users to the thread. Only applicable to private threads. + Defaults to ``True``. + slowmode_delay: Optional[:class:`int`] + Specifies the slowmode rate limit for user in this channel, in seconds. + The maximum value possible is ``21600``. By default no slowmode rate limit + if this is ``None``. + + Raises + ------- + Forbidden + You do not have permissions to create a thread. + HTTPException + Starting the thread failed. + + Returns + -------- + :class:`Thread` + The created thread + """ + + if type is None: + type = ChannelType.private_thread + + if message is None: + data = await self._state.http.start_thread_without_message( + self.id, + name=name, + auto_archive_duration=auto_archive_duration or self.default_auto_archive_duration, + type=type.value, # type: ignore # we're assuming that the user is passing a valid variant + reason=reason, + invitable=invitable, + rate_limit_per_user=slowmode_delay, + ) + else: + data = await self._state.http.start_thread_with_message( + self.id, + message.id, + name=name, + auto_archive_duration=auto_archive_duration or self.default_auto_archive_duration, + reason=reason, + rate_limit_per_user=slowmode_delay, + ) + + return Thread(guild=self.guild, state=self._state, data=data) + + async def archived_threads( + self, + *, + private: bool = False, + joined: bool = False, + limit: Optional[int] = 100, + before: Optional[Union[Snowflake, datetime.datetime]] = None, + ) -> AsyncIterator[Thread]: + """Returns an :term:`asynchronous iterator` that iterates over all archived threads in this text channel, + in order of decreasing ID for joined threads, and decreasing :attr:`Thread.archive_timestamp` otherwise. + + You must have :attr:`~Permissions.read_message_history` to do this. If iterating over private threads + then :attr:`~Permissions.manage_threads` is also required. + + .. versionadded:: 2.0 + + Parameters + ----------- + limit: Optional[:class:`bool`] + The number of threads to retrieve. + If ``None``, retrieves every archived thread in the channel. Note, however, + that this would make it a slow operation. + before: Optional[Union[:class:`abc.Snowflake`, :class:`datetime.datetime`]] + Retrieve archived channels before the given date or ID. + private: :class:`bool` + Whether to retrieve private archived threads. + joined: :class:`bool` + Whether to retrieve private archived threads that you've joined. + You cannot set ``joined`` to ``True`` and ``private`` to ``False``. + + Raises + ------ + Forbidden + You do not have permissions to get archived threads. + HTTPException + The request to get the archived threads failed. + ValueError + ``joined`` was set to ``True`` and ``private`` was set to ``False``. You cannot retrieve public archived + threads that you have joined. + + Yields + ------- + :class:`Thread` + The archived threads. + """ + if joined and not private: + raise ValueError('Cannot retrieve joined public archived threads') + + before_timestamp = None + + if isinstance(before, datetime.datetime): + if joined: + before_timestamp = str(utils.time_snowflake(before, high=False)) + else: + before_timestamp = before.isoformat() + elif before is not None: + if joined: + before_timestamp = str(before.id) + else: + before_timestamp = utils.snowflake_time(before.id).isoformat() + + update_before = lambda data: data['thread_metadata']['archive_timestamp'] + endpoint = self.guild._state.http.get_public_archived_threads + + if joined: + update_before = lambda data: data['id'] + endpoint = self.guild._state.http.get_joined_private_archived_threads + elif private: + endpoint = self.guild._state.http.get_private_archived_threads + + while True: + retrieve = 100 + if limit is not None: + if limit <= 0: + return + retrieve = max(2, min(retrieve, limit)) + + data = await endpoint(self.id, before=before_timestamp, limit=retrieve) + + threads = data.get('threads', []) + for raw_thread in threads: + yield Thread(guild=self.guild, state=self.guild._state, data=raw_thread) + # Currently the API doesn't let you request less than 2 threads. + # Bail out early if we had to retrieve more than what the limit was. + if limit is not None: + limit -= 1 + if limit <= 0: + return + + if not data.get('has_more', False): + return + + before_timestamp = update_before(threads[-1]) + + +class VocalGuildChannel(discord.abc.Messageable, discord.abc.Connectable, discord.abc.GuildChannel, Hashable): + __slots__ = ( + 'name', + 'id', + 'guild', + 'nsfw', + 'bitrate', + 'user_limit', + '_state', + 'position', + 'slowmode_delay', + '_overwrites', + 'category_id', + 'rtc_region', + 'video_quality_mode', + 'last_message_id', + ) + + def __init__(self, *, state: ConnectionState, guild: Guild, data: Union[VoiceChannelPayload, StageChannelPayload]): + self._state: ConnectionState = state + self.id: int = int(data['id']) + self._update(guild, data) + + async def _get_channel(self) -> Self: + return self + + def _get_voice_client_key(self) -> Tuple[int, str]: + return self.guild.id, 'guild_id' + + def _get_voice_state_pair(self) -> Tuple[int, int]: + return self.guild.id, self.id + + def _update(self, guild: Guild, data: Union[VoiceChannelPayload, StageChannelPayload]) -> None: + self.guild: Guild = guild + self.name: str = data['name'] + self.nsfw: bool = data.get('nsfw', False) + self.rtc_region: Optional[str] = data.get('rtc_region') + self.video_quality_mode: VideoQualityMode = try_enum(VideoQualityMode, data.get('video_quality_mode', 1)) + self.category_id: Optional[int] = utils._get_as_snowflake(data, 'parent_id') + self.last_message_id: Optional[int] = utils._get_as_snowflake(data, 'last_message_id') + self.position: int = data['position'] + self.slowmode_delay = data.get('rate_limit_per_user', 0) + self.bitrate: int = data['bitrate'] + self.user_limit: int = data['user_limit'] + self._fill_overwrites(data) + + @property + def _sorting_bucket(self) -> int: + return ChannelType.voice.value + + def is_nsfw(self) -> bool: + """:class:`bool`: Checks if the channel is NSFW. + + .. versionadded:: 2.0 + """ + return self.nsfw + + @property + def members(self) -> List[Member]: + """List[:class:`Member`]: Returns all members that are currently inside this voice channel.""" + ret = [] + for user_id, state in self.guild._voice_states.items(): + if state.channel and state.channel.id == self.id: + member = self.guild.get_member(user_id) + if member is not None: + ret.append(member) + return ret + + @property + def voice_states(self) -> Dict[int, VoiceState]: + """Returns a mapping of member IDs who have voice states in this channel. + + .. versionadded:: 1.3 + + .. note:: + + This function is intentionally low level to replace :attr:`members` + when the member cache is unavailable. + + Returns + -------- + Mapping[:class:`int`, :class:`VoiceState`] + The mapping of member ID to a voice state. + """ + # fmt: off + return { + key: value + for key, value in self.guild._voice_states.items() + if value.channel and value.channel.id == self.id + } + # fmt: on + + @property + def scheduled_events(self) -> List[ScheduledEvent]: + """List[:class:`ScheduledEvent`]: Returns all scheduled events for this channel. + + .. versionadded:: 2.0 + """ + return [event for event in self.guild.scheduled_events if event.channel_id == self.id] + + @utils.copy_doc(discord.abc.GuildChannel.permissions_for) + def permissions_for(self, obj: Union[Member, Role], /) -> Permissions: + base = super().permissions_for(obj) + self._apply_implicit_permissions(base) + + # voice channels cannot be edited by people who can't connect to them + # It also implicitly denies all other voice perms + if not base.connect: + denied = Permissions.voice() + denied.update(manage_channels=True, manage_roles=True) + base.value &= ~denied.value + return base + + @property + def last_message(self) -> Optional[Message]: + """Retrieves the last message from this channel in cache. + + The message might not be valid or point to an existing message. + + .. versionadded:: 2.0 + + .. admonition:: Reliable Fetching + :class: helpful + + For a slightly more reliable method of fetching the + last message, consider using either :meth:`history` + or :meth:`fetch_message` with the :attr:`last_message_id` + attribute. + + Returns + --------- + Optional[:class:`Message`] + The last message in this channel or ``None`` if not found. + """ + return self._state._get_message(self.last_message_id) if self.last_message_id else None + + def get_partial_message(self, message_id: int, /) -> PartialMessage: + """Creates a :class:`PartialMessage` from the message ID. + + This is useful if you want to work with a message and only have its ID without + doing an unnecessary API call. + + .. versionadded:: 2.0 + + Parameters + ------------ + message_id: :class:`int` + The message ID to create a partial message for. + + Returns + --------- + :class:`PartialMessage` + The partial message. + """ + + from .message import PartialMessage + + return PartialMessage(channel=self, id=message_id) # type: ignore # VocalGuildChannel is an impl detail + + async def delete_messages(self, messages: Iterable[Snowflake], *, reason: Optional[str] = None) -> None: + """|coro| + + Deletes a list of messages. This is similar to :meth:`Message.delete` + except it bulk deletes multiple messages. + + As a special case, if the number of messages is 0, then nothing + is done. If the number of messages is 1 then single message + delete is done. If it's more than two, then bulk delete is used. + + You cannot bulk delete more than 100 messages or messages that + are older than 14 days old. + + You must have :attr:`~Permissions.manage_messages` to do this. + + .. versionadded:: 2.0 + + Parameters + ----------- + messages: Iterable[:class:`abc.Snowflake`] + An iterable of messages denoting which ones to bulk delete. + reason: Optional[:class:`str`] + The reason for deleting the messages. Shows up on the audit log. + + Raises + ------ + ClientException + The number of messages to delete was more than 100. + Forbidden + You do not have proper permissions to delete the messages. + NotFound + If single delete, then the message was already deleted. + HTTPException + Deleting the messages failed. + """ + if not isinstance(messages, (list, tuple)): + messages = list(messages) + + if len(messages) == 0: + return # do nothing + + if len(messages) == 1: + message_id: int = messages[0].id + await self._state.http.delete_message(self.id, message_id) + return + + if len(messages) > 100: + raise ClientException('Can only bulk delete messages up to 100 messages') + + message_ids: SnowflakeList = [m.id for m in messages] + await self._state.http.delete_messages(self.id, message_ids, reason=reason) + + async def purge( + self, + *, + limit: Optional[int] = 100, + check: Callable[[Message], bool] = MISSING, + before: Optional[SnowflakeTime] = None, + after: Optional[SnowflakeTime] = None, + around: Optional[SnowflakeTime] = None, + oldest_first: Optional[bool] = None, + bulk: bool = True, + reason: Optional[str] = None, + ) -> List[Message]: + """|coro| + + Purges a list of messages that meet the criteria given by the predicate + ``check``. If a ``check`` is not provided then all messages are deleted + without discrimination. + + You must have :attr:`~Permissions.manage_messages` to + delete messages even if they are your own. + Having :attr:`~Permissions.read_message_history` is + also needed to retrieve message history. + + .. versionadded:: 2.0 + + Examples + --------- + + Deleting bot's messages :: + + def is_me(m): + return m.author == client.user + + deleted = await channel.purge(limit=100, check=is_me) + await channel.send(f'Deleted {len(deleted)} message(s)') + + Parameters + ----------- + limit: Optional[:class:`int`] + The number of messages to search through. This is not the number + of messages that will be deleted, though it can be. + check: Callable[[:class:`Message`], :class:`bool`] + The function used to check if a message should be deleted. + It must take a :class:`Message` as its sole parameter. + before: Optional[Union[:class:`abc.Snowflake`, :class:`datetime.datetime`]] + Same as ``before`` in :meth:`history`. + after: Optional[Union[:class:`abc.Snowflake`, :class:`datetime.datetime`]] + Same as ``after`` in :meth:`history`. + around: Optional[Union[:class:`abc.Snowflake`, :class:`datetime.datetime`]] + Same as ``around`` in :meth:`history`. + oldest_first: Optional[:class:`bool`] + Same as ``oldest_first`` in :meth:`history`. + bulk: :class:`bool` + If ``True``, use bulk delete. Setting this to ``False`` is useful for mass-deleting + a bot's own messages without :attr:`Permissions.manage_messages`. When ``True``, will + fall back to single delete if messages are older than two weeks. + reason: Optional[:class:`str`] + The reason for purging the messages. Shows up on the audit log. + + Raises + ------- + Forbidden + You do not have proper permissions to do the actions required. + HTTPException + Purging the messages failed. + + Returns + -------- + List[:class:`.Message`] + The list of messages that were deleted. + """ + + return await discord.abc._purge_helper( + self, + limit=limit, + check=check, + before=before, + after=after, + around=around, + oldest_first=oldest_first, + bulk=bulk, + reason=reason, + ) + + async def webhooks(self) -> List[Webhook]: + """|coro| + + Gets the list of webhooks from this channel. + + You must have :attr:`~.Permissions.manage_webhooks` to do this. + + .. versionadded:: 2.0 + + Raises + ------- + Forbidden + You don't have permissions to get the webhooks. + + Returns + -------- + List[:class:`Webhook`] + The webhooks for this channel. + """ + + from .webhook import Webhook + + data = await self._state.http.channel_webhooks(self.id) + return [Webhook.from_state(d, state=self._state) for d in data] + + async def create_webhook(self, *, name: str, avatar: Optional[bytes] = None, reason: Optional[str] = None) -> Webhook: + """|coro| + + Creates a webhook for this channel. + + You must have :attr:`~.Permissions.manage_webhooks` to do this. + + .. versionadded:: 2.0 + + Parameters + ------------- + name: :class:`str` + The webhook's name. + avatar: Optional[:class:`bytes`] + A :term:`py:bytes-like object` representing the webhook's default avatar. + This operates similarly to :meth:`~ClientUser.edit`. + reason: Optional[:class:`str`] + The reason for creating this webhook. Shows up in the audit logs. + + Raises + ------- + HTTPException + Creating the webhook failed. + Forbidden + You do not have permissions to create a webhook. + + Returns + -------- + :class:`Webhook` + The created webhook. + """ + + from .webhook import Webhook + + if avatar is not None: + avatar = utils._bytes_to_base64_data(avatar) # type: ignore # Silence reassignment error + + data = await self._state.http.create_webhook(self.id, name=str(name), avatar=avatar, reason=reason) + return Webhook.from_state(data, state=self._state) + + @utils.copy_doc(discord.abc.GuildChannel.clone) + async def clone( + self, *, name: Optional[str] = None, category: Optional[CategoryChannel] = None, reason: Optional[str] = None + ) -> Self: + base = { + 'bitrate': self.bitrate, + 'user_limit': self.user_limit, + 'rate_limit_per_user': self.slowmode_delay, + 'nsfw': self.nsfw, + 'video_quality_mode': self.video_quality_mode.value, + } + if self.rtc_region: + base['rtc_region'] = self.rtc_region + + return await self._clone_impl( + base, + name=name, + category=category, + reason=reason, + ) + + +class VoiceChannel(VocalGuildChannel): + """Represents a Discord guild voice channel. + + .. container:: operations + + .. describe:: x == y + + Checks if two channels are equal. + + .. describe:: x != y + + Checks if two channels are not equal. + + .. describe:: hash(x) + + Returns the channel's hash. + + .. describe:: str(x) + + Returns the channel's name. + + Attributes + ----------- + name: :class:`str` + The channel name. + guild: :class:`Guild` + The guild the channel belongs to. + id: :class:`int` + The channel ID. + nsfw: :class:`bool` + If the channel is marked as "not safe for work" or "age restricted". + + .. versionadded:: 2.0 + category_id: Optional[:class:`int`] + The category channel ID this channel belongs to, if applicable. + position: :class:`int` + The position in the channel list. This is a number that starts at 0. e.g. the + top channel is position 0. + bitrate: :class:`int` + The channel's preferred audio bitrate in bits per second. + user_limit: :class:`int` + The channel's limit for number of members that can be in a voice channel. + rtc_region: Optional[:class:`str`] + The region for the voice channel's voice communication. + A value of ``None`` indicates automatic voice region detection. + + .. versionadded:: 1.7 + + .. versionchanged:: 2.0 + The type of this attribute has changed to :class:`str`. + video_quality_mode: :class:`VideoQualityMode` + The camera video quality for the voice channel's participants. + + .. versionadded:: 2.0 + last_message_id: Optional[:class:`int`] + The last message ID of the message sent to this channel. It may + *not* point to an existing or valid message. + + .. versionadded:: 2.0 + slowmode_delay: :class:`int` + The number of seconds a member must wait between sending messages + in this channel. A value of ``0`` denotes that it is disabled. + Bots and users with :attr:`~Permissions.manage_channels` or + :attr:`~Permissions.manage_messages` bypass slowmode. + + .. versionadded:: 2.2 + """ + + __slots__ = () + + def __repr__(self) -> str: + attrs = [ + ('id', self.id), + ('name', self.name), + ('rtc_region', self.rtc_region), + ('position', self.position), + ('bitrate', self.bitrate), + ('video_quality_mode', self.video_quality_mode), + ('user_limit', self.user_limit), + ('category_id', self.category_id), + ] + joined = ' '.join('%s=%r' % t for t in attrs) + return f'<{self.__class__.__name__} {joined}>' + + @property + def _scheduled_event_entity_type(self) -> Optional[EntityType]: + return EntityType.voice + + @property + def type(self) -> Literal[ChannelType.voice]: + """:class:`ChannelType`: The channel's Discord type.""" + return ChannelType.voice + + @overload + async def edit(self) -> None: + ... + + @overload + async def edit(self, *, position: int, reason: Optional[str] = ...) -> None: + ... + + @overload + async def edit( + self, + *, + name: str = ..., + nsfw: bool = ..., + bitrate: int = ..., + user_limit: int = ..., + position: int = ..., + sync_permissions: int = ..., + category: Optional[CategoryChannel] = ..., + overwrites: Mapping[OverwriteKeyT, PermissionOverwrite] = ..., + rtc_region: Optional[str] = ..., + video_quality_mode: VideoQualityMode = ..., + slowmode_delay: int = ..., + status: Optional[str] = ..., + reason: Optional[str] = ..., + ) -> VoiceChannel: + ... + + async def edit(self, *, reason: Optional[str] = None, **options: Any) -> Optional[VoiceChannel]: + """|coro| + + Edits the channel. + + You must have :attr:`~Permissions.manage_channels` to do this. + + .. versionchanged:: 1.3 + The ``overwrites`` keyword-only parameter was added. + + .. versionchanged:: 2.0 + Edits are no longer in-place, the newly edited channel is returned instead. + + .. versionchanged:: 2.0 + The ``region`` parameter now accepts :class:`str` instead of an enum. + + .. versionchanged:: 2.0 + This function will now raise :exc:`TypeError` instead of + ``InvalidArgument``. + + Parameters + ---------- + name: :class:`str` + The new channel's name. + bitrate: :class:`int` + The new channel's bitrate. + nsfw: :class:`bool` + To mark the channel as NSFW or not. + user_limit: :class:`int` + The new channel's user limit. + position: :class:`int` + The new channel's position. + sync_permissions: :class:`bool` + Whether to sync permissions with the channel's new or pre-existing + category. Defaults to ``False``. + category: Optional[:class:`CategoryChannel`] + The new category for this channel. Can be ``None`` to remove the + category. + slowmode_delay: :class:`int` + Specifies the slowmode rate limit for user in this channel, in seconds. + A value of ``0`` disables slowmode. The maximum value possible is ``21600``. + reason: Optional[:class:`str`] + The reason for editing this channel. Shows up on the audit log. + overwrites: :class:`Mapping` + A :class:`Mapping` of target (either a role or a member) to + :class:`PermissionOverwrite` to apply to the channel. + rtc_region: Optional[:class:`str`] + The new region for the voice channel's voice communication. + A value of ``None`` indicates automatic voice region detection. + + .. versionadded:: 1.7 + video_quality_mode: :class:`VideoQualityMode` + The camera video quality for the voice channel's participants. + + .. versionadded:: 2.0 + status: Optional[:class:`str`] + The new voice channel status. It can be up to 500 characters. + Can be ``None`` to remove the status. + + .. versionadded:: 2.4 + + Raises + ------ + TypeError + If the permission overwrite information is not in proper form. + Forbidden + You do not have permissions to edit the channel. + HTTPException + Editing the channel failed. + + Returns + -------- + Optional[:class:`.VoiceChannel`] + The newly edited voice channel. If the edit was only positional + then ``None`` is returned instead. + """ + payload = await self._edit(options, reason=reason) + if payload is not None: + # the payload will always be the proper channel payload + return self.__class__(state=self._state, guild=self.guild, data=payload) # type: ignore + + async def send_sound(self, sound: Union[SoundboardSound, SoundboardDefaultSound], /) -> None: + """|coro| + + Sends a soundboard sound for this channel. + + You must have :attr:`~Permissions.speak` and :attr:`~Permissions.use_soundboard` to do this. + Additionally, you must have :attr:`~Permissions.use_external_sounds` if the sound is from + a different guild. + + .. versionadded:: 2.5 + + Parameters + ----------- + sound: Union[:class:`SoundboardSound`, :class:`SoundboardDefaultSound`] + The sound to send for this channel. + + Raises + ------- + Forbidden + You do not have permissions to send a sound for this channel. + HTTPException + Sending the sound failed. + """ + payload = {'sound_id': sound.id} + if not isinstance(sound, SoundboardDefaultSound) and self.guild.id != sound.guild.id: + payload['source_guild_id'] = sound.guild.id + + await self._state.http.send_soundboard_sound(self.id, **payload) + + +class StageChannel(VocalGuildChannel): + """Represents a Discord guild stage channel. + + .. versionadded:: 1.7 + + .. container:: operations + + .. describe:: x == y + + Checks if two channels are equal. + + .. describe:: x != y + + Checks if two channels are not equal. + + .. describe:: hash(x) + + Returns the channel's hash. + + .. describe:: str(x) + + Returns the channel's name. + + Attributes + ----------- + name: :class:`str` + The channel name. + guild: :class:`Guild` + The guild the channel belongs to. + id: :class:`int` + The channel ID. + nsfw: :class:`bool` + If the channel is marked as "not safe for work" or "age restricted". + + .. versionadded:: 2.0 + topic: Optional[:class:`str`] + The channel's topic. ``None`` if it isn't set. + category_id: Optional[:class:`int`] + The category channel ID this channel belongs to, if applicable. + position: :class:`int` + The position in the channel list. This is a number that starts at 0. e.g. the + top channel is position 0. + bitrate: :class:`int` + The channel's preferred audio bitrate in bits per second. + user_limit: :class:`int` + The channel's limit for number of members that can be in a stage channel. + rtc_region: Optional[:class:`str`] + The region for the stage channel's voice communication. + A value of ``None`` indicates automatic voice region detection. + video_quality_mode: :class:`VideoQualityMode` + The camera video quality for the stage channel's participants. + + .. versionadded:: 2.0 + last_message_id: Optional[:class:`int`] + The last message ID of the message sent to this channel. It may + *not* point to an existing or valid message. + + .. versionadded:: 2.2 + slowmode_delay: :class:`int` + The number of seconds a member must wait between sending messages + in this channel. A value of ``0`` denotes that it is disabled. + Bots and users with :attr:`~Permissions.manage_channels` or + :attr:`~Permissions.manage_messages` bypass slowmode. + + .. versionadded:: 2.2 + """ + + __slots__ = ('topic',) + + def __repr__(self) -> str: + attrs = [ + ('id', self.id), + ('name', self.name), + ('topic', self.topic), + ('rtc_region', self.rtc_region), + ('position', self.position), + ('bitrate', self.bitrate), + ('video_quality_mode', self.video_quality_mode), + ('user_limit', self.user_limit), + ('category_id', self.category_id), + ] + joined = ' '.join('%s=%r' % t for t in attrs) + return f'<{self.__class__.__name__} {joined}>' + + def _update(self, guild: Guild, data: StageChannelPayload) -> None: + super()._update(guild, data) + self.topic: Optional[str] = data.get('topic') + + @property + def _scheduled_event_entity_type(self) -> Optional[EntityType]: + return EntityType.stage_instance + + @property + def requesting_to_speak(self) -> List[Member]: + """List[:class:`Member`]: A list of members who are requesting to speak in the stage channel.""" + return [member for member in self.members if member.voice and member.voice.requested_to_speak_at is not None] + + @property + def speakers(self) -> List[Member]: + """List[:class:`Member`]: A list of members who have been permitted to speak in the stage channel. + + .. versionadded:: 2.0 + """ + return [ + member + for member in self.members + if member.voice and not member.voice.suppress and member.voice.requested_to_speak_at is None + ] + + @property + def listeners(self) -> List[Member]: + """List[:class:`Member`]: A list of members who are listening in the stage channel. + + .. versionadded:: 2.0 + """ + return [member for member in self.members if member.voice and member.voice.suppress] + + @property + def moderators(self) -> List[Member]: + """List[:class:`Member`]: A list of members who are moderating the stage channel. + + .. versionadded:: 2.0 + """ + required_permissions = Permissions.stage_moderator() + return [member for member in self.members if self.permissions_for(member) >= required_permissions] + + @property + def type(self) -> Literal[ChannelType.stage_voice]: + """:class:`ChannelType`: The channel's Discord type.""" + return ChannelType.stage_voice + + @property + def instance(self) -> Optional[StageInstance]: + """Optional[:class:`StageInstance`]: The running stage instance of the stage channel. + + .. versionadded:: 2.0 + """ + return utils.get(self.guild.stage_instances, channel_id=self.id) + + async def create_instance( + self, + *, + topic: str, + privacy_level: PrivacyLevel = MISSING, + send_start_notification: bool = False, + scheduled_event: Snowflake = MISSING, + reason: Optional[str] = None, + ) -> StageInstance: + """|coro| + + Create a stage instance. + + You must have :attr:`~Permissions.manage_channels` to do this. + + .. versionadded:: 2.0 + + Parameters + ----------- + topic: :class:`str` + The stage instance's topic. + privacy_level: :class:`PrivacyLevel` + The stage instance's privacy level. Defaults to :attr:`PrivacyLevel.guild_only`. + send_start_notification: :class:`bool` + Whether to send a start notification. This sends a push notification to @everyone if ``True``. Defaults to ``False``. + You must have :attr:`~Permissions.mention_everyone` to do this. + + .. versionadded:: 2.3 + scheduled_event: :class:`~discord.abc.Snowflake` + The guild scheduled event associated with the stage instance. + + .. versionadded:: 2.4 + reason: :class:`str` + The reason the stage instance was created. Shows up on the audit log. + + Raises + ------ + TypeError + If the ``privacy_level`` parameter is not the proper type. + Forbidden + You do not have permissions to create a stage instance. + HTTPException + Creating a stage instance failed. + + Returns + -------- + :class:`StageInstance` + The newly created stage instance. + """ + + payload: Dict[str, Any] = {'channel_id': self.id, 'topic': topic} + + if privacy_level is not MISSING: + if not isinstance(privacy_level, PrivacyLevel): + raise TypeError('privacy_level field must be of type PrivacyLevel') + + payload['privacy_level'] = privacy_level.value + + if scheduled_event is not MISSING: + payload['guild_scheduled_event_id'] = scheduled_event.id + + payload['send_start_notification'] = send_start_notification + + data = await self._state.http.create_stage_instance(**payload, reason=reason) + return StageInstance(guild=self.guild, state=self._state, data=data) + + async def fetch_instance(self) -> StageInstance: + """|coro| + + Gets the running :class:`StageInstance`. + + .. versionadded:: 2.0 + + Raises + ------- + NotFound + The stage instance or channel could not be found. + HTTPException + Getting the stage instance failed. + + Returns + -------- + :class:`StageInstance` + The stage instance. + """ + data = await self._state.http.get_stage_instance(self.id) + return StageInstance(guild=self.guild, state=self._state, data=data) + + @overload + async def edit(self) -> None: + ... + + @overload + async def edit(self, *, position: int, reason: Optional[str] = ...) -> None: + ... + + @overload + async def edit( + self, + *, + name: str = ..., + nsfw: bool = ..., + bitrate: int = ..., + user_limit: int = ..., + position: int = ..., + sync_permissions: int = ..., + category: Optional[CategoryChannel] = ..., + overwrites: Mapping[OverwriteKeyT, PermissionOverwrite] = ..., + rtc_region: Optional[str] = ..., + video_quality_mode: VideoQualityMode = ..., + slowmode_delay: int = ..., + reason: Optional[str] = ..., + ) -> StageChannel: + ... + + async def edit(self, *, reason: Optional[str] = None, **options: Any) -> Optional[StageChannel]: + """|coro| + + Edits the channel. + + You must have :attr:`~Permissions.manage_channels` to do this. + + .. versionchanged:: 2.0 + The ``topic`` parameter must now be set via :attr:`create_instance`. + + .. versionchanged:: 2.0 + Edits are no longer in-place, the newly edited channel is returned instead. + + .. versionchanged:: 2.0 + The ``region`` parameter now accepts :class:`str` instead of an enum. + + .. versionchanged:: 2.0 + This function will now raise :exc:`TypeError` instead of + ``InvalidArgument``. + + Parameters + ---------- + name: :class:`str` + The new channel's name. + bitrate: :class:`int` + The new channel's bitrate. + position: :class:`int` + The new channel's position. + nsfw: :class:`bool` + To mark the channel as NSFW or not. + user_limit: :class:`int` + The new channel's user limit. + sync_permissions: :class:`bool` + Whether to sync permissions with the channel's new or pre-existing + category. Defaults to ``False``. + category: Optional[:class:`CategoryChannel`] + The new category for this channel. Can be ``None`` to remove the + category. + slowmode_delay: :class:`int` + Specifies the slowmode rate limit for user in this channel, in seconds. + A value of ``0`` disables slowmode. The maximum value possible is ``21600``. + reason: Optional[:class:`str`] + The reason for editing this channel. Shows up on the audit log. + overwrites: :class:`Mapping` + A :class:`Mapping` of target (either a role or a member) to + :class:`PermissionOverwrite` to apply to the channel. + rtc_region: Optional[:class:`str`] + The new region for the stage channel's voice communication. + A value of ``None`` indicates automatic voice region detection. + video_quality_mode: :class:`VideoQualityMode` + The camera video quality for the stage channel's participants. + + .. versionadded:: 2.0 + + Raises + ------ + ValueError + If the permission overwrite information is not in proper form. + Forbidden + You do not have permissions to edit the channel. + HTTPException + Editing the channel failed. + + Returns + -------- + Optional[:class:`.StageChannel`] + The newly edited stage channel. If the edit was only positional + then ``None`` is returned instead. + """ + + payload = await self._edit(options, reason=reason) + if payload is not None: + # the payload will always be the proper channel payload + return self.__class__(state=self._state, guild=self.guild, data=payload) # type: ignore + + +class CategoryChannel(discord.abc.GuildChannel, Hashable): + """Represents a Discord channel category. + + These are useful to group channels to logical compartments. + + .. container:: operations + + .. describe:: x == y + + Checks if two channels are equal. + + .. describe:: x != y + + Checks if two channels are not equal. + + .. describe:: hash(x) + + Returns the category's hash. + + .. describe:: str(x) + + Returns the category's name. + + Attributes + ----------- + name: :class:`str` + The category name. + guild: :class:`Guild` + The guild the category belongs to. + id: :class:`int` + The category channel ID. + position: :class:`int` + The position in the category list. This is a number that starts at 0. e.g. the + top category is position 0. + nsfw: :class:`bool` + If the channel is marked as "not safe for work". + + .. note:: + + To check if the channel or the guild of that channel are marked as NSFW, consider :meth:`is_nsfw` instead. + """ + + __slots__ = ('name', 'id', 'guild', 'nsfw', '_state', 'position', '_overwrites', 'category_id') + + def __init__(self, *, state: ConnectionState, guild: Guild, data: CategoryChannelPayload): + self._state: ConnectionState = state + self.id: int = int(data['id']) + self._update(guild, data) + + def __repr__(self) -> str: + return f'' + + def _update(self, guild: Guild, data: CategoryChannelPayload) -> None: + self.guild: Guild = guild + self.name: str = data['name'] + self.category_id: Optional[int] = utils._get_as_snowflake(data, 'parent_id') + self.nsfw: bool = data.get('nsfw', False) + self.position: int = data['position'] + self._fill_overwrites(data) + + @property + def _sorting_bucket(self) -> int: + return ChannelType.category.value + + @property + def _scheduled_event_entity_type(self) -> Optional[EntityType]: + return None + + @property + def type(self) -> Literal[ChannelType.category]: + """:class:`ChannelType`: The channel's Discord type.""" + return ChannelType.category + + def is_nsfw(self) -> bool: + """:class:`bool`: Checks if the category is NSFW.""" + return self.nsfw + + @utils.copy_doc(discord.abc.GuildChannel.clone) + async def clone( + self, + *, + name: Optional[str] = None, + category: Optional[CategoryChannel] = None, + reason: Optional[str] = None, + ) -> CategoryChannel: + return await self._clone_impl({'nsfw': self.nsfw}, name=name, reason=reason) + + @overload + async def edit(self) -> None: + ... + + @overload + async def edit(self, *, position: int, reason: Optional[str] = ...) -> None: + ... + + @overload + async def edit( + self, + *, + name: str = ..., + position: int = ..., + nsfw: bool = ..., + overwrites: Mapping[OverwriteKeyT, PermissionOverwrite] = ..., + reason: Optional[str] = ..., + ) -> CategoryChannel: + ... + + async def edit(self, *, reason: Optional[str] = None, **options: Any) -> Optional[CategoryChannel]: + """|coro| + + Edits the channel. + + You must have :attr:`~Permissions.manage_channels` to do this. + + .. versionchanged:: 1.3 + The ``overwrites`` keyword-only parameter was added. + + .. versionchanged:: 2.0 + Edits are no longer in-place, the newly edited channel is returned instead. + + .. versionchanged:: 2.0 + This function will now raise :exc:`TypeError` or + :exc:`ValueError` instead of ``InvalidArgument``. + + Parameters + ---------- + name: :class:`str` + The new category's name. + position: :class:`int` + The new category's position. + nsfw: :class:`bool` + To mark the category as NSFW or not. + reason: Optional[:class:`str`] + The reason for editing this category. Shows up on the audit log. + overwrites: :class:`Mapping` + A :class:`Mapping` of target (either a role or a member) to + :class:`PermissionOverwrite` to apply to the channel. + + Raises + ------ + ValueError + If position is less than 0 or greater than the number of categories. + TypeError + The overwrite information is not in proper form. + Forbidden + You do not have permissions to edit the category. + HTTPException + Editing the category failed. + + Returns + -------- + Optional[:class:`.CategoryChannel`] + The newly edited category channel. If the edit was only positional + then ``None`` is returned instead. + """ + + payload = await self._edit(options, reason=reason) + if payload is not None: + # the payload will always be the proper channel payload + return self.__class__(state=self._state, guild=self.guild, data=payload) # type: ignore + + @utils.copy_doc(discord.abc.GuildChannel.move) + async def move(self, **kwargs: Any) -> None: + kwargs.pop('category', None) + await super().move(**kwargs) + + @property + def channels(self) -> List[GuildChannelType]: + """List[:class:`abc.GuildChannel`]: Returns the channels that are under this category. + + These are sorted by the official Discord UI, which places voice channels below the text channels. + """ + + def comparator(channel): + return (not isinstance(channel, TextChannel), channel.position) + + ret = [c for c in self.guild.channels if c.category_id == self.id] + ret.sort(key=comparator) + return ret + + @property + def text_channels(self) -> List[TextChannel]: + """List[:class:`TextChannel`]: Returns the text channels that are under this category.""" + ret = [c for c in self.guild.channels if c.category_id == self.id and isinstance(c, TextChannel)] + ret.sort(key=lambda c: (c.position, c.id)) + return ret + + @property + def voice_channels(self) -> List[VoiceChannel]: + """List[:class:`VoiceChannel`]: Returns the voice channels that are under this category.""" + ret = [c for c in self.guild.channels if c.category_id == self.id and isinstance(c, VoiceChannel)] + ret.sort(key=lambda c: (c.position, c.id)) + return ret + + @property + def stage_channels(self) -> List[StageChannel]: + """List[:class:`StageChannel`]: Returns the stage channels that are under this category. + + .. versionadded:: 1.7 + """ + ret = [c for c in self.guild.channels if c.category_id == self.id and isinstance(c, StageChannel)] + ret.sort(key=lambda c: (c.position, c.id)) + return ret + + @property + def forums(self) -> List[ForumChannel]: + """List[:class:`ForumChannel`]: Returns the forum channels that are under this category. + + .. versionadded:: 2.4 + """ + r = [c for c in self.guild.channels if c.category_id == self.id and isinstance(c, ForumChannel)] + r.sort(key=lambda c: (c.position, c.id)) + return r + + async def create_text_channel(self, name: str, **options: Any) -> TextChannel: + """|coro| + + A shortcut method to :meth:`Guild.create_text_channel` to create a :class:`TextChannel` in the category. + + Returns + ------- + :class:`TextChannel` + The channel that was just created. + """ + return await self.guild.create_text_channel(name, category=self, **options) + + async def create_voice_channel(self, name: str, **options: Any) -> VoiceChannel: + """|coro| + + A shortcut method to :meth:`Guild.create_voice_channel` to create a :class:`VoiceChannel` in the category. + + Returns + ------- + :class:`VoiceChannel` + The channel that was just created. + """ + return await self.guild.create_voice_channel(name, category=self, **options) + + async def create_stage_channel(self, name: str, **options: Any) -> StageChannel: + """|coro| + + A shortcut method to :meth:`Guild.create_stage_channel` to create a :class:`StageChannel` in the category. + + .. versionadded:: 1.7 + + Returns + ------- + :class:`StageChannel` + The channel that was just created. + """ + return await self.guild.create_stage_channel(name, category=self, **options) + + async def create_forum(self, name: str, **options: Any) -> ForumChannel: + """|coro| + + A shortcut method to :meth:`Guild.create_forum` to create a :class:`ForumChannel` in the category. + + .. versionadded:: 2.0 + + Returns + -------- + :class:`ForumChannel` + The channel that was just created. + """ + return await self.guild.create_forum(name, category=self, **options) + + +class ForumTag(Hashable): + """Represents a forum tag that can be applied to a thread within a :class:`ForumChannel`. + + .. versionadded:: 2.1 + + .. container:: operations + + .. describe:: x == y + + Checks if two forum tags are equal. + + .. describe:: x != y + + Checks if two forum tags are not equal. + + .. describe:: hash(x) + + Returns the forum tag's hash. + + .. describe:: str(x) + + Returns the forum tag's name. + + + Attributes + ----------- + id: :class:`int` + The ID of the tag. If this was manually created then the ID will be ``0``. + name: :class:`str` + The name of the tag. Can only be up to 20 characters. + moderated: :class:`bool` + Whether this tag can only be added or removed by a moderator with + the :attr:`~Permissions.manage_threads` permission. + emoji: Optional[:class:`PartialEmoji`] + The emoji that is used to represent this tag. + Note that if the emoji is a custom emoji, it will *not* have name information. + """ + + __slots__ = ('name', 'id', 'moderated', 'emoji') + + def __init__(self, *, name: str, emoji: Optional[EmojiInputType] = None, moderated: bool = False) -> None: + self.name: str = name + self.id: int = 0 + self.moderated: bool = moderated + self.emoji: Optional[PartialEmoji] = None + if isinstance(emoji, _EmojiTag): + self.emoji = emoji._to_partial() + elif isinstance(emoji, str): + self.emoji = PartialEmoji.from_str(emoji) + elif emoji is not None: + raise TypeError(f'emoji must be a Emoji, PartialEmoji, str or None not {emoji.__class__.__name__}') + + @classmethod + def from_data(cls, *, state: ConnectionState, data: ForumTagPayload) -> Self: + self = cls.__new__(cls) + self.name = data['name'] + self.id = int(data['id']) + self.moderated = data.get('moderated', False) + + emoji_name = data['emoji_name'] or '' + emoji_id = utils._get_as_snowflake(data, 'emoji_id') or None # Coerce 0 -> None + if not emoji_name and not emoji_id: + self.emoji = None + else: + self.emoji = PartialEmoji.with_state(state=state, name=emoji_name, id=emoji_id) + return self + + def to_dict(self) -> Dict[str, Any]: + payload: Dict[str, Any] = { + 'name': self.name, + 'moderated': self.moderated, + } + if self.emoji is not None: + payload.update(self.emoji._to_forum_tag_payload()) + else: + payload.update(emoji_id=None, emoji_name=None) + + if self.id: + payload['id'] = self.id + + return payload + + def __repr__(self) -> str: + return f'' + + def __str__(self) -> str: + return self.name + + +class ForumChannel(discord.abc.GuildChannel, Hashable): + """Represents a Discord guild forum channel. + + .. versionadded:: 2.0 + + .. container:: operations + + .. describe:: x == y + + Checks if two forums are equal. + + .. describe:: x != y + + Checks if two forums are not equal. + + .. describe:: hash(x) + + Returns the forum's hash. + + .. describe:: str(x) + + Returns the forum's name. + + Attributes + ----------- + name: :class:`str` + The forum name. + guild: :class:`Guild` + The guild the forum belongs to. + id: :class:`int` + The forum ID. + category_id: Optional[:class:`int`] + The category channel ID this forum belongs to, if applicable. + topic: Optional[:class:`str`] + The forum's topic. ``None`` if it doesn't exist. Called "Guidelines" in the UI. + Can be up to 4096 characters long. + position: :class:`int` + The position in the channel list. This is a number that starts at 0. e.g. the + top channel is position 0. + last_message_id: Optional[:class:`int`] + The last thread ID that was created on this forum. This technically also + coincides with the message ID that started the thread that was created. + It may *not* point to an existing or valid thread or message. + slowmode_delay: :class:`int` + The number of seconds a member must wait between creating threads + in this forum. A value of ``0`` denotes that it is disabled. + Bots and users with :attr:`~Permissions.manage_channels` or + :attr:`~Permissions.manage_messages` bypass slowmode. + nsfw: :class:`bool` + If the forum is marked as "not safe for work" or "age restricted". + default_auto_archive_duration: :class:`int` + The default auto archive duration in minutes for threads created in this forum. + default_thread_slowmode_delay: :class:`int` + The default slowmode delay in seconds for threads created in this forum. + + .. versionadded:: 2.1 + default_reaction_emoji: Optional[:class:`PartialEmoji`] + The default reaction emoji for threads created in this forum to show in the + add reaction button. + + .. versionadded:: 2.1 + default_layout: :class:`ForumLayoutType` + The default layout for posts in this forum channel. + Defaults to :attr:`ForumLayoutType.not_set`. + + .. versionadded:: 2.2 + default_sort_order: Optional[:class:`ForumOrderType`] + The default sort order for posts in this forum channel. + + .. versionadded:: 2.3 + """ + + __slots__ = ( + 'name', + 'id', + 'guild', + 'topic', + '_state', + '_flags', + '_type', + 'nsfw', + 'category_id', + 'position', + 'slowmode_delay', + '_overwrites', + 'last_message_id', + 'default_auto_archive_duration', + 'default_thread_slowmode_delay', + 'default_reaction_emoji', + 'default_layout', + 'default_sort_order', + '_available_tags', + '_flags', + ) + + def __init__(self, *, state: ConnectionState, guild: Guild, data: Union[ForumChannelPayload, MediaChannelPayload]): + self._state: ConnectionState = state + self.id: int = int(data['id']) + self._type: Literal[15, 16] = data['type'] + self._update(guild, data) + + def __repr__(self) -> str: + attrs = [ + ('id', self.id), + ('name', self.name), + ('position', self.position), + ('nsfw', self.nsfw), + ('category_id', self.category_id), + ] + joined = ' '.join('%s=%r' % t for t in attrs) + return f'<{self.__class__.__name__} {joined}>' + + def _update(self, guild: Guild, data: Union[ForumChannelPayload, MediaChannelPayload]) -> None: + self.guild: Guild = guild + self.name: str = data['name'] + self.category_id: Optional[int] = utils._get_as_snowflake(data, 'parent_id') + self.topic: Optional[str] = data.get('topic') + self.position: int = data['position'] + self.nsfw: bool = data.get('nsfw', False) + self.slowmode_delay: int = data.get('rate_limit_per_user', 0) + self.default_auto_archive_duration: ThreadArchiveDuration = data.get('default_auto_archive_duration', 1440) + self.last_message_id: Optional[int] = utils._get_as_snowflake(data, 'last_message_id') + # This takes advantage of the fact that dicts are ordered since Python 3.7 + tags = [ForumTag.from_data(state=self._state, data=tag) for tag in data.get('available_tags', [])] + self.default_thread_slowmode_delay: int = data.get('default_thread_rate_limit_per_user', 0) + self.default_layout: ForumLayoutType = try_enum(ForumLayoutType, data.get('default_forum_layout', 0)) + self._available_tags: Dict[int, ForumTag] = {tag.id: tag for tag in tags} + + self.default_reaction_emoji: Optional[PartialEmoji] = None + default_reaction_emoji = data.get('default_reaction_emoji') + if default_reaction_emoji: + self.default_reaction_emoji = PartialEmoji.with_state( + state=self._state, + id=utils._get_as_snowflake(default_reaction_emoji, 'emoji_id') or None, # Coerce 0 -> None + name=default_reaction_emoji.get('emoji_name') or '', + ) + + self.default_sort_order: Optional[ForumOrderType] = None + default_sort_order = data.get('default_sort_order') + if default_sort_order is not None: + self.default_sort_order = try_enum(ForumOrderType, default_sort_order) + + self._flags: int = data.get('flags', 0) + self._fill_overwrites(data) + + @property + def type(self) -> Literal[ChannelType.forum, ChannelType.media]: + """:class:`ChannelType`: The channel's Discord type.""" + if self._type == 16: + return ChannelType.media + return ChannelType.forum + + @property + def _sorting_bucket(self) -> int: + return ChannelType.text.value + + @property + def members(self) -> List[Member]: + """List[:class:`Member`]: Returns all members that can see this channel. + + .. versionadded:: 2.5 + """ + return [m for m in self.guild.members if self.permissions_for(m).read_messages] + + @property + def _scheduled_event_entity_type(self) -> Optional[EntityType]: + return None + + @utils.copy_doc(discord.abc.GuildChannel.permissions_for) + def permissions_for(self, obj: Union[Member, Role], /) -> Permissions: + base = super().permissions_for(obj) + self._apply_implicit_permissions(base) + + # text channels do not have voice related permissions + denied = Permissions.voice() + base.value &= ~denied.value + return base + + def get_thread(self, thread_id: int, /) -> Optional[Thread]: + """Returns a thread with the given ID. + + .. note:: + + This does not always retrieve archived threads, as they are not retained in the internal + cache. Use :func:`Guild.fetch_channel` instead. + + .. versionadded:: 2.2 + + Parameters + ----------- + thread_id: :class:`int` + The ID to search for. + + Returns + -------- + Optional[:class:`Thread`] + The returned thread or ``None`` if not found. + """ + thread = self.guild.get_thread(thread_id) + if thread is not None and thread.parent_id == self.id: + return thread + return None + + @property + def threads(self) -> List[Thread]: + """List[:class:`Thread`]: Returns all the threads that you can see.""" + return [thread for thread in self.guild._threads.values() if thread.parent_id == self.id] + + @property + def flags(self) -> ChannelFlags: + """:class:`ChannelFlags`: The flags associated with this thread. + + .. versionadded:: 2.1 + """ + return ChannelFlags._from_value(self._flags) + + @property + def available_tags(self) -> Sequence[ForumTag]: + """Sequence[:class:`ForumTag`]: Returns all the available tags for this forum. + + .. versionadded:: 2.1 + """ + return utils.SequenceProxy(self._available_tags.values()) + + def get_tag(self, tag_id: int, /) -> Optional[ForumTag]: + """Returns the tag with the given ID. + + .. versionadded:: 2.1 + + Parameters + ---------- + tag_id: :class:`int` + The ID to search for. + + Returns + ------- + Optional[:class:`ForumTag`] + The tag with the given ID, or ``None`` if not found. + """ + return self._available_tags.get(tag_id) + + def is_nsfw(self) -> bool: + """:class:`bool`: Checks if the forum is NSFW.""" + return self.nsfw + + def is_media(self) -> bool: + """:class:`bool`: Checks if the channel is a media channel. + + .. versionadded:: 2.4 + """ + return self._type == ChannelType.media.value + + @utils.copy_doc(discord.abc.GuildChannel.clone) + async def clone( + self, + *, + name: Optional[str] = None, + category: Optional[CategoryChannel], + reason: Optional[str] = None, + ) -> ForumChannel: + base = { + 'topic': self.topic, + 'rate_limit_per_user': self.slowmode_delay, + 'nsfw': self.nsfw, + 'default_auto_archive_duration': self.default_auto_archive_duration, + 'available_tags': [tag.to_dict() for tag in self.available_tags], + 'default_thread_rate_limit_per_user': self.default_thread_slowmode_delay, + } + if self.default_sort_order: + base['default_sort_order'] = self.default_sort_order.value + if self.default_reaction_emoji: + base['default_reaction_emoji'] = self.default_reaction_emoji._to_forum_tag_payload() + if not self.is_media() and self.default_layout: + base['default_forum_layout'] = self.default_layout.value + + return await self._clone_impl( + base, + name=name, + category=category, + reason=reason, + ) + + @overload + async def edit(self) -> None: + ... + + @overload + async def edit(self, *, position: int, reason: Optional[str] = ...) -> None: + ... + + @overload + async def edit( + self, + *, + reason: Optional[str] = ..., + name: str = ..., + topic: str = ..., + position: int = ..., + nsfw: bool = ..., + sync_permissions: bool = ..., + category: Optional[CategoryChannel] = ..., + slowmode_delay: int = ..., + default_auto_archive_duration: ThreadArchiveDuration = ..., + type: ChannelType = ..., + overwrites: Mapping[OverwriteKeyT, PermissionOverwrite] = ..., + available_tags: Sequence[ForumTag] = ..., + default_thread_slowmode_delay: int = ..., + default_reaction_emoji: Optional[EmojiInputType] = ..., + default_layout: ForumLayoutType = ..., + default_sort_order: ForumOrderType = ..., + require_tag: bool = ..., + ) -> ForumChannel: + ... + + async def edit(self, *, reason: Optional[str] = None, **options: Any) -> Optional[ForumChannel]: + """|coro| + + Edits the forum. + + You must have :attr:`~Permissions.manage_channels` to do this. + + Parameters + ---------- + name: :class:`str` + The new forum name. + topic: :class:`str` + The new forum's topic. + position: :class:`int` + The new forum's position. + nsfw: :class:`bool` + To mark the forum as NSFW or not. + sync_permissions: :class:`bool` + Whether to sync permissions with the forum's new or pre-existing + category. Defaults to ``False``. + category: Optional[:class:`CategoryChannel`] + The new category for this forum. Can be ``None`` to remove the + category. + slowmode_delay: :class:`int` + Specifies the slowmode rate limit for user in this forum, in seconds. + A value of ``0`` disables slowmode. The maximum value possible is ``21600``. + type: :class:`ChannelType` + Change the type of this text forum. Currently, only conversion between + :attr:`ChannelType.text` and :attr:`ChannelType.news` is supported. This + is only available to guilds that contain ``NEWS`` in :attr:`Guild.features`. + reason: Optional[:class:`str`] + The reason for editing this forum. Shows up on the audit log. + overwrites: :class:`Mapping` + A :class:`Mapping` of target (either a role or a member) to + :class:`PermissionOverwrite` to apply to the forum. + default_auto_archive_duration: :class:`int` + The new default auto archive duration in minutes for threads created in this channel. + Must be one of ``60``, ``1440``, ``4320``, or ``10080``. + available_tags: Sequence[:class:`ForumTag`] + The new available tags for this forum. + + .. versionadded:: 2.1 + default_thread_slowmode_delay: :class:`int` + The new default slowmode delay for threads in this channel. + + .. versionadded:: 2.1 + default_reaction_emoji: Optional[Union[:class:`Emoji`, :class:`PartialEmoji`, :class:`str`]] + The new default reaction emoji for threads in this channel. + + .. versionadded:: 2.1 + default_layout: :class:`ForumLayoutType` + The new default layout for posts in this forum. + + .. versionadded:: 2.2 + default_sort_order: Optional[:class:`ForumOrderType`] + The new default sort order for posts in this forum. + + .. versionadded:: 2.3 + require_tag: :class:`bool` + Whether to require a tag for threads in this channel or not. + + .. versionadded:: 2.1 + + Raises + ------ + ValueError + The new ``position`` is less than 0 or greater than the number of channels. + TypeError + The permission overwrite information is not in proper form or a type + is not the expected type. + Forbidden + You do not have permissions to edit the forum. + HTTPException + Editing the forum failed. + + Returns + -------- + Optional[:class:`.ForumChannel`] + The newly edited forum channel. If the edit was only positional + then ``None`` is returned instead. + """ + + try: + tags: Sequence[ForumTag] = options.pop('available_tags') + except KeyError: + pass + else: + options['available_tags'] = [tag.to_dict() for tag in tags] + + try: + default_reaction_emoji: Optional[EmojiInputType] = options.pop('default_reaction_emoji') + except KeyError: + pass + else: + if default_reaction_emoji is None: + options['default_reaction_emoji'] = None + elif isinstance(default_reaction_emoji, _EmojiTag): + options['default_reaction_emoji'] = default_reaction_emoji._to_partial()._to_forum_tag_payload() + elif isinstance(default_reaction_emoji, str): + options['default_reaction_emoji'] = PartialEmoji.from_str(default_reaction_emoji)._to_forum_tag_payload() + + try: + require_tag = options.pop('require_tag') + except KeyError: + pass + else: + flags = self.flags + flags.require_tag = require_tag + options['flags'] = flags.value + + try: + layout = options.pop('default_layout') + except KeyError: + pass + else: + if not isinstance(layout, ForumLayoutType): + raise TypeError(f'default_layout parameter must be a ForumLayoutType not {layout.__class__.__name__}') + + options['default_forum_layout'] = layout.value + + try: + sort_order = options.pop('default_sort_order') + except KeyError: + pass + else: + if sort_order is None: + options['default_sort_order'] = None + else: + if not isinstance(sort_order, ForumOrderType): + raise TypeError( + f'default_sort_order parameter must be a ForumOrderType not {sort_order.__class__.__name__}' + ) + + options['default_sort_order'] = sort_order.value + + payload = await self._edit(options, reason=reason) + if payload is not None: + # the payload will always be the proper channel payload + return self.__class__(state=self._state, guild=self.guild, data=payload) # type: ignore + + async def create_tag( + self, + *, + name: str, + emoji: Optional[PartialEmoji] = None, + moderated: bool = False, + reason: Optional[str] = None, + ) -> ForumTag: + """|coro| + + Creates a new tag in this forum. + + You must have :attr:`~Permissions.manage_channels` to do this. + + Parameters + ---------- + name: :class:`str` + The name of the tag. Can only be up to 20 characters. + emoji: Optional[Union[:class:`str`, :class:`PartialEmoji`]] + The emoji to use for the tag. + moderated: :class:`bool` + Whether the tag can only be applied by moderators. + reason: Optional[:class:`str`] + The reason for creating this tag. Shows up on the audit log. + + Raises + ------ + Forbidden + You do not have permissions to create a tag in this forum. + HTTPException + Creating the tag failed. + + Returns + ------- + :class:`ForumTag` + The newly created tag. + """ + + prior = list(self._available_tags.values()) + result = ForumTag(name=name, emoji=emoji, moderated=moderated) + prior.append(result) + payload = await self._state.http.edit_channel( + self.id, reason=reason, available_tags=[tag.to_dict() for tag in prior] + ) + try: + result.id = int(payload['available_tags'][-1]['id']) # type: ignore + except (KeyError, IndexError, ValueError): + pass + + return result + + async def create_thread( + self, + *, + name: str, + auto_archive_duration: ThreadArchiveDuration = MISSING, + slowmode_delay: Optional[int] = None, + content: Optional[str] = None, + tts: bool = False, + embed: Embed = MISSING, + embeds: Sequence[Embed] = MISSING, + file: File = MISSING, + files: Sequence[File] = MISSING, + stickers: Sequence[Union[GuildSticker, StickerItem]] = MISSING, + allowed_mentions: AllowedMentions = MISSING, + mention_author: bool = MISSING, + applied_tags: Sequence[ForumTag] = MISSING, + view: View = MISSING, + suppress_embeds: bool = False, + reason: Optional[str] = None, + ) -> ThreadWithMessage: + """|coro| + + Creates a thread in this forum. + + This thread is a public thread with the initial message given. Currently in order + to start a thread in this forum, the user needs :attr:`~discord.Permissions.send_messages`. + + You must send at least one of ``content``, ``embed``, ``embeds``, ``file``, ``files``, + or ``view`` to create a thread in a forum, since forum channels must have a starter message. + + Parameters + ----------- + name: :class:`str` + The name of the thread. + auto_archive_duration: :class:`int` + The duration in minutes before a thread is automatically hidden from the channel list. + If not provided, the channel's default auto archive duration is used. + + Must be one of ``60``, ``1440``, ``4320``, or ``10080``, if provided. + slowmode_delay: Optional[:class:`int`] + Specifies the slowmode rate limit for user in this channel, in seconds. + The maximum value possible is ``21600``. By default no slowmode rate limit + if this is ``None``. + content: Optional[:class:`str`] + The content of the message to send with the thread. + tts: :class:`bool` + Indicates if the message should be sent using text-to-speech. + embed: :class:`~discord.Embed` + The rich embed for the content. + embeds: List[:class:`~discord.Embed`] + A list of embeds to upload. Must be a maximum of 10. + file: :class:`~discord.File` + The file to upload. + files: List[:class:`~discord.File`] + A list of files to upload. Must be a maximum of 10. + allowed_mentions: :class:`~discord.AllowedMentions` + Controls the mentions being processed in this message. If this is + passed, then the object is merged with :attr:`~discord.Client.allowed_mentions`. + The merging behaviour only overrides attributes that have been explicitly passed + to the object, otherwise it uses the attributes set in :attr:`~discord.Client.allowed_mentions`. + If no object is passed at all then the defaults given by :attr:`~discord.Client.allowed_mentions` + are used instead. + mention_author: :class:`bool` + If set, overrides the :attr:`~discord.AllowedMentions.replied_user` attribute of ``allowed_mentions``. + applied_tags: List[:class:`discord.ForumTag`] + A list of tags to apply to the thread. + view: :class:`discord.ui.View` + A Discord UI View to add to the message. + stickers: Sequence[Union[:class:`~discord.GuildSticker`, :class:`~discord.StickerItem`]] + A list of stickers to upload. Must be a maximum of 3. + suppress_embeds: :class:`bool` + Whether to suppress embeds for the message. This sends the message without any embeds if set to ``True``. + reason: :class:`str` + The reason for creating a new thread. Shows up on the audit log. + + Raises + ------- + Forbidden + You do not have permissions to create a thread. + HTTPException + Starting the thread failed. + ValueError + The ``files`` or ``embeds`` list is not of the appropriate size. + TypeError + You specified both ``file`` and ``files``, + or you specified both ``embed`` and ``embeds``. + + Returns + -------- + Tuple[:class:`Thread`, :class:`Message`] + The created thread with the created message. + This is also accessible as a namedtuple with ``thread`` and ``message`` fields. + """ + + state = self._state + previous_allowed_mention = state.allowed_mentions + if stickers is MISSING: + sticker_ids = MISSING + else: + sticker_ids: SnowflakeList = [s.id for s in stickers] + + if view and not hasattr(view, '__discord_ui_view__'): + raise TypeError(f'view parameter must be View not {view.__class__.__name__}') + + if suppress_embeds: + flags = MessageFlags._from_value(4) + else: + flags = MISSING + + content = str(content) if content else MISSING + + channel_payload = { + 'name': name, + 'auto_archive_duration': auto_archive_duration or self.default_auto_archive_duration, + 'rate_limit_per_user': slowmode_delay, + 'type': 11, # Private threads don't seem to be allowed + } + + if applied_tags is not MISSING: + channel_payload['applied_tags'] = [str(tag.id) for tag in applied_tags] + + with handle_message_parameters( + content=content, + tts=tts, + file=file, + files=files, + embed=embed, + embeds=embeds, + allowed_mentions=allowed_mentions, + previous_allowed_mentions=previous_allowed_mention, + mention_author=None if mention_author is MISSING else mention_author, + stickers=sticker_ids, + view=view, + flags=flags, + channel_payload=channel_payload, + ) as params: + # Circular import + from .message import Message + + data = await state.http.start_thread_in_forum(self.id, params=params, reason=reason) + thread = Thread(guild=self.guild, state=self._state, data=data) + message = Message(state=self._state, channel=thread, data=data['message']) + if view and not view.is_finished(): + self._state.store_view(view, message.id) + + return ThreadWithMessage(thread=thread, message=message) + + async def webhooks(self) -> List[Webhook]: + """|coro| + + Gets the list of webhooks from this channel. + + You must have :attr:`~.Permissions.manage_webhooks` to do this. + + Raises + ------- + Forbidden + You don't have permissions to get the webhooks. + + Returns + -------- + List[:class:`Webhook`] + The webhooks for this channel. + """ + + from .webhook import Webhook + + data = await self._state.http.channel_webhooks(self.id) + return [Webhook.from_state(d, state=self._state) for d in data] + + async def create_webhook(self, *, name: str, avatar: Optional[bytes] = None, reason: Optional[str] = None) -> Webhook: + """|coro| + + Creates a webhook for this channel. + + You must have :attr:`~.Permissions.manage_webhooks` to do this. + + Parameters + ------------- + name: :class:`str` + The webhook's name. + avatar: Optional[:class:`bytes`] + A :term:`py:bytes-like object` representing the webhook's default avatar. + This operates similarly to :meth:`~ClientUser.edit`. + reason: Optional[:class:`str`] + The reason for creating this webhook. Shows up in the audit logs. + + Raises + ------- + HTTPException + Creating the webhook failed. + Forbidden + You do not have permissions to create a webhook. + + Returns + -------- + :class:`Webhook` + The created webhook. + """ + + from .webhook import Webhook + + if avatar is not None: + avatar = utils._bytes_to_base64_data(avatar) # type: ignore # Silence reassignment error + + data = await self._state.http.create_webhook(self.id, name=str(name), avatar=avatar, reason=reason) + return Webhook.from_state(data, state=self._state) + + async def archived_threads( + self, + *, + limit: Optional[int] = 100, + before: Optional[Union[Snowflake, datetime.datetime]] = None, + ) -> AsyncIterator[Thread]: + """Returns an :term:`asynchronous iterator` that iterates over all archived threads in this forum + in order of decreasing :attr:`Thread.archive_timestamp`. + + You must have :attr:`~Permissions.read_message_history` to do this. + + .. versionadded:: 2.0 + + Parameters + ----------- + limit: Optional[:class:`bool`] + The number of threads to retrieve. + If ``None``, retrieves every archived thread in the channel. Note, however, + that this would make it a slow operation. + before: Optional[Union[:class:`abc.Snowflake`, :class:`datetime.datetime`]] + Retrieve archived channels before the given date or ID. + + Raises + ------ + Forbidden + You do not have permissions to get archived threads. + HTTPException + The request to get the archived threads failed. + + Yields + ------- + :class:`Thread` + The archived threads. + """ + before_timestamp = None + + if isinstance(before, datetime.datetime): + before_timestamp = before.isoformat() + elif before is not None: + before_timestamp = utils.snowflake_time(before.id).isoformat() + + update_before = lambda data: data['thread_metadata']['archive_timestamp'] + + while True: + retrieve = 100 + if limit is not None: + if limit <= 0: + return + retrieve = max(2, min(retrieve, limit)) + + data = await self.guild._state.http.get_public_archived_threads(self.id, before=before_timestamp, limit=retrieve) + + threads = data.get('threads', []) + for raw_thread in threads: + yield Thread(guild=self.guild, state=self.guild._state, data=raw_thread) + # Currently the API doesn't let you request less than 2 threads. + # Bail out early if we had to retrieve more than what the limit was. + if limit is not None: + limit -= 1 + if limit <= 0: + return + + if not data.get('has_more', False): + return + + before_timestamp = update_before(threads[-1]) + + +class DMChannel(discord.abc.Messageable, discord.abc.PrivateChannel, Hashable): + """Represents a Discord direct message channel. + + .. container:: operations + + .. describe:: x == y + + Checks if two channels are equal. + + .. describe:: x != y + + Checks if two channels are not equal. + + .. describe:: hash(x) + + Returns the channel's hash. + + .. describe:: str(x) + + Returns a string representation of the channel + + Attributes + ---------- + recipient: Optional[:class:`User`] + The user you are participating with in the direct message channel. + If this channel is received through the gateway, the recipient information + may not be always available. + recipients: List[:class:`User`] + The users you are participating with in the DM channel. + + .. versionadded:: 2.4 + me: :class:`ClientUser` + The user presenting yourself. + id: :class:`int` + The direct message channel ID. + """ + + __slots__ = ('id', 'recipients', 'me', '_state') + + def __init__(self, *, me: ClientUser, state: ConnectionState, data: DMChannelPayload): + self._state: ConnectionState = state + self.recipients: List[User] = [state.store_user(u) for u in data.get('recipients', [])] + self.me: ClientUser = me + self.id: int = int(data['id']) + + async def _get_channel(self) -> Self: + return self + + def __str__(self) -> str: + if self.recipient: + return f'Direct Message with {self.recipient}' + return 'Direct Message with Unknown User' + + def __repr__(self) -> str: + return f'' + + @classmethod + def _from_message(cls, state: ConnectionState, channel_id: int) -> Self: + self = cls.__new__(cls) + self._state = state + self.id = channel_id + self.recipients = [] + # state.user won't be None here + self.me = state.user # type: ignore + return self + + @property + def recipient(self) -> Optional[User]: + if self.recipients: + return self.recipients[0] + return None + + @property + def type(self) -> Literal[ChannelType.private]: + """:class:`ChannelType`: The channel's Discord type.""" + return ChannelType.private + + @property + def guild(self) -> Optional[Guild]: + """Optional[:class:`Guild`]: The guild this DM channel belongs to. Always ``None``. + + This is mainly provided for compatibility purposes in duck typing. + + .. versionadded:: 2.0 + """ + return None + + @property + def jump_url(self) -> str: + """:class:`str`: Returns a URL that allows the client to jump to the channel. + + .. versionadded:: 2.0 + """ + return f'https://discord.com/channels/@me/{self.id}' + + @property + def created_at(self) -> datetime.datetime: + """:class:`datetime.datetime`: Returns the direct message channel's creation time in UTC.""" + return utils.snowflake_time(self.id) + + def permissions_for(self, obj: Any = None, /) -> Permissions: + """Handles permission resolution for a :class:`User`. + + This function is there for compatibility with other channel types. + + Actual direct messages do not really have the concept of permissions. + + This returns all the Text related permissions set to ``True`` except: + + - :attr:`~Permissions.send_tts_messages`: You cannot send TTS messages in a DM. + - :attr:`~Permissions.manage_messages`: You cannot delete others messages in a DM. + - :attr:`~Permissions.create_private_threads`: There are no threads in a DM. + - :attr:`~Permissions.create_public_threads`: There are no threads in a DM. + - :attr:`~Permissions.manage_threads`: There are no threads in a DM. + - :attr:`~Permissions.send_messages_in_threads`: There are no threads in a DM. + + .. versionchanged:: 2.0 + + ``obj`` parameter is now positional-only. + + .. versionchanged:: 2.1 + + Thread related permissions are now set to ``False``. + + Parameters + ----------- + obj: :class:`User` + The user to check permissions for. This parameter is ignored + but kept for compatibility with other ``permissions_for`` methods. + + Returns + -------- + :class:`Permissions` + The resolved permissions. + """ + return Permissions._dm_permissions() + + def get_partial_message(self, message_id: int, /) -> PartialMessage: + """Creates a :class:`PartialMessage` from the message ID. + + This is useful if you want to work with a message and only have its ID without + doing an unnecessary API call. + + .. versionadded:: 1.6 + + .. versionchanged:: 2.0 + + ``message_id`` parameter is now positional-only. + + Parameters + ------------ + message_id: :class:`int` + The message ID to create a partial message for. + + Returns + --------- + :class:`PartialMessage` + The partial message. + """ + + from .message import PartialMessage + + return PartialMessage(channel=self, id=message_id) + + +class GroupChannel(discord.abc.Messageable, discord.abc.PrivateChannel, Hashable): + """Represents a Discord group channel. + + .. container:: operations + + .. describe:: x == y + + Checks if two channels are equal. + + .. describe:: x != y + + Checks if two channels are not equal. + + .. describe:: hash(x) + + Returns the channel's hash. + + .. describe:: str(x) + + Returns a string representation of the channel + + Attributes + ---------- + recipients: List[:class:`User`] + The users you are participating with in the group channel. + me: :class:`ClientUser` + The user presenting yourself. + id: :class:`int` + The group channel ID. + owner: Optional[:class:`User`] + The user that owns the group channel. + owner_id: :class:`int` + The owner ID that owns the group channel. + + .. versionadded:: 2.0 + name: Optional[:class:`str`] + The group channel's name if provided. + """ + + __slots__ = ('id', 'recipients', 'owner_id', 'owner', '_icon', 'name', 'me', '_state') + + def __init__(self, *, me: ClientUser, state: ConnectionState, data: GroupChannelPayload): + self._state: ConnectionState = state + self.id: int = int(data['id']) + self.me: ClientUser = me + self._update_group(data) + + def _update_group(self, data: GroupChannelPayload) -> None: + self.owner_id: Optional[int] = utils._get_as_snowflake(data, 'owner_id') + self._icon: Optional[str] = data.get('icon') + self.name: Optional[str] = data.get('name') + self.recipients: List[User] = [self._state.store_user(u) for u in data.get('recipients', [])] + + self.owner: Optional[BaseUser] + if self.owner_id == self.me.id: + self.owner = self.me + else: + self.owner = utils.find(lambda u: u.id == self.owner_id, self.recipients) + + async def _get_channel(self) -> Self: + return self + + def __str__(self) -> str: + if self.name: + return self.name + + if len(self.recipients) == 0: + return 'Unnamed' + + return ', '.join(map(lambda x: x.name, self.recipients)) + + def __repr__(self) -> str: + return f'' + + @property + def type(self) -> Literal[ChannelType.group]: + """:class:`ChannelType`: The channel's Discord type.""" + return ChannelType.group + + @property + def guild(self) -> Optional[Guild]: + """Optional[:class:`Guild`]: The guild this group channel belongs to. Always ``None``. + + This is mainly provided for compatibility purposes in duck typing. + + .. versionadded:: 2.0 + """ + return None + + @property + def icon(self) -> Optional[Asset]: + """Optional[:class:`Asset`]: Returns the channel's icon asset if available.""" + if self._icon is None: + return None + return Asset._from_icon(self._state, self.id, self._icon, path='channel') + + @property + def created_at(self) -> datetime.datetime: + """:class:`datetime.datetime`: Returns the channel's creation time in UTC.""" + return utils.snowflake_time(self.id) + + @property + def jump_url(self) -> str: + """:class:`str`: Returns a URL that allows the client to jump to the channel. + + .. versionadded:: 2.0 + """ + return f'https://discord.com/channels/@me/{self.id}' + + def permissions_for(self, obj: Snowflake, /) -> Permissions: + """Handles permission resolution for a :class:`User`. + + This function is there for compatibility with other channel types. + + Actual direct messages do not really have the concept of permissions. + + This returns all the Text related permissions set to ``True`` except: + + - :attr:`~Permissions.send_tts_messages`: You cannot send TTS messages in a DM. + - :attr:`~Permissions.manage_messages`: You cannot delete others messages in a DM. + - :attr:`~Permissions.create_private_threads`: There are no threads in a DM. + - :attr:`~Permissions.create_public_threads`: There are no threads in a DM. + - :attr:`~Permissions.manage_threads`: There are no threads in a DM. + - :attr:`~Permissions.send_messages_in_threads`: There are no threads in a DM. + + This also checks the kick_members permission if the user is the owner. + + .. versionchanged:: 2.0 + + ``obj`` parameter is now positional-only. + + .. versionchanged:: 2.1 + + Thread related permissions are now set to ``False``. + + Parameters + ----------- + obj: :class:`~discord.abc.Snowflake` + The user to check permissions for. + + Returns + -------- + :class:`Permissions` + The resolved permissions for the user. + """ + + base = Permissions._dm_permissions() + base.mention_everyone = True + + if obj.id == self.owner_id: + base.kick_members = True + + return base + + async def leave(self) -> None: + """|coro| + + Leave the group. + + If you are the only one in the group, this deletes it as well. + + Raises + ------- + HTTPException + Leaving the group failed. + """ + + await self._state.http.leave_group(self.id) + + +class PartialMessageable(discord.abc.Messageable, Hashable): + """Represents a partial messageable to aid with working messageable channels when + only a channel ID is present. + + The only way to construct this class is through :meth:`Client.get_partial_messageable`. + + Note that this class is trimmed down and has no rich attributes. + + .. versionadded:: 2.0 + + .. container:: operations + + .. describe:: x == y + + Checks if two partial messageables are equal. + + .. describe:: x != y + + Checks if two partial messageables are not equal. + + .. describe:: hash(x) + + Returns the partial messageable's hash. + + Attributes + ----------- + id: :class:`int` + The channel ID associated with this partial messageable. + guild_id: Optional[:class:`int`] + The guild ID associated with this partial messageable. + type: Optional[:class:`ChannelType`] + The channel type associated with this partial messageable, if given. + """ + + def __init__(self, state: ConnectionState, id: int, guild_id: Optional[int] = None, type: Optional[ChannelType] = None): + self._state: ConnectionState = state + self.id: int = id + self.guild_id: Optional[int] = guild_id + self.type: Optional[ChannelType] = type + + def __repr__(self) -> str: + return f'<{self.__class__.__name__} id={self.id} type={self.type!r}>' + + async def _get_channel(self) -> PartialMessageable: + return self + + @property + def guild(self) -> Optional[Guild]: + """Optional[:class:`Guild`]: The guild this partial messageable is in.""" + return self._state._get_guild(self.guild_id) + + @property + def jump_url(self) -> str: + """:class:`str`: Returns a URL that allows the client to jump to the channel.""" + if self.guild_id is None: + return f'https://discord.com/channels/@me/{self.id}' + return f'https://discord.com/channels/{self.guild_id}/{self.id}' + + @property + def created_at(self) -> datetime.datetime: + """:class:`datetime.datetime`: Returns the channel's creation time in UTC.""" + return utils.snowflake_time(self.id) + + def permissions_for(self, obj: Any = None, /) -> Permissions: + """Handles permission resolution for a :class:`User`. + + This function is there for compatibility with other channel types. + + Since partial messageables cannot reasonably have the concept of + permissions, this will always return :meth:`Permissions.none`. + + Parameters + ----------- + obj: :class:`User` + The user to check permissions for. This parameter is ignored + but kept for compatibility with other ``permissions_for`` methods. + + Returns + -------- + :class:`Permissions` + The resolved permissions. + """ + + return Permissions.none() + + @property + def mention(self) -> str: + """:class:`str`: Returns a string that allows you to mention the channel. + + .. versionadded:: 2.5 + """ + return f'<#{self.id}>' + + def get_partial_message(self, message_id: int, /) -> PartialMessage: + """Creates a :class:`PartialMessage` from the message ID. + + This is useful if you want to work with a message and only have its ID without + doing an unnecessary API call. + + Parameters + ------------ + message_id: :class:`int` + The message ID to create a partial message for. + + Returns + --------- + :class:`PartialMessage` + The partial message. + """ + + from .message import PartialMessage + + return PartialMessage(channel=self, id=message_id) + + +def _guild_channel_factory(channel_type: int): + value = try_enum(ChannelType, channel_type) + if value is ChannelType.text: + return TextChannel, value + elif value is ChannelType.voice: + return VoiceChannel, value + elif value is ChannelType.category: + return CategoryChannel, value + elif value is ChannelType.news: + return TextChannel, value + elif value is ChannelType.stage_voice: + return StageChannel, value + elif value is ChannelType.forum: + return ForumChannel, value + elif value is ChannelType.media: + return ForumChannel, value + else: + return None, value + + +def _channel_factory(channel_type: int): + cls, value = _guild_channel_factory(channel_type) + if value is ChannelType.private: + return DMChannel, value + elif value is ChannelType.group: + return GroupChannel, value + else: + return cls, value + + +def _threaded_channel_factory(channel_type: int): + cls, value = _channel_factory(channel_type) + if value in (ChannelType.private_thread, ChannelType.public_thread, ChannelType.news_thread): + return Thread, value + return cls, value + + +def _threaded_guild_channel_factory(channel_type: int): + cls, value = _guild_channel_factory(channel_type) + if value in (ChannelType.private_thread, ChannelType.public_thread, ChannelType.news_thread): + return Thread, value + return cls, value diff --git a/venv/lib/python3.12/site-packages/discord/client.py b/venv/lib/python3.12/site-packages/discord/client.py new file mode 100644 index 00000000..b997bd96 --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/client.py @@ -0,0 +1,3289 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from __future__ import annotations + +import asyncio +import datetime +import logging +from typing import ( + TYPE_CHECKING, + Any, + AsyncIterator, + Callable, + Coroutine, + Dict, + Generator, + List, + Literal, + Optional, + Sequence, + Tuple, + Type, + TypeVar, + Union, + overload, +) + +import aiohttp + +from .sku import SKU, Entitlement +from .user import User, ClientUser +from .invite import Invite +from .template import Template +from .widget import Widget +from .guild import Guild, GuildPreview +from .emoji import Emoji +from .channel import _threaded_channel_factory, PartialMessageable +from .enums import ChannelType, EntitlementOwnerType +from .mentions import AllowedMentions +from .errors import * +from .enums import Status +from .flags import ApplicationFlags, Intents +from .gateway import * +from .activity import ActivityTypes, BaseActivity, create_activity +from .voice_client import VoiceClient +from .http import HTTPClient +from .state import ConnectionState +from . import utils +from .utils import MISSING, time_snowflake +from .object import Object +from .backoff import ExponentialBackoff +from .webhook import Webhook +from .appinfo import AppInfo +from .ui.view import View +from .ui.dynamic import DynamicItem +from .stage_instance import StageInstance +from .threads import Thread +from .sticker import GuildSticker, StandardSticker, StickerPack, _sticker_factory +from .soundboard import SoundboardDefaultSound, SoundboardSound + +if TYPE_CHECKING: + from types import TracebackType + + from typing_extensions import Self + + from .abc import Messageable, PrivateChannel, Snowflake, SnowflakeTime + from .app_commands import Command, ContextMenu + from .automod import AutoModAction, AutoModRule + from .channel import DMChannel, GroupChannel + from .ext.commands import AutoShardedBot, Bot, Context, CommandError + from .guild import GuildChannel + from .integrations import Integration + from .interactions import Interaction + from .member import Member, VoiceState + from .message import Message + from .raw_models import ( + RawAppCommandPermissionsUpdateEvent, + RawBulkMessageDeleteEvent, + RawIntegrationDeleteEvent, + RawMemberRemoveEvent, + RawMessageDeleteEvent, + RawMessageUpdateEvent, + RawReactionActionEvent, + RawReactionClearEmojiEvent, + RawReactionClearEvent, + RawThreadDeleteEvent, + RawThreadMembersUpdate, + RawThreadUpdateEvent, + RawTypingEvent, + RawPollVoteActionEvent, + ) + from .reaction import Reaction + from .role import Role + from .scheduled_event import ScheduledEvent + from .threads import ThreadMember + from .types.guild import Guild as GuildPayload + from .ui.item import Item + from .voice_client import VoiceProtocol + from .audit_logs import AuditLogEntry + from .poll import PollAnswer + from .subscription import Subscription + + +# fmt: off +__all__ = ( + 'Client', +) +# fmt: on + +T = TypeVar('T') +Coro = Coroutine[Any, Any, T] +CoroT = TypeVar('CoroT', bound=Callable[..., Coro[Any]]) + +_log = logging.getLogger(__name__) + + +class _LoopSentinel: + __slots__ = () + + def __getattr__(self, attr: str) -> None: + msg = ( + 'loop attribute cannot be accessed in non-async contexts. ' + 'Consider using either an asynchronous main function and passing it to asyncio.run or ' + 'using asynchronous initialisation hooks such as Client.setup_hook' + ) + raise AttributeError(msg) + + +_loop: Any = _LoopSentinel() + + +class Client: + r"""Represents a client connection that connects to Discord. + This class is used to interact with the Discord WebSocket and API. + + .. container:: operations + + .. describe:: async with x + + Asynchronously initialises the client and automatically cleans up. + + .. versionadded:: 2.0 + + A number of options can be passed to the :class:`Client`. + + Parameters + ----------- + max_messages: Optional[:class:`int`] + The maximum number of messages to store in the internal message cache. + This defaults to ``1000``. Passing in ``None`` disables the message cache. + + .. versionchanged:: 1.3 + Allow disabling the message cache and change the default size to ``1000``. + proxy: Optional[:class:`str`] + Proxy URL. + proxy_auth: Optional[:class:`aiohttp.BasicAuth`] + An object that represents proxy HTTP Basic Authorization. + shard_id: Optional[:class:`int`] + Integer starting at ``0`` and less than :attr:`.shard_count`. + shard_count: Optional[:class:`int`] + The total number of shards. + application_id: :class:`int` + The client's application ID. + intents: :class:`Intents` + The intents that you want to enable for the session. This is a way of + disabling and enabling certain gateway events from triggering and being sent. + + .. versionadded:: 1.5 + + .. versionchanged:: 2.0 + Parameter is now required. + member_cache_flags: :class:`MemberCacheFlags` + Allows for finer control over how the library caches members. + If not given, defaults to cache as much as possible with the + currently selected intents. + + .. versionadded:: 1.5 + chunk_guilds_at_startup: :class:`bool` + Indicates if :func:`.on_ready` should be delayed to chunk all guilds + at start-up if necessary. This operation is incredibly slow for large + amounts of guilds. The default is ``True`` if :attr:`Intents.members` + is ``True``. + + .. versionadded:: 1.5 + status: Optional[:class:`.Status`] + A status to start your presence with upon logging on to Discord. + activity: Optional[:class:`.BaseActivity`] + An activity to start your presence with upon logging on to Discord. + allowed_mentions: Optional[:class:`AllowedMentions`] + Control how the client handles mentions by default on every message sent. + + .. versionadded:: 1.4 + heartbeat_timeout: :class:`float` + The maximum numbers of seconds before timing out and restarting the + WebSocket in the case of not receiving a HEARTBEAT_ACK. Useful if + processing the initial packets take too long to the point of disconnecting + you. The default timeout is 60 seconds. + guild_ready_timeout: :class:`float` + The maximum number of seconds to wait for the GUILD_CREATE stream to end before + preparing the member cache and firing READY. The default timeout is 2 seconds. + + .. versionadded:: 1.4 + assume_unsync_clock: :class:`bool` + Whether to assume the system clock is unsynced. This applies to the ratelimit handling + code. If this is set to ``True``, the default, then the library uses the time to reset + a rate limit bucket given by Discord. If this is ``False`` then your system clock is + used to calculate how long to sleep for. If this is set to ``False`` it is recommended to + sync your system clock to Google's NTP server. + + .. versionadded:: 1.3 + enable_debug_events: :class:`bool` + Whether to enable events that are useful only for debugging gateway related information. + + Right now this involves :func:`on_socket_raw_receive` and :func:`on_socket_raw_send`. If + this is ``False`` then those events will not be dispatched (due to performance considerations). + To enable these events, this must be set to ``True``. Defaults to ``False``. + + .. versionadded:: 2.0 + enable_raw_presences: :class:`bool` + Whether to manually enable or disable the :func:`on_raw_presence_update` event. + + Setting this flag to ``True`` requires :attr:`Intents.presences` to be enabled. + + By default, this flag is set to ``True`` only when :attr:`Intents.presences` is enabled and :attr:`Intents.members` + is disabled, otherwise it's set to ``False``. + + .. versionadded:: 2.5 + http_trace: :class:`aiohttp.TraceConfig` + The trace configuration to use for tracking HTTP requests the library does using ``aiohttp``. + This allows you to check requests the library is using. For more information, check the + `aiohttp documentation `_. + + .. versionadded:: 2.0 + max_ratelimit_timeout: Optional[:class:`float`] + The maximum number of seconds to wait when a non-global rate limit is encountered. + If a request requires sleeping for more than the seconds passed in, then + :exc:`~discord.RateLimited` will be raised. By default, there is no timeout limit. + In order to prevent misuse and unnecessary bans, the minimum value this can be + set to is ``30.0`` seconds. + + .. versionadded:: 2.0 + connector: Optional[:class:`aiohttp.BaseConnector`] + The aiohttp connector to use for this client. This can be used to control underlying aiohttp + behavior, such as setting a dns resolver or sslcontext. + + .. versionadded:: 2.5 + + Attributes + ----------- + ws + The websocket gateway the client is currently connected to. Could be ``None``. + """ + + def __init__(self, *, intents: Intents, **options: Any) -> None: + self.loop: asyncio.AbstractEventLoop = _loop + # self.ws is set in the connect method + self.ws: DiscordWebSocket = None # type: ignore + self._listeners: Dict[str, List[Tuple[asyncio.Future, Callable[..., bool]]]] = {} + self.shard_id: Optional[int] = options.get('shard_id') + self.shard_count: Optional[int] = options.get('shard_count') + + connector: Optional[aiohttp.BaseConnector] = options.get('connector', None) + proxy: Optional[str] = options.pop('proxy', None) + proxy_auth: Optional[aiohttp.BasicAuth] = options.pop('proxy_auth', None) + unsync_clock: bool = options.pop('assume_unsync_clock', True) + http_trace: Optional[aiohttp.TraceConfig] = options.pop('http_trace', None) + max_ratelimit_timeout: Optional[float] = options.pop('max_ratelimit_timeout', None) + self.http: HTTPClient = HTTPClient( + self.loop, + connector, + proxy=proxy, + proxy_auth=proxy_auth, + unsync_clock=unsync_clock, + http_trace=http_trace, + max_ratelimit_timeout=max_ratelimit_timeout, + ) + + self._handlers: Dict[str, Callable[..., None]] = { + 'ready': self._handle_ready, + } + + self._hooks: Dict[str, Callable[..., Coroutine[Any, Any, Any]]] = { + 'before_identify': self._call_before_identify_hook, + } + + self._enable_debug_events: bool = options.pop('enable_debug_events', False) + self._connection: ConnectionState[Self] = self._get_state(intents=intents, **options) + self._connection.shard_count = self.shard_count + self._closing_task: Optional[asyncio.Task[None]] = None + self._ready: asyncio.Event = MISSING + self._application: Optional[AppInfo] = None + self._connection._get_websocket = self._get_websocket + self._connection._get_client = lambda: self + + if VoiceClient.warn_nacl: + VoiceClient.warn_nacl = False + _log.warning("PyNaCl is not installed, voice will NOT be supported") + + async def __aenter__(self) -> Self: + await self._async_setup_hook() + return self + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc_value: Optional[BaseException], + traceback: Optional[TracebackType], + ) -> None: + # This avoids double-calling a user-provided .close() + if self._closing_task: + await self._closing_task + else: + await self.close() + + # internals + + def _get_websocket(self, guild_id: Optional[int] = None, *, shard_id: Optional[int] = None) -> DiscordWebSocket: + return self.ws + + def _get_state(self, **options: Any) -> ConnectionState[Self]: + return ConnectionState(dispatch=self.dispatch, handlers=self._handlers, hooks=self._hooks, http=self.http, **options) + + def _handle_ready(self) -> None: + self._ready.set() + + @property + def latency(self) -> float: + """:class:`float`: Measures latency between a HEARTBEAT and a HEARTBEAT_ACK in seconds. + + This could be referred to as the Discord WebSocket protocol latency. + """ + ws = self.ws + return float('nan') if not ws else ws.latency + + def is_ws_ratelimited(self) -> bool: + """:class:`bool`: Whether the websocket is currently rate limited. + + This can be useful to know when deciding whether you should query members + using HTTP or via the gateway. + + .. versionadded:: 1.6 + """ + if self.ws: + return self.ws.is_ratelimited() + return False + + @property + def user(self) -> Optional[ClientUser]: + """Optional[:class:`.ClientUser`]: Represents the connected client. ``None`` if not logged in.""" + return self._connection.user + + @property + def guilds(self) -> Sequence[Guild]: + """Sequence[:class:`.Guild`]: The guilds that the connected client is a member of.""" + return self._connection.guilds + + @property + def emojis(self) -> Sequence[Emoji]: + """Sequence[:class:`.Emoji`]: The emojis that the connected client has. + + .. note:: + + This not include the emojis that are owned by the application. + Use :meth:`.fetch_application_emoji` to get those. + """ + return self._connection.emojis + + @property + def stickers(self) -> Sequence[GuildSticker]: + """Sequence[:class:`.GuildSticker`]: The stickers that the connected client has. + + .. versionadded:: 2.0 + """ + return self._connection.stickers + + @property + def soundboard_sounds(self) -> List[SoundboardSound]: + """List[:class:`.SoundboardSound`]: The soundboard sounds that the connected client has. + + .. versionadded:: 2.5 + """ + return self._connection.soundboard_sounds + + @property + def cached_messages(self) -> Sequence[Message]: + """Sequence[:class:`.Message`]: Read-only list of messages the connected client has cached. + + .. versionadded:: 1.1 + """ + return utils.SequenceProxy(self._connection._messages or []) + + @property + def private_channels(self) -> Sequence[PrivateChannel]: + """Sequence[:class:`.abc.PrivateChannel`]: The private channels that the connected client is participating on. + + .. note:: + + This returns only up to 128 most recent private channels due to an internal working + on how Discord deals with private channels. + """ + return self._connection.private_channels + + @property + def voice_clients(self) -> List[VoiceProtocol]: + """List[:class:`.VoiceProtocol`]: Represents a list of voice connections. + + These are usually :class:`.VoiceClient` instances. + """ + return self._connection.voice_clients + + @property + def application_id(self) -> Optional[int]: + """Optional[:class:`int`]: The client's application ID. + + If this is not passed via ``__init__`` then this is retrieved + through the gateway when an event contains the data or after a call + to :meth:`~discord.Client.login`. Usually after :func:`~discord.on_connect` + is called. + + .. versionadded:: 2.0 + """ + return self._connection.application_id + + @property + def application_flags(self) -> ApplicationFlags: + """:class:`~discord.ApplicationFlags`: The client's application flags. + + .. versionadded:: 2.0 + """ + return self._connection.application_flags + + @property + def application(self) -> Optional[AppInfo]: + """Optional[:class:`~discord.AppInfo`]: The client's application info. + + This is retrieved on :meth:`~discord.Client.login` and is not updated + afterwards. This allows populating the application_id without requiring a + gateway connection. + + This is ``None`` if accessed before :meth:`~discord.Client.login` is called. + + .. seealso:: The :meth:`~discord.Client.application_info` API call + + .. versionadded:: 2.0 + """ + return self._application + + def is_ready(self) -> bool: + """:class:`bool`: Specifies if the client's internal cache is ready for use.""" + return self._ready is not MISSING and self._ready.is_set() + + async def _run_event( + self, + coro: Callable[..., Coroutine[Any, Any, Any]], + event_name: str, + *args: Any, + **kwargs: Any, + ) -> None: + try: + await coro(*args, **kwargs) + except asyncio.CancelledError: + pass + except Exception: + try: + await self.on_error(event_name, *args, **kwargs) + except asyncio.CancelledError: + pass + + def _schedule_event( + self, + coro: Callable[..., Coroutine[Any, Any, Any]], + event_name: str, + *args: Any, + **kwargs: Any, + ) -> asyncio.Task: + wrapped = self._run_event(coro, event_name, *args, **kwargs) + # Schedules the task + return self.loop.create_task(wrapped, name=f'discord.py: {event_name}') + + def dispatch(self, event: str, /, *args: Any, **kwargs: Any) -> None: + _log.debug('Dispatching event %s', event) + method = 'on_' + event + + listeners = self._listeners.get(event) + if listeners: + removed = [] + for i, (future, condition) in enumerate(listeners): + if future.cancelled(): + removed.append(i) + continue + + try: + result = condition(*args) + except Exception as exc: + future.set_exception(exc) + removed.append(i) + else: + if result: + if len(args) == 0: + future.set_result(None) + elif len(args) == 1: + future.set_result(args[0]) + else: + future.set_result(args) + removed.append(i) + + if len(removed) == len(listeners): + self._listeners.pop(event) + else: + for idx in reversed(removed): + del listeners[idx] + + try: + coro = getattr(self, method) + except AttributeError: + pass + else: + self._schedule_event(coro, method, *args, **kwargs) + + async def on_error(self, event_method: str, /, *args: Any, **kwargs: Any) -> None: + """|coro| + + The default error handler provided by the client. + + By default this logs to the library logger however it could be + overridden to have a different implementation. + Check :func:`~discord.on_error` for more details. + + .. versionchanged:: 2.0 + + ``event_method`` parameter is now positional-only + and instead of writing to ``sys.stderr`` it logs instead. + """ + _log.exception('Ignoring exception in %s', event_method) + + # hooks + + async def _call_before_identify_hook(self, shard_id: Optional[int], *, initial: bool = False) -> None: + # This hook is an internal hook that actually calls the public one. + # It allows the library to have its own hook without stepping on the + # toes of those who need to override their own hook. + await self.before_identify_hook(shard_id, initial=initial) + + async def before_identify_hook(self, shard_id: Optional[int], *, initial: bool = False) -> None: + """|coro| + + A hook that is called before IDENTIFYing a session. This is useful + if you wish to have more control over the synchronization of multiple + IDENTIFYing clients. + + The default implementation sleeps for 5 seconds. + + .. versionadded:: 1.4 + + Parameters + ------------ + shard_id: :class:`int` + The shard ID that requested being IDENTIFY'd + initial: :class:`bool` + Whether this IDENTIFY is the first initial IDENTIFY. + """ + + if not initial: + await asyncio.sleep(5.0) + + async def _async_setup_hook(self) -> None: + # Called whenever the client needs to initialise asyncio objects with a running loop + loop = asyncio.get_running_loop() + self.loop = loop + self.http.loop = loop + self._connection.loop = loop + + self._ready = asyncio.Event() + + async def setup_hook(self) -> None: + """|coro| + + A coroutine to be called to setup the bot, by default this is blank. + + To perform asynchronous setup after the bot is logged in but before + it has connected to the Websocket, overwrite this coroutine. + + This is only called once, in :meth:`login`, and will be called before + any events are dispatched, making it a better solution than doing such + setup in the :func:`~discord.on_ready` event. + + .. warning:: + + Since this is called *before* the websocket connection is made therefore + anything that waits for the websocket will deadlock, this includes things + like :meth:`wait_for` and :meth:`wait_until_ready`. + + .. versionadded:: 2.0 + """ + pass + + # login state management + + async def login(self, token: str) -> None: + """|coro| + + Logs in the client with the specified credentials and + calls the :meth:`setup_hook`. + + + Parameters + ----------- + token: :class:`str` + The authentication token. Do not prefix this token with + anything as the library will do it for you. + + Raises + ------ + LoginFailure + The wrong credentials are passed. + HTTPException + An unknown HTTP related error occurred, + usually when it isn't 200 or the known incorrect credentials + passing status code. + """ + + _log.info('logging in using static token') + + if self.loop is _loop: + await self._async_setup_hook() + + if not isinstance(token, str): + raise TypeError(f'expected token to be a str, received {token.__class__.__name__} instead') + token = token.strip() + + data = await self.http.static_login(token) + self._connection.user = ClientUser(state=self._connection, data=data) + self._application = await self.application_info() + if self._connection.application_id is None: + self._connection.application_id = self._application.id + + if self._application.interactions_endpoint_url is not None: + _log.warning( + 'Application has an interaction endpoint URL set, this means registered components and app commands will not be received by the library.' + ) + + if not self._connection.application_flags: + self._connection.application_flags = self._application.flags + + await self.setup_hook() + + async def connect(self, *, reconnect: bool = True) -> None: + """|coro| + + Creates a websocket connection and lets the websocket listen + to messages from Discord. This is a loop that runs the entire + event system and miscellaneous aspects of the library. Control + is not resumed until the WebSocket connection is terminated. + + Parameters + ----------- + reconnect: :class:`bool` + If we should attempt reconnecting, either due to internet + failure or a specific failure on Discord's part. Certain + disconnects that lead to bad state will not be handled (such as + invalid sharding payloads or bad tokens). + + Raises + ------- + GatewayNotFound + If the gateway to connect to Discord is not found. Usually if this + is thrown then there is a Discord API outage. + ConnectionClosed + The websocket connection has been terminated. + """ + + backoff = ExponentialBackoff() + ws_params = { + 'initial': True, + 'shard_id': self.shard_id, + } + while not self.is_closed(): + try: + coro = DiscordWebSocket.from_client(self, **ws_params) + self.ws = await asyncio.wait_for(coro, timeout=60.0) + ws_params['initial'] = False + while True: + await self.ws.poll_event() + except ReconnectWebSocket as e: + _log.debug('Got a request to %s the websocket.', e.op) + self.dispatch('disconnect') + ws_params.update(sequence=self.ws.sequence, resume=e.resume, session=self.ws.session_id) + if e.resume: + ws_params['gateway'] = self.ws.gateway + continue + except ( + OSError, + HTTPException, + GatewayNotFound, + ConnectionClosed, + aiohttp.ClientError, + asyncio.TimeoutError, + ) as exc: + self.dispatch('disconnect') + if not reconnect: + await self.close() + if isinstance(exc, ConnectionClosed) and exc.code == 1000: + # clean close, don't re-raise this + return + raise + + if self.is_closed(): + return + + # If we get connection reset by peer then try to RESUME + if isinstance(exc, OSError) and exc.errno in (54, 10054): + ws_params.update( + sequence=self.ws.sequence, + gateway=self.ws.gateway, + initial=False, + resume=True, + session=self.ws.session_id, + ) + continue + + # We should only get this when an unhandled close code happens, + # such as a clean disconnect (1000) or a bad state (bad token, no sharding, etc) + # sometimes, discord sends us 1000 for unknown reasons so we should reconnect + # regardless and rely on is_closed instead + if isinstance(exc, ConnectionClosed): + if exc.code == 4014: + raise PrivilegedIntentsRequired(exc.shard_id) from None + if exc.code != 1000: + await self.close() + raise + + retry = backoff.delay() + _log.exception("Attempting a reconnect in %.2fs", retry) + await asyncio.sleep(retry) + # Always try to RESUME the connection + # If the connection is not RESUME-able then the gateway will invalidate the session. + # This is apparently what the official Discord client does. + ws_params.update( + sequence=self.ws.sequence, + gateway=self.ws.gateway, + resume=True, + session=self.ws.session_id, + ) + + async def close(self) -> None: + """|coro| + + Closes the connection to Discord. + """ + if self._closing_task: + return await self._closing_task + + async def _close(): + await self._connection.close() + + if self.ws is not None and self.ws.open: + await self.ws.close(code=1000) + + await self.http.close() + + if self._ready is not MISSING: + self._ready.clear() + + self.loop = MISSING + + self._closing_task = asyncio.create_task(_close()) + await self._closing_task + + def clear(self) -> None: + """Clears the internal state of the bot. + + After this, the bot can be considered "re-opened", i.e. :meth:`is_closed` + and :meth:`is_ready` both return ``False`` along with the bot's internal + cache cleared. + """ + self._closing_task = None + self._ready.clear() + self._connection.clear() + self.http.clear() + + async def start(self, token: str, *, reconnect: bool = True) -> None: + """|coro| + + A shorthand coroutine for :meth:`login` + :meth:`connect`. + + Parameters + ----------- + token: :class:`str` + The authentication token. Do not prefix this token with + anything as the library will do it for you. + reconnect: :class:`bool` + If we should attempt reconnecting, either due to internet + failure or a specific failure on Discord's part. Certain + disconnects that lead to bad state will not be handled (such as + invalid sharding payloads or bad tokens). + + Raises + ------- + TypeError + An unexpected keyword argument was received. + """ + await self.login(token) + await self.connect(reconnect=reconnect) + + def run( + self, + token: str, + *, + reconnect: bool = True, + log_handler: Optional[logging.Handler] = MISSING, + log_formatter: logging.Formatter = MISSING, + log_level: int = MISSING, + root_logger: bool = False, + ) -> None: + """A blocking call that abstracts away the event loop + initialisation from you. + + If you want more control over the event loop then this + function should not be used. Use :meth:`start` coroutine + or :meth:`connect` + :meth:`login`. + + This function also sets up the logging library to make it easier + for beginners to know what is going on with the library. For more + advanced users, this can be disabled by passing ``None`` to + the ``log_handler`` parameter. + + .. warning:: + + This function must be the last function to call due to the fact that it + is blocking. That means that registration of events or anything being + called after this function call will not execute until it returns. + + Parameters + ----------- + token: :class:`str` + The authentication token. Do not prefix this token with + anything as the library will do it for you. + reconnect: :class:`bool` + If we should attempt reconnecting, either due to internet + failure or a specific failure on Discord's part. Certain + disconnects that lead to bad state will not be handled (such as + invalid sharding payloads or bad tokens). + log_handler: Optional[:class:`logging.Handler`] + The log handler to use for the library's logger. If this is ``None`` + then the library will not set up anything logging related. Logging + will still work if ``None`` is passed, though it is your responsibility + to set it up. + + The default log handler if not provided is :class:`logging.StreamHandler`. + + .. versionadded:: 2.0 + log_formatter: :class:`logging.Formatter` + The formatter to use with the given log handler. If not provided then it + defaults to a colour based logging formatter (if available). + + .. versionadded:: 2.0 + log_level: :class:`int` + The default log level for the library's logger. This is only applied if the + ``log_handler`` parameter is not ``None``. Defaults to ``logging.INFO``. + + .. versionadded:: 2.0 + root_logger: :class:`bool` + Whether to set up the root logger rather than the library logger. + By default, only the library logger (``'discord'``) is set up. If this + is set to ``True`` then the root logger is set up as well. + + Defaults to ``False``. + + .. versionadded:: 2.0 + """ + + async def runner(): + async with self: + await self.start(token, reconnect=reconnect) + + if log_handler is not None: + utils.setup_logging( + handler=log_handler, + formatter=log_formatter, + level=log_level, + root=root_logger, + ) + + try: + asyncio.run(runner()) + except KeyboardInterrupt: + # nothing to do here + # `asyncio.run` handles the loop cleanup + # and `self.start` closes all sockets and the HTTPClient instance. + return + + # properties + + def is_closed(self) -> bool: + """:class:`bool`: Indicates if the websocket connection is closed.""" + return self._closing_task is not None + + @property + def activity(self) -> Optional[ActivityTypes]: + """Optional[:class:`.BaseActivity`]: The activity being used upon + logging in. + """ + return create_activity(self._connection._activity, self._connection) + + @activity.setter + def activity(self, value: Optional[ActivityTypes]) -> None: + if value is None: + self._connection._activity = None + elif isinstance(value, BaseActivity): + # ConnectionState._activity is typehinted as ActivityPayload, we're passing Dict[str, Any] + self._connection._activity = value.to_dict() # type: ignore + else: + raise TypeError('activity must derive from BaseActivity.') + + @property + def status(self) -> Status: + """:class:`.Status`: + The status being used upon logging on to Discord. + + .. versionadded: 2.0 + """ + if self._connection._status in set(state.value for state in Status): + return Status(self._connection._status) + return Status.online + + @status.setter + def status(self, value: Status) -> None: + if value is Status.offline: + self._connection._status = 'invisible' + elif isinstance(value, Status): + self._connection._status = str(value) + else: + raise TypeError('status must derive from Status.') + + @property + def allowed_mentions(self) -> Optional[AllowedMentions]: + """Optional[:class:`~discord.AllowedMentions`]: The allowed mention configuration. + + .. versionadded:: 1.4 + """ + return self._connection.allowed_mentions + + @allowed_mentions.setter + def allowed_mentions(self, value: Optional[AllowedMentions]) -> None: + if value is None or isinstance(value, AllowedMentions): + self._connection.allowed_mentions = value + else: + raise TypeError(f'allowed_mentions must be AllowedMentions not {value.__class__.__name__}') + + @property + def intents(self) -> Intents: + """:class:`~discord.Intents`: The intents configured for this connection. + + .. versionadded:: 1.5 + """ + return self._connection.intents + + # helpers/getters + + @property + def users(self) -> List[User]: + """List[:class:`~discord.User`]: Returns a list of all the users the bot can see.""" + return list(self._connection._users.values()) + + def get_channel(self, id: int, /) -> Optional[Union[GuildChannel, Thread, PrivateChannel]]: + """Returns a channel or thread with the given ID. + + .. versionchanged:: 2.0 + + ``id`` parameter is now positional-only. + + Parameters + ----------- + id: :class:`int` + The ID to search for. + + Returns + -------- + Optional[Union[:class:`.abc.GuildChannel`, :class:`.Thread`, :class:`.abc.PrivateChannel`]] + The returned channel or ``None`` if not found. + """ + return self._connection.get_channel(id) # type: ignore # The cache contains all channel types + + def get_partial_messageable( + self, id: int, *, guild_id: Optional[int] = None, type: Optional[ChannelType] = None + ) -> PartialMessageable: + """Returns a partial messageable with the given channel ID. + + This is useful if you have a channel_id but don't want to do an API call + to send messages to it. + + .. versionadded:: 2.0 + + Parameters + ----------- + id: :class:`int` + The channel ID to create a partial messageable for. + guild_id: Optional[:class:`int`] + The optional guild ID to create a partial messageable for. + + This is not required to actually send messages, but it does allow the + :meth:`~discord.PartialMessageable.jump_url` and + :attr:`~discord.PartialMessageable.guild` properties to function properly. + type: Optional[:class:`.ChannelType`] + The underlying channel type for the partial messageable. + + Returns + -------- + :class:`.PartialMessageable` + The partial messageable + """ + return PartialMessageable(state=self._connection, id=id, guild_id=guild_id, type=type) + + def get_stage_instance(self, id: int, /) -> Optional[StageInstance]: + """Returns a stage instance with the given stage channel ID. + + .. versionadded:: 2.0 + + Parameters + ----------- + id: :class:`int` + The ID to search for. + + Returns + -------- + Optional[:class:`.StageInstance`] + The stage instance or ``None`` if not found. + """ + from .channel import StageChannel + + channel = self._connection.get_channel(id) + + if isinstance(channel, StageChannel): + return channel.instance + + def get_guild(self, id: int, /) -> Optional[Guild]: + """Returns a guild with the given ID. + + .. versionchanged:: 2.0 + + ``id`` parameter is now positional-only. + + Parameters + ----------- + id: :class:`int` + The ID to search for. + + Returns + -------- + Optional[:class:`.Guild`] + The guild or ``None`` if not found. + """ + return self._connection._get_guild(id) + + def get_user(self, id: int, /) -> Optional[User]: + """Returns a user with the given ID. + + .. versionchanged:: 2.0 + + ``id`` parameter is now positional-only. + + Parameters + ----------- + id: :class:`int` + The ID to search for. + + Returns + -------- + Optional[:class:`~discord.User`] + The user or ``None`` if not found. + """ + return self._connection.get_user(id) + + def get_emoji(self, id: int, /) -> Optional[Emoji]: + """Returns an emoji with the given ID. + + .. versionchanged:: 2.0 + + ``id`` parameter is now positional-only. + + Parameters + ----------- + id: :class:`int` + The ID to search for. + + Returns + -------- + Optional[:class:`.Emoji`] + The custom emoji or ``None`` if not found. + """ + return self._connection.get_emoji(id) + + def get_sticker(self, id: int, /) -> Optional[GuildSticker]: + """Returns a guild sticker with the given ID. + + .. versionadded:: 2.0 + + .. note:: + + To retrieve standard stickers, use :meth:`.fetch_sticker`. + or :meth:`.fetch_premium_sticker_packs`. + + Returns + -------- + Optional[:class:`.GuildSticker`] + The sticker or ``None`` if not found. + """ + return self._connection.get_sticker(id) + + def get_soundboard_sound(self, id: int, /) -> Optional[SoundboardSound]: + """Returns a soundboard sound with the given ID. + + .. versionadded:: 2.5 + + Parameters + ---------- + id: :class:`int` + The ID to search for. + + Returns + -------- + Optional[:class:`.SoundboardSound`] + The soundboard sound or ``None`` if not found. + """ + return self._connection.get_soundboard_sound(id) + + def get_all_channels(self) -> Generator[GuildChannel, None, None]: + """A generator that retrieves every :class:`.abc.GuildChannel` the client can 'access'. + + This is equivalent to: :: + + for guild in client.guilds: + for channel in guild.channels: + yield channel + + .. note:: + + Just because you receive a :class:`.abc.GuildChannel` does not mean that + you can communicate in said channel. :meth:`.abc.GuildChannel.permissions_for` should + be used for that. + + Yields + ------ + :class:`.abc.GuildChannel` + A channel the client can 'access'. + """ + + for guild in self.guilds: + yield from guild.channels + + def get_all_members(self) -> Generator[Member, None, None]: + """Returns a generator with every :class:`.Member` the client can see. + + This is equivalent to: :: + + for guild in client.guilds: + for member in guild.members: + yield member + + Yields + ------ + :class:`.Member` + A member the client can see. + """ + for guild in self.guilds: + yield from guild.members + + # listeners/waiters + + async def wait_until_ready(self) -> None: + """|coro| + + Waits until the client's internal cache is all ready. + + .. warning:: + + Calling this inside :meth:`setup_hook` can lead to a deadlock. + """ + if self._ready is not MISSING: + await self._ready.wait() + else: + raise RuntimeError( + 'Client has not been properly initialised. ' + 'Please use the login method or asynchronous context manager before calling this method' + ) + + # App Commands + + @overload + async def wait_for( + self, + event: Literal['raw_app_command_permissions_update'], + /, + *, + check: Optional[Callable[[RawAppCommandPermissionsUpdateEvent], bool]] = ..., + timeout: Optional[float] = ..., + ) -> RawAppCommandPermissionsUpdateEvent: + ... + + @overload + async def wait_for( + self, + event: Literal['app_command_completion'], + /, + *, + check: Optional[Callable[[Interaction[Self], Union[Command[Any, ..., Any], ContextMenu]], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Tuple[Interaction[Self], Union[Command[Any, ..., Any], ContextMenu]]: + ... + + # AutoMod + + @overload + async def wait_for( + self, + event: Literal['automod_rule_create', 'automod_rule_update', 'automod_rule_delete'], + /, + *, + check: Optional[Callable[[AutoModRule], bool]] = ..., + timeout: Optional[float] = ..., + ) -> AutoModRule: + ... + + @overload + async def wait_for( + self, + event: Literal['automod_action'], + /, + *, + check: Optional[Callable[[AutoModAction], bool]] = ..., + timeout: Optional[float] = ..., + ) -> AutoModAction: + ... + + # Channels + + @overload + async def wait_for( + self, + event: Literal['private_channel_update'], + /, + *, + check: Optional[Callable[[GroupChannel, GroupChannel], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Tuple[GroupChannel, GroupChannel]: + ... + + @overload + async def wait_for( + self, + event: Literal['private_channel_pins_update'], + /, + *, + check: Optional[Callable[[PrivateChannel, datetime.datetime], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Tuple[PrivateChannel, datetime.datetime]: + ... + + @overload + async def wait_for( + self, + event: Literal['guild_channel_delete', 'guild_channel_create'], + /, + *, + check: Optional[Callable[[GuildChannel], bool]] = ..., + timeout: Optional[float] = ..., + ) -> GuildChannel: + ... + + @overload + async def wait_for( + self, + event: Literal['guild_channel_update'], + /, + *, + check: Optional[Callable[[GuildChannel, GuildChannel], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Tuple[GuildChannel, GuildChannel]: + ... + + @overload + async def wait_for( + self, + event: Literal['guild_channel_pins_update'], + /, + *, + check: Optional[ + Callable[ + [Union[GuildChannel, Thread], Optional[datetime.datetime]], + bool, + ] + ], + timeout: Optional[float] = ..., + ) -> Tuple[Union[GuildChannel, Thread], Optional[datetime.datetime]]: + ... + + @overload + async def wait_for( + self, + event: Literal['typing'], + /, + *, + check: Optional[Callable[[Messageable, Union[User, Member], datetime.datetime], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Tuple[Messageable, Union[User, Member], datetime.datetime]: + ... + + @overload + async def wait_for( + self, + event: Literal['raw_typing'], + /, + *, + check: Optional[Callable[[RawTypingEvent], bool]] = ..., + timeout: Optional[float] = ..., + ) -> RawTypingEvent: + ... + + # Debug & Gateway events + + @overload + async def wait_for( + self, + event: Literal['connect', 'disconnect', 'ready', 'resumed'], + /, + *, + check: Optional[Callable[[], bool]] = ..., + timeout: Optional[float] = ..., + ) -> None: + ... + + @overload + async def wait_for( + self, + event: Literal['shard_connect', 'shard_disconnect', 'shard_ready', 'shard_resumed'], + /, + *, + check: Optional[Callable[[int], bool]] = ..., + timeout: Optional[float] = ..., + ) -> int: + ... + + @overload + async def wait_for( + self, + event: Literal['socket_event_type', 'socket_raw_receive'], + /, + *, + check: Optional[Callable[[str], bool]] = ..., + timeout: Optional[float] = ..., + ) -> str: + ... + + @overload + async def wait_for( + self, + event: Literal['socket_raw_send'], + /, + *, + check: Optional[Callable[[Union[str, bytes]], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Union[str, bytes]: + ... + + # Entitlements + @overload + async def wait_for( + self, + event: Literal['entitlement_create', 'entitlement_update', 'entitlement_delete'], + /, + *, + check: Optional[Callable[[Entitlement], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Entitlement: + ... + + # Guilds + + @overload + async def wait_for( + self, + event: Literal[ + 'guild_available', + 'guild_unavailable', + 'guild_join', + 'guild_remove', + ], + /, + *, + check: Optional[Callable[[Guild], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Guild: + ... + + @overload + async def wait_for( + self, + event: Literal['guild_update'], + /, + *, + check: Optional[Callable[[Guild, Guild], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Tuple[Guild, Guild]: + ... + + @overload + async def wait_for( + self, + event: Literal['guild_emojis_update'], + /, + *, + check: Optional[Callable[[Guild, Sequence[Emoji], Sequence[Emoji]], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Tuple[Guild, Sequence[Emoji], Sequence[Emoji]]: + ... + + @overload + async def wait_for( + self, + event: Literal['guild_stickers_update'], + /, + *, + check: Optional[Callable[[Guild, Sequence[GuildSticker], Sequence[GuildSticker]], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Tuple[Guild, Sequence[GuildSticker], Sequence[GuildSticker]]: + ... + + @overload + async def wait_for( + self, + event: Literal['invite_create', 'invite_delete'], + /, + *, + check: Optional[Callable[[Invite], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Invite: + ... + + @overload + async def wait_for( + self, + event: Literal['audit_log_entry_create'], + /, + *, + check: Optional[Callable[[AuditLogEntry], bool]] = ..., + timeout: Optional[float] = ..., + ) -> AuditLogEntry: + ... + + # Integrations + + @overload + async def wait_for( + self, + event: Literal['integration_create', 'integration_update'], + /, + *, + check: Optional[Callable[[Integration], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Integration: + ... + + @overload + async def wait_for( + self, + event: Literal['guild_integrations_update'], + /, + *, + check: Optional[Callable[[Guild], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Guild: + ... + + @overload + async def wait_for( + self, + event: Literal['webhooks_update'], + /, + *, + check: Optional[Callable[[GuildChannel], bool]] = ..., + timeout: Optional[float] = ..., + ) -> GuildChannel: + ... + + @overload + async def wait_for( + self, + event: Literal['raw_integration_delete'], + /, + *, + check: Optional[Callable[[RawIntegrationDeleteEvent], bool]] = ..., + timeout: Optional[float] = ..., + ) -> RawIntegrationDeleteEvent: + ... + + # Interactions + + @overload + async def wait_for( + self, + event: Literal['interaction'], + /, + *, + check: Optional[Callable[[Interaction[Self]], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Interaction[Self]: + ... + + # Members + + @overload + async def wait_for( + self, + event: Literal['member_join', 'member_remove'], + /, + *, + check: Optional[Callable[[Member], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Member: + ... + + @overload + async def wait_for( + self, + event: Literal['raw_member_remove'], + /, + *, + check: Optional[Callable[[RawMemberRemoveEvent], bool]] = ..., + timeout: Optional[float] = ..., + ) -> RawMemberRemoveEvent: + ... + + @overload + async def wait_for( + self, + event: Literal['member_update', 'presence_update'], + /, + *, + check: Optional[Callable[[Member, Member], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Tuple[Member, Member]: + ... + + @overload + async def wait_for( + self, + event: Literal['user_update'], + /, + *, + check: Optional[Callable[[User, User], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Tuple[User, User]: + ... + + @overload + async def wait_for( + self, + event: Literal['member_ban'], + /, + *, + check: Optional[Callable[[Guild, Union[User, Member]], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Tuple[Guild, Union[User, Member]]: + ... + + @overload + async def wait_for( + self, + event: Literal['member_unban'], + /, + *, + check: Optional[Callable[[Guild, User], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Tuple[Guild, User]: + ... + + # Messages + + @overload + async def wait_for( + self, + event: Literal['message', 'message_delete'], + /, + *, + check: Optional[Callable[[Message], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Message: + ... + + @overload + async def wait_for( + self, + event: Literal['message_edit'], + /, + *, + check: Optional[Callable[[Message, Message], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Tuple[Message, Message]: + ... + + @overload + async def wait_for( + self, + event: Literal['bulk_message_delete'], + /, + *, + check: Optional[Callable[[List[Message]], bool]] = ..., + timeout: Optional[float] = ..., + ) -> List[Message]: + ... + + @overload + async def wait_for( + self, + event: Literal['raw_message_edit'], + /, + *, + check: Optional[Callable[[RawMessageUpdateEvent], bool]] = ..., + timeout: Optional[float] = ..., + ) -> RawMessageUpdateEvent: + ... + + @overload + async def wait_for( + self, + event: Literal['raw_message_delete'], + /, + *, + check: Optional[Callable[[RawMessageDeleteEvent], bool]] = ..., + timeout: Optional[float] = ..., + ) -> RawMessageDeleteEvent: + ... + + @overload + async def wait_for( + self, + event: Literal['raw_bulk_message_delete'], + /, + *, + check: Optional[Callable[[RawBulkMessageDeleteEvent], bool]] = ..., + timeout: Optional[float] = ..., + ) -> RawBulkMessageDeleteEvent: + ... + + # Reactions + + @overload + async def wait_for( + self, + event: Literal['reaction_add', 'reaction_remove'], + /, + *, + check: Optional[Callable[[Reaction, Union[Member, User]], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Tuple[Reaction, Union[Member, User]]: + ... + + @overload + async def wait_for( + self, + event: Literal['reaction_clear'], + /, + *, + check: Optional[Callable[[Message, List[Reaction]], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Tuple[Message, List[Reaction]]: + ... + + @overload + async def wait_for( + self, + event: Literal['reaction_clear_emoji'], + /, + *, + check: Optional[Callable[[Reaction], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Reaction: + ... + + @overload + async def wait_for( + self, + event: Literal['raw_reaction_add', 'raw_reaction_remove'], + /, + *, + check: Optional[Callable[[RawReactionActionEvent], bool]] = ..., + timeout: Optional[float] = ..., + ) -> RawReactionActionEvent: + ... + + @overload + async def wait_for( + self, + event: Literal['raw_reaction_clear'], + /, + *, + check: Optional[Callable[[RawReactionClearEvent], bool]] = ..., + timeout: Optional[float] = ..., + ) -> RawReactionClearEvent: + ... + + @overload + async def wait_for( + self, + event: Literal['raw_reaction_clear_emoji'], + /, + *, + check: Optional[Callable[[RawReactionClearEmojiEvent], bool]] = ..., + timeout: Optional[float] = ..., + ) -> RawReactionClearEmojiEvent: + ... + + # Roles + + @overload + async def wait_for( + self, + event: Literal['guild_role_create', 'guild_role_delete'], + /, + *, + check: Optional[Callable[[Role], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Role: + ... + + @overload + async def wait_for( + self, + event: Literal['guild_role_update'], + /, + *, + check: Optional[Callable[[Role, Role], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Tuple[Role, Role]: + ... + + # Scheduled Events + + @overload + async def wait_for( + self, + event: Literal['scheduled_event_create', 'scheduled_event_delete'], + /, + *, + check: Optional[Callable[[ScheduledEvent], bool]] = ..., + timeout: Optional[float] = ..., + ) -> ScheduledEvent: + ... + + @overload + async def wait_for( + self, + event: Literal['scheduled_event_user_add', 'scheduled_event_user_remove'], + /, + *, + check: Optional[Callable[[ScheduledEvent, User], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Tuple[ScheduledEvent, User]: + ... + + # Stages + + @overload + async def wait_for( + self, + event: Literal['stage_instance_create', 'stage_instance_delete'], + /, + *, + check: Optional[Callable[[StageInstance], bool]] = ..., + timeout: Optional[float] = ..., + ) -> StageInstance: + ... + + @overload + async def wait_for( + self, + event: Literal['stage_instance_update'], + /, + *, + check: Optional[Callable[[StageInstance, StageInstance], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Coroutine[Any, Any, Tuple[StageInstance, StageInstance]]: + ... + + # Subscriptions + @overload + async def wait_for( + self, + event: Literal['subscription_create', 'subscription_update', 'subscription_delete'], + /, + *, + check: Optional[Callable[[Subscription], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Subscription: + ... + + # Threads + @overload + async def wait_for( + self, + event: Literal['thread_create', 'thread_join', 'thread_remove', 'thread_delete'], + /, + *, + check: Optional[Callable[[Thread], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Thread: + ... + + @overload + async def wait_for( + self, + event: Literal['thread_update'], + /, + *, + check: Optional[Callable[[Thread, Thread], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Tuple[Thread, Thread]: + ... + + @overload + async def wait_for( + self, + event: Literal['raw_thread_update'], + /, + *, + check: Optional[Callable[[RawThreadUpdateEvent], bool]] = ..., + timeout: Optional[float] = ..., + ) -> RawThreadUpdateEvent: + ... + + @overload + async def wait_for( + self, + event: Literal['raw_thread_delete'], + /, + *, + check: Optional[Callable[[RawThreadDeleteEvent], bool]] = ..., + timeout: Optional[float] = ..., + ) -> RawThreadDeleteEvent: + ... + + @overload + async def wait_for( + self, + event: Literal['thread_member_join', 'thread_member_remove'], + /, + *, + check: Optional[Callable[[ThreadMember], bool]] = ..., + timeout: Optional[float] = ..., + ) -> ThreadMember: + ... + + @overload + async def wait_for( + self, + event: Literal['raw_thread_member_remove'], + /, + *, + check: Optional[Callable[[RawThreadMembersUpdate], bool]] = ..., + timeout: Optional[float] = ..., + ) -> RawThreadMembersUpdate: + ... + + # Voice + + @overload + async def wait_for( + self, + event: Literal['voice_state_update'], + /, + *, + check: Optional[Callable[[Member, VoiceState, VoiceState], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Tuple[Member, VoiceState, VoiceState]: + ... + + # Polls + + @overload + async def wait_for( + self, + event: Literal['poll_vote_add', 'poll_vote_remove'], + /, + *, + check: Optional[Callable[[Union[User, Member], PollAnswer], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Tuple[Union[User, Member], PollAnswer]: + ... + + @overload + async def wait_for( + self, + event: Literal['raw_poll_vote_add', 'raw_poll_vote_remove'], + /, + *, + check: Optional[Callable[[RawPollVoteActionEvent], bool]] = ..., + timeout: Optional[float] = ..., + ) -> RawPollVoteActionEvent: + ... + + # Commands + + @overload + async def wait_for( + self: Union[Bot, AutoShardedBot], + event: Literal["command", "command_completion"], + /, + *, + check: Optional[Callable[[Context[Any]], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Context[Any]: + ... + + @overload + async def wait_for( + self: Union[Bot, AutoShardedBot], + event: Literal["command_error"], + /, + *, + check: Optional[Callable[[Context[Any], CommandError], bool]] = ..., + timeout: Optional[float] = ..., + ) -> Tuple[Context[Any], CommandError]: + ... + + @overload + async def wait_for( + self, + event: str, + /, + *, + check: Optional[Callable[..., bool]] = ..., + timeout: Optional[float] = ..., + ) -> Any: + ... + + def wait_for( + self, + event: str, + /, + *, + check: Optional[Callable[..., bool]] = None, + timeout: Optional[float] = None, + ) -> Coro[Any]: + """|coro| + + Waits for a WebSocket event to be dispatched. + + This could be used to wait for a user to reply to a message, + or to react to a message, or to edit a message in a self-contained + way. + + The ``timeout`` parameter is passed onto :func:`asyncio.wait_for`. By default, + it does not timeout. Note that this does propagate the + :exc:`asyncio.TimeoutError` for you in case of timeout and is provided for + ease of use. + + In case the event returns multiple arguments, a :class:`tuple` containing those + arguments is returned instead. Please check the + :ref:`documentation ` for a list of events and their + parameters. + + This function returns the **first event that meets the requirements**. + + Examples + --------- + + Waiting for a user reply: :: + + @client.event + async def on_message(message): + if message.content.startswith('$greet'): + channel = message.channel + await channel.send('Say hello!') + + def check(m): + return m.content == 'hello' and m.channel == channel + + msg = await client.wait_for('message', check=check) + await channel.send(f'Hello {msg.author}!') + + Waiting for a thumbs up reaction from the message author: :: + + @client.event + async def on_message(message): + if message.content.startswith('$thumb'): + channel = message.channel + await channel.send('Send me that \N{THUMBS UP SIGN} reaction, mate') + + def check(reaction, user): + return user == message.author and str(reaction.emoji) == '\N{THUMBS UP SIGN}' + + try: + reaction, user = await client.wait_for('reaction_add', timeout=60.0, check=check) + except asyncio.TimeoutError: + await channel.send('\N{THUMBS DOWN SIGN}') + else: + await channel.send('\N{THUMBS UP SIGN}') + + .. versionchanged:: 2.0 + + ``event`` parameter is now positional-only. + + + Parameters + ------------ + event: :class:`str` + The event name, similar to the :ref:`event reference `, + but without the ``on_`` prefix, to wait for. + check: Optional[Callable[..., :class:`bool`]] + A predicate to check what to wait for. The arguments must meet the + parameters of the event being waited for. + timeout: Optional[:class:`float`] + The number of seconds to wait before timing out and raising + :exc:`asyncio.TimeoutError`. + + Raises + ------- + asyncio.TimeoutError + If a timeout is provided and it was reached. + + Returns + -------- + Any + Returns no arguments, a single argument, or a :class:`tuple` of multiple + arguments that mirrors the parameters passed in the + :ref:`event reference `. + """ + + future = self.loop.create_future() + if check is None: + + def _check(*args): + return True + + check = _check + + ev = event.lower() + try: + listeners = self._listeners[ev] + except KeyError: + listeners = [] + self._listeners[ev] = listeners + + listeners.append((future, check)) + return asyncio.wait_for(future, timeout) + + # event registration + + def event(self, coro: CoroT, /) -> CoroT: + """A decorator that registers an event to listen to. + + You can find more info about the events on the :ref:`documentation below `. + + The events must be a :ref:`coroutine `, if not, :exc:`TypeError` is raised. + + Example + --------- + + .. code-block:: python3 + + @client.event + async def on_ready(): + print('Ready!') + + .. versionchanged:: 2.0 + + ``coro`` parameter is now positional-only. + + Raises + -------- + TypeError + The coroutine passed is not actually a coroutine. + """ + + if not asyncio.iscoroutinefunction(coro): + raise TypeError('event registered must be a coroutine function') + + setattr(self, coro.__name__, coro) + _log.debug('%s has successfully been registered as an event', coro.__name__) + return coro + + async def change_presence( + self, + *, + activity: Optional[BaseActivity] = None, + status: Optional[Status] = None, + ) -> None: + """|coro| + + Changes the client's presence. + + Example + --------- + + .. code-block:: python3 + + game = discord.Game("with the API") + await client.change_presence(status=discord.Status.idle, activity=game) + + .. versionchanged:: 2.0 + Removed the ``afk`` keyword-only parameter. + + .. versionchanged:: 2.0 + This function will now raise :exc:`TypeError` instead of + ``InvalidArgument``. + + Parameters + ---------- + activity: Optional[:class:`.BaseActivity`] + The activity being done. ``None`` if no currently active activity is done. + status: Optional[:class:`.Status`] + Indicates what status to change to. If ``None``, then + :attr:`.Status.online` is used. + + Raises + ------ + TypeError + If the ``activity`` parameter is not the proper type. + """ + + if status is None: + status_str = 'online' + status = Status.online + elif status is Status.offline: + status_str = 'invisible' + status = Status.offline + else: + status_str = str(status) + + await self.ws.change_presence(activity=activity, status=status_str) + + for guild in self._connection.guilds: + me = guild.me + if me is None: + continue + + if activity is not None: + me.activities = (activity,) # type: ignore # Type checker does not understand the downcast here + else: + me.activities = () + + me.status = status + + # Guild stuff + + async def fetch_guilds( + self, + *, + limit: Optional[int] = 200, + before: Optional[SnowflakeTime] = None, + after: Optional[SnowflakeTime] = None, + with_counts: bool = True, + ) -> AsyncIterator[Guild]: + """Retrieves an :term:`asynchronous iterator` that enables receiving your guilds. + + .. note:: + + Using this, you will only receive :attr:`.Guild.owner`, :attr:`.Guild.icon`, + :attr:`.Guild.id`, :attr:`.Guild.name`, :attr:`.Guild.approximate_member_count`, + and :attr:`.Guild.approximate_presence_count` per :class:`.Guild`. + + .. note:: + + This method is an API call. For general usage, consider :attr:`guilds` instead. + + Examples + --------- + + Usage :: + + async for guild in client.fetch_guilds(limit=150): + print(guild.name) + + Flattening into a list :: + + guilds = [guild async for guild in client.fetch_guilds(limit=150)] + # guilds is now a list of Guild... + + All parameters are optional. + + Parameters + ----------- + limit: Optional[:class:`int`] + The number of guilds to retrieve. + If ``None``, it retrieves every guild you have access to. Note, however, + that this would make it a slow operation. + Defaults to ``200``. + + .. versionchanged:: 2.0 + + The default has been changed to 200. + + before: Union[:class:`.abc.Snowflake`, :class:`datetime.datetime`] + Retrieves guilds before this date or object. + If a datetime is provided, it is recommended to use a UTC aware datetime. + If the datetime is naive, it is assumed to be local time. + after: Union[:class:`.abc.Snowflake`, :class:`datetime.datetime`] + Retrieve guilds after this date or object. + If a datetime is provided, it is recommended to use a UTC aware datetime. + If the datetime is naive, it is assumed to be local time. + with_counts: :class:`bool` + Whether to include count information in the guilds. This fills the + :attr:`.Guild.approximate_member_count` and :attr:`.Guild.approximate_presence_count` + attributes without needing any privileged intents. Defaults to ``True``. + + .. versionadded:: 2.3 + + Raises + ------ + HTTPException + Getting the guilds failed. + + Yields + -------- + :class:`.Guild` + The guild with the guild data parsed. + """ + + async def _before_strategy(retrieve: int, before: Optional[Snowflake], limit: Optional[int]): + before_id = before.id if before else None + data = await self.http.get_guilds(retrieve, before=before_id, with_counts=with_counts) + + if data: + if limit is not None: + limit -= len(data) + + before = Object(id=int(data[0]['id'])) + + return data, before, limit + + async def _after_strategy(retrieve: int, after: Optional[Snowflake], limit: Optional[int]): + after_id = after.id if after else None + data = await self.http.get_guilds(retrieve, after=after_id, with_counts=with_counts) + + if data: + if limit is not None: + limit -= len(data) + + after = Object(id=int(data[-1]['id'])) + + return data, after, limit + + if isinstance(before, datetime.datetime): + before = Object(id=time_snowflake(before, high=False)) + if isinstance(after, datetime.datetime): + after = Object(id=time_snowflake(after, high=True)) + + predicate: Optional[Callable[[GuildPayload], bool]] = None + strategy, state = _after_strategy, after + + if before: + strategy, state = _before_strategy, before + + if before and after: + predicate = lambda m: int(m['id']) > after.id + + while True: + retrieve = 200 if limit is None else min(limit, 200) + if retrieve < 1: + return + + data, state, limit = await strategy(retrieve, state, limit) + + if predicate: + data = filter(predicate, data) + + count = 0 + + for count, raw_guild in enumerate(data, 1): + yield Guild(state=self._connection, data=raw_guild) + + if count < 200: + # There's no data left after this + break + + async def fetch_template(self, code: Union[Template, str]) -> Template: + """|coro| + + Gets a :class:`.Template` from a discord.new URL or code. + + Parameters + ----------- + code: Union[:class:`.Template`, :class:`str`] + The Discord Template Code or URL (must be a discord.new URL). + + Raises + ------- + NotFound + The template is invalid. + HTTPException + Getting the template failed. + + Returns + -------- + :class:`.Template` + The template from the URL/code. + """ + code = utils.resolve_template(code) + data = await self.http.get_template(code) + return Template(data=data, state=self._connection) + + async def fetch_guild(self, guild_id: int, /, *, with_counts: bool = True) -> Guild: + """|coro| + + Retrieves a :class:`.Guild` from an ID. + + .. note:: + + Using this, you will **not** receive :attr:`.Guild.channels`, :attr:`.Guild.members`, + :attr:`.Member.activity` and :attr:`.Member.voice` per :class:`.Member`. + + .. note:: + + This method is an API call. For general usage, consider :meth:`get_guild` instead. + + .. versionchanged:: 2.0 + + ``guild_id`` parameter is now positional-only. + + + Parameters + ----------- + guild_id: :class:`int` + The guild's ID to fetch from. + with_counts: :class:`bool` + Whether to include count information in the guild. This fills the + :attr:`.Guild.approximate_member_count` and :attr:`.Guild.approximate_presence_count` + attributes without needing any privileged intents. Defaults to ``True``. + + .. versionadded:: 2.0 + + Raises + ------ + NotFound + The guild doesn't exist or you got no access to it. + HTTPException + Getting the guild failed. + + Returns + -------- + :class:`.Guild` + The guild from the ID. + """ + data = await self.http.get_guild(guild_id, with_counts=with_counts) + return Guild(data=data, state=self._connection) + + async def fetch_guild_preview(self, guild_id: int) -> GuildPreview: + """|coro| + + Retrieves a preview of a :class:`.Guild` from an ID. If the guild is discoverable, + you don't have to be a member of it. + + .. versionadded:: 2.5 + + Raises + ------ + NotFound + The guild doesn't exist, or is not discoverable and you are not in it. + HTTPException + Getting the guild failed. + + Returns + -------- + :class:`.GuildPreview` + The guild preview from the ID. + """ + data = await self.http.get_guild_preview(guild_id) + return GuildPreview(data=data, state=self._connection) + + async def create_guild( + self, + *, + name: str, + icon: bytes = MISSING, + code: str = MISSING, + ) -> Guild: + """|coro| + + Creates a :class:`.Guild`. + + Bot accounts in more than 10 guilds are not allowed to create guilds. + + .. versionchanged:: 2.0 + ``name`` and ``icon`` parameters are now keyword-only. The ``region`` parameter has been removed. + + .. versionchanged:: 2.0 + This function will now raise :exc:`ValueError` instead of + ``InvalidArgument``. + + Parameters + ---------- + name: :class:`str` + The name of the guild. + icon: Optional[:class:`bytes`] + The :term:`py:bytes-like object` representing the icon. See :meth:`.ClientUser.edit` + for more details on what is expected. + code: :class:`str` + The code for a template to create the guild with. + + .. versionadded:: 1.4 + + Raises + ------ + HTTPException + Guild creation failed. + ValueError + Invalid icon image format given. Must be PNG or JPG. + + Returns + ------- + :class:`.Guild` + The guild created. This is not the same guild that is + added to cache. + """ + if icon is not MISSING: + icon_base64 = utils._bytes_to_base64_data(icon) + else: + icon_base64 = None + + if code: + data = await self.http.create_from_template(code, name, icon_base64) + else: + data = await self.http.create_guild(name, icon_base64) + return Guild(data=data, state=self._connection) + + async def fetch_stage_instance(self, channel_id: int, /) -> StageInstance: + """|coro| + + Gets a :class:`.StageInstance` for a stage channel id. + + .. versionadded:: 2.0 + + Parameters + ----------- + channel_id: :class:`int` + The stage channel ID. + + Raises + ------- + NotFound + The stage instance or channel could not be found. + HTTPException + Getting the stage instance failed. + + Returns + -------- + :class:`.StageInstance` + The stage instance from the stage channel ID. + """ + data = await self.http.get_stage_instance(channel_id) + guild = self.get_guild(int(data['guild_id'])) + # Guild can technically be None here but this is being explicitly silenced right now. + return StageInstance(guild=guild, state=self._connection, data=data) # type: ignore + + # Invite management + + async def fetch_invite( + self, + url: Union[Invite, str], + *, + with_counts: bool = True, + with_expiration: bool = True, + scheduled_event_id: Optional[int] = None, + ) -> Invite: + """|coro| + + Gets an :class:`.Invite` from a discord.gg URL or ID. + + .. note:: + + If the invite is for a guild you have not joined, the guild and channel + attributes of the returned :class:`.Invite` will be :class:`.PartialInviteGuild` and + :class:`.PartialInviteChannel` respectively. + + Parameters + ----------- + url: Union[:class:`.Invite`, :class:`str`] + The Discord invite ID or URL (must be a discord.gg URL). + with_counts: :class:`bool` + Whether to include count information in the invite. This fills the + :attr:`.Invite.approximate_member_count` and :attr:`.Invite.approximate_presence_count` + fields. + with_expiration: :class:`bool` + Whether to include the expiration date of the invite. This fills the + :attr:`.Invite.expires_at` field. + + .. versionadded:: 2.0 + scheduled_event_id: Optional[:class:`int`] + The ID of the scheduled event this invite is for. + + .. note:: + + It is not possible to provide a url that contains an ``event_id`` parameter + when using this parameter. + + .. versionadded:: 2.0 + + Raises + ------- + ValueError + The url contains an ``event_id``, but ``scheduled_event_id`` has also been provided. + NotFound + The invite has expired or is invalid. + HTTPException + Getting the invite failed. + + Returns + -------- + :class:`.Invite` + The invite from the URL/ID. + """ + + resolved = utils.resolve_invite(url) + + if scheduled_event_id and resolved.event: + raise ValueError('Cannot specify scheduled_event_id and contain an event_id in the url.') + + scheduled_event_id = scheduled_event_id or resolved.event + + data = await self.http.get_invite( + resolved.code, + with_counts=with_counts, + with_expiration=with_expiration, + guild_scheduled_event_id=scheduled_event_id, + ) + return Invite.from_incomplete(state=self._connection, data=data) + + async def delete_invite(self, invite: Union[Invite, str], /) -> None: + """|coro| + + Revokes an :class:`.Invite`, URL, or ID to an invite. + + You must have :attr:`~.Permissions.manage_channels` in + the associated guild to do this. + + .. versionchanged:: 2.0 + + ``invite`` parameter is now positional-only. + + Parameters + ---------- + invite: Union[:class:`.Invite`, :class:`str`] + The invite to revoke. + + Raises + ------- + Forbidden + You do not have permissions to revoke invites. + NotFound + The invite is invalid or expired. + HTTPException + Revoking the invite failed. + """ + + resolved = utils.resolve_invite(invite) + await self.http.delete_invite(resolved.code) + + # Miscellaneous stuff + + async def fetch_widget(self, guild_id: int, /) -> Widget: + """|coro| + + Gets a :class:`.Widget` from a guild ID. + + .. note:: + + The guild must have the widget enabled to get this information. + + .. versionchanged:: 2.0 + + ``guild_id`` parameter is now positional-only. + + Parameters + ----------- + guild_id: :class:`int` + The ID of the guild. + + Raises + ------- + Forbidden + The widget for this guild is disabled. + HTTPException + Retrieving the widget failed. + + Returns + -------- + :class:`.Widget` + The guild's widget. + """ + data = await self.http.get_widget(guild_id) + + return Widget(state=self._connection, data=data) + + async def application_info(self) -> AppInfo: + """|coro| + + Retrieves the bot's application information. + + Raises + ------- + HTTPException + Retrieving the information failed somehow. + + Returns + -------- + :class:`.AppInfo` + The bot's application information. + """ + data = await self.http.application_info() + return AppInfo(self._connection, data) + + async def fetch_user(self, user_id: int, /) -> User: + """|coro| + + Retrieves a :class:`~discord.User` based on their ID. + You do not have to share any guilds with the user to get this information, + however many operations do require that you do. + + .. note:: + + This method is an API call. If you have :attr:`discord.Intents.members` and member cache enabled, consider :meth:`get_user` instead. + + .. versionchanged:: 2.0 + + ``user_id`` parameter is now positional-only. + + Parameters + ----------- + user_id: :class:`int` + The user's ID to fetch from. + + Raises + ------- + NotFound + A user with this ID does not exist. + HTTPException + Fetching the user failed. + + Returns + -------- + :class:`~discord.User` + The user you requested. + """ + data = await self.http.get_user(user_id) + return User(state=self._connection, data=data) + + async def fetch_channel(self, channel_id: int, /) -> Union[GuildChannel, PrivateChannel, Thread]: + """|coro| + + Retrieves a :class:`.abc.GuildChannel`, :class:`.abc.PrivateChannel`, or :class:`.Thread` with the specified ID. + + .. note:: + + This method is an API call. For general usage, consider :meth:`get_channel` instead. + + .. versionadded:: 1.2 + + .. versionchanged:: 2.0 + + ``channel_id`` parameter is now positional-only. + + Raises + ------- + InvalidData + An unknown channel type was received from Discord. + HTTPException + Retrieving the channel failed. + NotFound + Invalid Channel ID. + Forbidden + You do not have permission to fetch this channel. + + Returns + -------- + Union[:class:`.abc.GuildChannel`, :class:`.abc.PrivateChannel`, :class:`.Thread`] + The channel from the ID. + """ + data = await self.http.get_channel(channel_id) + + factory, ch_type = _threaded_channel_factory(data['type']) + if factory is None: + raise InvalidData('Unknown channel type {type} for channel ID {id}.'.format_map(data)) + + if ch_type in (ChannelType.group, ChannelType.private): + # the factory will be a DMChannel or GroupChannel here + channel = factory(me=self.user, data=data, state=self._connection) # type: ignore + else: + # the factory can't be a DMChannel or GroupChannel here + guild_id = int(data['guild_id']) # type: ignore + guild = self._connection._get_or_create_unavailable_guild(guild_id) + # the factory should be a GuildChannel or Thread + channel = factory(guild=guild, state=self._connection, data=data) # type: ignore + + return channel + + async def fetch_webhook(self, webhook_id: int, /) -> Webhook: + """|coro| + + Retrieves a :class:`.Webhook` with the specified ID. + + .. versionchanged:: 2.0 + + ``webhook_id`` parameter is now positional-only. + + Raises + -------- + HTTPException + Retrieving the webhook failed. + NotFound + Invalid webhook ID. + Forbidden + You do not have permission to fetch this webhook. + + Returns + --------- + :class:`.Webhook` + The webhook you requested. + """ + data = await self.http.get_webhook(webhook_id) + return Webhook.from_state(data, state=self._connection) + + async def fetch_sticker(self, sticker_id: int, /) -> Union[StandardSticker, GuildSticker]: + """|coro| + + Retrieves a :class:`.Sticker` with the specified ID. + + .. versionadded:: 2.0 + + Raises + -------- + HTTPException + Retrieving the sticker failed. + NotFound + Invalid sticker ID. + + Returns + -------- + Union[:class:`.StandardSticker`, :class:`.GuildSticker`] + The sticker you requested. + """ + data = await self.http.get_sticker(sticker_id) + cls, _ = _sticker_factory(data['type']) + # The type checker is not smart enough to figure out the constructor is correct + return cls(state=self._connection, data=data) # type: ignore + + async def fetch_skus(self) -> List[SKU]: + """|coro| + + Retrieves the bot's available SKUs. + + .. versionadded:: 2.4 + + Raises + ------- + MissingApplicationID + The application ID could not be found. + HTTPException + Retrieving the SKUs failed. + + Returns + -------- + List[:class:`.SKU`] + The bot's available SKUs. + """ + + if self.application_id is None: + raise MissingApplicationID + + data = await self.http.get_skus(self.application_id) + return [SKU(state=self._connection, data=sku) for sku in data] + + async def fetch_entitlement(self, entitlement_id: int, /) -> Entitlement: + """|coro| + + Retrieves a :class:`.Entitlement` with the specified ID. + + .. versionadded:: 2.4 + + Parameters + ----------- + entitlement_id: :class:`int` + The entitlement's ID to fetch from. + + Raises + ------- + NotFound + An entitlement with this ID does not exist. + MissingApplicationID + The application ID could not be found. + HTTPException + Fetching the entitlement failed. + + Returns + -------- + :class:`.Entitlement` + The entitlement you requested. + """ + + if self.application_id is None: + raise MissingApplicationID + + data = await self.http.get_entitlement(self.application_id, entitlement_id) + return Entitlement(state=self._connection, data=data) + + async def entitlements( + self, + *, + limit: Optional[int] = 100, + before: Optional[SnowflakeTime] = None, + after: Optional[SnowflakeTime] = None, + skus: Optional[Sequence[Snowflake]] = None, + user: Optional[Snowflake] = None, + guild: Optional[Snowflake] = None, + exclude_ended: bool = False, + exclude_deleted: bool = True, + ) -> AsyncIterator[Entitlement]: + """Retrieves an :term:`asynchronous iterator` of the :class:`.Entitlement` that applications has. + + .. versionadded:: 2.4 + + Examples + --------- + + Usage :: + + async for entitlement in client.entitlements(limit=100): + print(entitlement.user_id, entitlement.ends_at) + + Flattening into a list :: + + entitlements = [entitlement async for entitlement in client.entitlements(limit=100)] + # entitlements is now a list of Entitlement... + + All parameters are optional. + + Parameters + ----------- + limit: Optional[:class:`int`] + The number of entitlements to retrieve. If ``None``, it retrieves every entitlement for this application. + Note, however, that this would make it a slow operation. Defaults to ``100``. + before: Optional[Union[:class:`~discord.abc.Snowflake`, :class:`datetime.datetime`]] + Retrieve entitlements before this date or entitlement. + If a datetime is provided, it is recommended to use a UTC aware datetime. + If the datetime is naive, it is assumed to be local time. + after: Optional[Union[:class:`~discord.abc.Snowflake`, :class:`datetime.datetime`]] + Retrieve entitlements after this date or entitlement. + If a datetime is provided, it is recommended to use a UTC aware datetime. + If the datetime is naive, it is assumed to be local time. + skus: Optional[Sequence[:class:`~discord.abc.Snowflake`]] + A list of SKUs to filter by. + user: Optional[:class:`~discord.abc.Snowflake`] + The user to filter by. + guild: Optional[:class:`~discord.abc.Snowflake`] + The guild to filter by. + exclude_ended: :class:`bool` + Whether to exclude ended entitlements. Defaults to ``False``. + exclude_deleted: :class:`bool` + Whether to exclude deleted entitlements. Defaults to ``True``. + + .. versionadded:: 2.5 + + Raises + ------- + MissingApplicationID + The application ID could not be found. + HTTPException + Fetching the entitlements failed. + TypeError + Both ``after`` and ``before`` were provided, as Discord does not + support this type of pagination. + + Yields + -------- + :class:`.Entitlement` + The entitlement with the application. + """ + + if self.application_id is None: + raise MissingApplicationID + + if before is not None and after is not None: + raise TypeError('entitlements pagination does not support both before and after') + + # This endpoint paginates in ascending order. + endpoint = self.http.get_entitlements + + async def _before_strategy(retrieve: int, before: Optional[Snowflake], limit: Optional[int]): + before_id = before.id if before else None + data = await endpoint( + self.application_id, # type: ignore # We already check for None above + limit=retrieve, + before=before_id, + sku_ids=[sku.id for sku in skus] if skus else None, + user_id=user.id if user else None, + guild_id=guild.id if guild else None, + exclude_ended=exclude_ended, + exclude_deleted=exclude_deleted, + ) + + if data: + if limit is not None: + limit -= len(data) + + before = Object(id=int(data[0]['id'])) + + return data, before, limit + + async def _after_strategy(retrieve: int, after: Optional[Snowflake], limit: Optional[int]): + after_id = after.id if after else None + data = await endpoint( + self.application_id, # type: ignore # We already check for None above + limit=retrieve, + after=after_id, + sku_ids=[sku.id for sku in skus] if skus else None, + user_id=user.id if user else None, + guild_id=guild.id if guild else None, + exclude_ended=exclude_ended, + ) + + if data: + if limit is not None: + limit -= len(data) + + after = Object(id=int(data[-1]['id'])) + + return data, after, limit + + if isinstance(before, datetime.datetime): + before = Object(id=utils.time_snowflake(before, high=False)) + if isinstance(after, datetime.datetime): + after = Object(id=utils.time_snowflake(after, high=True)) + + if before: + strategy, state = _before_strategy, before + else: + strategy, state = _after_strategy, after + + while True: + retrieve = 100 if limit is None else min(limit, 100) + if retrieve < 1: + return + + data, state, limit = await strategy(retrieve, state, limit) + + # Terminate loop on next iteration; there's no data left after this + if len(data) < 100: + limit = 0 + + for e in data: + yield Entitlement(self._connection, e) + + async def create_entitlement( + self, + sku: Snowflake, + owner: Snowflake, + owner_type: EntitlementOwnerType, + ) -> None: + """|coro| + + Creates a test :class:`.Entitlement` for the application. + + .. versionadded:: 2.4 + + Parameters + ----------- + sku: :class:`~discord.abc.Snowflake` + The SKU to create the entitlement for. + owner: :class:`~discord.abc.Snowflake` + The ID of the owner. + owner_type: :class:`.EntitlementOwnerType` + The type of the owner. + + Raises + ------- + MissingApplicationID + The application ID could not be found. + NotFound + The SKU or owner could not be found. + HTTPException + Creating the entitlement failed. + """ + + if self.application_id is None: + raise MissingApplicationID + + await self.http.create_entitlement(self.application_id, sku.id, owner.id, owner_type.value) + + async def fetch_premium_sticker_packs(self) -> List[StickerPack]: + """|coro| + + Retrieves all available premium sticker packs. + + .. versionadded:: 2.0 + + Raises + ------- + HTTPException + Retrieving the sticker packs failed. + + Returns + --------- + List[:class:`.StickerPack`] + All available premium sticker packs. + """ + data = await self.http.list_premium_sticker_packs() + return [StickerPack(state=self._connection, data=pack) for pack in data['sticker_packs']] + + async def fetch_premium_sticker_pack(self, sticker_pack_id: int, /) -> StickerPack: + """|coro| + + Retrieves a premium sticker pack with the specified ID. + + .. versionadded:: 2.5 + + Parameters + ---------- + sticker_pack_id: :class:`int` + The sticker pack's ID to fetch from. + + Raises + ------- + NotFound + A sticker pack with this ID does not exist. + HTTPException + Retrieving the sticker pack failed. + + Returns + ------- + :class:`.StickerPack` + The retrieved premium sticker pack. + """ + data = await self.http.get_sticker_pack(sticker_pack_id) + return StickerPack(state=self._connection, data=data) + + async def fetch_soundboard_default_sounds(self) -> List[SoundboardDefaultSound]: + """|coro| + + Retrieves all default soundboard sounds. + + .. versionadded:: 2.5 + + Raises + ------- + HTTPException + Retrieving the default soundboard sounds failed. + + Returns + --------- + List[:class:`.SoundboardDefaultSound`] + All default soundboard sounds. + """ + data = await self.http.get_soundboard_default_sounds() + return [SoundboardDefaultSound(state=self._connection, data=sound) for sound in data] + + async def create_dm(self, user: Snowflake) -> DMChannel: + """|coro| + + Creates a :class:`.DMChannel` with this user. + + This should be rarely called, as this is done transparently for most + people. + + .. versionadded:: 2.0 + + Parameters + ----------- + user: :class:`~discord.abc.Snowflake` + The user to create a DM with. + + Returns + ------- + :class:`.DMChannel` + The channel that was created. + """ + state = self._connection + found = state._get_private_channel_by_user(user.id) + if found: + return found + + data = await state.http.start_private_message(user.id) + return state.add_dm_channel(data) + + def add_dynamic_items(self, *items: Type[DynamicItem[Item[Any]]]) -> None: + r"""Registers :class:`~discord.ui.DynamicItem` classes for persistent listening. + + This method accepts *class types* rather than instances. + + .. versionadded:: 2.4 + + Parameters + ----------- + \*items: Type[:class:`~discord.ui.DynamicItem`] + The classes of dynamic items to add. + + Raises + ------- + TypeError + A class is not a subclass of :class:`~discord.ui.DynamicItem`. + """ + + for item in items: + if not issubclass(item, DynamicItem): + raise TypeError(f'expected subclass of DynamicItem not {item.__name__}') + + self._connection.store_dynamic_items(*items) + + def remove_dynamic_items(self, *items: Type[DynamicItem[Item[Any]]]) -> None: + r"""Removes :class:`~discord.ui.DynamicItem` classes from persistent listening. + + This method accepts *class types* rather than instances. + + .. versionadded:: 2.4 + + Parameters + ----------- + \*items: Type[:class:`~discord.ui.DynamicItem`] + The classes of dynamic items to remove. + + Raises + ------- + TypeError + A class is not a subclass of :class:`~discord.ui.DynamicItem`. + """ + + for item in items: + if not issubclass(item, DynamicItem): + raise TypeError(f'expected subclass of DynamicItem not {item.__name__}') + + self._connection.remove_dynamic_items(*items) + + def add_view(self, view: View, *, message_id: Optional[int] = None) -> None: + """Registers a :class:`~discord.ui.View` for persistent listening. + + This method should be used for when a view is comprised of components + that last longer than the lifecycle of the program. + + .. versionadded:: 2.0 + + Parameters + ------------ + view: :class:`discord.ui.View` + The view to register for dispatching. + message_id: Optional[:class:`int`] + The message ID that the view is attached to. This is currently used to + refresh the view's state during message update events. If not given + then message update events are not propagated for the view. + + Raises + ------- + TypeError + A view was not passed. + ValueError + The view is not persistent or is already finished. A persistent view has no timeout + and all their components have an explicitly provided custom_id. + """ + + if not isinstance(view, View): + raise TypeError(f'expected an instance of View not {view.__class__.__name__}') + + if not view.is_persistent(): + raise ValueError('View is not persistent. Items need to have a custom_id set and View must have no timeout') + + if view.is_finished(): + raise ValueError('View is already finished.') + + self._connection.store_view(view, message_id) + + @property + def persistent_views(self) -> Sequence[View]: + """Sequence[:class:`.View`]: A sequence of persistent views added to the client. + + .. versionadded:: 2.0 + """ + return self._connection.persistent_views + + async def create_application_emoji( + self, + *, + name: str, + image: bytes, + ) -> Emoji: + """|coro| + + Create an emoji for the current application. + + .. versionadded:: 2.5 + + Parameters + ---------- + name: :class:`str` + The emoji name. Must be between 2 and 32 characters long. + image: :class:`bytes` + The :term:`py:bytes-like object` representing the image data to use. + Only JPG, PNG and GIF images are supported. + + Raises + ------ + MissingApplicationID + The application ID could not be found. + HTTPException + Creating the emoji failed. + + Returns + ------- + :class:`.Emoji` + The emoji that was created. + """ + if self.application_id is None: + raise MissingApplicationID + + img = utils._bytes_to_base64_data(image) + data = await self.http.create_application_emoji(self.application_id, name, img) + return Emoji(guild=Object(0), state=self._connection, data=data) + + async def fetch_application_emoji(self, emoji_id: int, /) -> Emoji: + """|coro| + + Retrieves an emoji for the current application. + + .. versionadded:: 2.5 + + Parameters + ---------- + emoji_id: :class:`int` + The emoji ID to retrieve. + + Raises + ------ + MissingApplicationID + The application ID could not be found. + HTTPException + Retrieving the emoji failed. + + Returns + ------- + :class:`.Emoji` + The emoji requested. + """ + if self.application_id is None: + raise MissingApplicationID + + data = await self.http.get_application_emoji(self.application_id, emoji_id) + return Emoji(guild=Object(0), state=self._connection, data=data) + + async def fetch_application_emojis(self) -> List[Emoji]: + """|coro| + + Retrieves all emojis for the current application. + + .. versionadded:: 2.5 + + Raises + ------- + MissingApplicationID + The application ID could not be found. + HTTPException + Retrieving the emojis failed. + + Returns + ------- + List[:class:`.Emoji`] + The list of emojis for the current application. + """ + if self.application_id is None: + raise MissingApplicationID + + data = await self.http.get_application_emojis(self.application_id) + return [Emoji(guild=Object(0), state=self._connection, data=emoji) for emoji in data['items']] diff --git a/venv/lib/python3.12/site-packages/discord/colour.py b/venv/lib/python3.12/site-packages/discord/colour.py new file mode 100644 index 00000000..7e3a3713 --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/colour.py @@ -0,0 +1,526 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" +from __future__ import annotations + +import colorsys +import random +import re + +from typing import TYPE_CHECKING, Optional, Tuple, Union + +if TYPE_CHECKING: + from typing_extensions import Self + +__all__ = ( + 'Colour', + 'Color', +) + +RGB_REGEX = re.compile(r'rgb\s*\((?P[0-9.]+%?)\s*,\s*(?P[0-9.]+%?)\s*,\s*(?P[0-9.]+%?)\s*\)') + + +def parse_hex_number(argument: str) -> Colour: + arg = ''.join(i * 2 for i in argument) if len(argument) == 3 else argument + try: + value = int(arg, base=16) + if not (0 <= value <= 0xFFFFFF): + raise ValueError('hex number out of range for 24-bit colour') + except ValueError: + raise ValueError('invalid hex digit given') from None + else: + return Color(value=value) + + +def parse_rgb_number(number: str) -> int: + if number[-1] == '%': + value = float(number[:-1]) + if not (0 <= value <= 100): + raise ValueError('rgb percentage can only be between 0 to 100') + return round(255 * (value / 100)) + + value = int(number) + if not (0 <= value <= 255): + raise ValueError('rgb number can only be between 0 to 255') + return value + + +def parse_rgb(argument: str, *, regex: re.Pattern[str] = RGB_REGEX) -> Colour: + match = regex.match(argument) + if match is None: + raise ValueError('invalid rgb syntax found') + + red = parse_rgb_number(match.group('r')) + green = parse_rgb_number(match.group('g')) + blue = parse_rgb_number(match.group('b')) + return Color.from_rgb(red, green, blue) + + +class Colour: + """Represents a Discord role colour. This class is similar + to a (red, green, blue) :class:`tuple`. + + There is an alias for this called Color. + + .. container:: operations + + .. describe:: x == y + + Checks if two colours are equal. + + .. describe:: x != y + + Checks if two colours are not equal. + + .. describe:: hash(x) + + Return the colour's hash. + + .. describe:: str(x) + + Returns the hex format for the colour. + + .. describe:: int(x) + + Returns the raw colour value. + + .. note:: + + The colour values in the classmethods are mostly provided as-is and can change between + versions should the Discord client's representation of that colour also change. + + Attributes + ------------ + value: :class:`int` + The raw integer colour value. + """ + + __slots__ = ('value',) + + def __init__(self, value: int): + if not isinstance(value, int): + raise TypeError(f'Expected int parameter, received {value.__class__.__name__} instead.') + + self.value: int = value + + def _get_byte(self, byte: int) -> int: + return (self.value >> (8 * byte)) & 0xFF + + def __eq__(self, other: object) -> bool: + return isinstance(other, Colour) and self.value == other.value + + def __ne__(self, other: object) -> bool: + return not self.__eq__(other) + + def __str__(self) -> str: + return f'#{self.value:0>6x}' + + def __int__(self) -> int: + return self.value + + def __repr__(self) -> str: + return f'' + + def __hash__(self) -> int: + return hash(self.value) + + @property + def r(self) -> int: + """:class:`int`: Returns the red component of the colour.""" + return self._get_byte(2) + + @property + def g(self) -> int: + """:class:`int`: Returns the green component of the colour.""" + return self._get_byte(1) + + @property + def b(self) -> int: + """:class:`int`: Returns the blue component of the colour.""" + return self._get_byte(0) + + def to_rgb(self) -> Tuple[int, int, int]: + """Tuple[:class:`int`, :class:`int`, :class:`int`]: Returns an (r, g, b) tuple representing the colour.""" + return (self.r, self.g, self.b) + + @classmethod + def from_rgb(cls, r: int, g: int, b: int) -> Self: + """Constructs a :class:`Colour` from an RGB tuple.""" + return cls((r << 16) + (g << 8) + b) + + @classmethod + def from_hsv(cls, h: float, s: float, v: float) -> Self: + """Constructs a :class:`Colour` from an HSV tuple.""" + rgb = colorsys.hsv_to_rgb(h, s, v) + return cls.from_rgb(*(int(x * 255) for x in rgb)) + + @classmethod + def from_str(cls, value: str) -> Colour: + """Constructs a :class:`Colour` from a string. + + The following formats are accepted: + + - ``0x`` + - ``#`` + - ``0x#`` + - ``rgb(, , )`` + + Like CSS, ```` can be either 0-255 or 0-100% and ```` can be + either a 6 digit hex number or a 3 digit hex shortcut (e.g. #FFF). + + .. versionadded:: 2.0 + + Raises + ------- + ValueError + The string could not be converted into a colour. + """ + + if not value: + raise ValueError('unknown colour format given') + + if value[0] == '#': + return parse_hex_number(value[1:]) + + if value[0:2] == '0x': + rest = value[2:] + # Legacy backwards compatible syntax + if rest.startswith('#'): + return parse_hex_number(rest[1:]) + return parse_hex_number(rest) + + arg = value.lower() + if arg[0:3] == 'rgb': + return parse_rgb(arg) + + raise ValueError('unknown colour format given') + + @classmethod + def default(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0``. + + .. colour:: #000000 + """ + return cls(0) + + @classmethod + def random(cls, *, seed: Optional[Union[int, str, float, bytes, bytearray]] = None) -> Self: + """A factory method that returns a :class:`Colour` with a random hue. + + .. note:: + + The random algorithm works by choosing a colour with a random hue but + with maxed out saturation and value. + + .. versionadded:: 1.6 + + Parameters + ------------ + seed: Optional[Union[:class:`int`, :class:`str`, :class:`float`, :class:`bytes`, :class:`bytearray`]] + The seed to initialize the RNG with. If ``None`` is passed the default RNG is used. + + .. versionadded:: 1.7 + """ + rand = random if seed is None else random.Random(seed) + return cls.from_hsv(rand.random(), 1, 1) + + @classmethod + def teal(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0x1ABC9C``. + + .. colour:: #1ABC9C + """ + return cls(0x1ABC9C) + + @classmethod + def dark_teal(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0x11806A``. + + .. colour:: #11806A + """ + return cls(0x11806A) + + @classmethod + def brand_green(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0x57F287``. + + .. colour:: #57F287 + + + .. versionadded:: 2.0 + """ + return cls(0x57F287) + + @classmethod + def green(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0x2ECC71``. + + .. colour:: #2ECC71 + """ + return cls(0x2ECC71) + + @classmethod + def dark_green(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0x1F8B4C``. + + .. colour:: #1F8B4C + """ + return cls(0x1F8B4C) + + @classmethod + def blue(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0x3498DB``. + + .. colour:: #3498DB + """ + return cls(0x3498DB) + + @classmethod + def dark_blue(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0x206694``. + + .. colour:: #206694 + """ + return cls(0x206694) + + @classmethod + def purple(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0x9B59B6``. + + .. colour:: #9B59B6 + """ + return cls(0x9B59B6) + + @classmethod + def dark_purple(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0x71368A``. + + .. colour:: #71368A + """ + return cls(0x71368A) + + @classmethod + def magenta(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0xE91E63``. + + .. colour:: #E91E63 + """ + return cls(0xE91E63) + + @classmethod + def dark_magenta(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0xAD1457``. + + .. colour:: #AD1457 + """ + return cls(0xAD1457) + + @classmethod + def gold(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0xF1C40F``. + + .. colour:: #F1C40F + """ + return cls(0xF1C40F) + + @classmethod + def dark_gold(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0xC27C0E``. + + .. colour:: #C27C0E + """ + return cls(0xC27C0E) + + @classmethod + def orange(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0xE67E22``. + + .. colour:: #E67E22 + """ + return cls(0xE67E22) + + @classmethod + def dark_orange(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0xA84300``. + + .. colour:: #A84300 + """ + return cls(0xA84300) + + @classmethod + def brand_red(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0xED4245``. + + .. colour:: #ED4245 + + .. versionadded:: 2.0 + """ + return cls(0xED4245) + + @classmethod + def red(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0xE74C3C``. + + .. colour:: #E74C3C + """ + return cls(0xE74C3C) + + @classmethod + def dark_red(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0x992D22``. + + .. colour:: #992D22 + """ + return cls(0x992D22) + + @classmethod + def lighter_grey(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0x95A5A6``. + + .. colour:: #95A5A6 + """ + return cls(0x95A5A6) + + lighter_gray = lighter_grey + + @classmethod + def dark_grey(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0x607d8b``. + + .. colour:: #607d8b + """ + return cls(0x607D8B) + + dark_gray = dark_grey + + @classmethod + def light_grey(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0x979C9F``. + + .. colour:: #979C9F + """ + return cls(0x979C9F) + + light_gray = light_grey + + @classmethod + def darker_grey(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0x546E7A``. + + .. colour:: #546E7A + """ + return cls(0x546E7A) + + darker_gray = darker_grey + + @classmethod + def og_blurple(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0x7289DA``. + + .. colour:: #7289DA + """ + return cls(0x7289DA) + + @classmethod + def blurple(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0x5865F2``. + + .. colour:: #5865F2 + """ + return cls(0x5865F2) + + @classmethod + def greyple(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0x99AAB5``. + + .. colour:: #99AAB5 + """ + return cls(0x99AAB5) + + @classmethod + def dark_theme(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0x313338``. + + This will appear transparent on Discord's dark theme. + + .. colour:: #313338 + + .. versionadded:: 1.5 + + .. versionchanged:: 2.2 + Updated colour from previous ``0x36393F`` to reflect discord theme changes. + """ + return cls(0x313338) + + @classmethod + def fuchsia(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0xEB459E``. + + .. colour:: #EB459E + + .. versionadded:: 2.0 + """ + return cls(0xEB459E) + + @classmethod + def yellow(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0xFEE75C``. + + .. colour:: #FEE75C + + .. versionadded:: 2.0 + """ + return cls(0xFEE75C) + + @classmethod + def dark_embed(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0x2B2D31``. + + .. colour:: #2B2D31 + + .. versionadded:: 2.2 + """ + return cls(0x2B2D31) + + @classmethod + def light_embed(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0xEEEFF1``. + + .. colour:: #EEEFF1 + + .. versionadded:: 2.2 + """ + return cls(0xEEEFF1) + + @classmethod + def pink(cls) -> Self: + """A factory method that returns a :class:`Colour` with a value of ``0xEB459F``. + + .. colour:: #EB459F + + .. versionadded:: 2.3 + """ + return cls(0xEB459F) + + +Color = Colour diff --git a/venv/lib/python3.12/site-packages/discord/components.py b/venv/lib/python3.12/site-packages/discord/components.py new file mode 100644 index 00000000..b3f978eb --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/components.py @@ -0,0 +1,663 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from __future__ import annotations + +from typing import ClassVar, List, Literal, Optional, TYPE_CHECKING, Tuple, Union, overload +from .enums import try_enum, ComponentType, ButtonStyle, TextStyle, ChannelType, SelectDefaultValueType +from .utils import get_slots, MISSING +from .partial_emoji import PartialEmoji, _EmojiTag + +if TYPE_CHECKING: + from typing_extensions import Self + + from .types.components import ( + Component as ComponentPayload, + ButtonComponent as ButtonComponentPayload, + SelectMenu as SelectMenuPayload, + SelectOption as SelectOptionPayload, + ActionRow as ActionRowPayload, + TextInput as TextInputPayload, + ActionRowChildComponent as ActionRowChildComponentPayload, + SelectDefaultValues as SelectDefaultValuesPayload, + ) + from .emoji import Emoji + from .abc import Snowflake + + ActionRowChildComponentType = Union['Button', 'SelectMenu', 'TextInput'] + + +__all__ = ( + 'Component', + 'ActionRow', + 'Button', + 'SelectMenu', + 'SelectOption', + 'TextInput', + 'SelectDefaultValue', +) + + +class Component: + """Represents a Discord Bot UI Kit Component. + + Currently, the only components supported by Discord are: + + - :class:`ActionRow` + - :class:`Button` + - :class:`SelectMenu` + - :class:`TextInput` + + This class is abstract and cannot be instantiated. + + .. versionadded:: 2.0 + """ + + __slots__: Tuple[str, ...] = () + + __repr_info__: ClassVar[Tuple[str, ...]] + + def __repr__(self) -> str: + attrs = ' '.join(f'{key}={getattr(self, key)!r}' for key in self.__repr_info__) + return f'<{self.__class__.__name__} {attrs}>' + + @property + def type(self) -> ComponentType: + """:class:`ComponentType`: The type of component.""" + raise NotImplementedError + + @classmethod + def _raw_construct(cls, **kwargs) -> Self: + self = cls.__new__(cls) + for slot in get_slots(cls): + try: + value = kwargs[slot] + except KeyError: + pass + else: + setattr(self, slot, value) + return self + + def to_dict(self) -> ComponentPayload: + raise NotImplementedError + + +class ActionRow(Component): + """Represents a Discord Bot UI Kit Action Row. + + This is a component that holds up to 5 children components in a row. + + This inherits from :class:`Component`. + + .. versionadded:: 2.0 + + Attributes + ------------ + children: List[Union[:class:`Button`, :class:`SelectMenu`, :class:`TextInput`]] + The children components that this holds, if any. + """ + + __slots__: Tuple[str, ...] = ('children',) + + __repr_info__: ClassVar[Tuple[str, ...]] = __slots__ + + def __init__(self, data: ActionRowPayload, /) -> None: + self.children: List[ActionRowChildComponentType] = [] + + for component_data in data.get('components', []): + component = _component_factory(component_data) + + if component is not None: + self.children.append(component) + + @property + def type(self) -> Literal[ComponentType.action_row]: + """:class:`ComponentType`: The type of component.""" + return ComponentType.action_row + + def to_dict(self) -> ActionRowPayload: + return { + 'type': self.type.value, + 'components': [child.to_dict() for child in self.children], + } + + +class Button(Component): + """Represents a button from the Discord Bot UI Kit. + + This inherits from :class:`Component`. + + .. note:: + + The user constructible and usable type to create a button is :class:`discord.ui.Button` + not this one. + + .. versionadded:: 2.0 + + Attributes + ----------- + style: :class:`.ButtonStyle` + The style of the button. + custom_id: Optional[:class:`str`] + The ID of the button that gets received during an interaction. + If this button is for a URL, it does not have a custom ID. + url: Optional[:class:`str`] + The URL this button sends you to. + disabled: :class:`bool` + Whether the button is disabled or not. + label: Optional[:class:`str`] + The label of the button, if any. + emoji: Optional[:class:`PartialEmoji`] + The emoji of the button, if available. + sku_id: Optional[:class:`int`] + The SKU ID this button sends you to, if available. + + .. versionadded:: 2.4 + """ + + __slots__: Tuple[str, ...] = ( + 'style', + 'custom_id', + 'url', + 'disabled', + 'label', + 'emoji', + 'sku_id', + ) + + __repr_info__: ClassVar[Tuple[str, ...]] = __slots__ + + def __init__(self, data: ButtonComponentPayload, /) -> None: + self.style: ButtonStyle = try_enum(ButtonStyle, data['style']) + self.custom_id: Optional[str] = data.get('custom_id') + self.url: Optional[str] = data.get('url') + self.disabled: bool = data.get('disabled', False) + self.label: Optional[str] = data.get('label') + self.emoji: Optional[PartialEmoji] + try: + self.emoji = PartialEmoji.from_dict(data['emoji']) # pyright: ignore[reportTypedDictNotRequiredAccess] + except KeyError: + self.emoji = None + + try: + self.sku_id: Optional[int] = int(data['sku_id']) # pyright: ignore[reportTypedDictNotRequiredAccess] + except KeyError: + self.sku_id = None + + @property + def type(self) -> Literal[ComponentType.button]: + """:class:`ComponentType`: The type of component.""" + return ComponentType.button + + def to_dict(self) -> ButtonComponentPayload: + payload: ButtonComponentPayload = { + 'type': 2, + 'style': self.style.value, + 'disabled': self.disabled, + } + + if self.sku_id: + payload['sku_id'] = str(self.sku_id) + + if self.label: + payload['label'] = self.label + + if self.custom_id: + payload['custom_id'] = self.custom_id + + if self.url: + payload['url'] = self.url + + if self.emoji: + payload['emoji'] = self.emoji.to_dict() + + return payload + + +class SelectMenu(Component): + """Represents a select menu from the Discord Bot UI Kit. + + A select menu is functionally the same as a dropdown, however + on mobile it renders a bit differently. + + .. note:: + + The user constructible and usable type to create a select menu is + :class:`discord.ui.Select` not this one. + + .. versionadded:: 2.0 + + Attributes + ------------ + type: :class:`ComponentType` + The type of component. + custom_id: Optional[:class:`str`] + The ID of the select menu that gets received during an interaction. + placeholder: Optional[:class:`str`] + The placeholder text that is shown if nothing is selected, if any. + min_values: :class:`int` + The minimum number of items that must be chosen for this select menu. + Defaults to 1 and must be between 0 and 25. + max_values: :class:`int` + The maximum number of items that must be chosen for this select menu. + Defaults to 1 and must be between 1 and 25. + options: List[:class:`SelectOption`] + A list of options that can be selected in this menu. + disabled: :class:`bool` + Whether the select is disabled or not. + channel_types: List[:class:`.ChannelType`] + A list of channel types that are allowed to be chosen in this select menu. + """ + + __slots__: Tuple[str, ...] = ( + 'type', + 'custom_id', + 'placeholder', + 'min_values', + 'max_values', + 'options', + 'disabled', + 'channel_types', + 'default_values', + ) + + __repr_info__: ClassVar[Tuple[str, ...]] = __slots__ + + def __init__(self, data: SelectMenuPayload, /) -> None: + self.type: ComponentType = try_enum(ComponentType, data['type']) + self.custom_id: str = data['custom_id'] + self.placeholder: Optional[str] = data.get('placeholder') + self.min_values: int = data.get('min_values', 1) + self.max_values: int = data.get('max_values', 1) + self.options: List[SelectOption] = [SelectOption.from_dict(option) for option in data.get('options', [])] + self.disabled: bool = data.get('disabled', False) + self.channel_types: List[ChannelType] = [try_enum(ChannelType, t) for t in data.get('channel_types', [])] + self.default_values: List[SelectDefaultValue] = [ + SelectDefaultValue.from_dict(d) for d in data.get('default_values', []) + ] + + def to_dict(self) -> SelectMenuPayload: + payload: SelectMenuPayload = { + 'type': self.type.value, # type: ignore # we know this is a select menu. + 'custom_id': self.custom_id, + 'min_values': self.min_values, + 'max_values': self.max_values, + 'disabled': self.disabled, + } + if self.placeholder: + payload['placeholder'] = self.placeholder + if self.options: + payload['options'] = [op.to_dict() for op in self.options] + if self.channel_types: + payload['channel_types'] = [t.value for t in self.channel_types] + if self.default_values: + payload["default_values"] = [v.to_dict() for v in self.default_values] + + return payload + + +class SelectOption: + """Represents a select menu's option. + + These can be created by users. + + .. versionadded:: 2.0 + + Parameters + ----------- + label: :class:`str` + The label of the option. This is displayed to users. + Can only be up to 100 characters. + value: :class:`str` + The value of the option. This is not displayed to users. + If not provided when constructed then it defaults to the label. + Can only be up to 100 characters. + description: Optional[:class:`str`] + An additional description of the option, if any. + Can only be up to 100 characters. + emoji: Optional[Union[:class:`str`, :class:`Emoji`, :class:`PartialEmoji`]] + The emoji of the option, if available. + default: :class:`bool` + Whether this option is selected by default. + + Attributes + ----------- + label: :class:`str` + The label of the option. This is displayed to users. + value: :class:`str` + The value of the option. This is not displayed to users. + If not provided when constructed then it defaults to the + label. + description: Optional[:class:`str`] + An additional description of the option, if any. + default: :class:`bool` + Whether this option is selected by default. + """ + + __slots__: Tuple[str, ...] = ( + 'label', + 'value', + 'description', + '_emoji', + 'default', + ) + + def __init__( + self, + *, + label: str, + value: str = MISSING, + description: Optional[str] = None, + emoji: Optional[Union[str, Emoji, PartialEmoji]] = None, + default: bool = False, + ) -> None: + self.label: str = label + self.value: str = label if value is MISSING else value + self.description: Optional[str] = description + + self.emoji = emoji + self.default: bool = default + + def __repr__(self) -> str: + return ( + f'' + ) + + def __str__(self) -> str: + if self.emoji: + base = f'{self.emoji} {self.label}' + else: + base = self.label + + if self.description: + return f'{base}\n{self.description}' + return base + + @property + def emoji(self) -> Optional[PartialEmoji]: + """Optional[:class:`.PartialEmoji`]: The emoji of the option, if available.""" + return self._emoji + + @emoji.setter + def emoji(self, value: Optional[Union[str, Emoji, PartialEmoji]]) -> None: + if value is not None: + if isinstance(value, str): + self._emoji = PartialEmoji.from_str(value) + elif isinstance(value, _EmojiTag): + self._emoji = value._to_partial() + else: + raise TypeError(f'expected str, Emoji, or PartialEmoji, received {value.__class__.__name__} instead') + else: + self._emoji = None + + @classmethod + def from_dict(cls, data: SelectOptionPayload) -> SelectOption: + try: + emoji = PartialEmoji.from_dict(data['emoji']) # pyright: ignore[reportTypedDictNotRequiredAccess] + except KeyError: + emoji = None + + return cls( + label=data['label'], + value=data['value'], + description=data.get('description'), + emoji=emoji, + default=data.get('default', False), + ) + + def to_dict(self) -> SelectOptionPayload: + payload: SelectOptionPayload = { + 'label': self.label, + 'value': self.value, + 'default': self.default, + } + + if self.emoji: + payload['emoji'] = self.emoji.to_dict() + + if self.description: + payload['description'] = self.description + + return payload + + +class TextInput(Component): + """Represents a text input from the Discord Bot UI Kit. + + .. note:: + The user constructible and usable type to create a text input is + :class:`discord.ui.TextInput` not this one. + + .. versionadded:: 2.0 + + Attributes + ------------ + custom_id: Optional[:class:`str`] + The ID of the text input that gets received during an interaction. + label: :class:`str` + The label to display above the text input. + style: :class:`TextStyle` + The style of the text input. + placeholder: Optional[:class:`str`] + The placeholder text to display when the text input is empty. + value: Optional[:class:`str`] + The default value of the text input. + required: :class:`bool` + Whether the text input is required. + min_length: Optional[:class:`int`] + The minimum length of the text input. + max_length: Optional[:class:`int`] + The maximum length of the text input. + """ + + __slots__: Tuple[str, ...] = ( + 'style', + 'label', + 'custom_id', + 'placeholder', + 'value', + 'required', + 'min_length', + 'max_length', + ) + + __repr_info__: ClassVar[Tuple[str, ...]] = __slots__ + + def __init__(self, data: TextInputPayload, /) -> None: + self.style: TextStyle = try_enum(TextStyle, data['style']) + self.label: str = data['label'] + self.custom_id: str = data['custom_id'] + self.placeholder: Optional[str] = data.get('placeholder') + self.value: Optional[str] = data.get('value') + self.required: bool = data.get('required', True) + self.min_length: Optional[int] = data.get('min_length') + self.max_length: Optional[int] = data.get('max_length') + + @property + def type(self) -> Literal[ComponentType.text_input]: + """:class:`ComponentType`: The type of component.""" + return ComponentType.text_input + + def to_dict(self) -> TextInputPayload: + payload: TextInputPayload = { + 'type': self.type.value, + 'style': self.style.value, + 'label': self.label, + 'custom_id': self.custom_id, + 'required': self.required, + } + + if self.placeholder: + payload['placeholder'] = self.placeholder + + if self.value: + payload['value'] = self.value + + if self.min_length: + payload['min_length'] = self.min_length + + if self.max_length: + payload['max_length'] = self.max_length + + return payload + + @property + def default(self) -> Optional[str]: + """Optional[:class:`str`]: The default value of the text input. + + This is an alias to :attr:`value`. + """ + return self.value + + +class SelectDefaultValue: + """Represents a select menu's default value. + + These can be created by users. + + .. versionadded:: 2.4 + + Parameters + ----------- + id: :class:`int` + The id of a role, user, or channel. + type: :class:`SelectDefaultValueType` + The type of value that ``id`` represents. + """ + + def __init__( + self, + *, + id: int, + type: SelectDefaultValueType, + ) -> None: + self.id: int = id + self._type: SelectDefaultValueType = type + + @property + def type(self) -> SelectDefaultValueType: + """:class:`SelectDefaultValueType`: The type of value that ``id`` represents.""" + return self._type + + @type.setter + def type(self, value: SelectDefaultValueType) -> None: + if not isinstance(value, SelectDefaultValueType): + raise TypeError(f'expected SelectDefaultValueType, received {value.__class__.__name__} instead') + + self._type = value + + def __repr__(self) -> str: + return f'' + + @classmethod + def from_dict(cls, data: SelectDefaultValuesPayload) -> SelectDefaultValue: + return cls( + id=data['id'], + type=try_enum(SelectDefaultValueType, data['type']), + ) + + def to_dict(self) -> SelectDefaultValuesPayload: + return { + 'id': self.id, + 'type': self._type.value, + } + + @classmethod + def from_channel(cls, channel: Snowflake, /) -> Self: + """Creates a :class:`SelectDefaultValue` with the type set to :attr:`~SelectDefaultValueType.channel`. + + Parameters + ----------- + channel: :class:`~discord.abc.Snowflake` + The channel to create the default value for. + + Returns + -------- + :class:`SelectDefaultValue` + The default value created with the channel. + """ + return cls( + id=channel.id, + type=SelectDefaultValueType.channel, + ) + + @classmethod + def from_role(cls, role: Snowflake, /) -> Self: + """Creates a :class:`SelectDefaultValue` with the type set to :attr:`~SelectDefaultValueType.role`. + + Parameters + ----------- + role: :class:`~discord.abc.Snowflake` + The role to create the default value for. + + Returns + -------- + :class:`SelectDefaultValue` + The default value created with the role. + """ + return cls( + id=role.id, + type=SelectDefaultValueType.role, + ) + + @classmethod + def from_user(cls, user: Snowflake, /) -> Self: + """Creates a :class:`SelectDefaultValue` with the type set to :attr:`~SelectDefaultValueType.user`. + + Parameters + ----------- + user: :class:`~discord.abc.Snowflake` + The user to create the default value for. + + Returns + -------- + :class:`SelectDefaultValue` + The default value created with the user. + """ + return cls( + id=user.id, + type=SelectDefaultValueType.user, + ) + + +@overload +def _component_factory(data: ActionRowChildComponentPayload) -> Optional[ActionRowChildComponentType]: + ... + + +@overload +def _component_factory(data: ComponentPayload) -> Optional[Union[ActionRow, ActionRowChildComponentType]]: + ... + + +def _component_factory(data: ComponentPayload) -> Optional[Union[ActionRow, ActionRowChildComponentType]]: + if data['type'] == 1: + return ActionRow(data) + elif data['type'] == 2: + return Button(data) + elif data['type'] == 4: + return TextInput(data) + elif data['type'] in (3, 5, 6, 7, 8): + return SelectMenu(data) diff --git a/venv/lib/python3.12/site-packages/discord/context_managers.py b/venv/lib/python3.12/site-packages/discord/context_managers.py new file mode 100644 index 00000000..09803c95 --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/context_managers.py @@ -0,0 +1,92 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from __future__ import annotations + +import asyncio +from typing import TYPE_CHECKING, Generator, Optional, Type, TypeVar + +if TYPE_CHECKING: + from .abc import Messageable, MessageableChannel + + from types import TracebackType + + BE = TypeVar('BE', bound=BaseException) + +# fmt: off +__all__ = ( + 'Typing', +) +# fmt: on + + +def _typing_done_callback(fut: asyncio.Future) -> None: + # just retrieve any exception and call it a day + try: + fut.exception() + except (asyncio.CancelledError, Exception): + pass + + +class Typing: + def __init__(self, messageable: Messageable) -> None: + self.loop: asyncio.AbstractEventLoop = messageable._state.loop + self.messageable: Messageable = messageable + self.channel: Optional[MessageableChannel] = None + + async def _get_channel(self) -> MessageableChannel: + if self.channel: + return self.channel + + self.channel = channel = await self.messageable._get_channel() + return channel + + async def wrapped_typer(self) -> None: + channel = await self._get_channel() + await channel._state.http.send_typing(channel.id) + + def __await__(self) -> Generator[None, None, None]: + return self.wrapped_typer().__await__() + + async def do_typing(self) -> None: + channel = await self._get_channel() + typing = channel._state.http.send_typing + + while True: + await asyncio.sleep(5) + await typing(channel.id) + + async def __aenter__(self) -> None: + channel = await self._get_channel() + await channel._state.http.send_typing(channel.id) + self.task: asyncio.Task[None] = self.loop.create_task(self.do_typing()) + self.task.add_done_callback(_typing_done_callback) + + async def __aexit__( + self, + exc_type: Optional[Type[BE]], + exc: Optional[BE], + traceback: Optional[TracebackType], + ) -> None: + self.task.cancel() diff --git a/venv/lib/python3.12/site-packages/discord/embeds.py b/venv/lib/python3.12/site-packages/discord/embeds.py new file mode 100644 index 00000000..7f84e410 --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/embeds.py @@ -0,0 +1,779 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from __future__ import annotations + +import datetime +from typing import Any, Dict, List, Mapping, Optional, Protocol, TYPE_CHECKING, TypeVar, Union + +from . import utils +from .colour import Colour +from .flags import AttachmentFlags, EmbedFlags + +# fmt: off +__all__ = ( + 'Embed', +) +# fmt: on + + +class EmbedProxy: + def __init__(self, layer: Dict[str, Any]): + self.__dict__.update(layer) + + def __len__(self) -> int: + return len(self.__dict__) + + def __repr__(self) -> str: + inner = ', '.join((f'{k}={getattr(self, k)!r}' for k in dir(self) if not k.startswith('_'))) + return f'EmbedProxy({inner})' + + def __getattr__(self, attr: str) -> None: + return None + + def __eq__(self, other: object) -> bool: + return isinstance(other, EmbedProxy) and self.__dict__ == other.__dict__ + + +class EmbedMediaProxy(EmbedProxy): + def __init__(self, layer: Dict[str, Any]): + super().__init__(layer) + self._flags = self.__dict__.pop('flags', 0) + + @property + def flags(self) -> AttachmentFlags: + return AttachmentFlags._from_value(self._flags or 0) + + +if TYPE_CHECKING: + from typing_extensions import Self + + from .types.embed import Embed as EmbedData, EmbedType + + T = TypeVar('T') + + class _EmbedFooterProxy(Protocol): + text: Optional[str] + icon_url: Optional[str] + + class _EmbedFieldProxy(Protocol): + name: Optional[str] + value: Optional[str] + inline: bool + + class _EmbedMediaProxy(Protocol): + url: Optional[str] + proxy_url: Optional[str] + height: Optional[int] + width: Optional[int] + flags: AttachmentFlags + + class _EmbedProviderProxy(Protocol): + name: Optional[str] + url: Optional[str] + + class _EmbedAuthorProxy(Protocol): + name: Optional[str] + url: Optional[str] + icon_url: Optional[str] + proxy_icon_url: Optional[str] + + +class Embed: + """Represents a Discord embed. + + .. container:: operations + + .. describe:: len(x) + + Returns the total size of the embed. + Useful for checking if it's within the 6000 character limit. + + .. describe:: bool(b) + + Returns whether the embed has any data set. + + .. versionadded:: 2.0 + + .. describe:: x == y + + Checks if two embeds are equal. + + .. versionadded:: 2.0 + + For ease of use, all parameters that expect a :class:`str` are implicitly + casted to :class:`str` for you. + + .. versionchanged:: 2.0 + ``Embed.Empty`` has been removed in favour of ``None``. + + Attributes + ----------- + title: Optional[:class:`str`] + The title of the embed. + This can be set during initialisation. + Can only be up to 256 characters. + type: :class:`str` + The type of embed. Usually "rich". + This can be set during initialisation. + Possible strings for embed types can be found on discord's + :ddocs:`api docs ` + description: Optional[:class:`str`] + The description of the embed. + This can be set during initialisation. + Can only be up to 4096 characters. + url: Optional[:class:`str`] + The URL of the embed. + This can be set during initialisation. + timestamp: Optional[:class:`datetime.datetime`] + The timestamp of the embed content. This is an aware datetime. + If a naive datetime is passed, it is converted to an aware + datetime with the local timezone. + colour: Optional[Union[:class:`Colour`, :class:`int`]] + The colour code of the embed. Aliased to ``color`` as well. + This can be set during initialisation. + """ + + __slots__ = ( + 'title', + 'url', + 'type', + '_timestamp', + '_colour', + '_footer', + '_image', + '_thumbnail', + '_video', + '_provider', + '_author', + '_fields', + 'description', + '_flags', + ) + + def __init__( + self, + *, + colour: Optional[Union[int, Colour]] = None, + color: Optional[Union[int, Colour]] = None, + title: Optional[Any] = None, + type: EmbedType = 'rich', + url: Optional[Any] = None, + description: Optional[Any] = None, + timestamp: Optional[datetime.datetime] = None, + ): + + self.colour = colour if colour is not None else color + self.title: Optional[str] = title + self.type: EmbedType = type + self.url: Optional[str] = url + self.description: Optional[str] = description + self._flags: int = 0 + + if self.title is not None: + self.title = str(self.title) + + if self.description is not None: + self.description = str(self.description) + + if self.url is not None: + self.url = str(self.url) + + if timestamp is not None: + self.timestamp = timestamp + + @classmethod + def from_dict(cls, data: Mapping[str, Any]) -> Self: + """Converts a :class:`dict` to a :class:`Embed` provided it is in the + format that Discord expects it to be in. + + You can find out about this format in the :ddocs:`official Discord documentation `. + + Parameters + ----------- + data: :class:`dict` + The dictionary to convert into an embed. + """ + # we are bypassing __init__ here since it doesn't apply here + self = cls.__new__(cls) + + # fill in the basic fields + + self.title = data.get('title', None) + self.type = data.get('type', None) + self.description = data.get('description', None) + self.url = data.get('url', None) + self._flags = data.get('flags', 0) + + if self.title is not None: + self.title = str(self.title) + + if self.description is not None: + self.description = str(self.description) + + if self.url is not None: + self.url = str(self.url) + + # try to fill in the more rich fields + + try: + self._colour = Colour(value=data['color']) + except KeyError: + pass + + try: + self._timestamp = utils.parse_time(data['timestamp']) + except KeyError: + pass + + for attr in ('thumbnail', 'video', 'provider', 'author', 'fields', 'image', 'footer'): + try: + value = data[attr] + except KeyError: + continue + else: + setattr(self, '_' + attr, value) + + return self + + def copy(self) -> Self: + """Returns a shallow copy of the embed.""" + return self.__class__.from_dict(self.to_dict()) + + def __len__(self) -> int: + total = len(self.title or '') + len(self.description or '') + for field in getattr(self, '_fields', []): + total += len(field['name']) + len(field['value']) + + try: + footer_text = self._footer['text'] + except (AttributeError, KeyError): + pass + else: + total += len(footer_text) + + try: + author = self._author + except AttributeError: + pass + else: + total += len(author['name']) + + return total + + def __bool__(self) -> bool: + return any( + ( + self.title, + self.url, + self.description, + self.colour, + self.fields, + self.timestamp, + self.author, + self.thumbnail, + self.footer, + self.image, + self.provider, + self.video, + ) + ) + + def __eq__(self, other: Embed) -> bool: + return isinstance(other, Embed) and ( + self.type == other.type + and self.title == other.title + and self.url == other.url + and self.description == other.description + and self.colour == other.colour + and self.fields == other.fields + and self.timestamp == other.timestamp + and self.author == other.author + and self.thumbnail == other.thumbnail + and self.footer == other.footer + and self.image == other.image + and self.provider == other.provider + and self.video == other.video + and self._flags == other._flags + ) + + @property + def flags(self) -> EmbedFlags: + """:class:`EmbedFlags`: The flags of this embed. + + .. versionadded:: 2.5 + """ + return EmbedFlags._from_value(self._flags or 0) + + @property + def colour(self) -> Optional[Colour]: + return getattr(self, '_colour', None) + + @colour.setter + def colour(self, value: Optional[Union[int, Colour]]) -> None: + if value is None: + self._colour = None + elif isinstance(value, Colour): + self._colour = value + elif isinstance(value, int): + self._colour = Colour(value=value) + else: + raise TypeError(f'Expected discord.Colour, int, or None but received {value.__class__.__name__} instead.') + + color = colour + + @property + def timestamp(self) -> Optional[datetime.datetime]: + return getattr(self, '_timestamp', None) + + @timestamp.setter + def timestamp(self, value: Optional[datetime.datetime]) -> None: + if isinstance(value, datetime.datetime): + if value.tzinfo is None: + value = value.astimezone() + self._timestamp = value + elif value is None: + self._timestamp = None + else: + raise TypeError(f"Expected datetime.datetime or None received {value.__class__.__name__} instead") + + @property + def footer(self) -> _EmbedFooterProxy: + """Returns an ``EmbedProxy`` denoting the footer contents. + + See :meth:`set_footer` for possible values you can access. + + If the attribute has no value then ``None`` is returned. + """ + # Lying to the type checker for better developer UX. + return EmbedProxy(getattr(self, '_footer', {})) # type: ignore + + def set_footer(self, *, text: Optional[Any] = None, icon_url: Optional[Any] = None) -> Self: + """Sets the footer for the embed content. + + This function returns the class instance to allow for fluent-style + chaining. + + Parameters + ----------- + text: :class:`str` + The footer text. Can only be up to 2048 characters. + icon_url: :class:`str` + The URL of the footer icon. Only HTTP(S) is supported. + Inline attachment URLs are also supported, see :ref:`local_image`. + """ + + self._footer = {} + if text is not None: + self._footer['text'] = str(text) + + if icon_url is not None: + self._footer['icon_url'] = str(icon_url) + + return self + + def remove_footer(self) -> Self: + """Clears embed's footer information. + + This function returns the class instance to allow for fluent-style + chaining. + + .. versionadded:: 2.0 + """ + try: + del self._footer + except AttributeError: + pass + + return self + + @property + def image(self) -> _EmbedMediaProxy: + """Returns an ``EmbedProxy`` denoting the image contents. + + Possible attributes you can access are: + + - ``url`` for the image URL. + - ``proxy_url`` for the proxied image URL. + - ``width`` for the image width. + - ``height`` for the image height. + - ``flags`` for the image's attachment flags. + + If the attribute has no value then ``None`` is returned. + """ + # Lying to the type checker for better developer UX. + return EmbedMediaProxy(getattr(self, '_image', {})) # type: ignore + + def set_image(self, *, url: Optional[Any]) -> Self: + """Sets the image for the embed content. + + This function returns the class instance to allow for fluent-style + chaining. + + Parameters + ----------- + url: Optional[:class:`str`] + The source URL for the image. Only HTTP(S) is supported. + If ``None`` is passed, any existing image is removed. + Inline attachment URLs are also supported, see :ref:`local_image`. + """ + + if url is None: + try: + del self._image + except AttributeError: + pass + else: + self._image = { + 'url': str(url), + } + + return self + + @property + def thumbnail(self) -> _EmbedMediaProxy: + """Returns an ``EmbedProxy`` denoting the thumbnail contents. + + Possible attributes you can access are: + + - ``url`` for the thumbnail URL. + - ``proxy_url`` for the proxied thumbnail URL. + - ``width`` for the thumbnail width. + - ``height`` for the thumbnail height. + - ``flags`` for the thumbnail's attachment flags. + + If the attribute has no value then ``None`` is returned. + """ + # Lying to the type checker for better developer UX. + return EmbedMediaProxy(getattr(self, '_thumbnail', {})) # type: ignore + + def set_thumbnail(self, *, url: Optional[Any]) -> Self: + """Sets the thumbnail for the embed content. + + This function returns the class instance to allow for fluent-style + chaining. + + Parameters + ----------- + url: Optional[:class:`str`] + The source URL for the thumbnail. Only HTTP(S) is supported. + If ``None`` is passed, any existing thumbnail is removed. + Inline attachment URLs are also supported, see :ref:`local_image`. + """ + + if url is None: + try: + del self._thumbnail + except AttributeError: + pass + else: + self._thumbnail = { + 'url': str(url), + } + + return self + + @property + def video(self) -> _EmbedMediaProxy: + """Returns an ``EmbedProxy`` denoting the video contents. + + Possible attributes include: + + - ``url`` for the video URL. + - ``proxy_url`` for the proxied video URL. + - ``height`` for the video height. + - ``width`` for the video width. + - ``flags`` for the video's attachment flags. + + If the attribute has no value then ``None`` is returned. + """ + # Lying to the type checker for better developer UX. + return EmbedMediaProxy(getattr(self, '_video', {})) # type: ignore + + @property + def provider(self) -> _EmbedProviderProxy: + """Returns an ``EmbedProxy`` denoting the provider contents. + + The only attributes that might be accessed are ``name`` and ``url``. + + If the attribute has no value then ``None`` is returned. + """ + # Lying to the type checker for better developer UX. + return EmbedProxy(getattr(self, '_provider', {})) # type: ignore + + @property + def author(self) -> _EmbedAuthorProxy: + """Returns an ``EmbedProxy`` denoting the author contents. + + See :meth:`set_author` for possible values you can access. + + If the attribute has no value then ``None`` is returned. + """ + # Lying to the type checker for better developer UX. + return EmbedProxy(getattr(self, '_author', {})) # type: ignore + + def set_author(self, *, name: Any, url: Optional[Any] = None, icon_url: Optional[Any] = None) -> Self: + """Sets the author for the embed content. + + This function returns the class instance to allow for fluent-style + chaining. + + Parameters + ----------- + name: :class:`str` + The name of the author. Can only be up to 256 characters. + url: :class:`str` + The URL for the author. + icon_url: :class:`str` + The URL of the author icon. Only HTTP(S) is supported. + Inline attachment URLs are also supported, see :ref:`local_image`. + """ + + self._author = { + 'name': str(name), + } + + if url is not None: + self._author['url'] = str(url) + + if icon_url is not None: + self._author['icon_url'] = str(icon_url) + + return self + + def remove_author(self) -> Self: + """Clears embed's author information. + + This function returns the class instance to allow for fluent-style + chaining. + + .. versionadded:: 1.4 + """ + try: + del self._author + except AttributeError: + pass + + return self + + @property + def fields(self) -> List[_EmbedFieldProxy]: + """List[``EmbedProxy``]: Returns a :class:`list` of ``EmbedProxy`` denoting the field contents. + + See :meth:`add_field` for possible values you can access. + + If the attribute has no value then ``None`` is returned. + """ + # Lying to the type checker for better developer UX. + return [EmbedProxy(d) for d in getattr(self, '_fields', [])] # type: ignore + + def add_field(self, *, name: Any, value: Any, inline: bool = True) -> Self: + """Adds a field to the embed object. + + This function returns the class instance to allow for fluent-style + chaining. Can only be up to 25 fields. + + Parameters + ----------- + name: :class:`str` + The name of the field. Can only be up to 256 characters. + value: :class:`str` + The value of the field. Can only be up to 1024 characters. + inline: :class:`bool` + Whether the field should be displayed inline. + """ + + field = { + 'inline': inline, + 'name': str(name), + 'value': str(value), + } + + try: + self._fields.append(field) + except AttributeError: + self._fields = [field] + + return self + + def insert_field_at(self, index: int, *, name: Any, value: Any, inline: bool = True) -> Self: + """Inserts a field before a specified index to the embed. + + This function returns the class instance to allow for fluent-style + chaining. Can only be up to 25 fields. + + .. versionadded:: 1.2 + + Parameters + ----------- + index: :class:`int` + The index of where to insert the field. + name: :class:`str` + The name of the field. Can only be up to 256 characters. + value: :class:`str` + The value of the field. Can only be up to 1024 characters. + inline: :class:`bool` + Whether the field should be displayed inline. + """ + + field = { + 'inline': inline, + 'name': str(name), + 'value': str(value), + } + + try: + self._fields.insert(index, field) + except AttributeError: + self._fields = [field] + + return self + + def clear_fields(self) -> Self: + """Removes all fields from this embed. + + This function returns the class instance to allow for fluent-style + chaining. + + .. versionchanged:: 2.0 + This function now returns the class instance. + """ + try: + self._fields.clear() + except AttributeError: + self._fields = [] + + return self + + def remove_field(self, index: int) -> Self: + """Removes a field at a specified index. + + If the index is invalid or out of bounds then the error is + silently swallowed. + + This function returns the class instance to allow for fluent-style + chaining. + + .. note:: + + When deleting a field by index, the index of the other fields + shift to fill the gap just like a regular list. + + .. versionchanged:: 2.0 + This function now returns the class instance. + + Parameters + ----------- + index: :class:`int` + The index of the field to remove. + """ + try: + del self._fields[index] + except (AttributeError, IndexError): + pass + + return self + + def set_field_at(self, index: int, *, name: Any, value: Any, inline: bool = True) -> Self: + """Modifies a field to the embed object. + + The index must point to a valid pre-existing field. Can only be up to 25 fields. + + This function returns the class instance to allow for fluent-style + chaining. + + Parameters + ----------- + index: :class:`int` + The index of the field to modify. + name: :class:`str` + The name of the field. Can only be up to 256 characters. + value: :class:`str` + The value of the field. Can only be up to 1024 characters. + inline: :class:`bool` + Whether the field should be displayed inline. + + Raises + ------- + IndexError + An invalid index was provided. + """ + + try: + field = self._fields[index] + except (TypeError, IndexError, AttributeError): + raise IndexError('field index out of range') + + field['name'] = str(name) + field['value'] = str(value) + field['inline'] = inline + return self + + def to_dict(self) -> EmbedData: + """Converts this embed object into a dict.""" + + # add in the raw data into the dict + # fmt: off + result = { + key[1:]: getattr(self, key) + for key in self.__slots__ + if key[0] == '_' and hasattr(self, key) + } + # fmt: on + + # deal with basic convenience wrappers + + try: + colour = result.pop('colour') + except KeyError: + pass + else: + if colour: + result['color'] = colour.value + + try: + timestamp = result.pop('timestamp') + except KeyError: + pass + else: + if timestamp: + if timestamp.tzinfo: + result['timestamp'] = timestamp.astimezone(tz=datetime.timezone.utc).isoformat() + else: + result['timestamp'] = timestamp.replace(tzinfo=datetime.timezone.utc).isoformat() + + # add in the non raw attribute ones + if self.type: + result['type'] = self.type + + if self.description: + result['description'] = self.description + + if self.url: + result['url'] = self.url + + if self.title: + result['title'] = self.title + + return result # type: ignore # This payload is equivalent to the EmbedData type diff --git a/venv/lib/python3.12/site-packages/discord/emoji.py b/venv/lib/python3.12/site-packages/discord/emoji.py new file mode 100644 index 00000000..74f344ac --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/emoji.py @@ -0,0 +1,302 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from __future__ import annotations +from typing import Any, Collection, Iterator, List, Optional, TYPE_CHECKING, Tuple + +from .asset import Asset, AssetMixin +from .utils import SnowflakeList, snowflake_time, MISSING +from .partial_emoji import _EmojiTag, PartialEmoji +from .user import User +from .errors import MissingApplicationID +from .object import Object + +# fmt: off +__all__ = ( + 'Emoji', +) +# fmt: on + +if TYPE_CHECKING: + from .types.emoji import Emoji as EmojiPayload + from .guild import Guild + from .state import ConnectionState + from .abc import Snowflake + from .role import Role + from datetime import datetime + + +class Emoji(_EmojiTag, AssetMixin): + """Represents a custom emoji. + + Depending on the way this object was created, some of the attributes can + have a value of ``None``. + + .. container:: operations + + .. describe:: x == y + + Checks if two emoji are the same. + + .. describe:: x != y + + Checks if two emoji are not the same. + + .. describe:: hash(x) + + Return the emoji's hash. + + .. describe:: iter(x) + + Returns an iterator of ``(field, value)`` pairs. This allows this class + to be used as an iterable in list/dict/etc constructions. + + .. describe:: str(x) + + Returns the emoji rendered for discord. + + Attributes + ----------- + name: :class:`str` + The name of the emoji. + id: :class:`int` + The emoji's ID. + require_colons: :class:`bool` + If colons are required to use this emoji in the client (:PJSalt: vs PJSalt). + animated: :class:`bool` + Whether an emoji is animated or not. + managed: :class:`bool` + If this emoji is managed by a Twitch integration. + guild_id: :class:`int` + The guild ID the emoji belongs to. + available: :class:`bool` + Whether the emoji is available for use. + user: Optional[:class:`User`] + The user that created the emoji. This can only be retrieved using :meth:`Guild.fetch_emoji` and + having :attr:`~Permissions.manage_emojis`. + + Or if :meth:`.is_application_owned` is ``True``, this is the team member that uploaded + the emoji, or the bot user if it was uploaded using the API and this can + only be retrieved using :meth:`~discord.Client.fetch_application_emoji` or :meth:`~discord.Client.fetch_application_emojis`. + """ + + __slots__: Tuple[str, ...] = ( + 'require_colons', + 'animated', + 'managed', + 'id', + 'name', + '_roles', + 'guild_id', + '_state', + 'user', + 'available', + ) + + def __init__(self, *, guild: Snowflake, state: ConnectionState, data: EmojiPayload) -> None: + self.guild_id: int = guild.id + self._state: ConnectionState = state + self._from_data(data) + + def _from_data(self, emoji: EmojiPayload) -> None: + self.require_colons: bool = emoji.get('require_colons', False) + self.managed: bool = emoji.get('managed', False) + self.id: int = int(emoji['id']) # type: ignore # This won't be None for full emoji objects. + self.name: str = emoji['name'] # type: ignore # This won't be None for full emoji objects. + self.animated: bool = emoji.get('animated', False) + self.available: bool = emoji.get('available', True) + self._roles: SnowflakeList = SnowflakeList(map(int, emoji.get('roles', []))) + user = emoji.get('user') + self.user: Optional[User] = User(state=self._state, data=user) if user else None + + def _to_partial(self) -> PartialEmoji: + return PartialEmoji(name=self.name, animated=self.animated, id=self.id) + + def __iter__(self) -> Iterator[Tuple[str, Any]]: + for attr in self.__slots__: + if attr[0] != '_': + value = getattr(self, attr, None) + if value is not None: + yield (attr, value) + + def __str__(self) -> str: + if self.animated: + return f'' + return f'<:{self.name}:{self.id}>' + + def __repr__(self) -> str: + return f'' + + def __eq__(self, other: object) -> bool: + return isinstance(other, _EmojiTag) and self.id == other.id + + def __ne__(self, other: object) -> bool: + return not self.__eq__(other) + + def __hash__(self) -> int: + return self.id >> 22 + + @property + def created_at(self) -> datetime: + """:class:`datetime.datetime`: Returns the emoji's creation time in UTC.""" + return snowflake_time(self.id) + + @property + def url(self) -> str: + """:class:`str`: Returns the URL of the emoji.""" + fmt = 'gif' if self.animated else 'png' + return f'{Asset.BASE}/emojis/{self.id}.{fmt}' + + @property + def roles(self) -> List[Role]: + """List[:class:`Role`]: A :class:`list` of roles that is allowed to use this emoji. + + If roles is empty, the emoji is unrestricted. + """ + guild = self.guild + if guild is None: + return [] + + return [role for role in guild.roles if self._roles.has(role.id)] + + @property + def guild(self) -> Optional[Guild]: + """:class:`Guild`: The guild this emoji belongs to.""" + return self._state._get_guild(self.guild_id) + + def is_usable(self) -> bool: + """:class:`bool`: Whether the bot can use this emoji. + + .. versionadded:: 1.3 + """ + if not self.available or not self.guild or self.guild.unavailable: + return False + if not self._roles: + return True + emoji_roles, my_roles = self._roles, self.guild.me._roles + return any(my_roles.has(role_id) for role_id in emoji_roles) + + async def delete(self, *, reason: Optional[str] = None) -> None: + """|coro| + + Deletes the custom emoji. + + You must have :attr:`~Permissions.manage_emojis` to do this if + :meth:`.is_application_owned` is ``False``. + + Parameters + ----------- + reason: Optional[:class:`str`] + The reason for deleting this emoji. Shows up on the audit log. + + This does not apply if :meth:`.is_application_owned` is ``True``. + + Raises + ------- + Forbidden + You are not allowed to delete emojis. + HTTPException + An error occurred deleting the emoji. + MissingApplicationID + The emoji is owned by an application but the application ID is missing. + """ + if self.is_application_owned(): + application_id = self._state.application_id + if application_id is None: + raise MissingApplicationID + + await self._state.http.delete_application_emoji(application_id, self.id) + return + + await self._state.http.delete_custom_emoji(self.guild_id, self.id, reason=reason) + + async def edit( + self, *, name: str = MISSING, roles: Collection[Snowflake] = MISSING, reason: Optional[str] = None + ) -> Emoji: + r"""|coro| + + Edits the custom emoji. + + You must have :attr:`~Permissions.manage_emojis` to do this. + + .. versionchanged:: 2.0 + The newly updated emoji is returned. + + Parameters + ----------- + name: :class:`str` + The new emoji name. + roles: List[:class:`~discord.abc.Snowflake`] + A list of roles that can use this emoji. An empty list can be passed to make it available to everyone. + + This does not apply if :meth:`.is_application_owned` is ``True``. + + reason: Optional[:class:`str`] + The reason for editing this emoji. Shows up on the audit log. + + This does not apply if :meth:`.is_application_owned` is ``True``. + + Raises + ------- + Forbidden + You are not allowed to edit emojis. + HTTPException + An error occurred editing the emoji. + MissingApplicationID + The emoji is owned by an application but the application ID is missing + + Returns + -------- + :class:`Emoji` + The newly updated emoji. + """ + + payload = {} + if name is not MISSING: + payload['name'] = name + if roles is not MISSING: + payload['roles'] = [role.id for role in roles] + + if self.is_application_owned(): + application_id = self._state.application_id + if application_id is None: + raise MissingApplicationID + + payload.pop('roles', None) + data = await self._state.http.edit_application_emoji( + application_id, + self.id, + payload=payload, + ) + return Emoji(guild=Object(0), data=data, state=self._state) + + data = await self._state.http.edit_custom_emoji(self.guild_id, self.id, payload=payload, reason=reason) + return Emoji(guild=self.guild, data=data, state=self._state) # type: ignore # if guild is None, the http request would have failed + + def is_application_owned(self) -> bool: + """:class:`bool`: Whether the emoji is owned by an application. + + .. versionadded:: 2.5 + """ + return self.guild_id == 0 diff --git a/venv/lib/python3.12/site-packages/discord/enums.py b/venv/lib/python3.12/site-packages/discord/enums.py new file mode 100644 index 00000000..7915bcb4 --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/enums.py @@ -0,0 +1,881 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" +from __future__ import annotations + +import types +from collections import namedtuple +from typing import Any, ClassVar, Dict, List, Optional, TYPE_CHECKING, Tuple, Type, TypeVar, Iterator, Mapping + +__all__ = ( + 'Enum', + 'ChannelType', + 'MessageType', + 'SpeakingState', + 'VerificationLevel', + 'ContentFilter', + 'Status', + 'DefaultAvatar', + 'AuditLogAction', + 'AuditLogActionCategory', + 'UserFlags', + 'ActivityType', + 'NotificationLevel', + 'TeamMembershipState', + 'TeamMemberRole', + 'WebhookType', + 'ExpireBehaviour', + 'ExpireBehavior', + 'StickerType', + 'StickerFormatType', + 'InviteTarget', + 'VideoQualityMode', + 'ComponentType', + 'ButtonStyle', + 'TextStyle', + 'PrivacyLevel', + 'InteractionType', + 'InteractionResponseType', + 'NSFWLevel', + 'MFALevel', + 'Locale', + 'EntityType', + 'EventStatus', + 'AppCommandType', + 'AppCommandOptionType', + 'AppCommandPermissionType', + 'AutoModRuleTriggerType', + 'AutoModRuleEventType', + 'AutoModRuleActionType', + 'ForumLayoutType', + 'ForumOrderType', + 'SelectDefaultValueType', + 'SKUType', + 'EntitlementType', + 'EntitlementOwnerType', + 'PollLayoutType', + 'VoiceChannelEffectAnimationType', + 'SubscriptionStatus', + 'MessageReferenceType', +) + + +def _create_value_cls(name: str, comparable: bool): + # All the type ignores here are due to the type checker being unable to recognise + # Runtime type creation without exploding. + cls = namedtuple('_EnumValue_' + name, 'name value') + cls.__repr__ = lambda self: f'<{name}.{self.name}: {self.value!r}>' + cls.__str__ = lambda self: f'{name}.{self.name}' + if comparable: + cls.__le__ = lambda self, other: isinstance(other, self.__class__) and self.value <= other.value + cls.__ge__ = lambda self, other: isinstance(other, self.__class__) and self.value >= other.value + cls.__lt__ = lambda self, other: isinstance(other, self.__class__) and self.value < other.value + cls.__gt__ = lambda self, other: isinstance(other, self.__class__) and self.value > other.value + return cls + + +def _is_descriptor(obj): + return hasattr(obj, '__get__') or hasattr(obj, '__set__') or hasattr(obj, '__delete__') + + +class EnumMeta(type): + if TYPE_CHECKING: + __name__: ClassVar[str] + _enum_member_names_: ClassVar[List[str]] + _enum_member_map_: ClassVar[Dict[str, Any]] + _enum_value_map_: ClassVar[Dict[Any, Any]] + + def __new__( + cls, + name: str, + bases: Tuple[type, ...], + attrs: Dict[str, Any], + *, + comparable: bool = False, + ) -> EnumMeta: + value_mapping = {} + member_mapping = {} + member_names = [] + + value_cls = _create_value_cls(name, comparable) + for key, value in list(attrs.items()): + is_descriptor = _is_descriptor(value) + if key[0] == '_' and not is_descriptor: + continue + + # Special case classmethod to just pass through + if isinstance(value, classmethod): + continue + + if is_descriptor: + setattr(value_cls, key, value) + del attrs[key] + continue + + try: + new_value = value_mapping[value] + except KeyError: + new_value = value_cls(name=key, value=value) + value_mapping[value] = new_value + member_names.append(key) + + member_mapping[key] = new_value + attrs[key] = new_value + + attrs['_enum_value_map_'] = value_mapping + attrs['_enum_member_map_'] = member_mapping + attrs['_enum_member_names_'] = member_names + attrs['_enum_value_cls_'] = value_cls + actual_cls = super().__new__(cls, name, bases, attrs) + value_cls._actual_enum_cls_ = actual_cls # type: ignore # Runtime attribute isn't understood + return actual_cls + + def __iter__(cls) -> Iterator[Any]: + return (cls._enum_member_map_[name] for name in cls._enum_member_names_) + + def __reversed__(cls) -> Iterator[Any]: + return (cls._enum_member_map_[name] for name in reversed(cls._enum_member_names_)) + + def __len__(cls) -> int: + return len(cls._enum_member_names_) + + def __repr__(cls) -> str: + return f'' + + @property + def __members__(cls) -> Mapping[str, Any]: + return types.MappingProxyType(cls._enum_member_map_) + + def __call__(cls, value: str) -> Any: + try: + return cls._enum_value_map_[value] + except (KeyError, TypeError): + raise ValueError(f"{value!r} is not a valid {cls.__name__}") + + def __getitem__(cls, key: str) -> Any: + return cls._enum_member_map_[key] + + def __setattr__(cls, name: str, value: Any) -> None: + raise TypeError('Enums are immutable.') + + def __delattr__(cls, attr: str) -> None: + raise TypeError('Enums are immutable') + + def __instancecheck__(self, instance: Any) -> bool: + # isinstance(x, Y) + # -> __instancecheck__(Y, x) + try: + return instance._actual_enum_cls_ is self + except AttributeError: + return False + + +if TYPE_CHECKING: + from enum import Enum +else: + + class Enum(metaclass=EnumMeta): + @classmethod + def try_value(cls, value): + try: + return cls._enum_value_map_[value] + except (KeyError, TypeError): + return value + + +class ChannelType(Enum): + text = 0 + private = 1 + voice = 2 + group = 3 + category = 4 + news = 5 + news_thread = 10 + public_thread = 11 + private_thread = 12 + stage_voice = 13 + forum = 15 + media = 16 + + def __str__(self) -> str: + return self.name + + +class MessageReferenceType(Enum): + default = 0 + reply = 0 + forward = 1 + + +class MessageType(Enum): + default = 0 + recipient_add = 1 + recipient_remove = 2 + call = 3 + channel_name_change = 4 + channel_icon_change = 5 + pins_add = 6 + new_member = 7 + premium_guild_subscription = 8 + premium_guild_tier_1 = 9 + premium_guild_tier_2 = 10 + premium_guild_tier_3 = 11 + channel_follow_add = 12 + guild_stream = 13 + guild_discovery_disqualified = 14 + guild_discovery_requalified = 15 + guild_discovery_grace_period_initial_warning = 16 + guild_discovery_grace_period_final_warning = 17 + thread_created = 18 + reply = 19 + chat_input_command = 20 + thread_starter_message = 21 + guild_invite_reminder = 22 + context_menu_command = 23 + auto_moderation_action = 24 + role_subscription_purchase = 25 + interaction_premium_upsell = 26 + stage_start = 27 + stage_end = 28 + stage_speaker = 29 + stage_raise_hand = 30 + stage_topic = 31 + guild_application_premium_subscription = 32 + guild_incident_alert_mode_enabled = 36 + guild_incident_alert_mode_disabled = 37 + guild_incident_report_raid = 38 + guild_incident_report_false_alarm = 39 + purchase_notification = 44 + poll_result = 46 + + +class SpeakingState(Enum): + none = 0 + voice = 1 + soundshare = 2 + priority = 4 + + def __str__(self) -> str: + return self.name + + def __int__(self) -> int: + return self.value + + +class VerificationLevel(Enum, comparable=True): + none = 0 + low = 1 + medium = 2 + high = 3 + highest = 4 + + def __str__(self) -> str: + return self.name + + +class ContentFilter(Enum, comparable=True): + disabled = 0 + no_role = 1 + all_members = 2 + + def __str__(self) -> str: + return self.name + + +class Status(Enum): + online = 'online' + offline = 'offline' + idle = 'idle' + dnd = 'dnd' + do_not_disturb = 'dnd' + invisible = 'invisible' + + def __str__(self) -> str: + return self.value + + +class DefaultAvatar(Enum): + blurple = 0 + grey = 1 + gray = 1 + green = 2 + orange = 3 + red = 4 + pink = 5 + + def __str__(self) -> str: + return self.name + + +class NotificationLevel(Enum, comparable=True): + all_messages = 0 + only_mentions = 1 + + +class AuditLogActionCategory(Enum): + create = 1 + delete = 2 + update = 3 + + +class AuditLogAction(Enum): + # fmt: off + guild_update = 1 + channel_create = 10 + channel_update = 11 + channel_delete = 12 + overwrite_create = 13 + overwrite_update = 14 + overwrite_delete = 15 + kick = 20 + member_prune = 21 + ban = 22 + unban = 23 + member_update = 24 + member_role_update = 25 + member_move = 26 + member_disconnect = 27 + bot_add = 28 + role_create = 30 + role_update = 31 + role_delete = 32 + invite_create = 40 + invite_update = 41 + invite_delete = 42 + webhook_create = 50 + webhook_update = 51 + webhook_delete = 52 + emoji_create = 60 + emoji_update = 61 + emoji_delete = 62 + message_delete = 72 + message_bulk_delete = 73 + message_pin = 74 + message_unpin = 75 + integration_create = 80 + integration_update = 81 + integration_delete = 82 + stage_instance_create = 83 + stage_instance_update = 84 + stage_instance_delete = 85 + sticker_create = 90 + sticker_update = 91 + sticker_delete = 92 + scheduled_event_create = 100 + scheduled_event_update = 101 + scheduled_event_delete = 102 + thread_create = 110 + thread_update = 111 + thread_delete = 112 + app_command_permission_update = 121 + soundboard_sound_create = 130 + soundboard_sound_update = 131 + soundboard_sound_delete = 132 + automod_rule_create = 140 + automod_rule_update = 141 + automod_rule_delete = 142 + automod_block_message = 143 + automod_flag_message = 144 + automod_timeout_member = 145 + creator_monetization_request_created = 150 + creator_monetization_terms_accepted = 151 + # fmt: on + + @property + def category(self) -> Optional[AuditLogActionCategory]: + # fmt: off + lookup: Dict[AuditLogAction, Optional[AuditLogActionCategory]] = { + AuditLogAction.guild_update: AuditLogActionCategory.update, + AuditLogAction.channel_create: AuditLogActionCategory.create, + AuditLogAction.channel_update: AuditLogActionCategory.update, + AuditLogAction.channel_delete: AuditLogActionCategory.delete, + AuditLogAction.overwrite_create: AuditLogActionCategory.create, + AuditLogAction.overwrite_update: AuditLogActionCategory.update, + AuditLogAction.overwrite_delete: AuditLogActionCategory.delete, + AuditLogAction.kick: None, + AuditLogAction.member_prune: None, + AuditLogAction.ban: None, + AuditLogAction.unban: None, + AuditLogAction.member_update: AuditLogActionCategory.update, + AuditLogAction.member_role_update: AuditLogActionCategory.update, + AuditLogAction.member_move: None, + AuditLogAction.member_disconnect: None, + AuditLogAction.bot_add: None, + AuditLogAction.role_create: AuditLogActionCategory.create, + AuditLogAction.role_update: AuditLogActionCategory.update, + AuditLogAction.role_delete: AuditLogActionCategory.delete, + AuditLogAction.invite_create: AuditLogActionCategory.create, + AuditLogAction.invite_update: AuditLogActionCategory.update, + AuditLogAction.invite_delete: AuditLogActionCategory.delete, + AuditLogAction.webhook_create: AuditLogActionCategory.create, + AuditLogAction.webhook_update: AuditLogActionCategory.update, + AuditLogAction.webhook_delete: AuditLogActionCategory.delete, + AuditLogAction.emoji_create: AuditLogActionCategory.create, + AuditLogAction.emoji_update: AuditLogActionCategory.update, + AuditLogAction.emoji_delete: AuditLogActionCategory.delete, + AuditLogAction.message_delete: AuditLogActionCategory.delete, + AuditLogAction.message_bulk_delete: AuditLogActionCategory.delete, + AuditLogAction.message_pin: None, + AuditLogAction.message_unpin: None, + AuditLogAction.integration_create: AuditLogActionCategory.create, + AuditLogAction.integration_update: AuditLogActionCategory.update, + AuditLogAction.integration_delete: AuditLogActionCategory.delete, + AuditLogAction.stage_instance_create: AuditLogActionCategory.create, + AuditLogAction.stage_instance_update: AuditLogActionCategory.update, + AuditLogAction.stage_instance_delete: AuditLogActionCategory.delete, + AuditLogAction.sticker_create: AuditLogActionCategory.create, + AuditLogAction.sticker_update: AuditLogActionCategory.update, + AuditLogAction.sticker_delete: AuditLogActionCategory.delete, + AuditLogAction.scheduled_event_create: AuditLogActionCategory.create, + AuditLogAction.scheduled_event_update: AuditLogActionCategory.update, + AuditLogAction.scheduled_event_delete: AuditLogActionCategory.delete, + AuditLogAction.thread_create: AuditLogActionCategory.create, + AuditLogAction.thread_delete: AuditLogActionCategory.delete, + AuditLogAction.thread_update: AuditLogActionCategory.update, + AuditLogAction.app_command_permission_update: AuditLogActionCategory.update, + AuditLogAction.automod_rule_create: AuditLogActionCategory.create, + AuditLogAction.automod_rule_update: AuditLogActionCategory.update, + AuditLogAction.automod_rule_delete: AuditLogActionCategory.delete, + AuditLogAction.automod_block_message: None, + AuditLogAction.automod_flag_message: None, + AuditLogAction.automod_timeout_member: None, + AuditLogAction.creator_monetization_request_created: None, + AuditLogAction.creator_monetization_terms_accepted: None, + AuditLogAction.soundboard_sound_create: AuditLogActionCategory.create, + AuditLogAction.soundboard_sound_update: AuditLogActionCategory.update, + AuditLogAction.soundboard_sound_delete: AuditLogActionCategory.delete, + } + # fmt: on + return lookup[self] + + @property + def target_type(self) -> Optional[str]: + v = self.value + if v == -1: + return 'all' + elif v < 10: + return 'guild' + elif v < 20: + return 'channel' + elif v < 30: + return 'user' + elif v < 40: + return 'role' + elif v < 50: + return 'invite' + elif v < 60: + return 'webhook' + elif v < 70: + return 'emoji' + elif v == 73: + return 'channel' + elif v < 80: + return 'message' + elif v < 83: + return 'integration' + elif v < 90: + return 'stage_instance' + elif v < 93: + return 'sticker' + elif v < 103: + return 'guild_scheduled_event' + elif v < 113: + return 'thread' + elif v < 122: + return 'integration_or_app_command' + elif 139 < v < 143: + return 'auto_moderation' + elif v < 146: + return 'user' + elif v < 152: + return 'creator_monetization' + + +class UserFlags(Enum): + staff = 1 + partner = 2 + hypesquad = 4 + bug_hunter = 8 + mfa_sms = 16 + premium_promo_dismissed = 32 + hypesquad_bravery = 64 + hypesquad_brilliance = 128 + hypesquad_balance = 256 + early_supporter = 512 + team_user = 1024 + system = 4096 + has_unread_urgent_messages = 8192 + bug_hunter_level_2 = 16384 + verified_bot = 65536 + verified_bot_developer = 131072 + discord_certified_moderator = 262144 + bot_http_interactions = 524288 + spammer = 1048576 + active_developer = 4194304 + + +class ActivityType(Enum): + unknown = -1 + playing = 0 + streaming = 1 + listening = 2 + watching = 3 + custom = 4 + competing = 5 + + def __int__(self) -> int: + return self.value + + +class TeamMembershipState(Enum): + invited = 1 + accepted = 2 + + +class TeamMemberRole(Enum): + admin = 'admin' + developer = 'developer' + read_only = 'read_only' + + +class WebhookType(Enum): + incoming = 1 + channel_follower = 2 + application = 3 + + +class ExpireBehaviour(Enum): + remove_role = 0 + kick = 1 + + +ExpireBehavior = ExpireBehaviour + + +class StickerType(Enum): + standard = 1 + guild = 2 + + +class StickerFormatType(Enum): + png = 1 + apng = 2 + lottie = 3 + gif = 4 + + @property + def file_extension(self) -> str: + # fmt: off + lookup: Dict[StickerFormatType, str] = { + StickerFormatType.png: 'png', + StickerFormatType.apng: 'png', + StickerFormatType.lottie: 'json', + StickerFormatType.gif: 'gif', + } + # fmt: on + return lookup.get(self, 'png') + + +class InviteTarget(Enum): + unknown = 0 + stream = 1 + embedded_application = 2 + + +class InteractionType(Enum): + ping = 1 + application_command = 2 + component = 3 + autocomplete = 4 + modal_submit = 5 + + +class InteractionResponseType(Enum): + pong = 1 + # ack = 2 (deprecated) + # channel_message = 3 (deprecated) + channel_message = 4 # (with source) + deferred_channel_message = 5 # (with source) + deferred_message_update = 6 # for components + message_update = 7 # for components + autocomplete_result = 8 + modal = 9 # for modals + # premium_required = 10 (deprecated) + + +class VideoQualityMode(Enum): + auto = 1 + full = 2 + + def __int__(self) -> int: + return self.value + + +class ComponentType(Enum): + action_row = 1 + button = 2 + select = 3 + string_select = 3 + text_input = 4 + user_select = 5 + role_select = 6 + mentionable_select = 7 + channel_select = 8 + + def __int__(self) -> int: + return self.value + + +class ButtonStyle(Enum): + primary = 1 + secondary = 2 + success = 3 + danger = 4 + link = 5 + premium = 6 + + # Aliases + blurple = 1 + grey = 2 + gray = 2 + green = 3 + red = 4 + url = 5 + + def __int__(self) -> int: + return self.value + + +class TextStyle(Enum): + short = 1 + paragraph = 2 + + # Aliases + long = 2 + + def __int__(self) -> int: + return self.value + + +class PrivacyLevel(Enum): + guild_only = 2 + + +class NSFWLevel(Enum, comparable=True): + default = 0 + explicit = 1 + safe = 2 + age_restricted = 3 + + +class MFALevel(Enum, comparable=True): + disabled = 0 + require_2fa = 1 + + +class Locale(Enum): + american_english = 'en-US' + british_english = 'en-GB' + bulgarian = 'bg' + chinese = 'zh-CN' + taiwan_chinese = 'zh-TW' + croatian = 'hr' + czech = 'cs' + indonesian = 'id' + danish = 'da' + dutch = 'nl' + finnish = 'fi' + french = 'fr' + german = 'de' + greek = 'el' + hindi = 'hi' + hungarian = 'hu' + italian = 'it' + japanese = 'ja' + korean = 'ko' + latin_american_spanish = 'es-419' + lithuanian = 'lt' + norwegian = 'no' + polish = 'pl' + brazil_portuguese = 'pt-BR' + romanian = 'ro' + russian = 'ru' + spain_spanish = 'es-ES' + swedish = 'sv-SE' + thai = 'th' + turkish = 'tr' + ukrainian = 'uk' + vietnamese = 'vi' + + def __str__(self) -> str: + return self.value + + +E = TypeVar('E', bound='Enum') + + +class EntityType(Enum): + stage_instance = 1 + voice = 2 + external = 3 + + +class EventStatus(Enum): + scheduled = 1 + active = 2 + completed = 3 + canceled = 4 + + ended = 3 + cancelled = 4 + + +class AppCommandOptionType(Enum): + subcommand = 1 + subcommand_group = 2 + string = 3 + integer = 4 + boolean = 5 + user = 6 + channel = 7 + role = 8 + mentionable = 9 + number = 10 + attachment = 11 + + +class AppCommandType(Enum): + chat_input = 1 + user = 2 + message = 3 + + +class AppCommandPermissionType(Enum): + role = 1 + user = 2 + channel = 3 + + +class AutoModRuleTriggerType(Enum): + keyword = 1 + harmful_link = 2 + spam = 3 + keyword_preset = 4 + mention_spam = 5 + member_profile = 6 + + +class AutoModRuleEventType(Enum): + message_send = 1 + member_update = 2 + + +class AutoModRuleActionType(Enum): + block_message = 1 + send_alert_message = 2 + timeout = 3 + block_member_interactions = 4 + + +class ForumLayoutType(Enum): + not_set = 0 + list_view = 1 + gallery_view = 2 + + +class ForumOrderType(Enum): + latest_activity = 0 + creation_date = 1 + + +class SelectDefaultValueType(Enum): + user = 'user' + role = 'role' + channel = 'channel' + + +class SKUType(Enum): + durable = 2 + consumable = 3 + subscription = 5 + subscription_group = 6 + + +class EntitlementType(Enum): + purchase = 1 + premium_subscription = 2 + developer_gift = 3 + test_mode_purchase = 4 + free_purchase = 5 + user_gift = 6 + premium_purchase = 7 + application_subscription = 8 + + +class EntitlementOwnerType(Enum): + guild = 1 + user = 2 + + +class PollLayoutType(Enum): + default = 1 + + +class InviteType(Enum): + guild = 0 + group_dm = 1 + friend = 2 + + +class ReactionType(Enum): + normal = 0 + burst = 1 + + +class VoiceChannelEffectAnimationType(Enum): + premium = 0 + basic = 1 + + +class SubscriptionStatus(Enum): + active = 0 + ending = 1 + inactive = 2 + + +def create_unknown_value(cls: Type[E], val: Any) -> E: + value_cls = cls._enum_value_cls_ # type: ignore # This is narrowed below + name = f'unknown_{val}' + return value_cls(name=name, value=val) + + +def try_enum(cls: Type[E], val: Any) -> E: + """A function that tries to turn the value into enum ``cls``. + + If it fails it returns a proxy invalid value instead. + """ + + try: + return cls._enum_value_map_[val] # type: ignore # All errors are caught below + except (KeyError, TypeError, AttributeError): + return create_unknown_value(cls, val) diff --git a/venv/lib/python3.12/site-packages/discord/errors.py b/venv/lib/python3.12/site-packages/discord/errors.py new file mode 100644 index 00000000..a4084257 --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/errors.py @@ -0,0 +1,305 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from __future__ import annotations +from typing import Dict, List, Optional, TYPE_CHECKING, Any, Tuple, Union + +if TYPE_CHECKING: + from aiohttp import ClientResponse, ClientWebSocketResponse + from requests import Response + + _ResponseType = Union[ClientResponse, Response] + + from .interactions import Interaction + +__all__ = ( + 'DiscordException', + 'ClientException', + 'GatewayNotFound', + 'HTTPException', + 'RateLimited', + 'Forbidden', + 'NotFound', + 'DiscordServerError', + 'InvalidData', + 'LoginFailure', + 'ConnectionClosed', + 'PrivilegedIntentsRequired', + 'InteractionResponded', + 'MissingApplicationID', +) + +APP_ID_NOT_FOUND = ( + 'Client does not have an application_id set. Either the function was called before on_ready ' + 'was called or application_id was not passed to the Client constructor.' +) + + +class DiscordException(Exception): + """Base exception class for discord.py + + Ideally speaking, this could be caught to handle any exceptions raised from this library. + """ + + pass + + +class ClientException(DiscordException): + """Exception that's raised when an operation in the :class:`Client` fails. + + These are usually for exceptions that happened due to user input. + """ + + pass + + +class GatewayNotFound(DiscordException): + """An exception that is raised when the gateway for Discord could not be found""" + + def __init__(self): + message = 'The gateway to connect to discord was not found.' + super().__init__(message) + + +def _flatten_error_dict(d: Dict[str, Any], key: str = '') -> Dict[str, str]: + items: List[Tuple[str, str]] = [] + for k, v in d.items(): + new_key = key + '.' + k if key else k + + if isinstance(v, dict): + try: + _errors: List[Dict[str, Any]] = v['_errors'] + except KeyError: + items.extend(_flatten_error_dict(v, new_key).items()) + else: + items.append((new_key, ' '.join(x.get('message', '') for x in _errors))) + else: + items.append((new_key, v)) + + return dict(items) + + +class HTTPException(DiscordException): + """Exception that's raised when an HTTP request operation fails. + + Attributes + ------------ + response: :class:`aiohttp.ClientResponse` + The response of the failed HTTP request. This is an + instance of :class:`aiohttp.ClientResponse`. In some cases + this could also be a :class:`requests.Response`. + + text: :class:`str` + The text of the error. Could be an empty string. + status: :class:`int` + The status code of the HTTP request. + code: :class:`int` + The Discord specific error code for the failure. + """ + + def __init__(self, response: _ResponseType, message: Optional[Union[str, Dict[str, Any]]]): + self.response: _ResponseType = response + self.status: int = response.status # type: ignore # This attribute is filled by the library even if using requests + self.code: int + self.text: str + if isinstance(message, dict): + self.code = message.get('code', 0) + base = message.get('message', '') + errors = message.get('errors') + self._errors: Optional[Dict[str, Any]] = errors + if errors: + errors = _flatten_error_dict(errors) + helpful = '\n'.join('In %s: %s' % t for t in errors.items()) + self.text = base + '\n' + helpful + else: + self.text = base + else: + self.text = message or '' + self.code = 0 + + fmt = '{0.status} {0.reason} (error code: {1})' + if len(self.text): + fmt += ': {2}' + + super().__init__(fmt.format(self.response, self.code, self.text)) + + +class RateLimited(DiscordException): + """Exception that's raised for when status code 429 occurs + and the timeout is greater than the configured maximum using + the ``max_ratelimit_timeout`` parameter in :class:`Client`. + + This is not raised during global ratelimits. + + Since sometimes requests are halted pre-emptively before they're + even made, this **does not** subclass :exc:`HTTPException`. + + .. versionadded:: 2.0 + + Attributes + ------------ + retry_after: :class:`float` + The amount of seconds that the client should wait before retrying + the request. + """ + + def __init__(self, retry_after: float): + self.retry_after = retry_after + super().__init__(f'Too many requests. Retry in {retry_after:.2f} seconds.') + + +class Forbidden(HTTPException): + """Exception that's raised for when status code 403 occurs. + + Subclass of :exc:`HTTPException` + """ + + pass + + +class NotFound(HTTPException): + """Exception that's raised for when status code 404 occurs. + + Subclass of :exc:`HTTPException` + """ + + pass + + +class DiscordServerError(HTTPException): + """Exception that's raised for when a 500 range status code occurs. + + Subclass of :exc:`HTTPException`. + + .. versionadded:: 1.5 + """ + + pass + + +class InvalidData(ClientException): + """Exception that's raised when the library encounters unknown + or invalid data from Discord. + """ + + pass + + +class LoginFailure(ClientException): + """Exception that's raised when the :meth:`Client.login` function + fails to log you in from improper credentials or some other misc. + failure. + """ + + pass + + +class ConnectionClosed(ClientException): + """Exception that's raised when the gateway connection is + closed for reasons that could not be handled internally. + + Attributes + ----------- + code: :class:`int` + The close code of the websocket. + reason: :class:`str` + The reason provided for the closure. + shard_id: Optional[:class:`int`] + The shard ID that got closed if applicable. + """ + + def __init__(self, socket: ClientWebSocketResponse, *, shard_id: Optional[int], code: Optional[int] = None): + # This exception is just the same exception except + # reconfigured to subclass ClientException for users + self.code: int = code or socket.close_code or -1 + # aiohttp doesn't seem to consistently provide close reason + self.reason: str = '' + self.shard_id: Optional[int] = shard_id + super().__init__(f'Shard ID {self.shard_id} WebSocket closed with {self.code}') + + +class PrivilegedIntentsRequired(ClientException): + """Exception that's raised when the gateway is requesting privileged intents + but they're not ticked in the developer page yet. + + Go to https://discord.com/developers/applications/ and enable the intents + that are required. Currently these are as follows: + + - :attr:`Intents.members` + - :attr:`Intents.presences` + - :attr:`Intents.message_content` + + Attributes + ----------- + shard_id: Optional[:class:`int`] + The shard ID that got closed if applicable. + """ + + def __init__(self, shard_id: Optional[int]): + self.shard_id: Optional[int] = shard_id + msg = ( + 'Shard ID %s is requesting privileged intents that have not been explicitly enabled in the ' + 'developer portal. It is recommended to go to https://discord.com/developers/applications/ ' + 'and explicitly enable the privileged intents within your application\'s page. If this is not ' + 'possible, then consider disabling the privileged intents instead.' + ) + super().__init__(msg % shard_id) + + +class InteractionResponded(ClientException): + """Exception that's raised when sending another interaction response using + :class:`InteractionResponse` when one has already been done before. + + An interaction can only respond once. + + .. versionadded:: 2.0 + + Attributes + ----------- + interaction: :class:`Interaction` + The interaction that's already been responded to. + """ + + def __init__(self, interaction: Interaction): + self.interaction: Interaction = interaction + super().__init__('This interaction has already been responded to before') + + +class MissingApplicationID(ClientException): + """An exception raised when the client does not have an application ID set. + + An application ID is required for syncing application commands and various + other application tasks such as SKUs or application emojis. + + This inherits from :exc:`~discord.app_commands.AppCommandError` + and :class:`~discord.ClientException`. + + .. versionadded:: 2.0 + + .. versionchanged:: 2.5 + This is now exported to the ``discord`` namespace and now inherits from :class:`~discord.ClientException`. + """ + + def __init__(self, message: Optional[str] = None): + super().__init__(message or APP_ID_NOT_FOUND) diff --git a/venv/lib/python3.12/site-packages/discord/ext/commands/__init__.py b/venv/lib/python3.12/site-packages/discord/ext/commands/__init__.py new file mode 100644 index 00000000..08dab54d --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/ext/commands/__init__.py @@ -0,0 +1,21 @@ +""" +discord.ext.commands +~~~~~~~~~~~~~~~~~~~~~ + +An extension module to facilitate creation of bot commands. + +:copyright: (c) 2015-present Rapptz +:license: MIT, see LICENSE for more details. +""" + +from .bot import * +from .cog import * +from .context import * +from .converter import * +from .cooldowns import * +from .core import * +from .errors import * +from .flags import * +from .help import * +from .parameters import * +from .hybrid import * diff --git a/venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..db31dfe2fb8836600ea9894ab196baaa06b2c7a0 GIT binary patch literal 677 zcmZvZzi$&U6vyo(ZBj!AXp3M#@<E& z%=`@uj0}iBf&btXCMGsenL6R4%}qR6Papq$Uw_}X?QMc$e0hH}|BMm(QBBs-xPa4n zgbzrfS4d*nDDbBSKBq=a&6-*@ZPc_`Q@f^4OlYJ3hQio|Q&}E{ z^p@z-!QK9T&pPm+1AWe|4NEdCl!(v6kUl+naff;U`sC=~@OX4cC&tB+4yc5{RpArz zGg^wexWu=QyO+y$no1+mv~0$@WmA}}Yzw196kKjan1c)8Dl~;OC)$^-_-`mT!8zl6 zxiKkt78i3UY)LG4dzHP67ai>|P! zo~=D(X{xjeX`0x@S?9sI{}0_xR8=|QdolfLVvK(`I=J;`7vY^1y1GKwR_OY_5vO}A Qw7WtPZhS|3?n=Dz7uB87^#A|> literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/_types.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/_types.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0c5445b66cd3f66d7c376775952f8647e257921a GIT binary patch literal 3408 zcmZWrO>7&-72YM6f6E{J|5=tZlK(`P5@RJU95-;hq9}tu?l1cFKrx{6MP3gUgDm4>uwQjQVmp?KA?zh@gAJ|{)+5CT%cvgJTj|kz zi@kbZvCokc?x^53x1&uw=*BdoEpO8*s;@9`%VZPBkYymb+CVi-Oi(aN zmaJ8^>L!wT1)!*;RR%Mrv0-h?1cR`OWYaVhO$K{NHI%vz=(0ueHna*h(X<7=PZhcv zQ_&a?AS#wCNUMT1jECk@Z5oTFWJ43p=rN%3C!oaJAzCEr8=hr>fm0vn+$}CEQII;A&N#vW~)m=;|fYg2HQ% z`HDxDJ7WBg)D%z#a_2u1~z6Y^pzv6>e0D7Tu=WeZ7wUjVb2RAw;` zD9M#%Mw|sy;GyJAn4rS4kWN!5URVY1^MI2_iEM5?pITZL(Q-DukOby@5RldX!AhQ|Vjb_$+H#VzD4qa+2{Dz;&@d9&jF^XM45G}7$Es_o zLNbPge5wGh@{9Q_n5XFk4VtqI)ypJ1R%oi71RYldL}xCLtzN6Pu)MdNp4a<%Qb;~Hg z0i$9S<{;=x7;yZ2Oo#4-u?eqG!q9ctgh@gSVzarOz7@Gq!pHvJ7Vpg39LS10;Um!7 zFueo1o{~|ost{4fs2FvVVSp#2lnfq`9e{8^Z$l>T*c^BwicuFC0RcOp7+W&YU~kyL zBQug>D6n??9N*nHfb|7~nIa4Kw`-NbZn#TWxcj{D^L6gN&W!;#1N%Nmt1h@B-8itp zsobYrk#BgSUfYu>W96WSF*>U<=L>rF#P&`$F%TmvAqD z9}OnTX1=7!=HT?&Aa4QJr1A*;_(^=#gp)iDi6wY@M=9fKyfE`&9coD8g&Ltp&#&q- zu`r1z3h45cxwv8iEg6N1n$e3p&P}tu<`FBq`8qlC%?XBAz{(&r?r5Kz5k}fAA#?m`pTC<*Txe zCCTO`3C{6)g^oj#bgwQ~IxB=~k#S0BRR~Ro&6N!3)E-Hat8gSbH;^ewBuoX)Q!+)# z1xn6QGI2z%!@!&a@)`4O&&b~RUU+E1 zR-h0N!yBH@P#H>=;otND`II^6?f-qM;|^WPM5DG(lHfju+@U*qEGot(8K5IC zrhD4#?8G6;=|8!*7wc8U<|NpVbcYjz?qp&(+<+tLFe4|GI$Qh_H5Z^w-q}ptvSHk{ zJIRiBKNoU zq-VYvun-z-e$@Q+{(BF_KY!2~nrnyN0To~9{;lTL-cD=y(!+(v17D_E!&lnjpFi`|x%B`5 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/bot.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/bot.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..06e7cd0f2b67d5de7422826538ba34f377b3a1ec GIT binary patch literal 62915 zcmeFa33wdWogY}$2hcz_?)xCn1V{o+01e&;cu2TNLLxzm0Chm3fM$0CY!E=h)eVw> zKwGAiHRzE;G9H`MSdO3>txZKrL?^Rjd6IlKDS6{$=9@(eR2uGZcR7hR-z1xCU{RA; zviIBl{okv4Rn;sW(#SL8@0*fXcwP1C-S2<@|L;$7a=CP|m1BT`5jkV10EHYShT25d5=?PK-4;N2K${k;9`HX2C~@S z?160d*FE6IU&okdJZB(hJa-^>JZ~UxJbxg6ykMYUyl|j!yl9|kym+8^ykwwcymX*+ zylkLsynLX1ykekYymFvYt-orZ3gtM*s>Z7as@b!Qu@&Pr12rt2IaWLF9q^8?99W6p zu29xk-FW>#Jxgbgtr}lFu$raaV{6761{zq}GuAln8}PAo&e+=Vrh%sM=7DDRJ9n&Q z+&|!F>AbPl@pS|1#@7$5AKx&rVSMAjMp+6MDo>+5`D2^LHxFz^J{qGfYzzvD?*iTRlSKdK-WMoo@I~zL;lNn4<8cW zJr-&VRln#MI2`hYR^V@+P1-AkYF?B=wW6GUl+*vFTEM`OkT?8zXys1)W_jz7w?14S zvQrD+wDW8OPq25Z@NRYZiE!2ERrPbjpEn(9-ltgJHOSk*^8TSAlbRHHpPsh+)&|<} zX?Fkdu=hYuzjuEm7@mlQy^Z+c%g*kMPEIS4k>hc1W6GkzS!#G=FTQvoH6%pq?e7K;WW0hH$rMT1l0s67y; z`i3K8;h48Ej<(nJsbAFjnzK$8`MkY{N*sHzro{GeeN2lUm^dPQ8f>cH`G6lz` zLevKB^;l#)!fVK;&sqOt)bgnqdO+=L_KrtGkzx89X5E^cIyM%G9dGuAB2@ITsW@`R z=ph@<=4|w%HL7@H;ju9)A%b?ZzUr-OW_?917#q~D4iT&O)bZ#z^(0&L1Vc1DrA(ko z3<`BOiXme)j)sGAdO|H9j*g8*Pf^!`(TPxm`WtJ@W^)}l7Cjkeec{tP5sjm%ya_Y` ztPy-x)mO3O0kr*CSRF9b8=1(aM_PB#yQyQbI3_-Vv7d}8tiJSa`cePBZg1bgJ^fF# zAMW<{^mz{*KKOV~S9h1UuDuVx>zch!^z`pLc%~BBpJ#^&op@V(hsJ;uu z_V)DdIgDDm4|MnT`%x>NdAlFS4{zVT_Wk>*s_gb7X#HW-bJ*K?@X%9-d-m?@_wGBm zzpEP$JG#-b_KyACyef36bANl!fo5-4`+@eo)VjmogDB;2Hf7_j^FFb!n;ubp?fAd5 zzvo~tb))lOZ~tNZY(_5+_lr-T=;`Zj_O>7H=|fYq_Z&Wm;%PYX1&vuReb?K~OQE4= z10-eyS!lqHpwpr)UES^bQ5L4B*Ob|x{htV^_~ev3FoA`__GPTsmz%P;PfVv=ome1& zV`Je|<^g~Uti+UKKXypU(S_}o%ISaVQ1@WxzV1#;?B0~?;3O@Xz*x%F7yi;zcp`}J z`llzuj|Y^LgAys{kqP8Txq9MZg_R2kH8zGN&z@pQD`U|>2+i@Jy1`&{d>k7uhTlbl zN*Eh6d@?*ZG8GvM4MyrZ9T>(1lh;0a7oREh4Hng~*gb*Mj8cpxx+ zEZlx705FKjqqkI>+8Uodm8T|YdXEKyCzK|PS4uua{W^6#JTXWx8dDMur3%cy2ct^L zP7TRzpNdEOfE7aF5dD_>F*1Alm9>22oyVe66QLksUljvOgyDb@<=dl3TmpqLD^V)_ z8rAX}UVKLi*}iKJ*+1(SBep)t=LlqCIkbC&>RJY94aB{X@yW3;bu;D-00gpy<^^sX zj-2*l@kUMt#t2IS5+4f_1QsI#0O-Zle;jDkODJwU43Nn)dMAPF7-Ur;cv~PISK5aB z7$Lt}$sn&}$V;ynrcq0zQvH4}_5dMcAl!+OaHy@#yTQMXS4kP@8X7tljSry!;MSp` z@z@B`lK~|#9>x+vchDxR8$j?FLm7dwmgvOTw4XJ5#saJi>*O?$_rym3`VFmUSGZ*o>kex_)(Vsxj4Gj4 z?8R1fjAE@Q!Vl7A9U8)J!$`!|Dy4`ILI5-%Mq(H-+KW@McywG8sed#bo$`+3B`b%~ zN4x^;H$BrZCL_!T$I!0(4hnT35SyL|g76&nj)ddtE^WkU5s}Ejbem|E)?ut!B@n}S z1_;=S1u%$aG^$_u8NTv)>p`}vPgiHWc> z<2APwSjWE;3py|s+wEsLE+TWR4!2)EFWvOyUnu{b-Z}ZEr}FZ~dHbSg)%=$dp2j(O zDKCG{rR+ksH?XahP9&5r`jSAvke5}d5L98e7`@5E4P}13)9x%-&Xzm{&+lgim>`Hc z5FCPBlETt}3?YLJFhm-#PuqZDJ%cLoa5y}v1jQhtaJn#j@@?w)C23mr*?MP6cVgWU ztPTZcCmhu`{ z2YP|r@!15>#Nc2mdvK7GN=SPK2fs8G7~^l0NAVS_mwm;DXfHjZ+spVD1MHMuly2K( zXCu$UUQ>5af!Yt#a0!Xb4Ro9Ut~Ov{d)P6`BsuulaE0V>MmQs6d&QY0-S5B9CI-Ik zFXj$phBmXb<3$f77h71`iF6h?|58KoYI2mA^t1~(E7Km~=VKQP%c|Fm9N+>de9ZBLiyfM zH4{V(2#JnBEZpmJf)@f16P%GN4jIy5a4eQ` zhr+R-5@B3oDj(!{^i-HQD8{zL^e3PN;&>YqsEGgwK{GeO&3ynOX{ae{R{93uPY9yg z+02MM>v~=O`?3twG%F1fsApG1!Y_QwFPk(Ac0$_>cth}uU9--(07+A_QZVZT+u_pQ z>VF4SuqH{f8EIc++~o^`oa|z45oNMpS=zf1YNu!c`-Oh* zuho880hw8c*82$v$5C#9mV4GUx>`%?e?x)*Kwc0D{JKkCN8G37&^D1E6Qscs?cH6z zc7`$xxdrIPsIJkz)c-1Fc)nKut)&!qyj4qwGPS;*CAQNl_duKo0d`sEh;Pu|k8aXZ z`rpwldRj|qeTX$1TH>-UeRP}lmHu~>NT#&wJJNS;hQ8S1JGBf`l9C^PNc*LYI_Ao& zJ)4$hX`T(gec8RK%n0@$_}~=Kck~pfFUVF>Sz0QVDkO>MElGJ8 z^*aa=5H&WJ#32N51_uegD8=Zca)fS=<7RvvjE=-o#d>xW0}(k`>{u#u5Ik-01RxVn z41(_tZvS}gmsg|DU}_GF<3{ny7h61rR;%YK_#E%9t7xwQ~{LTek$T1-H04f4&&y_ zRvw}Bp!PuNqZBnj9}MM5{7hv=8QhI2U&5~#!52{7{Nl8?@+_XsOU-`zS-!Mk3$I}P zX8K#Xv}qgr`}6kwuV*H`>k{5|SF3J#cP$+5=lL7_-+%74=dQLbHlSrMgIx&PH?fA86wg;fjH z9gBsX3!YATvHR=0UtfEr|Lterc=lgB{o}zO4JLOzk=XUbjk+f(XHEN0R{bmgHGi^W zAki_9>?#!O?gQ8 z!md%;x@ngcxvrO`l%Xs^yvM7wkM(wH?G4E%u;+*+RZ8QuYuGg^@S^qvw1a@EvNX;9 z+bX^Ey?<;!CHw5X3ZbBxLx+^eNvNzKmeWK60A>t$LVQ6mlr(5enKm&(iY6|-_KpXp z8KgTERZc+40Qm&L3rL52`N~lgoGKV(vWG#yiK)rKwPtBY^Gd zdk!FI`2aeopn=xjOoadq>CH{xb?gdmzx)dV6CdUlof}EyHZ11)k}ltZ%ePcek}O!2 zC|EU@0iHU)`26g-*<@bR`*}?t7F1kbvske5{eq79;XmwMSkv*5WGgr--z-{jdHD6< zV$s@~DY4Oj7|D<}c`|*W=rxV>z zFK0?Q)xSU;wKwyNFL^F{7FI+*$e&!cT4l;4b7*4j^Fv_fAf?AR@TOYYd|_;yDF zk|t?2Z4(TmeEWMyq>-B-?}*%-l}F@R+waT&I0FQnos*m(K;;>HamHc21xE!5h)n7= z>ll%=#oZ+x#lk-01bJ#nbb=Ulj9@vNYkjH8fh7w;LdqVU81y;$vT{MPIvI!uk1Io{ zNjZUADsM0blt(%ej!1o(d@*D*w92FdDF;-&u~fzhtOxwHg-@oO>@8my)BzLP_zE8A zXhW;>-{WcQ7;dy4TsaJBT&`SjZJrOk@7jE27`LUI!V3e5oZ30tQb|R!WKE)EO|oQd zqGaur4Of)Kk_{h8a@MZ7?j?_Rt}E&BCLrW3xnf)J?7Y(dzGvsv#}_?2e_=uvV{Z zRzRe?)FWUp!v`zwg%74BK(oi{rMQ6pt0cuPOHWBJojN6*wm&7El99u2nWNv3qk$lz z@-SNIbETXBS7Tu%h+nDvsR>fu4GQWimDPPZ7-lqwLhB%vt%S#+;R75S;p@{G9E--n z8aT?*zqC^pMy8md(C?s_nH&uYv9C#e8G9Qy74lTnT#hGe*ClG#Emo}mNOEMA%=IkW z>^UV%rIpFjrbKDem7c}YEy?^XiTo|gPQ3rvBNbO%E`GJ@<*LP^)%=rA?UPH1c_Ac#v=Z8VLsJ@Rwibz%CG>p)YwLUa=*B=*4o13uboMrol4h@mbkQx~KHuxmdhf zU6S#@1ld2r@%|K8l{CU)HVAwxNdZrzO6uv-sk42SP%*s}PP=ymVWM z8+7Hma$5NYJy`)NJvu@iTu^`Bgr+}6Kl4AklzOU*wimCyQL2Kh`iw5$w8_O z71BSt2<)>}@)857CUO)467wp7hCp8>w)?D-@6OsRSII>@w^}9T*3Ye0iNbUd*5zBR zo-_7Y`|~TXvIKF;`p$0FD@$KRr1hA!19@yzvHt^?5f|bRE3$Xi@s=RJ-x7OEmR{QI z06P!ao4wa3E8EdVC<>fh+2rACI9EViMv0~^W90(AVar#!h!j);!m>gM(1T1>Gn>jd zc#O=Fd>MQJJ4jQIvIoZ@CJ>*bTw0Q^Yk~}nOi(GvOZYugsx57E!!od>V*dykXmzjK z{DaKIx;;OMFRt4^XQ%ZYeC5DfI~J<8-f(Ywr|-vue>`|Aukie-bEmMj=VRYL_1dXq z!~XXh_AixHUdX=HvhMA{HwKd}dlM~t=X#d%$`|sywCdd#-5iEr*>od+9qo^zxol92 zE7t;Q7d$Cn*tb+%e(BMRk0y)#iDLhi_`lft{7mc5{Yj)FF~z2iaAKXLh?DMhQ?&TKwaT^&UVgm zj#N{&bByHIWyojn&AsVG;+&xxwfBPef|bTZ96HJGpz2gUnJyYp2Q-M;;09G?no@&I z3L%F#GE)xH<)$)V0||AZa+cn_KsPFg?N8+okYY+Y;1#;KW;IJJt{I=U4b5vuSFwt$ zuq>8hohT1GbIDVf^sGpDR$M-Q#c{*avQ%>Hcb~oLxKg~Z_lZQwv4y7tbPtX!mK>kk zv*gK7da4ti>dTMc@T^)Ys+c>#w#*wg<$EY@W|caZv~tJ->1mjoHDiLYLQltG4|fPA zaYwoOlS3WeKkAyH&%|=ZXx|Od<>kss8Y~^sn7atUfpnX|?XRDg{)g9*Rrw2$h?UD8 zDZgUDRnD=V9j~?P^X%z?FKkaU^5Jjaj%H?TU&MZ91^t%qX5}@k6_9qXF*n1D%bMFoP?lV_H^YMl5BZ-osg{KDT9tba%4Bvh4DQ{5o zy6Hy9_KuB1t)D5jYF#UuqP$5Tk}XA$c8Io1h|YU~0P06ba6u*LC#2IaEBXnVQ9;ot z^0W<!k^L|k{AcRcHHl4U4=I)RBC!DusyWT+TL<# zHvQllY)m-l4E%cx&MfeDbk=AH6(&m}vgi=VmKm9PVb&J{&#a?3SlbiI0}eA_+>UAS zIkTsS{Ek_YQ%)GuDFJ2Li)WD9HG7Xkiwe|9_&yk&8VkW-QJ`9~sD+hk2&fSl^mqU^ z;{n*X4-do4pTw1#5hSzwHPp`xxyWh|Hu}IcWUWQ!S1?m2l?~}TU_B454_W~WpD>h0 zFlYzaqOvw#)>lJ$4`|oOq^YNM+s3daK>%=nPzy&w`E>O_i5w1u$bS8l0z*jHDq;wR zhGNq(e+-yaQBWuwTr!q~86+n?%%iJQ5vhDg*3|9|vhMZHczZ@BqRa|XG!&$Y7=+bi zxa`6!Xi|owkhBe9Juxwy@=c^t1;+z1UeutvDmXPxq5+89NJ9is-Xru2JR`%5DM(2) zp$e73K46AEtj`<)k~n0hT-(R#&F&$v5JL9J{*3C~wcWlC$*qtB;h+)+vhO3TD zZNw_LuVFaNq!CuqGQ6uTIJF-#gDl4N(S`wWPSA!?=&B7k=N+7^;|9?y0V0GSstA{D5aplaL5!9$n!yq8 z5AkEBKtsG@TYZf-N(dCpG*WxTZR@n>XUDif{|?*kM)+BaN{|BnRcClVI;_CBH7a}^Tx2!0!_=B76{v> z8igNb+MM+1W3ZV`iJ71^BO+`f82gV;!hHZ#DD8|>5qKgpb07xx2~lZ;j+itMp{BWJ zunm}&dx;t`e;Q`|LLsMU&KI*AqQJtW7SjhVts}I`>H1vTf%X~JA+`WXm_YrCQg-z# zQ(>SAIDzu=`JDz>+Zb5LezA!8{vcnMDZ=a`6N45SDAP)UtvTB~Y}1geih7vJempQX z#VwyyrJuf$Qu3JQ3BWf~%A?7M3D@XssqyJ+w6RF?jg7Sml3Y>~SHJJ6z7l_X_Kn#& zdD&slDp>O5oZokD--Z5f^#1Z@UIi(Y3x4j&hcq{<;L{i>7+xvxOaCOR&Hf{~%`R{h zZ4j~Hn(^cA1Zqe&%HM4~OUlrPHlEa5f`Rl(F9Z%!Q;e{Pn0y(xxP!c z%`p1!n1wHbSzwUSvryg-!B zb$s|W)&3DI!e^#;3~Fd$y$+i|2pmXYs4J$eEFecMY;xvgxS`lzbdjQ06Ft63Eyg9R zbW|(MKC-!SFd?C%S0Qq&Kd5G9`3bu~S1jN5BcU02&PqptlFrDm|B}xM1E6oqmt<&s zbIHm}7~pWjX?x1%Uzd`Hp^uH9R>@JW@%c1s=LkUd=}BexOr4k*4vlqjv&i$GX`+ao z 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�ubSmt~YGAKxmBO|UmY|POQwhA?1EZRN} zSRH|`hntTv>6>w2#Tw;SSOny0*!kikVYOkQv(X3S;I=xHO&?)(BK+Q`R3rc?EFW%l z2657#Xj8hO8_!~tzyf+$*^{w&NRyy?shgr_{BsOAMkk1XM>MUN7cv#0yx4g>hp3+c z05bAY*AsG#MJFI~*Opr}h*Ki?@ut`hWRu87C8n~-ey?|rVL?-I;nM-qs4>5O8X0Yp z)!t*-4GlFmtZZoZHmrQ8!3PB+D{*Lueh%rfc`8f&h7I%toi{-p<4t9jV!*lr-09nd zossgIHS^h zVl>tT23<8V)a1#OOMGm)n&v?D^WNtO4Vl0OOA`$3gQE8bY-*%0_iu%bPa}rR2wTx zTkTjgW8rb2Uq*sZp8y&Ku3#uaMJ=?%#IVq~VK*wUZfhU>~}>`kqHKcSx5~;)esG$6(2A)7UB^&3AO=Tv<<;>R|t;>jbovP$i!I%VP!B9 zvKShG_p}i~mlbbM7ut?K;Y*IlKs_;)8$&_ZX#|~Ezqy7B(=*|P01hr?>{L|Iq5r?S zYw2yP3c}~wH+JkKc1;rFLNO*OaU)ujkd&z9A*B%%A}d8I5<&u5Y3sC=0*hZJRAV2 zaKBoTw?L%pkK{vA@EBh3WvEs`hmKvws+dZup9I~czKc_LR2-`1hGvkd-yETf6c@aK z%S+Eey7Gr!+=FlMIHEgR{t1lR3`9vsqw3khoQRrX(?&_msS`Q-CgK=lS&>+4192+? z3Jjb<%hWuY@T{)o9?u6wCc*Hjxpd_z(};E^$MIF;|iQ{ z51|QCZ!TE_z|$*?yux7Bt_}cxO&wx5QDGUh)BVl2-<#>jrUiKlC*UG+21S=_rYp76 zJ8Io(&%7>i{D2O5E?*`e<6Xt{1>f}FKkP(_yR(jk*=6nyE+7S}bn*ihdyz9=PuY@P z=in5J>gZy1%a)3=BPeqx`qkTyzny65INk&*w}LqXx_mby5Ez31sl$RJc!N209SoZN z{b00wRM4*#=0(shcck~cPJy4wo%een!;|^r6pYAG+f&B`vewcqzzh5j*tGJKX%&$* z(tD{f;f}rQnK&<%tao_+EfTH=Cdnls-x57e;M6y2KZNwv;L~@*Y9OX>WeVyx{=L7` za#nM=bCtRAe(u7_9~G`)MR3H}x62#sRlw7T%|}d!s1L^Lj?5$yxw}$!yU2@hjW=P{ z&;xTbS(Kc=|2kC2NfZ2+36wyipabfs*Ltmi73%?b)hin^(IWYivKht~$|ercWIW06 zGEl6myfshq2FWA|L7A^&Mb5N#Fry`&Chn!Lo%eyp5@c~P=VTrLGI_uHbovwP3%r{h zFO}9FU?xo&IuvFREs_d|o%B6nwXk{%IVqk^_;4NfEzt`skF%)gdgU%A)83UOTI>kS zE)N8PM@2D|o`i$MtU;0(Nt|SegnY0@NT{uPQZzHCmY^zv774I))>RfXUM~(T(2iT9 zxZNIcuk-Dy8hRS%1#C%Zl{KogOsR0Lfq>H1S$_MNLpnG5}jLBs|e>JTGJ!~MHB6_E|Od#DUiHMLQR3;_(1Y!hGdrHI>`+X6kJ;U9FddGaH0$Wxi-jp+8sM}q_s<< z=xHr~55B2aJAT{x4nM_5Re`xEjH@(^zd~ulJe*O+D z@i3L%+WaB;v)Ra9-g)+NBlUW1`KdWD6skq{6KY_%zVvmmX8ax*sh78}{u-I8g&##T zwawq6nMO3To!N~})XalO+_-Y^+@z7}6pfH^VPBENRqBQB6Scwm~moS4zZXmBIeUI~vFv8|7`F^6QKkzF`cI25Pw5Bu)I$N&HU literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/cog.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/cog.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f76401637a81eaa9c873a1db423a2edf077f34ad GIT binary patch literal 34685 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 hm|HAfoqge{D^JDpo1^*7*DhXv}%{7=uJ;lKa@ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/converter.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/converter.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..353f1e0df05eca00c213ab2f17c63719faf882e6 GIT binary patch literal 63045 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%0AW^&1F;O`P|jNQ#?~RYl-Hrp0h@C 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�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 PV3g9W=Nao|d=ULFw&Ft( literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/cooldowns.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/cooldowns.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7926c08d49814ed812f82fe00ae615fa66f00cd0 GIT binary patch literal 15008 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 z%0D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

    Q z0vdU1;%zB!%Xn+%t%bK%-j?&$#@hFyZDHQu=amrKejP-CvSK2b`Nj# znqvPtZcq>$I&cudc&DuG_HXg&7;nGJ+rQ%N9B+**=W9&;fH%<@TglW7@|ImE*inFc z6`xThTH>&XmwE9dE1ns}@0WOQ5qAz^XD#-b_HF#4legP>+sxZu-b8v%k+VnvY!Yua z@uEcP7VRw&O<&2`a9}8YXn+4k`#+&AXmKF%AF;>~k;Ss!4pv&>ciID1!%qT*KMWN8 zFi`x%K;gT=Vk`J=Ano=R|D0J8u=0@eXMv?Z3Y7mSQ1|1&iXR8!-w(tu1}c6WX!}uM z^P8dKABQ)l!W(}Uet07M@Ob#)>8$Gf;IZuKwSnTQPdzjC%tTRRs;Kc;_GsC7pz+Oc z{^;iC?m1??kzaazeX{A+3;7$5<-D0&e0)K2@l6+U*B#43iEreT9B=q!;m11P%qcn^ z`egK2=S)_PRW}_AENy)&f3;OQSs0rR;rCKu-E;)Mh;ComFwHmc^P5#OQ^3@ID^S~X zYRTtXKiisYy5-!1f75^ zA6~v|(eAKSeZ1;a`H6*ig!JXRat~P6rqR2O52vDar}n}=rt{24PVYbdb*q z)d!O`3#TIm`WyUS%B_;W@l9dLbT*z$=j3Ds-_Au!f6Zr00woJ3n{Swov|1HX9eyw6 zHp$=mQ#^soyR6)qT&8wdS7~6yTn$`Mo6*3EYi{7u71NPoYo#<0zn5|wwTQ#_^SC1=^TqS>3A+@F$x1}rb^&YDT z$;P$l@6%RbiPd+cR^Krlh*=fMM|Zx%-mjD0& literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/errors.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/errors.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..59ff313f4c0a2fd7c9546a9adc96fe504e9359f8 GIT binary patch literal 49006 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 MpBOr# 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/flags.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/flags.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..366f484c9b0d2643001c165c645601b3f884b1a1 GIT binary patch literal 27897 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 z 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 po{{R-yoIZ za!6m>VJrzbzqk?POcJqFWt0^-6XPMTsbsd|nkkSAR9ZoEfkiKpfgPALfZSk90J=H{ zOS*LPiY*a22<(3B28hJ2X+mD1h$3}NAyaA)Y{DN1%>1421D;sJIp7nN4K-v_rZ<3d zpi0dmbAaF+z?h@NIp9IT=hsm1VUFWI&cW}VW09`HvA`#m)^H9oCC-5sd;^`xH}F9j z)uSNgkle|{c&&NxEegdL22wwWZvei8N8wVCWD-aK1#61J>$AN{JQURw2~&{D4CJeq zrKaP4$uM4-kOcFQaaxsDj5zLZ*&lJqw9&*oqF;(=d{Wzg_xv9t)GCwo>7n?StR>Hl zs3_yX;NHLkW{tG%C29fm{zo14T)BtyiQ^ElvCRs34R^o3H)30 zJRny>)>QLseQ>LsX$H!vVw+|(Z`$S62IGOMb&n9fw&t0!zX2eg9v+li`sd6{;u`ib zmf!S75ximG3!&m<6p*pUakC~z5fm0T4o(e^`aHwFK)m(=h9IP`7I|1oh>ygp9*|Hh zihwg1jfmGhAeCHP;_IFyk`h9v;uR0b0&zcrnW^rL4@knk=>?pVXj2}dD^Q_f6bde< za_b2#7{0hE(aw0bN^6AM)D}DLM+i4yXy|KUqoaXDh};}l(4eB7B?-=~P=OlMShDdv zbwE;;Rl9;x8M=|6X)rE}fDb!EoJYR8WnS!`Q}VwiCzqT=cmH>KJx7kj{Pp={V8fXu zw5BGevIUZ*iR%dd4G2{fP)*JXr947D8bIM7Ifuw$BV~}sBW{q#N?=lyj7&_&uw(6$ z%q`AIT9XQ|n0StX*WeJZ*#4XFic1``?Q=C(x_%2@ag_^2)I*0={=(3FbqKuTb&OZM zf%w5yv6_vq55G1X+H~NZwn$BgfmL#FN7`YLuVKV-7`Tv@XA@kTmwi8>o!XrLP)aHZE*j3`PndahXEamtv%Y4(TdtTlX+HmAUeMn5s<$I|tip-^cQcI+tH?ws z;A)|JEV7W7ESS0tWGW&lWW|;rvQ;e?ZCGr&F>!m_!ygtb74^)~Sco=JqV~G5y>9Wu z&+J>lim+F&Hgc8Y`Z`HOUgQQkF=DuY3lWhh?^GM`5) z9vwsulf}LnA)Xx}Yb6WfnI7d#kr1ru(v)qvHu^7Uf6{#nUcJn)c?B{WWb+aH7nvkV zqO^-`Z*^VoirAWA8UOyl!YLxM)V_gWgiu3gj;d6IExEOjiTF#jPgqaMJ5WIi6Av+B zjeFtwW^xc<<)sNQtenhryHD<+muh2j57M__7}b?dRf##CEXA?5y*Ft*tI?o@>;swB zbcVB?vxbk&+4L=>Lq7v23~~=Si9S(Z=po$gdBWTN1|Ee=t-7Sp7ghD{XV;;RRbV6% zC3(%Go%8C$GIDbT=+=Ez&znmE2m?CL#eMhXYLOhOdWdET2ZAcfiM6+8$mKJsC zf&-FtK?RC^erHPw|2KR~f%bpRgAeNbEzsc0(UHH1hnunxK}i%R?H}M#Chb9@1*&2= zu%4OrY~74T*Z>tRwTUC)0A(^zjr7RC=i14DZ~(Q6Jr}tkkptMnK8Ogg_G_lGLKZU- zr%@6lU~~B?%3*TQBD;c3D3RjjF9TktcsAjQS)~pUc;R+7o<#RQh^bgLfT@9 zDXd!Ph}bs5gq%g>WZpIxFKDBVO}8DJR`uKlSJX*{o1@Owu(LJlJQQ{wiZ~A^V51r& zA_FfKx6Ks`zG%(v+cmpm^^KIEGHj__BI_%Poif!0@fe!(AYceuaH@CJSL+V<;)`SW z{;QU5XE10q-sdrc|6SICxb+HM+^aC1B)Bd~Jb-bXWNwN=H`A7>KU9YJ@W7A3~odNAU(28IXjube1hsBzZlNmb|V%_wdLS4`0`e-QsMoj~EkKM4iv`vq55nFLt}^xV(5m%_QLLyZx}si_ z+(Ixi^5wKp+tI?5v9w~oqU~wa&KEmjWhl+5_Z~rp7N3tU0+~td5+RRPkr{gi3|mN~ z5rdW4#2JT@6PZ*eX)o#82_)SO^1U+^5QWKz4o%EhV)!O0Rw;6fE=I}j8on?*E~}xP zfh?JF$H~%w$?4eb1tvWi3htkRWTGs9iC#cm3oLA0lcEw=Qp>)fyq?sjgveg%XebRM z+@&vxfsQePhF4O3Un8I=4Q~&V7KP9uNZU*aKBWRMuW8_=Hj#|oa1fmw9mdU#%iTK) zG*VLi`4f&Bi{;~xakq^=#=zDBI}b_x5ER&;0+KPUL>@2 z;WA*9cL*QC_<%I50f9DOJe^g9&*)eM{}_xy$V4~_6Cm|-vy^4aQ=c^GD z+&+rDy@Z_)(DEPwRhfWAFa?a3kNHIP8L9)jPoi{CYFRRs9e%FVb<;>Q--IlL-&wP- z42G@M3w;sm2H5Rl)L3A5N%ID+I8b4iERFP;Q4<>~e6Y)bN)#Fe{Ops`O!%W3FW(|N zk!j!3d`o)`Xx6L-dU*USH=8y90gV?d^d%OCa-BiO7L{WbXA-F}GdUheSCjT@l0W z!kB>4Kb9PN-b|l)9LF?kDf*r`FH_)Yl0ISZG_m!*r@O{o(Wrg%+s9u~E_xp7aS2ZS zm9#5bnCwh@CGCoaeO6G>PrZaZszgKuaKysqd%5eHZgwa_$e2OKw2)x@+XRU?iJK~r z)U-f{*Y$J;gbRO20mNJs$$u{!NdPGe}0=B19=vDGPwVR1N1@^j>8~q?{ z1}Y1i0pG}#PKKdH?UJQFmV5TQkKfQP=7bKy-1^zjDKEMGgOS{!*$!og%s)a}BiV(s zUEh6Lyw5*2y||* zp;3#AV>`NYhxoYve3|>gp*0qLiZikZWE*?oeQKR3<2Ty1gUI;1*|id!_1o;(r<38f z{~Q~bouI#q?aK=KZ+!C#W0-ru9TWHw=n7%mRG7r;1GZsxGWfyfTLlBB4=X%)6Q23* zV~f6pV5t3gIQLBGq=#IuKaxA};7uqzNev`kjUZ6l*6g3SjoAO?_sdc7hgD~?5r@?oG<(=w-p ztyIW1a<-GRlN=Jf$F=`&snjA0VCC1)>n<^h9R@AQmTOptk_#7=L{e^~wb99zXztU< zs8G5fooe^xhPDbjmf5hdqnZr{JIqKUWR0H5bhmP8qA12&{+feQvAmPo0`U|*{p(hL zD`6y}7|q}wN{RT$gZ zyqeCu2GTn*GOvlt-p{YHq_{$|a#u50u$8n>Y|MKojp?Cibh}93#7g=myP(6Ow|BZ}f?w#T+|l9p&LO@= z*YNoycoF3noo`Jtymky5SUTTUQHL{ipy6i4h@0=jhTEF&h#jM zCxg6AzfB>J@Ly0N?37?5-zN|t)lZW`5B(BUZYH{02|OZ1%%I^kK*IchhC#wGampa! z1?-mlfI^tE!xxe!gfSrEiU}AQ8kE7zHN+H&KG3q}L%oFS686dfYuTENY$Aw?2OXZ7 z0#b^VwwWl?PB*lYozVrLTah5>q==zQ86D~>A5ttSeK7c$A@dT51fhG<{e=7&zD5l2 zSE35_i|2zPg$N^q0`w%tg9LMn+8V4VHTFWkRJ04wGlQ_1+AL@|fnj_QH%N*gQaDj` z2+U?h$)lhyXx}H#i(fb+Y6nQUM9mM`GEw537f(;pm~@H4_GcvJMOIlWv*gS$7pR$m zOaaYM->BSBl*X(pVmxRTs6*rp)I(e!$ihX(d5~gc0*;8J1QPnLaz_$|mq1g(1djQ! zw8YiG3L!mKh4zA>V!EiPMI6{9mCR)ARk?7v!=1sA)r}~zI@eJ3WaJOOEShLI%?|PMmB)j4H+9Nrs;{Ah z37#a_5IJLhnJ1WN0I64k4HF2#G}jcgA`e zB>oyjuC)x5AVZRgxP%7Fi6N*wlbUjpt}qS1+!ki8>nk*+sIJF0Jhp)egDOqK$5&u} z3(HqF2tnl&4Nu&BVg(?q3R7$q5kU}PO7oAMNbnGQk}U%S z6Z#5@D_4jED^pQaAoM@b0I(nkgJ?#e2>M<*xMZ$obVAVS_Jk~ZKC!`|QOI_3Q5)KK zG;BMGFA|e$I4MHX5<6{O>(>E$Op%$v&C+M{q#P2&DJnV>WRLDCof7-VP-VJx6NoY+ zC6F^j9ms;`9uVV407bZALJ;5o4rwKUxZm{V_5oh%XNlj-50AA3lDBi>hY} z9RtENqSTI(a_J~xv#D~B{MFYUB+K{^c~i)CV!;>M(-pRz2tE7=xrP(T2Z`_$>KD=L zWCq85hlDUAw=;1jFuDafuTWbur88l(M)xQWOd)Y3;8Z0eGf7xIA+iYFPg$}Q43bfO z3BzXXiE99^fN=0vln7t>2u%9>gDz!%B^CMCRQNO0j~|e)f}ERhrb`m$T<^;-q3O?3 zOAPE2tkXG(Jk=3&ZCVSbQp(WBS)Yqv>FO z5E9SgzFC!rm2v-i!a+)v2T6fEd4ZgEx*4L5FL!zdra(C-TjN*~F!=x#Ab_a?-6i7m z69Gw}yILU027&Z41(N0yfZ%Zg8B`OKU9_*p7AE190?fC8)Id%-ISz7$$)WWW z*U=Z_0zxGPRFT8T4#c7nzDLeFIPpxeyB;uBAlC`#Js_IssHGI^DTQ8CiV~a@vVok9 zfn$Cd4@9x_4HOM_c#SHlz^##;G#51w%Hj1Bs5TAn^`$ z__QxL+4+=wAPVrd|AVvsoOAqw+Y{#Y{DM4}qTHola6LccdVbDT{DO1-oXhz+SMp1Z z{TJH3VeQ^uXzRk-x}R$cey(+V0rH6+)P0?P)v7b6T~7bh%IPe#tz&vF*9@>$ipaHF~u&^>Rpl@hXLY_GQgnHIfemw;ukEnY^GvQQk5o aFMKSo7(#i;C*~y|@*d;wn&D;Z`u_#*KNws9 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/parameters.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/ext/commands/__pycache__/parameters.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3022b521c26afaeca590ada227f90120ed99f71a GIT binary patch literal 11347 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 T: + ... + + +# This is merely a tag type to avoid circular import issues. +# Yes, this is a terrible solution but ultimately it is the only solution. +class _BaseCommand: + __slots__ = () diff --git a/venv/lib/python3.12/site-packages/discord/ext/commands/bot.py b/venv/lib/python3.12/site-packages/discord/ext/commands/bot.py new file mode 100644 index 00000000..8ce872f1 --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/ext/commands/bot.py @@ -0,0 +1,1530 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from __future__ import annotations + + +import asyncio +import collections +import collections.abc +import inspect +import importlib.util +import sys +import logging +import types +from typing import ( + Any, + Callable, + Mapping, + List, + Dict, + TYPE_CHECKING, + Optional, + Sequence, + TypeVar, + Type, + Union, + Iterable, + Collection, + overload, +) + +import discord +from discord import app_commands +from discord.app_commands.tree import _retrieve_guild_ids +from discord.utils import MISSING, _is_submodule + +from .core import GroupMixin +from .view import StringView +from .context import Context +from . import errors +from .help import HelpCommand, DefaultHelpCommand +from .cog import Cog +from .hybrid import hybrid_command, hybrid_group, HybridCommand, HybridGroup + +if TYPE_CHECKING: + from typing_extensions import Self + + import importlib.machinery + + from discord.message import Message + from discord.interactions import Interaction + from discord.abc import User, Snowflake + from ._types import ( + _Bot, + BotT, + UserCheck, + CoroFunc, + ContextT, + MaybeAwaitableFunc, + ) + from .core import Command + from .hybrid import CommandCallback, ContextT, P + + _Prefix = Union[Iterable[str], str] + _PrefixCallable = MaybeAwaitableFunc[[BotT, Message], _Prefix] + PrefixType = Union[_Prefix, _PrefixCallable[BotT]] + +__all__ = ( + 'when_mentioned', + 'when_mentioned_or', + 'Bot', + 'AutoShardedBot', +) + +T = TypeVar('T') +CFT = TypeVar('CFT', bound='CoroFunc') + +_log = logging.getLogger(__name__) + + +def when_mentioned(bot: _Bot, msg: Message, /) -> List[str]: + """A callable that implements a command prefix equivalent to being mentioned. + + These are meant to be passed into the :attr:`.Bot.command_prefix` attribute. + + .. versionchanged:: 2.0 + + ``bot`` and ``msg`` parameters are now positional-only. + """ + # bot.user will never be None when this is called + return [f'<@{bot.user.id}> ', f'<@!{bot.user.id}> '] # type: ignore + + +def when_mentioned_or(*prefixes: str) -> Callable[[_Bot, Message], List[str]]: + """A callable that implements when mentioned or other prefixes provided. + + These are meant to be passed into the :attr:`.Bot.command_prefix` attribute. + + Example + -------- + + .. code-block:: python3 + + bot = commands.Bot(command_prefix=commands.when_mentioned_or('!')) + + + .. note:: + + This callable returns another callable, so if this is done inside a custom + callable, you must call the returned callable, for example: + + .. code-block:: python3 + + async def get_prefix(bot, message): + extras = await prefixes_for(message.guild) # returns a list + return commands.when_mentioned_or(*extras)(bot, message) + + + See Also + ---------- + :func:`.when_mentioned` + """ + + def inner(bot, msg): + r = list(prefixes) + r = when_mentioned(bot, msg) + r + return r + + return inner + + +class _DefaultRepr: + def __repr__(self): + return '' + + +_default: Any = _DefaultRepr() + + +class BotBase(GroupMixin[None]): + def __init__( + self, + command_prefix: PrefixType[BotT], + *, + help_command: Optional[HelpCommand] = _default, + tree_cls: Type[app_commands.CommandTree[Any]] = app_commands.CommandTree, + description: Optional[str] = None, + allowed_contexts: app_commands.AppCommandContext = MISSING, + allowed_installs: app_commands.AppInstallationType = MISSING, + intents: discord.Intents, + **options: Any, + ) -> None: + super().__init__(intents=intents, **options) + self.command_prefix: PrefixType[BotT] = command_prefix # type: ignore + self.extra_events: Dict[str, List[CoroFunc]] = {} + # Self doesn't have the ClientT bound, but since this is a mixin it technically does + self.__tree: app_commands.CommandTree[Self] = tree_cls(self) # type: ignore + if allowed_contexts is not MISSING: + self.__tree.allowed_contexts = allowed_contexts + if allowed_installs is not MISSING: + self.__tree.allowed_installs = allowed_installs + + self.__cogs: Dict[str, Cog] = {} + self.__extensions: Dict[str, types.ModuleType] = {} + self._checks: List[UserCheck] = [] + self._check_once: List[UserCheck] = [] + self._before_invoke: Optional[CoroFunc] = None + self._after_invoke: Optional[CoroFunc] = None + self._help_command: Optional[HelpCommand] = None + self.description: str = inspect.cleandoc(description) if description else '' + self.owner_id: Optional[int] = options.get('owner_id') + self.owner_ids: Optional[Collection[int]] = options.get('owner_ids', set()) + self.strip_after_prefix: bool = options.get('strip_after_prefix', False) + + if self.owner_id and self.owner_ids: + raise TypeError('Both owner_id and owner_ids are set.') + + if self.owner_ids and not isinstance(self.owner_ids, collections.abc.Collection): + raise TypeError(f'owner_ids must be a collection not {self.owner_ids.__class__.__name__}') + + if help_command is _default: + self.help_command = DefaultHelpCommand() + else: + self.help_command = help_command + + # internal helpers + + async def _async_setup_hook(self) -> None: + # self/super() resolves to Client/AutoShardedClient + await super()._async_setup_hook() # type: ignore + prefix = self.command_prefix + + # This has to be here because for the default logging set up to capture + # the logging calls, they have to come after the `Client.run` call. + # The best place to do this is in an async init scenario + if not self.intents.message_content: # type: ignore + trigger_warning = ( + (callable(prefix) and prefix is not when_mentioned) + or isinstance(prefix, str) + or (isinstance(prefix, collections.abc.Iterable) and len(list(prefix)) >= 1) + ) + if trigger_warning: + _log.warning('Privileged message content intent is missing, commands may not work as expected.') + + def dispatch(self, event_name: str, /, *args: Any, **kwargs: Any) -> None: + # super() will resolve to Client + super().dispatch(event_name, *args, **kwargs) # type: ignore + ev = 'on_' + event_name + for event in self.extra_events.get(ev, []): + self._schedule_event(event, ev, *args, **kwargs) # type: ignore + + @discord.utils.copy_doc(discord.Client.close) + async def close(self) -> None: + for extension in tuple(self.__extensions): + try: + await self.unload_extension(extension) + except Exception: + pass + + for cog in tuple(self.__cogs): + try: + await self.remove_cog(cog) + except Exception: + pass + + await super().close() # type: ignore + + # GroupMixin overrides + + @discord.utils.copy_doc(GroupMixin.add_command) + def add_command(self, command: Command[Any, ..., Any], /) -> None: + super().add_command(command) + if isinstance(command, (HybridCommand, HybridGroup)) and command.app_command: + # If a cog is also inheriting from app_commands.Group then it'll also + # add the hybrid commands as text commands, which would recursively add the + # hybrid commands as slash commands. This check just terminates that recursion + # from happening + if command.cog is None or not command.cog.__cog_is_app_commands_group__: + self.tree.add_command(command.app_command) + + @discord.utils.copy_doc(GroupMixin.remove_command) + def remove_command(self, name: str, /) -> Optional[Command[Any, ..., Any]]: + cmd: Optional[Command[Any, ..., Any]] = super().remove_command(name) + if isinstance(cmd, (HybridCommand, HybridGroup)) and cmd.app_command: + # See above + if cmd.cog is not None and cmd.cog.__cog_is_app_commands_group__: + return cmd + + guild_ids: Optional[List[int]] = cmd.app_command._guild_ids + if guild_ids is None: + self.__tree.remove_command(name) + else: + for guild_id in guild_ids: + self.__tree.remove_command(name, guild=discord.Object(id=guild_id)) + + return cmd + + def hybrid_command( + self, + name: Union[str, app_commands.locale_str] = MISSING, + with_app_command: bool = True, + *args: Any, + **kwargs: Any, + ) -> Callable[[CommandCallback[Any, ContextT, P, T]], HybridCommand[Any, P, T]]: + """A shortcut decorator that invokes :func:`~discord.ext.commands.hybrid_command` and adds it to + the internal command list via :meth:`add_command`. + + Returns + -------- + Callable[..., :class:`HybridCommand`] + A decorator that converts the provided method into a Command, adds it to the bot, then returns it. + """ + + def decorator(func: CommandCallback[Any, ContextT, P, T]): + kwargs.setdefault('parent', self) + result = hybrid_command(name=name, *args, with_app_command=with_app_command, **kwargs)(func) + self.add_command(result) + return result + + return decorator + + def hybrid_group( + self, + name: Union[str, app_commands.locale_str] = MISSING, + with_app_command: bool = True, + *args: Any, + **kwargs: Any, + ) -> Callable[[CommandCallback[Any, ContextT, P, T]], HybridGroup[Any, P, T]]: + """A shortcut decorator that invokes :func:`~discord.ext.commands.hybrid_group` and adds it to + the internal command list via :meth:`add_command`. + + Returns + -------- + Callable[..., :class:`HybridGroup`] + A decorator that converts the provided method into a Group, adds it to the bot, then returns it. + """ + + def decorator(func: CommandCallback[Any, ContextT, P, T]): + kwargs.setdefault('parent', self) + result = hybrid_group(name=name, *args, with_app_command=with_app_command, **kwargs)(func) + self.add_command(result) + return result + + return decorator + + # Error handler + + async def on_command_error(self, context: Context[BotT], exception: errors.CommandError, /) -> None: + """|coro| + + The default command error handler provided by the bot. + + By default this logs to the library logger, however it could be + overridden to have a different implementation. + + This only fires if you do not specify any listeners for command error. + + .. versionchanged:: 2.0 + + ``context`` and ``exception`` parameters are now positional-only. + Instead of writing to ``sys.stderr`` this now uses the library logger. + """ + if self.extra_events.get('on_command_error', None): + return + + command = context.command + if command and command.has_error_handler(): + return + + cog = context.cog + if cog and cog.has_error_handler(): + return + + _log.error('Ignoring exception in command %s', command, exc_info=exception) + + # global check registration + + def check(self, func: T, /) -> T: + r"""A decorator that adds a global check to the bot. + + A global check is similar to a :func:`.check` that is applied + on a per command basis except it is run before any command checks + have been verified and applies to every command the bot has. + + .. note:: + + This function can either be a regular function or a coroutine. + + Similar to a command :func:`.check`\, this takes a single parameter + of type :class:`.Context` and can only raise exceptions inherited from + :exc:`.CommandError`. + + Example + --------- + + .. code-block:: python3 + + @bot.check + def check_commands(ctx): + return ctx.command.qualified_name in allowed_commands + + .. versionchanged:: 2.0 + + ``func`` parameter is now positional-only. + """ + # T was used instead of Check to ensure the type matches on return + self.add_check(func) # type: ignore + return func + + def add_check(self, func: UserCheck[ContextT], /, *, call_once: bool = False) -> None: + """Adds a global check to the bot. + + This is the non-decorator interface to :meth:`.check` + and :meth:`.check_once`. + + .. versionchanged:: 2.0 + + ``func`` parameter is now positional-only. + + .. seealso:: The :func:`~discord.ext.commands.check` decorator + + Parameters + ----------- + func + The function that was used as a global check. + call_once: :class:`bool` + If the function should only be called once per + :meth:`.invoke` call. + """ + + if call_once: + self._check_once.append(func) + else: + self._checks.append(func) + + def remove_check(self, func: UserCheck[ContextT], /, *, call_once: bool = False) -> None: + """Removes a global check from the bot. + + This function is idempotent and will not raise an exception + if the function is not in the global checks. + + .. versionchanged:: 2.0 + + ``func`` parameter is now positional-only. + + Parameters + ----------- + func + The function to remove from the global checks. + call_once: :class:`bool` + If the function was added with ``call_once=True`` in + the :meth:`.Bot.add_check` call or using :meth:`.check_once`. + """ + l = self._check_once if call_once else self._checks + + try: + l.remove(func) + except ValueError: + pass + + def check_once(self, func: CFT, /) -> CFT: + r"""A decorator that adds a "call once" global check to the bot. + + Unlike regular global checks, this one is called only once + per :meth:`.invoke` call. + + Regular global checks are called whenever a command is called + or :meth:`.Command.can_run` is called. This type of check + bypasses that and ensures that it's called only once, even inside + the default help command. + + .. note:: + + When using this function the :class:`.Context` sent to a group subcommand + may only parse the parent command and not the subcommands due to it + being invoked once per :meth:`.Bot.invoke` call. + + .. note:: + + This function can either be a regular function or a coroutine. + + Similar to a command :func:`.check`\, this takes a single parameter + of type :class:`.Context` and can only raise exceptions inherited from + :exc:`.CommandError`. + + Example + --------- + + .. code-block:: python3 + + @bot.check_once + def whitelist(ctx): + return ctx.message.author.id in my_whitelist + + .. versionchanged:: 2.0 + + ``func`` parameter is now positional-only. + + """ + self.add_check(func, call_once=True) + return func + + async def can_run(self, ctx: Context[BotT], /, *, call_once: bool = False) -> bool: + data = self._check_once if call_once else self._checks + + if len(data) == 0: + return True + + return await discord.utils.async_all(f(ctx) for f in data) # type: ignore + + async def is_owner(self, user: User, /) -> bool: + """|coro| + + Checks if a :class:`~discord.User` or :class:`~discord.Member` is the owner of + this bot. + + If an :attr:`owner_id` is not set, it is fetched automatically + through the use of :meth:`~.Bot.application_info`. + + .. versionchanged:: 1.3 + The function also checks if the application is team-owned if + :attr:`owner_ids` is not set. + + .. versionchanged:: 2.0 + + ``user`` parameter is now positional-only. + + .. versionchanged:: 2.4 + + This function now respects the team member roles if the bot is team-owned. + In order to be considered an owner, they must be either an admin or + a developer. + + Parameters + ----------- + user: :class:`.abc.User` + The user to check for. + + Returns + -------- + :class:`bool` + Whether the user is the owner. + """ + + if self.owner_id: + return user.id == self.owner_id + elif self.owner_ids: + return user.id in self.owner_ids + else: + app: discord.AppInfo = await self.application_info() # type: ignore + if app.team: + self.owner_ids = ids = { + m.id + for m in app.team.members + if m.role in (discord.TeamMemberRole.admin, discord.TeamMemberRole.developer) + } + return user.id in ids + else: + self.owner_id = owner_id = app.owner.id + return user.id == owner_id + + def before_invoke(self, coro: CFT, /) -> CFT: + """A decorator that registers a coroutine as a pre-invoke hook. + + A pre-invoke hook is called directly before the command is + called. This makes it a useful function to set up database + connections or any type of set up required. + + This pre-invoke hook takes a sole parameter, a :class:`.Context`. + + .. note:: + + The :meth:`~.Bot.before_invoke` and :meth:`~.Bot.after_invoke` hooks are + only called if all checks and argument parsing procedures pass + without error. If any check or argument parsing procedures fail + then the hooks are not called. + + .. versionchanged:: 2.0 + + ``coro`` parameter is now positional-only. + + Parameters + ----------- + coro: :ref:`coroutine ` + The coroutine to register as the pre-invoke hook. + + Raises + ------- + TypeError + The coroutine passed is not actually a coroutine. + """ + if not asyncio.iscoroutinefunction(coro): + raise TypeError('The pre-invoke hook must be a coroutine.') + + self._before_invoke = coro + return coro + + def after_invoke(self, coro: CFT, /) -> CFT: + r"""A decorator that registers a coroutine as a post-invoke hook. + + A post-invoke hook is called directly after the command is + called. This makes it a useful function to clean-up database + connections or any type of clean up required. + + This post-invoke hook takes a sole parameter, a :class:`.Context`. + + .. note:: + + Similar to :meth:`~.Bot.before_invoke`\, this is not called unless + checks and argument parsing procedures succeed. This hook is, + however, **always** called regardless of the internal command + callback raising an error (i.e. :exc:`.CommandInvokeError`\). + This makes it ideal for clean-up scenarios. + + .. versionchanged:: 2.0 + + ``coro`` parameter is now positional-only. + + Parameters + ----------- + coro: :ref:`coroutine ` + The coroutine to register as the post-invoke hook. + + Raises + ------- + TypeError + The coroutine passed is not actually a coroutine. + """ + if not asyncio.iscoroutinefunction(coro): + raise TypeError('The post-invoke hook must be a coroutine.') + + self._after_invoke = coro + return coro + + # listener registration + + def add_listener(self, func: CoroFunc, /, name: str = MISSING) -> None: + """The non decorator alternative to :meth:`.listen`. + + .. versionchanged:: 2.0 + + ``func`` parameter is now positional-only. + + Parameters + ----------- + func: :ref:`coroutine ` + The function to call. + name: :class:`str` + The name of the event to listen for. Defaults to ``func.__name__``. + + Example + -------- + + .. code-block:: python3 + + async def on_ready(): pass + async def my_message(message): pass + + bot.add_listener(on_ready) + bot.add_listener(my_message, 'on_message') + + """ + name = func.__name__ if name is MISSING else name + + if not asyncio.iscoroutinefunction(func): + raise TypeError('Listeners must be coroutines') + + if name in self.extra_events: + self.extra_events[name].append(func) + else: + self.extra_events[name] = [func] + + def remove_listener(self, func: CoroFunc, /, name: str = MISSING) -> None: + """Removes a listener from the pool of listeners. + + .. versionchanged:: 2.0 + + ``func`` parameter is now positional-only. + + Parameters + ----------- + func + The function that was used as a listener to remove. + name: :class:`str` + The name of the event we want to remove. Defaults to + ``func.__name__``. + """ + + name = func.__name__ if name is MISSING else name + + if name in self.extra_events: + try: + self.extra_events[name].remove(func) + except ValueError: + pass + + def listen(self, name: str = MISSING) -> Callable[[CFT], CFT]: + """A decorator that registers another function as an external + event listener. Basically this allows you to listen to multiple + events from different places e.g. such as :func:`.on_ready` + + The functions being listened to must be a :ref:`coroutine `. + + Example + -------- + + .. code-block:: python3 + + @bot.listen() + async def on_message(message): + print('one') + + # in some other file... + + @bot.listen('on_message') + async def my_message(message): + print('two') + + Would print one and two in an unspecified order. + + Raises + ------- + TypeError + The function being listened to is not a coroutine. + """ + + def decorator(func: CFT) -> CFT: + self.add_listener(func, name) + return func + + return decorator + + # cogs + + async def add_cog( + self, + cog: Cog, + /, + *, + override: bool = False, + guild: Optional[Snowflake] = MISSING, + guilds: Sequence[Snowflake] = MISSING, + ) -> None: + """|coro| + + Adds a "cog" to the bot. + + A cog is a class that has its own event listeners and commands. + + If the cog is a :class:`.app_commands.Group` then it is added to + the bot's :class:`~discord.app_commands.CommandTree` as well. + + .. note:: + + Exceptions raised inside a :class:`.Cog`'s :meth:`~.Cog.cog_load` method will be + propagated to the caller. + + .. versionchanged:: 2.0 + + :exc:`.ClientException` is raised when a cog with the same name + is already loaded. + + .. versionchanged:: 2.0 + + ``cog`` parameter is now positional-only. + + .. versionchanged:: 2.0 + + This method is now a :term:`coroutine`. + + Parameters + ----------- + cog: :class:`.Cog` + The cog to register to the bot. + override: :class:`bool` + If a previously loaded cog with the same name should be ejected + instead of raising an error. + + .. versionadded:: 2.0 + guild: Optional[:class:`~discord.abc.Snowflake`] + If the cog is an application command group, then this would be the + guild where the cog group would be added to. If not given then + it becomes a global command instead. + + .. versionadded:: 2.0 + guilds: List[:class:`~discord.abc.Snowflake`] + If the cog is an application command group, then this would be the + guilds where the cog group would be added to. If not given then + it becomes a global command instead. Cannot be mixed with + ``guild``. + + .. versionadded:: 2.0 + + Raises + ------- + TypeError + The cog does not inherit from :class:`.Cog`. + CommandError + An error happened during loading. + ClientException + A cog with the same name is already loaded. + """ + + if not isinstance(cog, Cog): + raise TypeError('cogs must derive from Cog') + + cog_name = cog.__cog_name__ + existing = self.__cogs.get(cog_name) + + if existing is not None: + if not override: + raise discord.ClientException(f'Cog named {cog_name!r} already loaded') + await self.remove_cog(cog_name, guild=guild, guilds=guilds) + + if cog.__cog_app_commands_group__: + self.__tree.add_command(cog.__cog_app_commands_group__, override=override, guild=guild, guilds=guilds) + + cog = await cog._inject(self, override=override, guild=guild, guilds=guilds) + self.__cogs[cog_name] = cog + + def get_cog(self, name: str, /) -> Optional[Cog]: + """Gets the cog instance requested. + + If the cog is not found, ``None`` is returned instead. + + .. versionchanged:: 2.0 + + ``name`` parameter is now positional-only. + + Parameters + ----------- + name: :class:`str` + The name of the cog you are requesting. + This is equivalent to the name passed via keyword + argument in class creation or the class name if unspecified. + + Returns + -------- + Optional[:class:`Cog`] + The cog that was requested. If not found, returns ``None``. + """ + return self.__cogs.get(name) + + async def remove_cog( + self, + name: str, + /, + *, + guild: Optional[Snowflake] = MISSING, + guilds: Sequence[Snowflake] = MISSING, + ) -> Optional[Cog]: + """|coro| + + Removes a cog from the bot and returns it. + + All registered commands and event listeners that the + cog has registered will be removed as well. + + If no cog is found then this method has no effect. + + .. versionchanged:: 2.0 + + ``name`` parameter is now positional-only. + + .. versionchanged:: 2.0 + + This method is now a :term:`coroutine`. + + Parameters + ----------- + name: :class:`str` + The name of the cog to remove. + guild: Optional[:class:`~discord.abc.Snowflake`] + If the cog is an application command group, then this would be the + guild where the cog group would be removed from. If not given then + a global command is removed instead instead. + + .. versionadded:: 2.0 + guilds: List[:class:`~discord.abc.Snowflake`] + If the cog is an application command group, then this would be the + guilds where the cog group would be removed from. If not given then + a global command is removed instead instead. Cannot be mixed with + ``guild``. + + .. versionadded:: 2.0 + + Returns + ------- + Optional[:class:`.Cog`] + The cog that was removed. ``None`` if not found. + """ + + cog = self.__cogs.pop(name, None) + if cog is None: + return + + help_command = self._help_command + if help_command and help_command.cog is cog: + help_command.cog = None + + guild_ids = _retrieve_guild_ids(cog, guild, guilds) + if cog.__cog_app_commands_group__: + if guild_ids is None: + self.__tree.remove_command(name) + else: + for guild_id in guild_ids: + self.__tree.remove_command(name, guild=discord.Object(guild_id)) + + await cog._eject(self, guild_ids=guild_ids) + + return cog + + @property + def cogs(self) -> Mapping[str, Cog]: + """Mapping[:class:`str`, :class:`Cog`]: A read-only mapping of cog name to cog.""" + return types.MappingProxyType(self.__cogs) + + # extensions + + async def _remove_module_references(self, name: str) -> None: + # find all references to the module + # remove the cogs registered from the module + for cogname, cog in self.__cogs.copy().items(): + if _is_submodule(name, cog.__module__): + await self.remove_cog(cogname) + + # remove all the commands from the module + for cmd in self.all_commands.copy().values(): + if cmd.module is not None and _is_submodule(name, cmd.module): + if isinstance(cmd, GroupMixin): + cmd.recursively_remove_all_commands() + self.remove_command(cmd.name) + + # remove all the listeners from the module + for event_list in self.extra_events.copy().values(): + remove = [] + for index, event in enumerate(event_list): + if event.__module__ is not None and _is_submodule(name, event.__module__): + remove.append(index) + + for index in reversed(remove): + del event_list[index] + + # remove all relevant application commands from the tree + self.__tree._remove_with_module(name) + + async def _call_module_finalizers(self, lib: types.ModuleType, key: str) -> None: + try: + func = getattr(lib, 'teardown') + except AttributeError: + pass + else: + try: + await func(self) + except Exception: + pass + finally: + self.__extensions.pop(key, None) + sys.modules.pop(key, None) + name = lib.__name__ + for module in list(sys.modules.keys()): + if _is_submodule(name, module): + del sys.modules[module] + + async def _load_from_module_spec(self, spec: importlib.machinery.ModuleSpec, key: str) -> None: + # precondition: key not in self.__extensions + lib = importlib.util.module_from_spec(spec) + sys.modules[key] = lib + try: + spec.loader.exec_module(lib) # type: ignore + except Exception as e: + del sys.modules[key] + raise errors.ExtensionFailed(key, e) from e + + try: + setup = getattr(lib, 'setup') + except AttributeError: + del sys.modules[key] + raise errors.NoEntryPointError(key) + + try: + await setup(self) + except Exception as e: + del sys.modules[key] + await self._remove_module_references(lib.__name__) + await self._call_module_finalizers(lib, key) + raise errors.ExtensionFailed(key, e) from e + else: + self.__extensions[key] = lib + + def _resolve_name(self, name: str, package: Optional[str]) -> str: + try: + return importlib.util.resolve_name(name, package) + except ImportError: + raise errors.ExtensionNotFound(name) + + async def load_extension(self, name: str, *, package: Optional[str] = None) -> None: + """|coro| + + Loads an extension. + + An extension is a python module that contains commands, cogs, or + listeners. + + An extension must have a global function, ``setup`` defined as + the entry point on what to do when the extension is loaded. This entry + point must have a single argument, the ``bot``. + + .. versionchanged:: 2.0 + + This method is now a :term:`coroutine`. + + Parameters + ------------ + name: :class:`str` + The extension name to load. It must be dot separated like + regular Python imports if accessing a sub-module. e.g. + ``foo.test`` if you want to import ``foo/test.py``. + package: Optional[:class:`str`] + The package name to resolve relative imports with. + This is required when loading an extension using a relative path, e.g ``.foo.test``. + Defaults to ``None``. + + .. versionadded:: 1.7 + + Raises + -------- + ExtensionNotFound + The extension could not be imported. + This is also raised if the name of the extension could not + be resolved using the provided ``package`` parameter. + ExtensionAlreadyLoaded + The extension is already loaded. + NoEntryPointError + The extension does not have a setup function. + ExtensionFailed + The extension or its setup function had an execution error. + """ + + name = self._resolve_name(name, package) + if name in self.__extensions: + raise errors.ExtensionAlreadyLoaded(name) + + spec = importlib.util.find_spec(name) + if spec is None: + raise errors.ExtensionNotFound(name) + + await self._load_from_module_spec(spec, name) + + async def unload_extension(self, name: str, *, package: Optional[str] = None) -> None: + """|coro| + + Unloads an extension. + + When the extension is unloaded, all commands, listeners, and cogs are + removed from the bot and the module is un-imported. + + The extension can provide an optional global function, ``teardown``, + to do miscellaneous clean-up if necessary. This function takes a single + parameter, the ``bot``, similar to ``setup`` from + :meth:`~.Bot.load_extension`. + + .. versionchanged:: 2.0 + + This method is now a :term:`coroutine`. + + Parameters + ------------ + name: :class:`str` + The extension name to unload. It must be dot separated like + regular Python imports if accessing a sub-module. e.g. + ``foo.test`` if you want to import ``foo/test.py``. + package: Optional[:class:`str`] + The package name to resolve relative imports with. + This is required when unloading an extension using a relative path, e.g ``.foo.test``. + Defaults to ``None``. + + .. versionadded:: 1.7 + + Raises + ------- + ExtensionNotFound + The name of the extension could not + be resolved using the provided ``package`` parameter. + ExtensionNotLoaded + The extension was not loaded. + """ + + name = self._resolve_name(name, package) + lib = self.__extensions.get(name) + if lib is None: + raise errors.ExtensionNotLoaded(name) + + await self._remove_module_references(lib.__name__) + await self._call_module_finalizers(lib, name) + + async def reload_extension(self, name: str, *, package: Optional[str] = None) -> None: + """|coro| + + Atomically reloads an extension. + + This replaces the extension with the same extension, only refreshed. This is + equivalent to a :meth:`unload_extension` followed by a :meth:`load_extension` + except done in an atomic way. That is, if an operation fails mid-reload then + the bot will roll-back to the prior working state. + + Parameters + ------------ + name: :class:`str` + The extension name to reload. It must be dot separated like + regular Python imports if accessing a sub-module. e.g. + ``foo.test`` if you want to import ``foo/test.py``. + package: Optional[:class:`str`] + The package name to resolve relative imports with. + This is required when reloading an extension using a relative path, e.g ``.foo.test``. + Defaults to ``None``. + + .. versionadded:: 1.7 + + Raises + ------- + ExtensionNotLoaded + The extension was not loaded. + ExtensionNotFound + The extension could not be imported. + This is also raised if the name of the extension could not + be resolved using the provided ``package`` parameter. + NoEntryPointError + The extension does not have a setup function. + ExtensionFailed + The extension setup function had an execution error. + """ + + name = self._resolve_name(name, package) + lib = self.__extensions.get(name) + if lib is None: + raise errors.ExtensionNotLoaded(name) + + # get the previous module states from sys modules + # fmt: off + modules = { + name: module + for name, module in sys.modules.items() + if _is_submodule(lib.__name__, name) + } + # fmt: on + + try: + # Unload and then load the module... + await self._remove_module_references(lib.__name__) + await self._call_module_finalizers(lib, name) + await self.load_extension(name) + except Exception: + # if the load failed, the remnants should have been + # cleaned from the load_extension function call + # so let's load it from our old compiled library. + await lib.setup(self) + self.__extensions[name] = lib + + # revert sys.modules back to normal and raise back to caller + sys.modules.update(modules) + raise + + @property + def extensions(self) -> Mapping[str, types.ModuleType]: + """Mapping[:class:`str`, :class:`py:types.ModuleType`]: A read-only mapping of extension name to extension.""" + return types.MappingProxyType(self.__extensions) + + # help command stuff + + @property + def help_command(self) -> Optional[HelpCommand]: + return self._help_command + + @help_command.setter + def help_command(self, value: Optional[HelpCommand]) -> None: + if value is not None: + if not isinstance(value, HelpCommand): + raise TypeError('help_command must be a subclass of HelpCommand') + if self._help_command is not None: + self._help_command._remove_from_bot(self) + self._help_command = value + value._add_to_bot(self) + elif self._help_command is not None: + self._help_command._remove_from_bot(self) + self._help_command = None + else: + self._help_command = None + + # application command interop + + # As mentioned above, this is a mixin so the Self type hint fails here. + # However, since the only classes that can use this are subclasses of Client + # anyway, then this is sound. + @property + def tree(self) -> app_commands.CommandTree[Self]: # type: ignore + """:class:`~discord.app_commands.CommandTree`: The command tree responsible for handling the application commands + in this bot. + + .. versionadded:: 2.0 + """ + return self.__tree + + # command processing + + async def get_prefix(self, message: Message, /) -> Union[List[str], str]: + """|coro| + + Retrieves the prefix the bot is listening to + with the message as a context. + + .. versionchanged:: 2.0 + + ``message`` parameter is now positional-only. + + Parameters + ----------- + message: :class:`discord.Message` + The message context to get the prefix of. + + Returns + -------- + Union[List[:class:`str`], :class:`str`] + A list of prefixes or a single prefix that the bot is + listening for. + """ + prefix = ret = self.command_prefix + + if callable(prefix): + # self will be a Bot or AutoShardedBot + ret = await discord.utils.maybe_coroutine(prefix, self, message) # type: ignore + + if not isinstance(ret, str): + try: + ret = list(ret) # type: ignore + except TypeError: + # It's possible that a generator raised this exception. Don't + # replace it with our own error if that's the case. + if isinstance(ret, collections.abc.Iterable): + raise + + raise TypeError( + "command_prefix must be plain string, iterable of strings, or callable " + f"returning either of these, not {ret.__class__.__name__}" + ) + + return ret + + @overload + async def get_context( + self, + origin: Union[Message, Interaction], + /, + ) -> Context[Self]: # type: ignore + ... + + @overload + async def get_context( + self, + origin: Union[Message, Interaction], + /, + *, + cls: Type[ContextT], + ) -> ContextT: + ... + + async def get_context( + self, + origin: Union[Message, Interaction], + /, + *, + cls: Type[ContextT] = MISSING, + ) -> Any: + r"""|coro| + + Returns the invocation context from the message or interaction. + + This is a more low-level counter-part for :meth:`.process_commands` + to allow users more fine grained control over the processing. + + The returned context is not guaranteed to be a valid invocation + context, :attr:`.Context.valid` must be checked to make sure it is. + If the context is not valid then it is not a valid candidate to be + invoked under :meth:`~.Bot.invoke`. + + .. note:: + + In order for the custom context to be used inside an interaction-based + context (such as :class:`HybridCommand`) then this method must be + overridden to return that class. + + .. versionchanged:: 2.0 + + ``message`` parameter is now positional-only and renamed to ``origin``. + + Parameters + ----------- + origin: Union[:class:`discord.Message`, :class:`discord.Interaction`] + The message or interaction to get the invocation context from. + cls + The factory class that will be used to create the context. + By default, this is :class:`.Context`. Should a custom + class be provided, it must be similar enough to :class:`.Context`\'s + interface. + + Returns + -------- + :class:`.Context` + The invocation context. The type of this can change via the + ``cls`` parameter. + """ + if cls is MISSING: + cls = Context # type: ignore + + if isinstance(origin, discord.Interaction): + return await cls.from_interaction(origin) + + view = StringView(origin.content) + ctx = cls(prefix=None, view=view, bot=self, message=origin) + + if origin.author.id == self.user.id: # type: ignore + return ctx + + prefix = await self.get_prefix(origin) + invoked_prefix = prefix + + if isinstance(prefix, str): + if not view.skip_string(prefix): + return ctx + else: + try: + # if the context class' __init__ consumes something from the view this + # will be wrong. That seems unreasonable though. + if origin.content.startswith(tuple(prefix)): + invoked_prefix = discord.utils.find(view.skip_string, prefix) + else: + return ctx + + except TypeError: + if not isinstance(prefix, list): + raise TypeError( + "get_prefix must return either a string or a list of string, " f"not {prefix.__class__.__name__}" + ) + + # It's possible a bad command_prefix got us here. + for value in prefix: + if not isinstance(value, str): + raise TypeError( + "Iterable command_prefix or list returned from get_prefix must " + f"contain only strings, not {value.__class__.__name__}" + ) + + # Getting here shouldn't happen + raise + + if self.strip_after_prefix: + view.skip_ws() + + invoker = view.get_word() + ctx.invoked_with = invoker + # type-checker fails to narrow invoked_prefix type. + ctx.prefix = invoked_prefix # type: ignore + ctx.command = self.all_commands.get(invoker) + return ctx + + async def invoke(self, ctx: Context[BotT], /) -> None: + """|coro| + + Invokes the command given under the invocation context and + handles all the internal event dispatch mechanisms. + + .. versionchanged:: 2.0 + + ``ctx`` parameter is now positional-only. + + Parameters + ----------- + ctx: :class:`.Context` + The invocation context to invoke. + """ + if ctx.command is not None: + self.dispatch('command', ctx) + try: + if await self.can_run(ctx, call_once=True): + await ctx.command.invoke(ctx) + else: + raise errors.CheckFailure('The global check once functions failed.') + except errors.CommandError as exc: + await ctx.command.dispatch_error(ctx, exc) + else: + self.dispatch('command_completion', ctx) + elif ctx.invoked_with: + exc = errors.CommandNotFound(f'Command "{ctx.invoked_with}" is not found') + self.dispatch('command_error', ctx, exc) + + async def process_commands(self, message: Message, /) -> None: + """|coro| + + This function processes the commands that have been registered + to the bot and other groups. Without this coroutine, none of the + commands will be triggered. + + By default, this coroutine is called inside the :func:`.on_message` + event. If you choose to override the :func:`.on_message` event, then + you should invoke this coroutine as well. + + This is built using other low level tools, and is equivalent to a + call to :meth:`~.Bot.get_context` followed by a call to :meth:`~.Bot.invoke`. + + This also checks if the message's author is a bot and doesn't + call :meth:`~.Bot.get_context` or :meth:`~.Bot.invoke` if so. + + .. versionchanged:: 2.0 + + ``message`` parameter is now positional-only. + + Parameters + ----------- + message: :class:`discord.Message` + The message to process commands for. + """ + if message.author.bot: + return + + ctx = await self.get_context(message) + # the type of the invocation context's bot attribute will be correct + await self.invoke(ctx) # type: ignore + + async def on_message(self, message: Message, /) -> None: + await self.process_commands(message) + + +class Bot(BotBase, discord.Client): + """Represents a Discord bot. + + This class is a subclass of :class:`discord.Client` and as a result + anything that you can do with a :class:`discord.Client` you can do with + this bot. + + This class also subclasses :class:`.GroupMixin` to provide the functionality + to manage commands. + + Unlike :class:`discord.Client`, this class does not require manually setting + a :class:`~discord.app_commands.CommandTree` and is automatically set upon + instantiating the class. + + .. container:: operations + + .. describe:: async with x + + Asynchronously initialises the bot and automatically cleans up. + + .. versionadded:: 2.0 + + Attributes + ----------- + command_prefix + The command prefix is what the message content must contain initially + to have a command invoked. This prefix could either be a string to + indicate what the prefix should be, or a callable that takes in the bot + as its first parameter and :class:`discord.Message` as its second + parameter and returns the prefix. This is to facilitate "dynamic" + command prefixes. This callable can be either a regular function or + a coroutine. + + An empty string as the prefix always matches, enabling prefix-less + command invocation. While this may be useful in DMs it should be avoided + in servers, as it's likely to cause performance issues and unintended + command invocations. + + The command prefix could also be an iterable of strings indicating that + multiple checks for the prefix should be used and the first one to + match will be the invocation prefix. You can get this prefix via + :attr:`.Context.prefix`. + + .. note:: + + When passing multiple prefixes be careful to not pass a prefix + that matches a longer prefix occurring later in the sequence. For + example, if the command prefix is ``('!', '!?')`` the ``'!?'`` + prefix will never be matched to any message as the previous one + matches messages starting with ``!?``. This is especially important + when passing an empty string, it should always be last as no prefix + after it will be matched. + case_insensitive: :class:`bool` + Whether the commands should be case insensitive. Defaults to ``False``. This + attribute does not carry over to groups. You must set it to every group if + you require group commands to be case insensitive as well. + description: :class:`str` + The content prefixed into the default help message. + help_command: Optional[:class:`.HelpCommand`] + The help command implementation to use. This can be dynamically + set at runtime. To remove the help command pass ``None``. For more + information on implementing a help command, see :ref:`ext_commands_help_command`. + owner_id: Optional[:class:`int`] + The user ID that owns the bot. If this is not set and is then queried via + :meth:`.is_owner` then it is fetched automatically using + :meth:`~.Bot.application_info`. + owner_ids: Optional[Collection[:class:`int`]] + The user IDs that owns the bot. This is similar to :attr:`owner_id`. + If this is not set and the application is team based, then it is + fetched automatically using :meth:`~.Bot.application_info`. + For performance reasons it is recommended to use a :class:`set` + for the collection. You cannot set both ``owner_id`` and ``owner_ids``. + + .. versionadded:: 1.3 + strip_after_prefix: :class:`bool` + Whether to strip whitespace characters after encountering the command + prefix. This allows for ``! hello`` and ``!hello`` to both work if + the ``command_prefix`` is set to ``!``. Defaults to ``False``. + + .. versionadded:: 1.7 + tree_cls: Type[:class:`~discord.app_commands.CommandTree`] + The type of application command tree to use. Defaults to :class:`~discord.app_commands.CommandTree`. + + .. versionadded:: 2.0 + allowed_contexts: :class:`~discord.app_commands.AppCommandContext` + The default allowed contexts that applies to all application commands + in the application command tree. + + Note that you can override this on a per command basis. + + .. versionadded:: 2.4 + allowed_installs: :class:`~discord.app_commands.AppInstallationType` + The default allowed install locations that apply to all application commands + in the application command tree. + + Note that you can override this on a per command basis. + + .. versionadded:: 2.4 + """ + + pass + + +class AutoShardedBot(BotBase, discord.AutoShardedClient): + """This is similar to :class:`.Bot` except that it is inherited from + :class:`discord.AutoShardedClient` instead. + + .. container:: operations + + .. describe:: async with x + + Asynchronously initialises the bot and automatically cleans. + + .. versionadded:: 2.0 + """ + + pass diff --git a/venv/lib/python3.12/site-packages/discord/ext/commands/cog.py b/venv/lib/python3.12/site-packages/discord/ext/commands/cog.py new file mode 100644 index 00000000..659d69eb --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/ext/commands/cog.py @@ -0,0 +1,809 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" +from __future__ import annotations + +import inspect +import discord +import logging +from discord import app_commands +from discord.utils import maybe_coroutine, _to_kebab_case + +from typing import ( + Any, + Callable, + ClassVar, + Coroutine, + Dict, + Generator, + Iterable, + List, + Optional, + TYPE_CHECKING, + Sequence, + Tuple, + TypeVar, + Union, +) + +from ._types import _BaseCommand, BotT + +if TYPE_CHECKING: + from typing_extensions import Self + from discord.abc import Snowflake + from discord._types import ClientT + + from .bot import BotBase + from .context import Context + from .core import Command + +__all__ = ( + 'CogMeta', + 'Cog', + 'GroupCog', +) + +FuncT = TypeVar('FuncT', bound=Callable[..., Any]) + +MISSING: Any = discord.utils.MISSING +_log = logging.getLogger(__name__) + + +class CogMeta(type): + """A metaclass for defining a cog. + + Note that you should probably not use this directly. It is exposed + purely for documentation purposes along with making custom metaclasses to intermix + with other metaclasses such as the :class:`abc.ABCMeta` metaclass. + + For example, to create an abstract cog mixin class, the following would be done. + + .. code-block:: python3 + + import abc + + class CogABCMeta(commands.CogMeta, abc.ABCMeta): + pass + + class SomeMixin(metaclass=abc.ABCMeta): + pass + + class SomeCogMixin(SomeMixin, commands.Cog, metaclass=CogABCMeta): + pass + + .. note:: + + When passing an attribute of a metaclass that is documented below, note + that you must pass it as a keyword-only argument to the class creation + like the following example: + + .. code-block:: python3 + + class MyCog(commands.Cog, name='My Cog'): + pass + + Attributes + ----------- + name: :class:`str` + The cog name. By default, it is the name of the class with no modification. + description: :class:`str` + The cog description. By default, it is the cleaned docstring of the class. + + .. versionadded:: 1.6 + + command_attrs: :class:`dict` + A list of attributes to apply to every command inside this cog. The dictionary + is passed into the :class:`Command` options at ``__init__``. + If you specify attributes inside the command attribute in the class, it will + override the one specified inside this attribute. For example: + + .. code-block:: python3 + + class MyCog(commands.Cog, command_attrs=dict(hidden=True)): + @commands.command() + async def foo(self, ctx): + pass # hidden -> True + + @commands.command(hidden=False) + async def bar(self, ctx): + pass # hidden -> False + + group_name: Union[:class:`str`, :class:`~discord.app_commands.locale_str`] + The group name of a cog. This is only applicable for :class:`GroupCog` instances. + By default, it's the same value as :attr:`name`. + + .. versionadded:: 2.0 + group_description: Union[:class:`str`, :class:`~discord.app_commands.locale_str`] + The group description of a cog. This is only applicable for :class:`GroupCog` instances. + By default, it's the same value as :attr:`description`. + + .. versionadded:: 2.0 + group_nsfw: :class:`bool` + Whether the application command group is NSFW. This is only applicable for :class:`GroupCog` instances. + By default, it's ``False``. + + .. versionadded:: 2.0 + group_auto_locale_strings: :class:`bool` + If this is set to ``True``, then all translatable strings will implicitly + be wrapped into :class:`~discord.app_commands.locale_str` rather + than :class:`str`. Defaults to ``True``. + + .. versionadded:: 2.0 + group_extras: :class:`dict` + A dictionary that can be used to store extraneous data. + This is only applicable for :class:`GroupCog` instances. + The library will not touch any values or keys within this dictionary. + + .. versionadded:: 2.1 + """ + + __cog_name__: str + __cog_description__: str + __cog_group_name__: Union[str, app_commands.locale_str] + __cog_group_description__: Union[str, app_commands.locale_str] + __cog_group_nsfw__: bool + __cog_group_auto_locale_strings__: bool + __cog_group_extras__: Dict[Any, Any] + __cog_settings__: Dict[str, Any] + __cog_commands__: List[Command[Any, ..., Any]] + __cog_app_commands__: List[Union[app_commands.Group, app_commands.Command[Any, ..., Any]]] + __cog_listeners__: List[Tuple[str, str]] + + def __new__(cls, *args: Any, **kwargs: Any) -> CogMeta: + name, bases, attrs = args + if any(issubclass(base, app_commands.Group) for base in bases): + raise TypeError( + 'Cannot inherit from app_commands.Group with commands.Cog, consider using commands.GroupCog instead' + ) + + # If name='...' is given but not group_name='...' then name='...' is used for both. + # If neither is given then cog name is the class name but group name is kebab case + try: + cog_name = kwargs.pop('name') + except KeyError: + cog_name = name + try: + group_name = kwargs.pop('group_name') + except KeyError: + group_name = _to_kebab_case(name) + else: + group_name = kwargs.pop('group_name', cog_name) + + attrs['__cog_settings__'] = kwargs.pop('command_attrs', {}) + attrs['__cog_name__'] = cog_name + attrs['__cog_group_name__'] = group_name + attrs['__cog_group_nsfw__'] = kwargs.pop('group_nsfw', False) + attrs['__cog_group_auto_locale_strings__'] = kwargs.pop('group_auto_locale_strings', True) + attrs['__cog_group_extras__'] = kwargs.pop('group_extras', {}) + + description = kwargs.pop('description', None) + if description is None: + description = inspect.cleandoc(attrs.get('__doc__', '')) + + attrs['__cog_description__'] = description + attrs['__cog_group_description__'] = kwargs.pop('group_description', description or '\u2026') + + commands = {} + cog_app_commands = {} + listeners = {} + no_bot_cog = 'Commands or listeners must not start with cog_ or bot_ (in method {0.__name__}.{1})' + + new_cls = super().__new__(cls, name, bases, attrs, **kwargs) + for base in reversed(new_cls.__mro__): + for elem, value in base.__dict__.items(): + if elem in commands: + del commands[elem] + if elem in listeners: + del listeners[elem] + + is_static_method = isinstance(value, staticmethod) + if is_static_method: + value = value.__func__ + if isinstance(value, _BaseCommand): + if is_static_method: + raise TypeError(f'Command in method {base}.{elem!r} must not be staticmethod.') + if elem.startswith(('cog_', 'bot_')): + raise TypeError(no_bot_cog.format(base, elem)) + commands[elem] = value + elif isinstance(value, (app_commands.Group, app_commands.Command)) and value.parent is None: + if is_static_method: + raise TypeError(f'Command in method {base}.{elem!r} must not be staticmethod.') + if elem.startswith(('cog_', 'bot_')): + raise TypeError(no_bot_cog.format(base, elem)) + cog_app_commands[elem] = value + elif inspect.iscoroutinefunction(value): + try: + getattr(value, '__cog_listener__') + except AttributeError: + continue + else: + if elem.startswith(('cog_', 'bot_')): + raise TypeError(no_bot_cog.format(base, elem)) + listeners[elem] = value + + new_cls.__cog_commands__ = list(commands.values()) # this will be copied in Cog.__new__ + new_cls.__cog_app_commands__ = list(cog_app_commands.values()) + + listeners_as_list = [] + for listener in listeners.values(): + for listener_name in listener.__cog_listener_names__: + # I use __name__ instead of just storing the value so I can inject + # the self attribute when the time comes to add them to the bot + listeners_as_list.append((listener_name, listener.__name__)) + + new_cls.__cog_listeners__ = listeners_as_list + return new_cls + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args) + + @classmethod + def qualified_name(cls) -> str: + return cls.__cog_name__ + + +def _cog_special_method(func: FuncT) -> FuncT: + func.__cog_special_method__ = None + return func + + +class Cog(metaclass=CogMeta): + """The base class that all cogs must inherit from. + + A cog is a collection of commands, listeners, and optional state to + help group commands together. More information on them can be found on + the :ref:`ext_commands_cogs` page. + + When inheriting from this class, the options shown in :class:`CogMeta` + are equally valid here. + """ + + __cog_name__: str + __cog_description__: str + __cog_group_name__: Union[str, app_commands.locale_str] + __cog_group_description__: Union[str, app_commands.locale_str] + __cog_settings__: Dict[str, Any] + __cog_commands__: List[Command[Self, ..., Any]] + __cog_app_commands__: List[Union[app_commands.Group, app_commands.Command[Self, ..., Any]]] + __cog_listeners__: List[Tuple[str, str]] + __cog_is_app_commands_group__: ClassVar[bool] = False + __cog_app_commands_group__: Optional[app_commands.Group] + __discord_app_commands_error_handler__: Optional[ + Callable[[discord.Interaction, app_commands.AppCommandError], Coroutine[Any, Any, None]] + ] + + def __new__(cls, *args: Any, **kwargs: Any) -> Self: + # For issue 426, we need to store a copy of the command objects + # since we modify them to inject `self` to them. + # To do this, we need to interfere with the Cog creation process. + self = super().__new__(cls) + cmd_attrs = cls.__cog_settings__ + + # Either update the command with the cog provided defaults or copy it. + # r.e type ignore, type-checker complains about overriding a ClassVar + self.__cog_commands__ = tuple(c._update_copy(cmd_attrs) for c in cls.__cog_commands__) # type: ignore + + lookup = {cmd.qualified_name: cmd for cmd in self.__cog_commands__} + + # Register the application commands + children: List[Union[app_commands.Group, app_commands.Command[Self, ..., Any]]] = [] + app_command_refs: Dict[str, Union[app_commands.Group, app_commands.Command[Self, ..., Any]]] = {} + + if cls.__cog_is_app_commands_group__: + group = app_commands.Group( + name=cls.__cog_group_name__, + description=cls.__cog_group_description__, + nsfw=cls.__cog_group_nsfw__, + auto_locale_strings=cls.__cog_group_auto_locale_strings__, + parent=None, + guild_ids=getattr(cls, '__discord_app_commands_default_guilds__', None), + guild_only=getattr(cls, '__discord_app_commands_guild_only__', False), + allowed_contexts=getattr(cls, '__discord_app_commands_contexts__', None), + allowed_installs=getattr(cls, '__discord_app_commands_installation_types__', None), + default_permissions=getattr(cls, '__discord_app_commands_default_permissions__', None), + extras=cls.__cog_group_extras__, + ) + else: + group = None + + self.__cog_app_commands_group__ = group + + # Update the Command instances dynamically as well + for command in self.__cog_commands__: + setattr(self, command.callback.__name__, command) + parent = command.parent + if parent is not None: + # Get the latest parent reference + parent = lookup[parent.qualified_name] # type: ignore + + # Hybrid commands already deal with updating the reference + # Due to the copy below, so we need to handle them specially + if hasattr(parent, '__commands_is_hybrid__') and hasattr(command, '__commands_is_hybrid__'): + current: Optional[Union[app_commands.Group, app_commands.Command[Self, ..., Any]]] = getattr( + command, 'app_command', None + ) + updated = app_command_refs.get(command.qualified_name) + if current and updated: + command.app_command = updated # type: ignore # Safe attribute access + + # Update our parent's reference to our self + parent.remove_command(command.name) # type: ignore + parent.add_command(command) # type: ignore + + if hasattr(command, '__commands_is_hybrid__') and parent is None: + app_command: Optional[Union[app_commands.Group, app_commands.Command[Self, ..., Any]]] = getattr( + command, 'app_command', None + ) + if app_command: + group_parent = self.__cog_app_commands_group__ + app_command = app_command._copy_with(parent=group_parent, binding=self) + # The type checker does not see the app_command attribute even though it exists + command.app_command = app_command # type: ignore + + # Update all the references to point to the new copy + if isinstance(app_command, app_commands.Group): + for child in app_command.walk_commands(): + app_command_refs[child.qualified_name] = child + if hasattr(child, '__commands_is_hybrid_app_command__') and child.qualified_name in lookup: + child.wrapped = lookup[child.qualified_name] # type: ignore + + if self.__cog_app_commands_group__: + children.append(app_command) + + if Cog._get_overridden_method(self.cog_app_command_error) is not None: + error_handler = self.cog_app_command_error + else: + error_handler = None + + self.__discord_app_commands_error_handler__ = error_handler + + for command in cls.__cog_app_commands__: + copy = command._copy_with(parent=self.__cog_app_commands_group__, binding=self) + + # Update set bindings + if copy._attr: + setattr(self, copy._attr, copy) + + if isinstance(copy, app_commands.Group): + copy.__discord_app_commands_error_handler__ = error_handler + for command in copy._children.values(): + if isinstance(command, app_commands.Group): + command.__discord_app_commands_error_handler__ = error_handler + + children.append(copy) + + self.__cog_app_commands__ = children + if self.__cog_app_commands_group__: + self.__cog_app_commands_group__.module = cls.__module__ + mapping = {cmd.name: cmd for cmd in children} + if len(mapping) > 25: + raise TypeError('maximum number of application command children exceeded') + + self.__cog_app_commands_group__._children = mapping + + return self + + def get_commands(self) -> List[Command[Self, ..., Any]]: + r"""Returns the commands that are defined inside this cog. + + This does *not* include :class:`discord.app_commands.Command` or :class:`discord.app_commands.Group` + instances. + + Returns + -------- + List[:class:`.Command`] + A :class:`list` of :class:`.Command`\s that are + defined inside this cog, not including subcommands. + """ + return [c for c in self.__cog_commands__ if c.parent is None] + + def get_app_commands(self) -> List[Union[app_commands.Command[Self, ..., Any], app_commands.Group]]: + r"""Returns the app commands that are defined inside this cog. + + Returns + -------- + List[Union[:class:`discord.app_commands.Command`, :class:`discord.app_commands.Group`]] + A :class:`list` of :class:`discord.app_commands.Command`\s and :class:`discord.app_commands.Group`\s that are + defined inside this cog, not including subcommands. + """ + return [c for c in self.__cog_app_commands__ if c.parent is None] + + @property + def qualified_name(self) -> str: + """:class:`str`: Returns the cog's specified name, not the class name.""" + return self.__cog_name__ + + @property + def description(self) -> str: + """:class:`str`: Returns the cog's description, typically the cleaned docstring.""" + return self.__cog_description__ + + @description.setter + def description(self, description: str) -> None: + self.__cog_description__ = description + + def walk_commands(self) -> Generator[Command[Self, ..., Any], None, None]: + """An iterator that recursively walks through this cog's commands and subcommands. + + Yields + ------ + Union[:class:`.Command`, :class:`.Group`] + A command or group from the cog. + """ + from .core import GroupMixin + + for command in self.__cog_commands__: + if command.parent is None: + yield command + if isinstance(command, GroupMixin): + yield from command.walk_commands() + + def walk_app_commands(self) -> Generator[Union[app_commands.Command[Self, ..., Any], app_commands.Group], None, None]: + """An iterator that recursively walks through this cog's app commands and subcommands. + + Yields + ------ + Union[:class:`discord.app_commands.Command`, :class:`discord.app_commands.Group`] + An app command or group from the cog. + """ + for command in self.__cog_app_commands__: + yield command + if isinstance(command, app_commands.Group): + yield from command.walk_commands() + + @property + def app_command(self) -> Optional[app_commands.Group]: + """Optional[:class:`discord.app_commands.Group`]: Returns the associated group with this cog. + + This is only available if inheriting from :class:`GroupCog`. + """ + return self.__cog_app_commands_group__ + + def get_listeners(self) -> List[Tuple[str, Callable[..., Any]]]: + """Returns a :class:`list` of (name, function) listener pairs that are defined in this cog. + + Returns + -------- + List[Tuple[:class:`str`, :ref:`coroutine `]] + The listeners defined in this cog. + """ + return [(name, getattr(self, method_name)) for name, method_name in self.__cog_listeners__] + + @classmethod + def _get_overridden_method(cls, method: FuncT) -> Optional[FuncT]: + """Return None if the method is not overridden. Otherwise returns the overridden method.""" + return getattr(method.__func__, '__cog_special_method__', method) + + @classmethod + def listener(cls, name: str = MISSING) -> Callable[[FuncT], FuncT]: + """A decorator that marks a function as a listener. + + This is the cog equivalent of :meth:`.Bot.listen`. + + Parameters + ------------ + name: :class:`str` + The name of the event being listened to. If not provided, it + defaults to the function's name. + + Raises + -------- + TypeError + The function is not a coroutine function or a string was not passed as + the name. + """ + + if name is not MISSING and not isinstance(name, str): + raise TypeError(f'Cog.listener expected str but received {name.__class__.__name__} instead.') + + def decorator(func: FuncT) -> FuncT: + actual = func + if isinstance(actual, staticmethod): + actual = actual.__func__ + if not inspect.iscoroutinefunction(actual): + raise TypeError('Listener function must be a coroutine function.') + actual.__cog_listener__ = True + to_assign = name or actual.__name__ + try: + actual.__cog_listener_names__.append(to_assign) + except AttributeError: + actual.__cog_listener_names__ = [to_assign] + # we have to return `func` instead of `actual` because + # we need the type to be `staticmethod` for the metaclass + # to pick it up but the metaclass unfurls the function and + # thus the assignments need to be on the actual function + return func + + return decorator + + def has_error_handler(self) -> bool: + """:class:`bool`: Checks whether the cog has an error handler. + + .. versionadded:: 1.7 + """ + return not hasattr(self.cog_command_error.__func__, '__cog_special_method__') + + def has_app_command_error_handler(self) -> bool: + """:class:`bool`: Checks whether the cog has an app error handler. + + .. versionadded:: 2.1 + """ + return not hasattr(self.cog_app_command_error.__func__, '__cog_special_method__') + + @_cog_special_method + async def cog_load(self) -> None: + """|maybecoro| + + A special method that is called when the cog gets loaded. + + Subclasses must replace this if they want special asynchronous loading behaviour. + Note that the ``__init__`` special method does not allow asynchronous code to run + inside it, thus this is helpful for setting up code that needs to be asynchronous. + + .. versionadded:: 2.0 + """ + pass + + @_cog_special_method + async def cog_unload(self) -> None: + """|maybecoro| + + A special method that is called when the cog gets removed. + + Subclasses must replace this if they want special unloading behaviour. + + Exceptions raised in this method are ignored during extension unloading. + + .. versionchanged:: 2.0 + + This method can now be a :term:`coroutine`. + """ + pass + + @_cog_special_method + def bot_check_once(self, ctx: Context[BotT]) -> bool: + """A special method that registers as a :meth:`.Bot.check_once` + check. + + This function **can** be a coroutine and must take a sole parameter, + ``ctx``, to represent the :class:`.Context`. + """ + return True + + @_cog_special_method + def bot_check(self, ctx: Context[BotT]) -> bool: + """A special method that registers as a :meth:`.Bot.check` + check. + + This function **can** be a coroutine and must take a sole parameter, + ``ctx``, to represent the :class:`.Context`. + """ + return True + + @_cog_special_method + def cog_check(self, ctx: Context[BotT]) -> bool: + """A special method that registers as a :func:`~discord.ext.commands.check` + for every command and subcommand in this cog. + + This function **can** be a coroutine and must take a sole parameter, + ``ctx``, to represent the :class:`.Context`. + """ + return True + + @_cog_special_method + def interaction_check(self, interaction: discord.Interaction[ClientT], /) -> bool: + """A special method that registers as a :func:`discord.app_commands.check` + for every app command and subcommand in this cog. + + This function **can** be a coroutine and must take a sole parameter, + ``interaction``, to represent the :class:`~discord.Interaction`. + + .. versionadded:: 2.0 + """ + return True + + @_cog_special_method + async def cog_command_error(self, ctx: Context[BotT], error: Exception) -> None: + """|coro| + + A special method that is called whenever an error + is dispatched inside this cog. + + This is similar to :func:`.on_command_error` except only applying + to the commands inside this cog. + + This **must** be a coroutine. + + Parameters + ----------- + ctx: :class:`.Context` + The invocation context where the error happened. + error: :class:`CommandError` + The error that happened. + """ + pass + + @_cog_special_method + async def cog_app_command_error(self, interaction: discord.Interaction, error: app_commands.AppCommandError) -> None: + """|coro| + + A special method that is called whenever an error within + an application command is dispatched inside this cog. + + This is similar to :func:`discord.app_commands.CommandTree.on_error` except + only applying to the application commands inside this cog. + + This **must** be a coroutine. + + Parameters + ----------- + interaction: :class:`~discord.Interaction` + The interaction that is being handled. + error: :exc:`~discord.app_commands.AppCommandError` + The exception that was raised. + """ + pass + + @_cog_special_method + async def cog_before_invoke(self, ctx: Context[BotT]) -> None: + """|coro| + + A special method that acts as a cog local pre-invoke hook. + + This is similar to :meth:`.Command.before_invoke`. + + This **must** be a coroutine. + + Parameters + ----------- + ctx: :class:`.Context` + The invocation context. + """ + pass + + @_cog_special_method + async def cog_after_invoke(self, ctx: Context[BotT]) -> None: + """|coro| + + A special method that acts as a cog local post-invoke hook. + + This is similar to :meth:`.Command.after_invoke`. + + This **must** be a coroutine. + + Parameters + ----------- + ctx: :class:`.Context` + The invocation context. + """ + pass + + async def _inject(self, bot: BotBase, override: bool, guild: Optional[Snowflake], guilds: Sequence[Snowflake]) -> Self: + cls = self.__class__ + + # we'll call this first so that errors can propagate without + # having to worry about undoing anything + await maybe_coroutine(self.cog_load) + + # realistically, the only thing that can cause loading errors + # is essentially just the command loading, which raises if there are + # duplicates. When this condition is met, we want to undo all what + # we've added so far for some form of atomic loading. + for index, command in enumerate(self.__cog_commands__): + command.cog = self + if command.parent is None: + try: + bot.add_command(command) + except Exception as e: + # undo our additions + for to_undo in self.__cog_commands__[:index]: + if to_undo.parent is None: + bot.remove_command(to_undo.name) + try: + await maybe_coroutine(self.cog_unload) + finally: + raise e + + # check if we're overriding the default + if cls.bot_check is not Cog.bot_check: + bot.add_check(self.bot_check) + + if cls.bot_check_once is not Cog.bot_check_once: + bot.add_check(self.bot_check_once, call_once=True) + + # while Bot.add_listener can raise if it's not a coroutine, + # this precondition is already met by the listener decorator + # already, thus this should never raise. + # Outside of, memory errors and the like... + for name, method_name in self.__cog_listeners__: + bot.add_listener(getattr(self, method_name), name) + + # Only do this if these are "top level" commands + if not self.__cog_app_commands_group__: + for command in self.__cog_app_commands__: + # This is already atomic + bot.tree.add_command(command, override=override, guild=guild, guilds=guilds) + + return self + + async def _eject(self, bot: BotBase, guild_ids: Optional[Iterable[int]]) -> None: + cls = self.__class__ + + try: + for command in self.__cog_commands__: + if command.parent is None: + bot.remove_command(command.name) + + if not self.__cog_app_commands_group__: + for command in self.__cog_app_commands__: + guild_ids = guild_ids or command._guild_ids + if guild_ids is None: + bot.tree.remove_command(command.name) + else: + for guild_id in guild_ids: + bot.tree.remove_command(command.name, guild=discord.Object(id=guild_id)) + + for name, method_name in self.__cog_listeners__: + bot.remove_listener(getattr(self, method_name), name) + + if cls.bot_check is not Cog.bot_check: + bot.remove_check(self.bot_check) + + if cls.bot_check_once is not Cog.bot_check_once: + bot.remove_check(self.bot_check_once, call_once=True) + finally: + try: + await maybe_coroutine(self.cog_unload) + except Exception: + _log.exception('Ignoring exception in cog unload for Cog %r (%r)', cls, self.qualified_name) + + +class GroupCog(Cog): + """Represents a cog that also doubles as a parent :class:`discord.app_commands.Group` for + the application commands defined within it. + + This inherits from :class:`Cog` and the options in :class:`CogMeta` also apply to this. + See the :class:`Cog` documentation for methods. + + Decorators such as :func:`~discord.app_commands.guild_only`, :func:`~discord.app_commands.guilds`, + and :func:`~discord.app_commands.default_permissions` will apply to the group if used on top of the + cog. + + Hybrid commands will also be added to the Group, giving the ability to categorize slash commands into + groups, while keeping the prefix-style command as a root-level command. + + For example: + + .. code-block:: python3 + + from discord import app_commands + from discord.ext import commands + + @app_commands.guild_only() + class MyCog(commands.GroupCog, group_name='my-cog'): + pass + + .. versionadded:: 2.0 + """ + + __cog_is_app_commands_group__: ClassVar[bool] = True diff --git a/venv/lib/python3.12/site-packages/discord/ext/commands/context.py b/venv/lib/python3.12/site-packages/discord/ext/commands/context.py new file mode 100644 index 00000000..7198c120 --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/ext/commands/context.py @@ -0,0 +1,1089 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" +from __future__ import annotations + +import re +from typing import TYPE_CHECKING, Any, Dict, Generator, Generic, List, Optional, TypeVar, Union, Sequence, Type, overload + +import discord.abc +import discord.utils +from discord import Interaction, Message, Attachment, MessageType, User, PartialMessageable, Permissions, ChannelType, Thread +from discord.context_managers import Typing +from .view import StringView + +from ._types import BotT + +if TYPE_CHECKING: + from typing_extensions import Self, ParamSpec, TypeGuard + + from discord.abc import MessageableChannel + from discord.guild import Guild + from discord.member import Member + from discord.state import ConnectionState + from discord.user import ClientUser + from discord.voice_client import VoiceProtocol + from discord.embeds import Embed + from discord.file import File + from discord.mentions import AllowedMentions + from discord.sticker import GuildSticker, StickerItem + from discord.message import MessageReference, PartialMessage + from discord.ui import View + from discord.types.interactions import ApplicationCommandInteractionData + from discord.poll import Poll + + from .cog import Cog + from .core import Command + from .parameters import Parameter + + from types import TracebackType + + BE = TypeVar('BE', bound=BaseException) + +# fmt: off +__all__ = ( + 'Context', +) +# fmt: on + +MISSING: Any = discord.utils.MISSING + + +T = TypeVar('T') +CogT = TypeVar('CogT', bound="Cog") + +if TYPE_CHECKING: + P = ParamSpec('P') +else: + P = TypeVar('P') + + +def is_cog(obj: Any) -> TypeGuard[Cog]: + return hasattr(obj, '__cog_commands__') + + +class DeferTyping(Generic[BotT]): + def __init__(self, ctx: Context[BotT], *, ephemeral: bool): + self.ctx: Context[BotT] = ctx + self.ephemeral: bool = ephemeral + + async def do_defer(self) -> None: + if self.ctx.interaction and not self.ctx.interaction.response.is_done(): + await self.ctx.interaction.response.defer(ephemeral=self.ephemeral) + + def __await__(self) -> Generator[Any, None, None]: + return self.do_defer().__await__() + + async def __aenter__(self) -> None: + await self.do_defer() + + async def __aexit__( + self, + exc_type: Optional[Type[BE]], + exc: Optional[BE], + traceback: Optional[TracebackType], + ) -> None: + pass + + +class Context(discord.abc.Messageable, Generic[BotT]): + r"""Represents the context in which a command is being invoked under. + + This class contains a lot of meta data to help you understand more about + the invocation context. This class is not created manually and is instead + passed around to commands as the first parameter. + + This class implements the :class:`~discord.abc.Messageable` ABC. + + Attributes + ----------- + message: :class:`.Message` + The message that triggered the command being executed. + + .. note:: + + In the case of an interaction based context, this message is "synthetic" + and does not actually exist. Therefore, the ID on it is invalid similar + to ephemeral messages. + bot: :class:`.Bot` + The bot that contains the command being executed. + args: :class:`list` + The list of transformed arguments that were passed into the command. + If this is accessed during the :func:`.on_command_error` event + then this list could be incomplete. + kwargs: :class:`dict` + A dictionary of transformed arguments that were passed into the command. + Similar to :attr:`args`\, if this is accessed in the + :func:`.on_command_error` event then this dict could be incomplete. + current_parameter: Optional[:class:`Parameter`] + The parameter that is currently being inspected and converted. + This is only of use for within converters. + + .. versionadded:: 2.0 + current_argument: Optional[:class:`str`] + The argument string of the :attr:`current_parameter` that is currently being converted. + This is only of use for within converters. + + .. versionadded:: 2.0 + interaction: Optional[:class:`~discord.Interaction`] + The interaction associated with this context. + + .. versionadded:: 2.0 + prefix: Optional[:class:`str`] + The prefix that was used to invoke the command. For interaction based contexts, + this is ``/`` for slash commands and ``\u200b`` for context menu commands. + command: Optional[:class:`Command`] + The command that is being invoked currently. + invoked_with: Optional[:class:`str`] + The command name that triggered this invocation. Useful for finding out + which alias called the command. + invoked_parents: List[:class:`str`] + The command names of the parents that triggered this invocation. Useful for + finding out which aliases called the command. + + For example in commands ``?a b c test``, the invoked parents are ``['a', 'b', 'c']``. + + .. versionadded:: 1.7 + + invoked_subcommand: Optional[:class:`Command`] + The subcommand that was invoked. + If no valid subcommand was invoked then this is equal to ``None``. + subcommand_passed: Optional[:class:`str`] + The string that was attempted to call a subcommand. This does not have + to point to a valid registered subcommand and could just point to a + nonsense string. If nothing was passed to attempt a call to a + subcommand then this is set to ``None``. + command_failed: :class:`bool` + A boolean that indicates if the command failed to be parsed, checked, + or invoked. + """ + + def __init__( + self, + *, + message: Message, + bot: BotT, + view: StringView, + args: List[Any] = MISSING, + kwargs: Dict[str, Any] = MISSING, + prefix: Optional[str] = None, + command: Optional[Command[Any, ..., Any]] = None, + invoked_with: Optional[str] = None, + invoked_parents: List[str] = MISSING, + invoked_subcommand: Optional[Command[Any, ..., Any]] = None, + subcommand_passed: Optional[str] = None, + command_failed: bool = False, + current_parameter: Optional[Parameter] = None, + current_argument: Optional[str] = None, + interaction: Optional[Interaction[BotT]] = None, + ): + self.message: Message = message + self.bot: BotT = bot + self.args: List[Any] = args or [] + self.kwargs: Dict[str, Any] = kwargs or {} + self.prefix: Optional[str] = prefix + self.command: Optional[Command[Any, ..., Any]] = command + self.view: StringView = view + self.invoked_with: Optional[str] = invoked_with + self.invoked_parents: List[str] = invoked_parents or [] + self.invoked_subcommand: Optional[Command[Any, ..., Any]] = invoked_subcommand + self.subcommand_passed: Optional[str] = subcommand_passed + self.command_failed: bool = command_failed + self.current_parameter: Optional[Parameter] = current_parameter + self.current_argument: Optional[str] = current_argument + self.interaction: Optional[Interaction[BotT]] = interaction + self._state: ConnectionState = self.message._state + + @classmethod + async def from_interaction(cls, interaction: Interaction[BotT], /) -> Self: + """|coro| + + Creates a context from a :class:`discord.Interaction`. This only + works on application command based interactions, such as slash commands + or context menus. + + On slash command based interactions this creates a synthetic :class:`~discord.Message` + that points to an ephemeral message that the command invoker has executed. This means + that :attr:`Context.author` returns the member that invoked the command. + + In a message context menu based interaction, the :attr:`Context.message` attribute + is the message that the command is being executed on. This means that :attr:`Context.author` + returns the author of the message being targetted. To get the member that invoked + the command then :attr:`discord.Interaction.user` should be used instead. + + .. versionadded:: 2.0 + + Parameters + ----------- + interaction: :class:`discord.Interaction` + The interaction to create a context with. + + Raises + ------- + ValueError + The interaction does not have a valid command. + TypeError + The interaction client is not derived from :class:`Bot` or :class:`AutoShardedBot`. + """ + + # Circular import + from .bot import BotBase + + if not isinstance(interaction.client, BotBase): + raise TypeError('Interaction client is not derived from commands.Bot or commands.AutoShardedBot') + + command = interaction.command + if command is None: + raise ValueError('interaction does not have command data') + + bot: BotT = interaction.client + data: ApplicationCommandInteractionData = interaction.data # type: ignore + if interaction.message is None: + synthetic_payload = { + 'id': interaction.id, + 'reactions': [], + 'embeds': [], + 'mention_everyone': False, + 'tts': False, + 'pinned': False, + 'edited_timestamp': None, + 'type': MessageType.chat_input_command if data.get('type', 1) == 1 else MessageType.context_menu_command, + 'flags': 64, + 'content': '', + 'mentions': [], + 'mention_roles': [], + 'attachments': [], + } + + if interaction.channel_id is None: + raise RuntimeError('interaction channel ID is null, this is probably a Discord bug') + + channel = interaction.channel or PartialMessageable( + state=interaction._state, guild_id=interaction.guild_id, id=interaction.channel_id + ) + message = Message(state=interaction._state, channel=channel, data=synthetic_payload) # type: ignore + message.author = interaction.user + message.attachments = [a for _, a in interaction.namespace if isinstance(a, Attachment)] + else: + message = interaction.message + + prefix = '/' if data.get('type', 1) == 1 else '\u200b' # Mock the prefix + ctx = cls( + message=message, + bot=bot, + view=StringView(''), + args=[], + kwargs={}, + prefix=prefix, + interaction=interaction, + invoked_with=command.name, + command=command, # type: ignore # this will be a hybrid command, technically + ) + interaction._baton = ctx + ctx.command_failed = interaction.command_failed + return ctx + + async def invoke(self, command: Command[CogT, P, T], /, *args: P.args, **kwargs: P.kwargs) -> T: + r"""|coro| + + Calls a command with the arguments given. + + This is useful if you want to just call the callback that a + :class:`.Command` holds internally. + + .. note:: + + This does not handle converters, checks, cooldowns, pre-invoke, + or after-invoke hooks in any matter. It calls the internal callback + directly as-if it was a regular function. + + You must take care in passing the proper arguments when + using this function. + + .. versionchanged:: 2.0 + + ``command`` parameter is now positional-only. + + Parameters + ----------- + command: :class:`.Command` + The command that is going to be called. + \*args + The arguments to use. + \*\*kwargs + The keyword arguments to use. + + Raises + ------- + TypeError + The command argument to invoke is missing. + """ + return await command(self, *args, **kwargs) + + async def reinvoke(self, *, call_hooks: bool = False, restart: bool = True) -> None: + """|coro| + + Calls the command again. + + This is similar to :meth:`~.Context.invoke` except that it bypasses + checks, cooldowns, and error handlers. + + .. note:: + + If you want to bypass :exc:`.UserInputError` derived exceptions, + it is recommended to use the regular :meth:`~.Context.invoke` + as it will work more naturally. After all, this will end up + using the old arguments the user has used and will thus just + fail again. + + Parameters + ------------ + call_hooks: :class:`bool` + Whether to call the before and after invoke hooks. + restart: :class:`bool` + Whether to start the call chain from the very beginning + or where we left off (i.e. the command that caused the error). + The default is to start where we left off. + + Raises + ------- + ValueError + The context to reinvoke is not valid. + """ + cmd = self.command + view = self.view + if cmd is None: + raise ValueError('This context is not valid.') + + # some state to revert to when we're done + index, previous = view.index, view.previous + invoked_with = self.invoked_with + invoked_subcommand = self.invoked_subcommand + invoked_parents = self.invoked_parents + subcommand_passed = self.subcommand_passed + + if restart: + to_call = cmd.root_parent or cmd + view.index = len(self.prefix or '') + view.previous = 0 + self.invoked_parents = [] + self.invoked_with = view.get_word() # advance to get the root command + else: + to_call = cmd + + try: + await to_call.reinvoke(self, call_hooks=call_hooks) + finally: + self.command = cmd + view.index = index + view.previous = previous + self.invoked_with = invoked_with + self.invoked_subcommand = invoked_subcommand + self.invoked_parents = invoked_parents + self.subcommand_passed = subcommand_passed + + @property + def valid(self) -> bool: + """:class:`bool`: Checks if the invocation context is valid to be invoked with.""" + return self.prefix is not None and self.command is not None + + async def _get_channel(self) -> discord.abc.Messageable: + return self.channel + + @property + def clean_prefix(self) -> str: + """:class:`str`: The cleaned up invoke prefix. i.e. mentions are ``@name`` instead of ``<@id>``. + + .. versionadded:: 2.0 + """ + if self.prefix is None: + return '' + + user = self.me + # this breaks if the prefix mention is not the bot itself but I + # consider this to be an *incredibly* strange use case. I'd rather go + # for this common use case rather than waste performance for the + # odd one. + pattern = re.compile(r"<@!?%s>" % user.id) + return pattern.sub("@%s" % user.display_name.replace('\\', r'\\'), self.prefix) + + @property + def cog(self) -> Optional[Cog]: + """Optional[:class:`.Cog`]: Returns the cog associated with this context's command. None if it does not exist.""" + + if self.command is None: + return None + return self.command.cog + + @property + def filesize_limit(self) -> int: + """:class:`int`: Returns the maximum number of bytes files can have when uploaded to this guild or DM channel associated with this context. + + .. versionadded:: 2.3 + """ + return self.guild.filesize_limit if self.guild is not None else discord.utils.DEFAULT_FILE_SIZE_LIMIT_BYTES + + @discord.utils.cached_property + def guild(self) -> Optional[Guild]: + """Optional[:class:`.Guild`]: Returns the guild associated with this context's command. None if not available.""" + return self.message.guild + + @discord.utils.cached_property + def channel(self) -> MessageableChannel: + """Union[:class:`.abc.Messageable`]: Returns the channel associated with this context's command. + Shorthand for :attr:`.Message.channel`. + """ + return self.message.channel + + @discord.utils.cached_property + def author(self) -> Union[User, Member]: + """Union[:class:`~discord.User`, :class:`.Member`]: + Returns the author associated with this context's command. Shorthand for :attr:`.Message.author` + """ + return self.message.author + + @discord.utils.cached_property + def me(self) -> Union[Member, ClientUser]: + """Union[:class:`.Member`, :class:`.ClientUser`]: + Similar to :attr:`.Guild.me` except it may return the :class:`.ClientUser` in private message contexts. + """ + # bot.user will never be None at this point. + return self.guild.me if self.guild is not None else self.bot.user # type: ignore + + @discord.utils.cached_property + def permissions(self) -> Permissions: + """:class:`.Permissions`: Returns the resolved permissions for the invoking user in this channel. + Shorthand for :meth:`.abc.GuildChannel.permissions_for` or :attr:`.Interaction.permissions`. + + .. versionadded:: 2.0 + """ + if self.interaction is None and self.channel.type is ChannelType.private: + return Permissions._dm_permissions() + if not self.interaction: + # channel and author will always match relevant types here + return self.channel.permissions_for(self.author) # type: ignore + base = self.interaction.permissions + if self.channel.type in (ChannelType.voice, ChannelType.stage_voice): + if not base.connect: + # voice channels cannot be edited by people who can't connect to them + # It also implicitly denies all other voice perms + denied = Permissions.voice() + denied.update(manage_channels=True, manage_roles=True) + base.value &= ~denied.value + else: + # text channels do not have voice related permissions + denied = Permissions.voice() + base.value &= ~denied.value + return base + + @discord.utils.cached_property + def bot_permissions(self) -> Permissions: + """:class:`.Permissions`: Returns the resolved permissions for the bot in this channel. + Shorthand for :meth:`.abc.GuildChannel.permissions_for` or :attr:`.Interaction.app_permissions`. + + For interaction-based commands, this will reflect the effective permissions + for :class:`Context` calls, which may differ from calls through + other :class:`.abc.Messageable` endpoints, like :attr:`channel`. + + Notably, sending messages, embedding links, and attaching files are always + permitted, while reading messages might not be. + + .. versionadded:: 2.0 + """ + channel = self.channel + if self.interaction is None and channel.type == ChannelType.private: + return Permissions._dm_permissions() + if not self.interaction: + # channel and me will always match relevant types here + return channel.permissions_for(self.me) # type: ignore + guild = channel.guild + base = self.interaction.app_permissions + if self.channel.type in (ChannelType.voice, ChannelType.stage_voice): + if not base.connect: + # voice channels cannot be edited by people who can't connect to them + # It also implicitly denies all other voice perms + denied = Permissions.voice() + denied.update(manage_channels=True, manage_roles=True) + base.value &= ~denied.value + else: + # text channels do not have voice related permissions + denied = Permissions.voice() + base.value &= ~denied.value + base.update( + embed_links=True, + attach_files=True, + send_tts_messages=False, + ) + if isinstance(channel, Thread): + base.send_messages_in_threads = True + else: + base.send_messages = True + return base + + @property + def voice_client(self) -> Optional[VoiceProtocol]: + r"""Optional[:class:`.VoiceProtocol`]: A shortcut to :attr:`.Guild.voice_client`\, if applicable.""" + g = self.guild + return g.voice_client if g else None + + async def send_help(self, *args: Any) -> Any: + """send_help(entity=) + + |coro| + + Shows the help command for the specified entity if given. + The entity can be a command or a cog. + + If no entity is given, then it'll show help for the + entire bot. + + If the entity is a string, then it looks up whether it's a + :class:`Cog` or a :class:`Command`. + + .. note:: + + Due to the way this function works, instead of returning + something similar to :meth:`~.commands.HelpCommand.command_not_found` + this returns ``None`` on bad input or no help command. + + Parameters + ------------ + entity: Optional[Union[:class:`Command`, :class:`Cog`, :class:`str`]] + The entity to show help for. + + Returns + -------- + Any + The result of the help command, if any. + """ + from .core import Command, Group, wrap_callback + from .errors import CommandError + + bot = self.bot + cmd = bot.help_command + + if cmd is None: + return None + + cmd = cmd.copy() + cmd.context = self + + if len(args) == 0: + await cmd.prepare_help_command(self, None) + mapping = cmd.get_bot_mapping() + injected = wrap_callback(cmd.send_bot_help) + try: + return await injected(mapping) + except CommandError as e: + await cmd.on_help_command_error(self, e) + return None + + entity = args[0] + if isinstance(entity, str): + entity = bot.get_cog(entity) or bot.get_command(entity) + + if entity is None: + return None + + try: + entity.qualified_name + except AttributeError: + # if we're here then it's not a cog, group, or command. + return None + + await cmd.prepare_help_command(self, entity.qualified_name) + + try: + if is_cog(entity): + injected = wrap_callback(cmd.send_cog_help) + return await injected(entity) + elif isinstance(entity, Group): + injected = wrap_callback(cmd.send_group_help) + return await injected(entity) + elif isinstance(entity, Command): + injected = wrap_callback(cmd.send_command_help) + return await injected(entity) + else: + return None + except CommandError as e: + await cmd.on_help_command_error(self, e) + + @overload + async def reply( + self, + content: Optional[str] = ..., + *, + tts: bool = ..., + embed: Embed = ..., + file: File = ..., + stickers: Sequence[Union[GuildSticker, StickerItem]] = ..., + delete_after: float = ..., + nonce: Union[str, int] = ..., + allowed_mentions: AllowedMentions = ..., + reference: Union[Message, MessageReference, PartialMessage] = ..., + mention_author: bool = ..., + view: View = ..., + suppress_embeds: bool = ..., + ephemeral: bool = ..., + silent: bool = ..., + poll: Poll = ..., + ) -> Message: + ... + + @overload + async def reply( + self, + content: Optional[str] = ..., + *, + tts: bool = ..., + embed: Embed = ..., + files: Sequence[File] = ..., + stickers: Sequence[Union[GuildSticker, StickerItem]] = ..., + delete_after: float = ..., + nonce: Union[str, int] = ..., + allowed_mentions: AllowedMentions = ..., + reference: Union[Message, MessageReference, PartialMessage] = ..., + mention_author: bool = ..., + view: View = ..., + suppress_embeds: bool = ..., + ephemeral: bool = ..., + silent: bool = ..., + poll: Poll = ..., + ) -> Message: + ... + + @overload + async def reply( + self, + content: Optional[str] = ..., + *, + tts: bool = ..., + embeds: Sequence[Embed] = ..., + file: File = ..., + stickers: Sequence[Union[GuildSticker, StickerItem]] = ..., + delete_after: float = ..., + nonce: Union[str, int] = ..., + allowed_mentions: AllowedMentions = ..., + reference: Union[Message, MessageReference, PartialMessage] = ..., + mention_author: bool = ..., + view: View = ..., + suppress_embeds: bool = ..., + ephemeral: bool = ..., + silent: bool = ..., + poll: Poll = ..., + ) -> Message: + ... + + @overload + async def reply( + self, + content: Optional[str] = ..., + *, + tts: bool = ..., + embeds: Sequence[Embed] = ..., + files: Sequence[File] = ..., + stickers: Sequence[Union[GuildSticker, StickerItem]] = ..., + delete_after: float = ..., + nonce: Union[str, int] = ..., + allowed_mentions: AllowedMentions = ..., + reference: Union[Message, MessageReference, PartialMessage] = ..., + mention_author: bool = ..., + view: View = ..., + suppress_embeds: bool = ..., + ephemeral: bool = ..., + silent: bool = ..., + poll: Poll = ..., + ) -> Message: + ... + + async def reply(self, content: Optional[str] = None, **kwargs: Any) -> Message: + """|coro| + + A shortcut method to :meth:`send` to reply to the + :class:`~discord.Message` referenced by this context. + + For interaction based contexts, this is the same as :meth:`send`. + + .. versionadded:: 1.6 + + .. versionchanged:: 2.0 + This function will now raise :exc:`TypeError` or + :exc:`ValueError` instead of ``InvalidArgument``. + + Raises + -------- + ~discord.HTTPException + Sending the message failed. + ~discord.Forbidden + You do not have the proper permissions to send the message. + ValueError + The ``files`` list is not of the appropriate size + TypeError + You specified both ``file`` and ``files``. + + Returns + --------- + :class:`~discord.Message` + The message that was sent. + """ + if self.interaction is None: + return await self.send(content, reference=self.message, **kwargs) + else: + return await self.send(content, **kwargs) + + def typing(self, *, ephemeral: bool = False) -> Union[Typing, DeferTyping[BotT]]: + """Returns an asynchronous context manager that allows you to send a typing indicator to + the destination for an indefinite period of time, or 10 seconds if the context manager + is called using ``await``. + + In an interaction based context, this is equivalent to a :meth:`defer` call and + does not do any typing calls. + + Example Usage: :: + + async with channel.typing(): + # simulate something heavy + await asyncio.sleep(20) + + await channel.send('Done!') + + Example Usage: :: + + await channel.typing() + # Do some computational magic for about 10 seconds + await channel.send('Done!') + + .. versionchanged:: 2.0 + This no longer works with the ``with`` syntax, ``async with`` must be used instead. + + .. versionchanged:: 2.0 + Added functionality to ``await`` the context manager to send a typing indicator for 10 seconds. + + Parameters + ----------- + ephemeral: :class:`bool` + Indicates whether the deferred message will eventually be ephemeral. + Only valid for interaction based contexts. + + .. versionadded:: 2.0 + """ + if self.interaction is None: + return Typing(self) + return DeferTyping(self, ephemeral=ephemeral) + + async def defer(self, *, ephemeral: bool = False) -> None: + """|coro| + + Defers the interaction based contexts. + + This is typically used when the interaction is acknowledged + and a secondary action will be done later. + + If this isn't an interaction based context then it does nothing. + + Parameters + ----------- + ephemeral: :class:`bool` + Indicates whether the deferred message will eventually be ephemeral. + + Raises + ------- + HTTPException + Deferring the interaction failed. + InteractionResponded + This interaction has already been responded to before. + """ + + if self.interaction: + await self.interaction.response.defer(ephemeral=ephemeral) + + @overload + async def send( + self, + content: Optional[str] = ..., + *, + tts: bool = ..., + embed: Embed = ..., + file: File = ..., + stickers: Sequence[Union[GuildSticker, StickerItem]] = ..., + delete_after: float = ..., + nonce: Union[str, int] = ..., + allowed_mentions: AllowedMentions = ..., + reference: Union[Message, MessageReference, PartialMessage] = ..., + mention_author: bool = ..., + view: View = ..., + suppress_embeds: bool = ..., + ephemeral: bool = ..., + silent: bool = ..., + poll: Poll = ..., + ) -> Message: + ... + + @overload + async def send( + self, + content: Optional[str] = ..., + *, + tts: bool = ..., + embed: Embed = ..., + files: Sequence[File] = ..., + stickers: Sequence[Union[GuildSticker, StickerItem]] = ..., + delete_after: float = ..., + nonce: Union[str, int] = ..., + allowed_mentions: AllowedMentions = ..., + reference: Union[Message, MessageReference, PartialMessage] = ..., + mention_author: bool = ..., + view: View = ..., + suppress_embeds: bool = ..., + ephemeral: bool = ..., + silent: bool = ..., + poll: Poll = ..., + ) -> Message: + ... + + @overload + async def send( + self, + content: Optional[str] = ..., + *, + tts: bool = ..., + embeds: Sequence[Embed] = ..., + file: File = ..., + stickers: Sequence[Union[GuildSticker, StickerItem]] = ..., + delete_after: float = ..., + nonce: Union[str, int] = ..., + allowed_mentions: AllowedMentions = ..., + reference: Union[Message, MessageReference, PartialMessage] = ..., + mention_author: bool = ..., + view: View = ..., + suppress_embeds: bool = ..., + ephemeral: bool = ..., + silent: bool = ..., + poll: Poll = ..., + ) -> Message: + ... + + @overload + async def send( + self, + content: Optional[str] = ..., + *, + tts: bool = ..., + embeds: Sequence[Embed] = ..., + files: Sequence[File] = ..., + stickers: Sequence[Union[GuildSticker, StickerItem]] = ..., + delete_after: float = ..., + nonce: Union[str, int] = ..., + allowed_mentions: AllowedMentions = ..., + reference: Union[Message, MessageReference, PartialMessage] = ..., + mention_author: bool = ..., + view: View = ..., + suppress_embeds: bool = ..., + ephemeral: bool = ..., + silent: bool = ..., + poll: Poll = ..., + ) -> Message: + ... + + async def send( + self, + content: Optional[str] = None, + *, + tts: bool = False, + embed: Optional[Embed] = None, + embeds: Optional[Sequence[Embed]] = None, + file: Optional[File] = None, + files: Optional[Sequence[File]] = None, + stickers: Optional[Sequence[Union[GuildSticker, StickerItem]]] = None, + delete_after: Optional[float] = None, + nonce: Optional[Union[str, int]] = None, + allowed_mentions: Optional[AllowedMentions] = None, + reference: Optional[Union[Message, MessageReference, PartialMessage]] = None, + mention_author: Optional[bool] = None, + view: Optional[View] = None, + suppress_embeds: bool = False, + ephemeral: bool = False, + silent: bool = False, + poll: Poll = MISSING, + ) -> Message: + """|coro| + + Sends a message to the destination with the content given. + + This works similarly to :meth:`~discord.abc.Messageable.send` for non-interaction contexts. + + For interaction based contexts this does one of the following: + + - :meth:`discord.InteractionResponse.send_message` if no response has been given. + - A followup message if a response has been given. + - Regular send if the interaction has expired + + .. versionchanged:: 2.0 + This function will now raise :exc:`TypeError` or + :exc:`ValueError` instead of ``InvalidArgument``. + + Parameters + ------------ + content: Optional[:class:`str`] + The content of the message to send. + tts: :class:`bool` + Indicates if the message should be sent using text-to-speech. + embed: :class:`~discord.Embed` + The rich embed for the content. + file: :class:`~discord.File` + The file to upload. + files: List[:class:`~discord.File`] + A list of files to upload. Must be a maximum of 10. + nonce: :class:`int` + The nonce to use for sending this message. If the message was successfully sent, + then the message will have a nonce with this value. + delete_after: :class:`float` + If provided, the number of seconds to wait in the background + before deleting the message we just sent. If the deletion fails, + then it is silently ignored. + allowed_mentions: :class:`~discord.AllowedMentions` + Controls the mentions being processed in this message. If this is + passed, then the object is merged with :attr:`~discord.Client.allowed_mentions`. + The merging behaviour only overrides attributes that have been explicitly passed + to the object, otherwise it uses the attributes set in :attr:`~discord.Client.allowed_mentions`. + If no object is passed at all then the defaults given by :attr:`~discord.Client.allowed_mentions` + are used instead. + + .. versionadded:: 1.4 + + reference: Union[:class:`~discord.Message`, :class:`~discord.MessageReference`, :class:`~discord.PartialMessage`] + A reference to the :class:`~discord.Message` to which you are replying, this can be created using + :meth:`~discord.Message.to_reference` or passed directly as a :class:`~discord.Message`. You can control + whether this mentions the author of the referenced message using the :attr:`~discord.AllowedMentions.replied_user` + attribute of ``allowed_mentions`` or by setting ``mention_author``. + + This is ignored for interaction based contexts. + + .. versionadded:: 1.6 + + mention_author: Optional[:class:`bool`] + If set, overrides the :attr:`~discord.AllowedMentions.replied_user` attribute of ``allowed_mentions``. + This is ignored for interaction based contexts. + + .. versionadded:: 1.6 + view: :class:`discord.ui.View` + A Discord UI View to add to the message. + + .. versionadded:: 2.0 + embeds: List[:class:`~discord.Embed`] + A list of embeds to upload. Must be a maximum of 10. + + .. versionadded:: 2.0 + stickers: Sequence[Union[:class:`~discord.GuildSticker`, :class:`~discord.StickerItem`]] + A list of stickers to upload. Must be a maximum of 3. This is ignored for interaction based contexts. + + .. versionadded:: 2.0 + suppress_embeds: :class:`bool` + Whether to suppress embeds for the message. This sends the message without any embeds if set to ``True``. + + .. versionadded:: 2.0 + ephemeral: :class:`bool` + Indicates if the message should only be visible to the user who started the interaction. + If a view is sent with an ephemeral message and it has no timeout set then the timeout + is set to 15 minutes. **This is only applicable in contexts with an interaction**. + + .. versionadded:: 2.0 + silent: :class:`bool` + Whether to suppress push and desktop notifications for the message. This will increment the mention counter + in the UI, but will not actually send a notification. + + .. versionadded:: 2.2 + + poll: :class:`~discord.Poll` + The poll to send with this message. + + .. versionadded:: 2.4 + + Raises + -------- + ~discord.HTTPException + Sending the message failed. + ~discord.Forbidden + You do not have the proper permissions to send the message. + ValueError + The ``files`` list is not of the appropriate size. + TypeError + You specified both ``file`` and ``files``, + or you specified both ``embed`` and ``embeds``, + or the ``reference`` object is not a :class:`~discord.Message`, + :class:`~discord.MessageReference` or :class:`~discord.PartialMessage`. + + Returns + --------- + :class:`~discord.Message` + The message that was sent. + """ + + if self.interaction is None or self.interaction.is_expired(): + return await super().send( + content=content, + tts=tts, + embed=embed, + embeds=embeds, + file=file, + files=files, + stickers=stickers, + delete_after=delete_after, + nonce=nonce, + allowed_mentions=allowed_mentions, + reference=reference, + mention_author=mention_author, + view=view, + suppress_embeds=suppress_embeds, + silent=silent, + poll=poll, + ) # type: ignore # The overloads don't support Optional but the implementation does + + # Convert the kwargs from None to MISSING to appease the remaining implementations + kwargs = { + 'content': content, + 'tts': tts, + 'embed': MISSING if embed is None else embed, + 'embeds': MISSING if embeds is None else embeds, + 'file': MISSING if file is None else file, + 'files': MISSING if files is None else files, + 'allowed_mentions': MISSING if allowed_mentions is None else allowed_mentions, + 'view': MISSING if view is None else view, + 'suppress_embeds': suppress_embeds, + 'ephemeral': ephemeral, + 'silent': silent, + 'poll': poll, + } + + if self.interaction.response.is_done(): + msg = await self.interaction.followup.send(**kwargs, wait=True) + else: + response = await self.interaction.response.send_message(**kwargs) + if not isinstance(response.resource, discord.InteractionMessage): + msg = await self.interaction.original_response() + else: + msg = response.resource + + if delete_after is not None: + await msg.delete(delay=delete_after) + return msg diff --git a/venv/lib/python3.12/site-packages/discord/ext/commands/converter.py b/venv/lib/python3.12/site-packages/discord/ext/commands/converter.py new file mode 100644 index 00000000..d316f6cc --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/ext/commands/converter.py @@ -0,0 +1,1444 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from __future__ import annotations + +import inspect +import re +from typing import ( + TYPE_CHECKING, + Any, + Dict, + Generic, + Iterable, + List, + Literal, + Optional, + overload, + Protocol, + Tuple, + Type, + TypeVar, + Union, + runtime_checkable, +) +import types + +import discord + +from .errors import * + +if TYPE_CHECKING: + from discord.state import Channel + from discord.threads import Thread + + from .parameters import Parameter + from ._types import BotT, _Bot + from .context import Context + +__all__ = ( + 'Converter', + 'ObjectConverter', + 'MemberConverter', + 'UserConverter', + 'MessageConverter', + 'PartialMessageConverter', + 'TextChannelConverter', + 'InviteConverter', + 'GuildConverter', + 'RoleConverter', + 'GameConverter', + 'ColourConverter', + 'ColorConverter', + 'VoiceChannelConverter', + 'StageChannelConverter', + 'EmojiConverter', + 'PartialEmojiConverter', + 'CategoryChannelConverter', + 'ForumChannelConverter', + 'IDConverter', + 'ThreadConverter', + 'GuildChannelConverter', + 'GuildStickerConverter', + 'ScheduledEventConverter', + 'SoundboardSoundConverter', + 'clean_content', + 'Greedy', + 'Range', + 'run_converters', +) + + +def _get_from_guilds(bot: _Bot, getter: str, argument: Any) -> Any: + result = None + for guild in bot.guilds: + result = getattr(guild, getter)(argument) + if result: + return result + return result + + +_utils_get = discord.utils.get +T = TypeVar('T') +T_co = TypeVar('T_co', covariant=True) +CT = TypeVar('CT', bound=discord.abc.GuildChannel) +TT = TypeVar('TT', bound=discord.Thread) + + +@runtime_checkable +class Converter(Protocol[T_co]): + """The base class of custom converters that require the :class:`.Context` + to be passed to be useful. + + This allows you to implement converters that function similar to the + special cased ``discord`` classes. + + Classes that derive from this should override the :meth:`~.Converter.convert` + method to do its conversion logic. This method must be a :ref:`coroutine `. + """ + + async def convert(self, ctx: Context[BotT], argument: str) -> T_co: + """|coro| + + The method to override to do conversion logic. + + If an error is found while converting, it is recommended to + raise a :exc:`.CommandError` derived exception as it will + properly propagate to the error handlers. + + Note that if this method is called manually, :exc:`Exception` + should be caught to handle the cases where a subclass does + not explicitly inherit from :exc:`.CommandError`. + + Parameters + ----------- + ctx: :class:`.Context` + The invocation context that the argument is being used in. + argument: :class:`str` + The argument that is being converted. + + Raises + ------- + CommandError + A generic exception occurred when converting the argument. + BadArgument + The converter failed to convert the argument. + """ + raise NotImplementedError('Derived classes need to implement this.') + + +_ID_REGEX = re.compile(r'([0-9]{15,20})$') + + +class IDConverter(Converter[T_co]): + @staticmethod + def _get_id_match(argument): + return _ID_REGEX.match(argument) + + +class ObjectConverter(IDConverter[discord.Object]): + """Converts to a :class:`~discord.Object`. + + The argument must follow the valid ID or mention formats (e.g. ``<@80088516616269824>``). + + .. versionadded:: 2.0 + + The lookup strategy is as follows (in order): + + 1. Lookup by ID. + 2. Lookup by member, role, or channel mention. + """ + + async def convert(self, ctx: Context[BotT], argument: str) -> discord.Object: + match = self._get_id_match(argument) or re.match(r'<(?:@(?:!|&)?|#)([0-9]{15,20})>$', argument) + + if match is None: + raise ObjectNotFound(argument) + + result = int(match.group(1)) + + return discord.Object(id=result) + + +class MemberConverter(IDConverter[discord.Member]): + """Converts to a :class:`~discord.Member`. + + All lookups are via the local guild. If in a DM context, then the lookup + is done by the global cache. + + The lookup strategy is as follows (in order): + + 1. Lookup by ID. + 2. Lookup by mention. + 3. Lookup by username#discriminator (deprecated). + 4. Lookup by username#0 (deprecated, only gets users that migrated from their discriminator). + 5. Lookup by user name. + 6. Lookup by global name. + 7. Lookup by guild nickname. + + .. versionchanged:: 1.5 + Raise :exc:`.MemberNotFound` instead of generic :exc:`.BadArgument` + + .. versionchanged:: 1.5.1 + This converter now lazily fetches members from the gateway and HTTP APIs, + optionally caching the result if :attr:`.MemberCacheFlags.joined` is enabled. + + .. deprecated:: 2.3 + Looking up users by discriminator will be removed in a future version due to + the removal of discriminators in an API change. + """ + + async def query_member_named(self, guild: discord.Guild, argument: str) -> Optional[discord.Member]: + cache = guild._state.member_cache_flags.joined + username, _, discriminator = argument.rpartition('#') + + # If # isn't found then "discriminator" actually has the username + if not username: + discriminator, username = username, discriminator + + if discriminator == '0' or (len(discriminator) == 4 and discriminator.isdigit()): + lookup = username + predicate = lambda m: m.name == username and m.discriminator == discriminator + else: + lookup = argument + predicate = lambda m: m.name == argument or m.global_name == argument or m.nick == argument + + members = await guild.query_members(lookup, limit=100, cache=cache) + return discord.utils.find(predicate, members) + + async def query_member_by_id(self, bot: _Bot, guild: discord.Guild, user_id: int) -> Optional[discord.Member]: + ws = bot._get_websocket(shard_id=guild.shard_id) + cache = guild._state.member_cache_flags.joined + if ws.is_ratelimited(): + # If we're being rate limited on the WS, then fall back to using the HTTP API + # So we don't have to wait ~60 seconds for the query to finish + try: + member = await guild.fetch_member(user_id) + except discord.HTTPException: + return None + + if cache: + guild._add_member(member) + return member + + # If we're not being rate limited then we can use the websocket to actually query + members = await guild.query_members(limit=1, user_ids=[user_id], cache=cache) + if not members: + return None + return members[0] + + async def convert(self, ctx: Context[BotT], argument: str) -> discord.Member: + bot = ctx.bot + match = self._get_id_match(argument) or re.match(r'<@!?([0-9]{15,20})>$', argument) + guild = ctx.guild + result = None + user_id = None + + if match is None: + # not a mention... + if guild: + result = guild.get_member_named(argument) + else: + result = _get_from_guilds(bot, 'get_member_named', argument) + else: + user_id = int(match.group(1)) + if guild: + result = guild.get_member(user_id) or _utils_get(ctx.message.mentions, id=user_id) + else: + result = _get_from_guilds(bot, 'get_member', user_id) + + if not isinstance(result, discord.Member): + if guild is None: + raise MemberNotFound(argument) + + if user_id is not None: + result = await self.query_member_by_id(bot, guild, user_id) + else: + result = await self.query_member_named(guild, argument) + + if not result: + raise MemberNotFound(argument) + + return result + + +class UserConverter(IDConverter[discord.User]): + """Converts to a :class:`~discord.User`. + + All lookups are via the global user cache. + + The lookup strategy is as follows (in order): + + 1. Lookup by ID. + 2. Lookup by mention. + 3. Lookup by username#discriminator (deprecated). + 4. Lookup by username#0 (deprecated, only gets users that migrated from their discriminator). + 5. Lookup by user name. + 6. Lookup by global name. + + .. versionchanged:: 1.5 + Raise :exc:`.UserNotFound` instead of generic :exc:`.BadArgument` + + .. versionchanged:: 1.6 + This converter now lazily fetches users from the HTTP APIs if an ID is passed + and it's not available in cache. + + .. deprecated:: 2.3 + Looking up users by discriminator will be removed in a future version due to + the removal of discriminators in an API change. + """ + + async def convert(self, ctx: Context[BotT], argument: str) -> discord.User: + match = self._get_id_match(argument) or re.match(r'<@!?([0-9]{15,20})>$', argument) + result = None + state = ctx._state + + if match is not None: + user_id = int(match.group(1)) + result = ctx.bot.get_user(user_id) or _utils_get(ctx.message.mentions, id=user_id) + if result is None: + try: + result = await ctx.bot.fetch_user(user_id) + except discord.HTTPException: + raise UserNotFound(argument) from None + + return result # type: ignore + + username, _, discriminator = argument.rpartition('#') + + # If # isn't found then "discriminator" actually has the username + if not username: + discriminator, username = username, discriminator + + if discriminator == '0' or (len(discriminator) == 4 and discriminator.isdigit()): + predicate = lambda u: u.name == username and u.discriminator == discriminator + else: + predicate = lambda u: u.name == argument or u.global_name == argument + + result = discord.utils.find(predicate, state._users.values()) + if result is None: + raise UserNotFound(argument) + + return result + + +class PartialMessageConverter(Converter[discord.PartialMessage]): + """Converts to a :class:`discord.PartialMessage`. + + .. versionadded:: 1.7 + + The creation strategy is as follows (in order): + + 1. By "{channel ID}-{message ID}" (retrieved by shift-clicking on "Copy ID") + 2. By message ID (The message is assumed to be in the context channel.) + 3. By message URL + """ + + @staticmethod + def _get_id_matches(ctx: Context[BotT], argument: str) -> Tuple[Optional[int], int, int]: + id_regex = re.compile(r'(?:(?P[0-9]{15,20})-)?(?P[0-9]{15,20})$') + link_regex = re.compile( + r'https?://(?:(ptb|canary|www)\.)?discord(?:app)?\.com/channels/' + r'(?P[0-9]{15,20}|@me)' + r'/(?P[0-9]{15,20})/(?P[0-9]{15,20})/?$' + ) + match = id_regex.match(argument) or link_regex.match(argument) + if not match: + raise MessageNotFound(argument) + data = match.groupdict() + channel_id = discord.utils._get_as_snowflake(data, 'channel_id') or ctx.channel.id + message_id = int(data['message_id']) + guild_id = data.get('guild_id') + if guild_id is None: + guild_id = ctx.guild and ctx.guild.id + elif guild_id == '@me': + guild_id = None + else: + guild_id = int(guild_id) + return guild_id, message_id, channel_id + + @staticmethod + def _resolve_channel( + ctx: Context[BotT], guild_id: Optional[int], channel_id: Optional[int] + ) -> Optional[Union[Channel, Thread]]: + if channel_id is None: + # we were passed just a message id so we can assume the channel is the current context channel + return ctx.channel + + if guild_id is not None: + guild = ctx.bot.get_guild(guild_id) + if guild is None: + return None + return guild._resolve_channel(channel_id) + + return ctx.bot.get_channel(channel_id) + + async def convert(self, ctx: Context[BotT], argument: str) -> discord.PartialMessage: + guild_id, message_id, channel_id = self._get_id_matches(ctx, argument) + channel = self._resolve_channel(ctx, guild_id, channel_id) + if not channel or not isinstance(channel, discord.abc.Messageable): + raise ChannelNotFound(channel_id) + return discord.PartialMessage(channel=channel, id=message_id) + + +class MessageConverter(IDConverter[discord.Message]): + """Converts to a :class:`discord.Message`. + + .. versionadded:: 1.1 + + The lookup strategy is as follows (in order): + + 1. Lookup by "{channel ID}-{message ID}" (retrieved by shift-clicking on "Copy ID") + 2. Lookup by message ID (the message **must** be in the context channel) + 3. Lookup by message URL + + .. versionchanged:: 1.5 + Raise :exc:`.ChannelNotFound`, :exc:`.MessageNotFound` or :exc:`.ChannelNotReadable` instead of generic :exc:`.BadArgument` + """ + + async def convert(self, ctx: Context[BotT], argument: str) -> discord.Message: + guild_id, message_id, channel_id = PartialMessageConverter._get_id_matches(ctx, argument) + message = ctx.bot._connection._get_message(message_id) + if message: + return message + channel = PartialMessageConverter._resolve_channel(ctx, guild_id, channel_id) + if not channel or not isinstance(channel, discord.abc.Messageable): + raise ChannelNotFound(channel_id) + try: + return await channel.fetch_message(message_id) + except discord.NotFound: + raise MessageNotFound(argument) + except discord.Forbidden: + raise ChannelNotReadable(channel) # type: ignore # type-checker thinks channel could be a DMChannel at this point + + +class GuildChannelConverter(IDConverter[discord.abc.GuildChannel]): + """Converts to a :class:`~discord.abc.GuildChannel`. + + All lookups are via the local guild. If in a DM context, then the lookup + is done by the global cache. + + The lookup strategy is as follows (in order): + + 1. Lookup by ID. + 2. Lookup by mention. + 3. Lookup by channel URL. + 4. Lookup by name. + + .. versionadded:: 2.0 + + .. versionchanged:: 2.4 + Add lookup by channel URL, accessed via "Copy Link" in the Discord client within channels. + """ + + async def convert(self, ctx: Context[BotT], argument: str) -> discord.abc.GuildChannel: + return self._resolve_channel(ctx, argument, 'channels', discord.abc.GuildChannel) + + @staticmethod + def _parse_from_url(argument: str) -> Optional[re.Match[str]]: + link_regex = re.compile( + r'https?://(?:(?:ptb|canary|www)\.)?discord(?:app)?\.com/channels/' + r'(?:[0-9]{15,20}|@me)' + r'/([0-9]{15,20})(?:/(?:[0-9]{15,20})/?)?$' + ) + return link_regex.match(argument) + + @staticmethod + def _resolve_channel(ctx: Context[BotT], argument: str, attribute: str, type: Type[CT]) -> CT: + bot = ctx.bot + + match = ( + IDConverter._get_id_match(argument) + or re.match(r'<#([0-9]{15,20})>$', argument) + or GuildChannelConverter._parse_from_url(argument) + ) + result = None + guild = ctx.guild + + if match is None: + # not a mention + if guild: + iterable: Iterable[CT] = getattr(guild, attribute) + result: Optional[CT] = discord.utils.get(iterable, name=argument) + else: + + def check(c): + return isinstance(c, type) and c.name == argument + + result = discord.utils.find(check, bot.get_all_channels()) # type: ignore + else: + channel_id = int(match.group(1)) + if guild: + # guild.get_channel returns an explicit union instead of the base class + result = guild.get_channel(channel_id) # type: ignore + else: + result = _get_from_guilds(bot, 'get_channel', channel_id) + + if not isinstance(result, type): + raise ChannelNotFound(argument) + + return result + + @staticmethod + def _resolve_thread(ctx: Context[BotT], argument: str, attribute: str, type: Type[TT]) -> TT: + match = ( + IDConverter._get_id_match(argument) + or re.match(r'<#([0-9]{15,20})>$', argument) + or GuildChannelConverter._parse_from_url(argument) + ) + result = None + guild = ctx.guild + + if match is None: + # not a mention + if guild: + iterable: Iterable[TT] = getattr(guild, attribute) + result: Optional[TT] = discord.utils.get(iterable, name=argument) + else: + thread_id = int(match.group(1)) + if guild: + result = guild.get_thread(thread_id) # type: ignore + + if not result or not isinstance(result, type): + raise ThreadNotFound(argument) + + return result + + +class TextChannelConverter(IDConverter[discord.TextChannel]): + """Converts to a :class:`~discord.TextChannel`. + + All lookups are via the local guild. If in a DM context, then the lookup + is done by the global cache. + + The lookup strategy is as follows (in order): + + 1. Lookup by ID. + 2. Lookup by mention. + 3. Lookup by channel URL. + 4. Lookup by name + + .. versionchanged:: 1.5 + Raise :exc:`.ChannelNotFound` instead of generic :exc:`.BadArgument` + + .. versionchanged:: 2.4 + Add lookup by channel URL, accessed via "Copy Link" in the Discord client within channels. + """ + + async def convert(self, ctx: Context[BotT], argument: str) -> discord.TextChannel: + return GuildChannelConverter._resolve_channel(ctx, argument, 'text_channels', discord.TextChannel) + + +class VoiceChannelConverter(IDConverter[discord.VoiceChannel]): + """Converts to a :class:`~discord.VoiceChannel`. + + All lookups are via the local guild. If in a DM context, then the lookup + is done by the global cache. + + The lookup strategy is as follows (in order): + + 1. Lookup by ID. + 2. Lookup by mention. + 3. Lookup by channel URL. + 4. Lookup by name + + .. versionchanged:: 1.5 + Raise :exc:`.ChannelNotFound` instead of generic :exc:`.BadArgument` + + .. versionchanged:: 2.4 + Add lookup by channel URL, accessed via "Copy Link" in the Discord client within channels. + """ + + async def convert(self, ctx: Context[BotT], argument: str) -> discord.VoiceChannel: + return GuildChannelConverter._resolve_channel(ctx, argument, 'voice_channels', discord.VoiceChannel) + + +class StageChannelConverter(IDConverter[discord.StageChannel]): + """Converts to a :class:`~discord.StageChannel`. + + .. versionadded:: 1.7 + + All lookups are via the local guild. If in a DM context, then the lookup + is done by the global cache. + + The lookup strategy is as follows (in order): + + 1. Lookup by ID. + 2. Lookup by mention. + 3. Lookup by channel URL. + 4. Lookup by name + + .. versionchanged:: 2.4 + Add lookup by channel URL, accessed via "Copy Link" in the Discord client within channels. + """ + + async def convert(self, ctx: Context[BotT], argument: str) -> discord.StageChannel: + return GuildChannelConverter._resolve_channel(ctx, argument, 'stage_channels', discord.StageChannel) + + +class CategoryChannelConverter(IDConverter[discord.CategoryChannel]): + """Converts to a :class:`~discord.CategoryChannel`. + + All lookups are via the local guild. If in a DM context, then the lookup + is done by the global cache. + + The lookup strategy is as follows (in order): + + 1. Lookup by ID. + 2. Lookup by mention. + 3. Lookup by channel URL. + 4. Lookup by name + + .. versionchanged:: 2.4 + Add lookup by channel URL, accessed via "Copy Link" in the Discord client within channels. + + .. versionchanged:: 1.5 + Raise :exc:`.ChannelNotFound` instead of generic :exc:`.BadArgument` + """ + + async def convert(self, ctx: Context[BotT], argument: str) -> discord.CategoryChannel: + return GuildChannelConverter._resolve_channel(ctx, argument, 'categories', discord.CategoryChannel) + + +class ThreadConverter(IDConverter[discord.Thread]): + """Converts to a :class:`~discord.Thread`. + + All lookups are via the local guild. + + The lookup strategy is as follows (in order): + + 1. Lookup by ID. + 2. Lookup by mention. + 3. Lookup by channel URL. + 4. Lookup by name. + + .. versionadded: 2.0 + + .. versionchanged:: 2.4 + Add lookup by channel URL, accessed via "Copy Link" in the Discord client within channels. + """ + + async def convert(self, ctx: Context[BotT], argument: str) -> discord.Thread: + return GuildChannelConverter._resolve_thread(ctx, argument, 'threads', discord.Thread) + + +class ForumChannelConverter(IDConverter[discord.ForumChannel]): + """Converts to a :class:`~discord.ForumChannel`. + + All lookups are via the local guild. If in a DM context, then the lookup + is done by the global cache. + + The lookup strategy is as follows (in order): + + 1. Lookup by ID. + 2. Lookup by mention. + 3. Lookup by channel URL. + 4. Lookup by name + + .. versionadded:: 2.0 + + .. versionchanged:: 2.4 + Add lookup by channel URL, accessed via "Copy Link" in the Discord client within channels. + """ + + async def convert(self, ctx: Context[BotT], argument: str) -> discord.ForumChannel: + return GuildChannelConverter._resolve_channel(ctx, argument, 'forums', discord.ForumChannel) + + +class ColourConverter(Converter[discord.Colour]): + """Converts to a :class:`~discord.Colour`. + + .. versionchanged:: 1.5 + Add an alias named ColorConverter + + The following formats are accepted: + + - ``0x`` + - ``#`` + - ``0x#`` + - ``rgb(, , )`` + - Any of the ``classmethod`` in :class:`~discord.Colour` + + - The ``_`` in the name can be optionally replaced with spaces. + + Like CSS, ```` can be either 0-255 or 0-100% and ```` can be + either a 6 digit hex number or a 3 digit hex shortcut (e.g. #fff). + + .. versionchanged:: 1.5 + Raise :exc:`.BadColourArgument` instead of generic :exc:`.BadArgument` + + .. versionchanged:: 1.7 + Added support for ``rgb`` function and 3-digit hex shortcuts + """ + + async def convert(self, ctx: Context[BotT], argument: str) -> discord.Colour: + try: + return discord.Colour.from_str(argument) + except ValueError: + arg = argument.lower().replace(' ', '_') + method = getattr(discord.Colour, arg, None) + if arg.startswith('from_') or method is None or not inspect.ismethod(method): + raise BadColourArgument(arg) + return method() + + +ColorConverter = ColourConverter + + +class RoleConverter(IDConverter[discord.Role]): + """Converts to a :class:`~discord.Role`. + + All lookups are via the local guild. If in a DM context, the converter raises + :exc:`.NoPrivateMessage` exception. + + The lookup strategy is as follows (in order): + + 1. Lookup by ID. + 2. Lookup by mention. + 3. Lookup by name + + .. versionchanged:: 1.5 + Raise :exc:`.RoleNotFound` instead of generic :exc:`.BadArgument` + """ + + async def convert(self, ctx: Context[BotT], argument: str) -> discord.Role: + guild = ctx.guild + if not guild: + raise NoPrivateMessage() + + match = self._get_id_match(argument) or re.match(r'<@&([0-9]{15,20})>$', argument) + if match: + result = guild.get_role(int(match.group(1))) + else: + result = discord.utils.get(guild._roles.values(), name=argument) + + if result is None: + raise RoleNotFound(argument) + return result + + +class GameConverter(Converter[discord.Game]): + """Converts to a :class:`~discord.Game`.""" + + async def convert(self, ctx: Context[BotT], argument: str) -> discord.Game: + return discord.Game(name=argument) + + +class InviteConverter(Converter[discord.Invite]): + """Converts to a :class:`~discord.Invite`. + + This is done via an HTTP request using :meth:`.Bot.fetch_invite`. + + .. versionchanged:: 1.5 + Raise :exc:`.BadInviteArgument` instead of generic :exc:`.BadArgument` + """ + + async def convert(self, ctx: Context[BotT], argument: str) -> discord.Invite: + try: + invite = await ctx.bot.fetch_invite(argument) + return invite + except Exception as exc: + raise BadInviteArgument(argument) from exc + + +class GuildConverter(IDConverter[discord.Guild]): + """Converts to a :class:`~discord.Guild`. + + The lookup strategy is as follows (in order): + + 1. Lookup by ID. + 2. Lookup by name. (There is no disambiguation for Guilds with multiple matching names). + + .. versionadded:: 1.7 + """ + + async def convert(self, ctx: Context[BotT], argument: str) -> discord.Guild: + match = self._get_id_match(argument) + result = None + + if match is not None: + guild_id = int(match.group(1)) + result = ctx.bot.get_guild(guild_id) + + if result is None: + result = discord.utils.get(ctx.bot.guilds, name=argument) + + if result is None: + raise GuildNotFound(argument) + return result + + +class EmojiConverter(IDConverter[discord.Emoji]): + """Converts to a :class:`~discord.Emoji`. + + All lookups are done for the local guild first, if available. If that lookup + fails, then it checks the client's global cache. + + The lookup strategy is as follows (in order): + + 1. Lookup by ID. + 2. Lookup by extracting ID from the emoji. + 3. Lookup by name + + .. versionchanged:: 1.5 + Raise :exc:`.EmojiNotFound` instead of generic :exc:`.BadArgument` + """ + + async def convert(self, ctx: Context[BotT], argument: str) -> discord.Emoji: + match = self._get_id_match(argument) or re.match(r'$', argument) + result = None + bot = ctx.bot + guild = ctx.guild + + if match is None: + # Try to get the emoji by name. Try local guild first. + if guild: + result = discord.utils.get(guild.emojis, name=argument) + + if result is None: + result = discord.utils.get(bot.emojis, name=argument) + else: + emoji_id = int(match.group(1)) + + # Try to look up emoji by id. + result = bot.get_emoji(emoji_id) + + if result is None: + raise EmojiNotFound(argument) + + return result + + +class PartialEmojiConverter(Converter[discord.PartialEmoji]): + """Converts to a :class:`~discord.PartialEmoji`. + + This is done by extracting the animated flag, name and ID from the emoji. + + .. versionchanged:: 1.5 + Raise :exc:`.PartialEmojiConversionFailure` instead of generic :exc:`.BadArgument` + """ + + async def convert(self, ctx: Context[BotT], argument: str) -> discord.PartialEmoji: + match = re.match(r'<(a?):([a-zA-Z0-9\_]{1,32}):([0-9]{15,20})>$', argument) + + if match: + emoji_animated = bool(match.group(1)) + emoji_name = match.group(2) + emoji_id = int(match.group(3)) + + return discord.PartialEmoji.with_state( + ctx.bot._connection, animated=emoji_animated, name=emoji_name, id=emoji_id + ) + + raise PartialEmojiConversionFailure(argument) + + +class GuildStickerConverter(IDConverter[discord.GuildSticker]): + """Converts to a :class:`~discord.GuildSticker`. + + All lookups are done for the local guild first, if available. If that lookup + fails, then it checks the client's global cache. + + The lookup strategy is as follows (in order): + + 1. Lookup by ID. + 2. Lookup by name. + + .. versionadded:: 2.0 + """ + + async def convert(self, ctx: Context[BotT], argument: str) -> discord.GuildSticker: + match = self._get_id_match(argument) + result = None + bot = ctx.bot + guild = ctx.guild + + if match is None: + # Try to get the sticker by name. Try local guild first. + if guild: + result = discord.utils.get(guild.stickers, name=argument) + + if result is None: + result = discord.utils.get(bot.stickers, name=argument) + else: + sticker_id = int(match.group(1)) + + # Try to look up sticker by id. + result = bot.get_sticker(sticker_id) + + if result is None: + raise GuildStickerNotFound(argument) + + return result + + +class ScheduledEventConverter(IDConverter[discord.ScheduledEvent]): + """Converts to a :class:`~discord.ScheduledEvent`. + + Lookups are done for the local guild if available. Otherwise, for a DM context, + lookup is done by the global cache. + + The lookup strategy is as follows (in order): + + 1. Lookup by ID. + 2. Lookup by url. + 3. Lookup by name. + + .. versionadded:: 2.0 + """ + + async def convert(self, ctx: Context[BotT], argument: str) -> discord.ScheduledEvent: + guild = ctx.guild + match = self._get_id_match(argument) + result = None + + if match: + # ID match + event_id = int(match.group(1)) + if guild: + result = guild.get_scheduled_event(event_id) + else: + for guild in ctx.bot.guilds: + result = guild.get_scheduled_event(event_id) + if result: + break + else: + pattern = ( + r'https?://(?:(ptb|canary|www)\.)?discord\.com/events/' + r'(?P[0-9]{15,20})/' + r'(?P[0-9]{15,20})$' + ) + match = re.match(pattern, argument, flags=re.I) + if match: + # URL match + guild = ctx.bot.get_guild(int(match.group('guild_id'))) + + if guild: + event_id = int(match.group('event_id')) + result = guild.get_scheduled_event(event_id) + else: + # lookup by name + if guild: + result = discord.utils.get(guild.scheduled_events, name=argument) + else: + for guild in ctx.bot.guilds: + result = discord.utils.get(guild.scheduled_events, name=argument) + if result: + break + if result is None: + raise ScheduledEventNotFound(argument) + + return result + + +class SoundboardSoundConverter(IDConverter[discord.SoundboardSound]): + """Converts to a :class:`~discord.SoundboardSound`. + + Lookups are done for the local guild if available. Otherwise, for a DM context, + lookup is done by the global cache. + + The lookup strategy is as follows (in order): + + 1. Lookup by ID. + 2. Lookup by name. + + .. versionadded:: 2.5 + """ + + async def convert(self, ctx: Context[BotT], argument: str) -> discord.SoundboardSound: + guild = ctx.guild + match = self._get_id_match(argument) + result = None + + if match: + # ID match + sound_id = int(match.group(1)) + if guild: + result = guild.get_soundboard_sound(sound_id) + else: + result = ctx.bot.get_soundboard_sound(sound_id) + else: + # lookup by name + if guild: + result = discord.utils.get(guild.soundboard_sounds, name=argument) + else: + result = discord.utils.get(ctx.bot.soundboard_sounds, name=argument) + if result is None: + raise SoundboardSoundNotFound(argument) + + return result + + +class clean_content(Converter[str]): + """Converts the argument to mention scrubbed version of + said content. + + This behaves similarly to :attr:`~discord.Message.clean_content`. + + Attributes + ------------ + fix_channel_mentions: :class:`bool` + Whether to clean channel mentions. + use_nicknames: :class:`bool` + Whether to use nicknames when transforming mentions. + escape_markdown: :class:`bool` + Whether to also escape special markdown characters. + remove_markdown: :class:`bool` + Whether to also remove special markdown characters. This option is not supported with ``escape_markdown`` + + .. versionadded:: 1.7 + """ + + def __init__( + self, + *, + fix_channel_mentions: bool = False, + use_nicknames: bool = True, + escape_markdown: bool = False, + remove_markdown: bool = False, + ) -> None: + self.fix_channel_mentions = fix_channel_mentions + self.use_nicknames = use_nicknames + self.escape_markdown = escape_markdown + self.remove_markdown = remove_markdown + + async def convert(self, ctx: Context[BotT], argument: str) -> str: + msg = ctx.message + + if ctx.guild: + + def resolve_member(id: int) -> str: + m = _utils_get(msg.mentions, id=id) or ctx.guild.get_member(id) # type: ignore + return f'@{m.display_name if self.use_nicknames else m.name}' if m else '@deleted-user' + + def resolve_role(id: int) -> str: + r = _utils_get(msg.role_mentions, id=id) or ctx.guild.get_role(id) # type: ignore + return f'@{r.name}' if r else '@deleted-role' + + else: + + def resolve_member(id: int) -> str: + m = _utils_get(msg.mentions, id=id) or ctx.bot.get_user(id) + return f'@{m.display_name}' if m else '@deleted-user' + + def resolve_role(id: int) -> str: + return '@deleted-role' + + if self.fix_channel_mentions and ctx.guild: + + def resolve_channel(id: int) -> str: + c = ctx.guild._resolve_channel(id) # type: ignore + return f'#{c.name}' if c else '#deleted-channel' + + else: + + def resolve_channel(id: int) -> str: + return f'<#{id}>' + + transforms = { + '@': resolve_member, + '@!': resolve_member, + '#': resolve_channel, + '@&': resolve_role, + } + + def repl(match: re.Match) -> str: + type = match[1] + id = int(match[2]) + transformed = transforms[type](id) + return transformed + + result = re.sub(r'<(@[!&]?|#)([0-9]{15,20})>', repl, argument) + if self.escape_markdown: + result = discord.utils.escape_markdown(result) + elif self.remove_markdown: + result = discord.utils.remove_markdown(result) + + # Completely ensure no mentions escape: + return discord.utils.escape_mentions(result) + + +class Greedy(List[T]): + r"""A special converter that greedily consumes arguments until it can't. + As a consequence of this behaviour, most input errors are silently discarded, + since it is used as an indicator of when to stop parsing. + + When a parser error is met the greedy converter stops converting, undoes the + internal string parsing routine, and continues parsing regularly. + + For example, in the following code: + + .. code-block:: python3 + + @commands.command() + async def test(ctx, numbers: Greedy[int], reason: str): + await ctx.send("numbers: {}, reason: {}".format(numbers, reason)) + + An invocation of ``[p]test 1 2 3 4 5 6 hello`` would pass ``numbers`` with + ``[1, 2, 3, 4, 5, 6]`` and ``reason`` with ``hello``\. + + For more information, check :ref:`ext_commands_special_converters`. + + .. note:: + + For interaction based contexts the conversion error is propagated + rather than swallowed due to the difference in user experience with + application commands. + """ + + __slots__ = ('converter',) + + def __init__(self, *, converter: T) -> None: + self.converter: T = converter + + def __repr__(self) -> str: + converter = getattr(self.converter, '__name__', repr(self.converter)) + return f'Greedy[{converter}]' + + def __class_getitem__(cls, params: Union[Tuple[T], T]) -> Greedy[T]: + if not isinstance(params, tuple): + params = (params,) + if len(params) != 1: + raise TypeError('Greedy[...] only takes a single argument') + converter = params[0] + + args = getattr(converter, '__args__', ()) + if discord.utils.PY_310 and converter.__class__ is types.UnionType: # type: ignore + converter = Union[args] + + origin = getattr(converter, '__origin__', None) + + if not (callable(converter) or isinstance(converter, Converter) or origin is not None): + raise TypeError('Greedy[...] expects a type or a Converter instance.') + + if converter in (str, type(None)) or origin is Greedy: + raise TypeError(f'Greedy[{converter.__name__}] is invalid.') # type: ignore + + if origin is Union and type(None) in args: + raise TypeError(f'Greedy[{converter!r}] is invalid.') + + return cls(converter=converter) # type: ignore + + @property + def constructed_converter(self) -> Any: + # Only construct a converter once in order to maintain state between convert calls + if ( + inspect.isclass(self.converter) + and issubclass(self.converter, Converter) + and not inspect.ismethod(self.converter.convert) + ): + return self.converter() + return self.converter + + +if TYPE_CHECKING: + from typing_extensions import Annotated as Range +else: + + class Range: + """A special converter that can be applied to a parameter to require a numeric + or string type to fit within the range provided. + + During type checking time this is equivalent to :obj:`typing.Annotated` so type checkers understand + the intent of the code. + + Some example ranges: + + - ``Range[int, 10]`` means the minimum is 10 with no maximum. + - ``Range[int, None, 10]`` means the maximum is 10 with no minimum. + - ``Range[int, 1, 10]`` means the minimum is 1 and the maximum is 10. + - ``Range[float, 1.0, 5.0]`` means the minimum is 1.0 and the maximum is 5.0. + - ``Range[str, 1, 10]`` means the minimum length is 1 and the maximum length is 10. + + Inside a :class:`HybridCommand` this functions equivalently to :class:`discord.app_commands.Range`. + + If the value cannot be converted to the provided type or is outside the given range, + :class:`~.ext.commands.BadArgument` or :class:`~.ext.commands.RangeError` is raised to + the appropriate error handlers respectively. + + .. versionadded:: 2.0 + + Examples + ---------- + + .. code-block:: python3 + + @bot.command() + async def range(ctx: commands.Context, value: commands.Range[int, 10, 12]): + await ctx.send(f'Your value is {value}') + """ + + def __init__( + self, + *, + annotation: Any, + min: Optional[Union[int, float]] = None, + max: Optional[Union[int, float]] = None, + ) -> None: + self.annotation: Any = annotation + self.min: Optional[Union[int, float]] = min + self.max: Optional[Union[int, float]] = max + + if min and max and min > max: + raise TypeError('minimum cannot be larger than maximum') + + async def convert(self, ctx: Context[BotT], value: str) -> Union[int, float]: + try: + count = converted = self.annotation(value) + except ValueError: + raise BadArgument( + f'Converting to "{self.annotation.__name__}" failed for parameter "{ctx.current_parameter.name}".' + ) + + if self.annotation is str: + count = len(value) + + if (self.min is not None and count < self.min) or (self.max is not None and count > self.max): + raise RangeError(converted, minimum=self.min, maximum=self.max) + + return converted + + def __call__(self) -> None: + # Trick to allow it inside typing.Union + pass + + def __or__(self, rhs) -> Any: + return Union[self, rhs] + + def __repr__(self) -> str: + return f'{self.__class__.__name__}[{self.annotation.__name__}, {self.min}, {self.max}]' + + def __class_getitem__(cls, obj) -> Range: + if not isinstance(obj, tuple): + raise TypeError(f'expected tuple for arguments, received {obj.__class__.__name__} instead') + + if len(obj) == 2: + obj = (*obj, None) + elif len(obj) != 3: + raise TypeError('Range accepts either two or three arguments with the first being the type of range.') + + annotation, min, max = obj + + if min is None and max is None: + raise TypeError('Range must not be empty') + + if min is not None and max is not None: + # At this point max and min are both not none + if type(min) != type(max): + raise TypeError('Both min and max in Range must be the same type') + + if annotation not in (int, float, str): + raise TypeError(f'expected int, float, or str as range type, received {annotation!r} instead') + + if annotation in (str, int): + cast = int + else: + cast = float + + return cls( + annotation=annotation, + min=cast(min) if min is not None else None, + max=cast(max) if max is not None else None, + ) + + +def _convert_to_bool(argument: str) -> bool: + lowered = argument.lower() + if lowered in ('yes', 'y', 'true', 't', '1', 'enable', 'on'): + return True + elif lowered in ('no', 'n', 'false', 'f', '0', 'disable', 'off'): + return False + else: + raise BadBoolArgument(lowered) + + +_GenericAlias = type(List[T]) # type: ignore + + +def is_generic_type(tp: Any, *, _GenericAlias: type = _GenericAlias) -> bool: + return isinstance(tp, type) and issubclass(tp, Generic) or isinstance(tp, _GenericAlias) + + +CONVERTER_MAPPING: Dict[type, Any] = { + discord.Object: ObjectConverter, + discord.Member: MemberConverter, + discord.User: UserConverter, + discord.Message: MessageConverter, + discord.PartialMessage: PartialMessageConverter, + discord.TextChannel: TextChannelConverter, + discord.Invite: InviteConverter, + discord.Guild: GuildConverter, + discord.Role: RoleConverter, + discord.Game: GameConverter, + discord.Colour: ColourConverter, + discord.VoiceChannel: VoiceChannelConverter, + discord.StageChannel: StageChannelConverter, + discord.Emoji: EmojiConverter, + discord.PartialEmoji: PartialEmojiConverter, + discord.CategoryChannel: CategoryChannelConverter, + discord.Thread: ThreadConverter, + discord.abc.GuildChannel: GuildChannelConverter, + discord.GuildSticker: GuildStickerConverter, + discord.ScheduledEvent: ScheduledEventConverter, + discord.ForumChannel: ForumChannelConverter, + discord.SoundboardSound: SoundboardSoundConverter, +} + + +async def _actual_conversion(ctx: Context[BotT], converter: Any, argument: str, param: inspect.Parameter): + if converter is bool: + return _convert_to_bool(argument) + + try: + module = converter.__module__ + except AttributeError: + pass + else: + if module is not None and (module.startswith('discord.') and not module.endswith('converter')): + converter = CONVERTER_MAPPING.get(converter, converter) + + try: + if inspect.isclass(converter) and issubclass(converter, Converter): + if inspect.ismethod(converter.convert): + return await converter.convert(ctx, argument) + else: + return await converter().convert(ctx, argument) + elif isinstance(converter, Converter): + return await converter.convert(ctx, argument) + except CommandError: + raise + except Exception as exc: + raise ConversionError(converter, exc) from exc # type: ignore + + try: + return converter(argument) + except CommandError: + raise + except Exception as exc: + try: + name = converter.__name__ + except AttributeError: + name = converter.__class__.__name__ + + raise BadArgument(f'Converting to "{name}" failed for parameter "{param.name}".') from exc + + +@overload +async def run_converters( + ctx: Context[BotT], converter: Union[Type[Converter[T]], Converter[T]], argument: str, param: Parameter +) -> T: + ... + + +@overload +async def run_converters(ctx: Context[BotT], converter: Any, argument: str, param: Parameter) -> Any: + ... + + +async def run_converters(ctx: Context[BotT], converter: Any, argument: str, param: Parameter) -> Any: + """|coro| + + Runs converters for a given converter, argument, and parameter. + + This function does the same work that the library does under the hood. + + .. versionadded:: 2.0 + + Parameters + ------------ + ctx: :class:`Context` + The invocation context to run the converters under. + converter: Any + The converter to run, this corresponds to the annotation in the function. + argument: :class:`str` + The argument to convert to. + param: :class:`Parameter` + The parameter being converted. This is mainly for error reporting. + + Raises + ------- + CommandError + The converter failed to convert. + + Returns + -------- + Any + The resulting conversion. + """ + origin = getattr(converter, '__origin__', None) + + if origin is Union: + errors = [] + _NoneType = type(None) + union_args = converter.__args__ + for conv in union_args: + # if we got to this part in the code, then the previous conversions have failed + # so we should just undo the view, return the default, and allow parsing to continue + # with the other parameters + if conv is _NoneType and param.kind != param.VAR_POSITIONAL: + ctx.view.undo() + return None if param.required else await param.get_default(ctx) + + try: + value = await run_converters(ctx, conv, argument, param) + except CommandError as exc: + errors.append(exc) + else: + return value + + # if we're here, then we failed all the converters + raise BadUnionArgument(param, union_args, errors) + + if origin is Literal: + errors = [] + conversions = {} + literal_args = converter.__args__ + for literal in literal_args: + literal_type = type(literal) + try: + value = conversions[literal_type] + except KeyError: + try: + value = await _actual_conversion(ctx, literal_type, argument, param) + except CommandError as exc: + errors.append(exc) + conversions[literal_type] = object() + continue + else: + conversions[literal_type] = value + + if value == literal: + return value + + # if we're here, then we failed to match all the literals + raise BadLiteralArgument(param, literal_args, errors, argument) + + # This must be the last if-clause in the chain of origin checking + # Nearly every type is a generic type within the typing library + # So care must be taken to make sure a more specialised origin handle + # isn't overwritten by the widest if clause + if origin is not None and is_generic_type(converter): + converter = origin + + return await _actual_conversion(ctx, converter, argument, param) diff --git a/venv/lib/python3.12/site-packages/discord/ext/commands/cooldowns.py b/venv/lib/python3.12/site-packages/discord/ext/commands/cooldowns.py new file mode 100644 index 00000000..cf328d9b --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/ext/commands/cooldowns.py @@ -0,0 +1,285 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from __future__ import annotations + + +from typing import Any, Callable, Deque, Dict, Optional, Union, Generic, TypeVar, TYPE_CHECKING +from discord.enums import Enum +from discord.abc import PrivateChannel +import time +import asyncio +from collections import deque + +from .errors import MaxConcurrencyReached +from .context import Context +from discord.app_commands import Cooldown as Cooldown + +if TYPE_CHECKING: + from typing_extensions import Self + + from ...message import Message + +__all__ = ( + 'BucketType', + 'Cooldown', + 'CooldownMapping', + 'DynamicCooldownMapping', + 'MaxConcurrency', +) + +T_contra = TypeVar('T_contra', contravariant=True) + + +class BucketType(Enum): + default = 0 + user = 1 + guild = 2 + channel = 3 + member = 4 + category = 5 + role = 6 + + def get_key(self, msg: Union[Message, Context[Any]]) -> Any: + if self is BucketType.user: + return msg.author.id + elif self is BucketType.guild: + return (msg.guild or msg.author).id + elif self is BucketType.channel: + return msg.channel.id + elif self is BucketType.member: + return ((msg.guild and msg.guild.id), msg.author.id) + elif self is BucketType.category: + return (getattr(msg.channel, 'category', None) or msg.channel).id + elif self is BucketType.role: + # we return the channel id of a private-channel as there are only roles in guilds + # and that yields the same result as for a guild with only the @everyone role + # NOTE: PrivateChannel doesn't actually have an id attribute but we assume we are + # receiving a DMChannel or GroupChannel which inherit from PrivateChannel and do + return (msg.channel if isinstance(msg.channel, PrivateChannel) else msg.author.top_role).id # type: ignore + + def __call__(self, msg: Union[Message, Context[Any]]) -> Any: + return self.get_key(msg) + + +class CooldownMapping(Generic[T_contra]): + def __init__( + self, + original: Optional[Cooldown], + type: Callable[[T_contra], Any], + ) -> None: + if not callable(type): + raise TypeError('Cooldown type must be a BucketType or callable') + + self._cache: Dict[Any, Cooldown] = {} + self._cooldown: Optional[Cooldown] = original + self._type: Callable[[T_contra], Any] = type + + def copy(self) -> CooldownMapping[T_contra]: + ret = CooldownMapping(self._cooldown, self._type) + ret._cache = self._cache.copy() + return ret + + @property + def valid(self) -> bool: + return self._cooldown is not None + + @property + def type(self) -> Callable[[T_contra], Any]: + return self._type + + @classmethod + def from_cooldown(cls, rate: float, per: float, type: Callable[[T_contra], Any]) -> Self: + return cls(Cooldown(rate, per), type) + + def _bucket_key(self, msg: T_contra) -> Any: + return self._type(msg) + + def _verify_cache_integrity(self, current: Optional[float] = None) -> None: + # we want to delete all cache objects that haven't been used + # in a cooldown window. e.g. if we have a command that has a + # cooldown of 60s and it has not been used in 60s then that key should be deleted + current = current or time.time() + dead_keys = [k for k, v in self._cache.items() if current > v._last + v.per] + for k in dead_keys: + del self._cache[k] + + def create_bucket(self, message: T_contra) -> Cooldown: + return self._cooldown.copy() # type: ignore + + def get_bucket(self, message: T_contra, current: Optional[float] = None) -> Optional[Cooldown]: + if self._type is BucketType.default: + return self._cooldown + + self._verify_cache_integrity(current) + key = self._bucket_key(message) + if key not in self._cache: + bucket = self.create_bucket(message) + if bucket is not None: + self._cache[key] = bucket + else: + bucket = self._cache[key] + + return bucket + + def update_rate_limit(self, message: T_contra, current: Optional[float] = None, tokens: int = 1) -> Optional[float]: + bucket = self.get_bucket(message, current) + if bucket is None: + return None + return bucket.update_rate_limit(current, tokens=tokens) + + +class DynamicCooldownMapping(CooldownMapping[T_contra]): + def __init__( + self, + factory: Callable[[T_contra], Optional[Cooldown]], + type: Callable[[T_contra], Any], + ) -> None: + super().__init__(None, type) + self._factory: Callable[[T_contra], Optional[Cooldown]] = factory + + def copy(self) -> DynamicCooldownMapping[T_contra]: + ret = DynamicCooldownMapping(self._factory, self._type) + ret._cache = self._cache.copy() + return ret + + @property + def valid(self) -> bool: + return True + + def create_bucket(self, message: T_contra) -> Optional[Cooldown]: + return self._factory(message) + + +class _Semaphore: + """This class is a version of a semaphore. + + If you're wondering why asyncio.Semaphore isn't being used, + it's because it doesn't expose the internal value. This internal + value is necessary because I need to support both `wait=True` and + `wait=False`. + + An asyncio.Queue could have been used to do this as well -- but it is + not as inefficient since internally that uses two queues and is a bit + overkill for what is basically a counter. + """ + + __slots__ = ('value', 'loop', '_waiters') + + def __init__(self, number: int) -> None: + self.value: int = number + self.loop: asyncio.AbstractEventLoop = asyncio.get_running_loop() + self._waiters: Deque[asyncio.Future] = deque() + + def __repr__(self) -> str: + return f'<_Semaphore value={self.value} waiters={len(self._waiters)}>' + + def locked(self) -> bool: + return self.value == 0 + + def is_active(self) -> bool: + return len(self._waiters) > 0 + + def wake_up(self) -> None: + while self._waiters: + future = self._waiters.popleft() + if not future.done(): + future.set_result(None) + return + + async def acquire(self, *, wait: bool = False) -> bool: + if not wait and self.value <= 0: + # signal that we're not acquiring + return False + + while self.value <= 0: + future = self.loop.create_future() + self._waiters.append(future) + try: + await future + except: + future.cancel() + if self.value > 0 and not future.cancelled(): + self.wake_up() + raise + + self.value -= 1 + return True + + def release(self) -> None: + self.value += 1 + self.wake_up() + + +class MaxConcurrency: + __slots__ = ('number', 'per', 'wait', '_mapping') + + def __init__(self, number: int, *, per: BucketType, wait: bool) -> None: + self._mapping: Dict[Any, _Semaphore] = {} + self.per: BucketType = per + self.number: int = number + self.wait: bool = wait + + if number <= 0: + raise ValueError('max_concurrency \'number\' cannot be less than 1') + + if not isinstance(per, BucketType): + raise TypeError(f'max_concurrency \'per\' must be of type BucketType not {type(per)!r}') + + def copy(self) -> Self: + return self.__class__(self.number, per=self.per, wait=self.wait) + + def __repr__(self) -> str: + return f'' + + def get_key(self, message: Union[Message, Context[Any]]) -> Any: + return self.per.get_key(message) + + async def acquire(self, message: Union[Message, Context[Any]]) -> None: + key = self.get_key(message) + + try: + sem = self._mapping[key] + except KeyError: + self._mapping[key] = sem = _Semaphore(self.number) + + acquired = await sem.acquire(wait=self.wait) + if not acquired: + raise MaxConcurrencyReached(self.number, self.per) + + async def release(self, message: Union[Message, Context[Any]]) -> None: + # Technically there's no reason for this function to be async + # But it might be more useful in the future + key = self.get_key(message) + + try: + sem = self._mapping[key] + except KeyError: + # ...? peculiar + return + else: + sem.release() + + if sem.value >= self.number and not sem.is_active(): + del self._mapping[key] diff --git a/venv/lib/python3.12/site-packages/discord/ext/commands/core.py b/venv/lib/python3.12/site-packages/discord/ext/commands/core.py new file mode 100644 index 00000000..372fcbed --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/ext/commands/core.py @@ -0,0 +1,2640 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" +from __future__ import annotations + +import asyncio +import datetime +import functools +import inspect +from typing import ( + TYPE_CHECKING, + Any, + Callable, + Dict, + Generator, + Generic, + List, + Literal, + Optional, + Set, + Tuple, + Type, + TypeVar, + Union, + overload, +) +import re + +import discord + +from ._types import _BaseCommand, CogT +from .cog import Cog +from .context import Context +from .converter import Greedy, run_converters +from .cooldowns import BucketType, Cooldown, CooldownMapping, DynamicCooldownMapping, MaxConcurrency +from .errors import * +from .parameters import Parameter, Signature +from discord.app_commands.commands import NUMPY_DOCSTRING_ARG_REGEX + +if TYPE_CHECKING: + from typing_extensions import Concatenate, ParamSpec, Self + + from ._types import BotT, Check, ContextT, Coro, CoroFunc, Error, Hook, UserCheck + + +__all__ = ( + 'Command', + 'Group', + 'GroupMixin', + 'command', + 'group', + 'has_role', + 'has_permissions', + 'has_any_role', + 'check', + 'check_any', + 'before_invoke', + 'after_invoke', + 'bot_has_role', + 'bot_has_permissions', + 'bot_has_any_role', + 'cooldown', + 'dynamic_cooldown', + 'max_concurrency', + 'dm_only', + 'guild_only', + 'is_owner', + 'is_nsfw', + 'has_guild_permissions', + 'bot_has_guild_permissions', +) + +MISSING: Any = discord.utils.MISSING + +T = TypeVar('T') +CommandT = TypeVar('CommandT', bound='Command[Any, ..., Any]') +# CHT = TypeVar('CHT', bound='Check') +GroupT = TypeVar('GroupT', bound='Group[Any, ..., Any]') + +if TYPE_CHECKING: + P = ParamSpec('P') +else: + P = TypeVar('P') + + +def unwrap_function(function: Callable[..., Any], /) -> Callable[..., Any]: + partial = functools.partial + while True: + if hasattr(function, '__wrapped__'): + function = function.__wrapped__ + elif isinstance(function, partial): + function = function.func + else: + return function + + +def get_signature_parameters( + function: Callable[..., Any], + globalns: Dict[str, Any], + /, + *, + skip_parameters: Optional[int] = None, +) -> Dict[str, Parameter]: + signature = Signature.from_callable(function) + params: Dict[str, Parameter] = {} + cache: Dict[str, Any] = {} + eval_annotation = discord.utils.evaluate_annotation + required_params = discord.utils.is_inside_class(function) + 1 if skip_parameters is None else skip_parameters + if len(signature.parameters) < required_params: + raise TypeError(f'Command signature requires at least {required_params - 1} parameter(s)') + + iterator = iter(signature.parameters.items()) + for _ in range(0, required_params): + next(iterator) + + for name, parameter in iterator: + default = parameter.default + if isinstance(default, Parameter): # update from the default + if default.annotation is not Parameter.empty: + # There are a few cases to care about here. + # x: TextChannel = commands.CurrentChannel + # x = commands.CurrentChannel + # In both of these cases, the default parameter has an explicit annotation + # but in the second case it's only used as the fallback. + if default._fallback: + if parameter.annotation is Parameter.empty: + parameter._annotation = default.annotation + else: + parameter._annotation = default.annotation + + parameter._default = default.default + parameter._description = default._description + parameter._displayed_default = default._displayed_default + parameter._displayed_name = default._displayed_name + + annotation = parameter.annotation + + if annotation is None: + params[name] = parameter.replace(annotation=type(None)) + continue + + annotation = eval_annotation(annotation, globalns, globalns, cache) + if annotation is Greedy: + raise TypeError('Unparameterized Greedy[...] is disallowed in signature.') + + params[name] = parameter.replace(annotation=annotation) + + return params + + +PARAMETER_HEADING_REGEX = re.compile(r'Parameters?\n---+\n', re.I) + + +def _fold_text(input: str) -> str: + """Turns a single newline into a space, and multiple newlines into a newline.""" + + def replacer(m: re.Match[str]) -> str: + if len(m.group()) <= 1: + return ' ' + return '\n' + + return re.sub(r'\n+', replacer, inspect.cleandoc(input)) + + +def extract_descriptions_from_docstring(function: Callable[..., Any], params: Dict[str, Parameter], /) -> Optional[str]: + docstring = inspect.getdoc(function) + + if docstring is None: + return None + + divide = PARAMETER_HEADING_REGEX.split(docstring, 1) + if len(divide) == 1: + return docstring + + description, param_docstring = divide + for match in NUMPY_DOCSTRING_ARG_REGEX.finditer(param_docstring): + name = match.group('name') + + if name not in params: + is_display_name = discord.utils.get(params.values(), displayed_name=name) + if is_display_name: + name = is_display_name.name + else: + continue + + param = params[name] + if param.description is None: + param._description = _fold_text(match.group('description')) + + return _fold_text(description.strip()) + + +def wrap_callback(coro: Callable[P, Coro[T]], /) -> Callable[P, Coro[Optional[T]]]: + @functools.wraps(coro) + async def wrapped(*args: P.args, **kwargs: P.kwargs) -> Optional[T]: + try: + ret = await coro(*args, **kwargs) + except CommandError: + raise + except asyncio.CancelledError: + return + except Exception as exc: + raise CommandInvokeError(exc) from exc + return ret + + return wrapped + + +def hooked_wrapped_callback( + command: Command[Any, ..., Any], ctx: Context[BotT], coro: Callable[P, Coro[T]], / +) -> Callable[P, Coro[Optional[T]]]: + @functools.wraps(coro) + async def wrapped(*args: P.args, **kwargs: P.kwargs) -> Optional[T]: + try: + ret = await coro(*args, **kwargs) + except CommandError: + ctx.command_failed = True + raise + except asyncio.CancelledError: + ctx.command_failed = True + return + except Exception as exc: + ctx.command_failed = True + raise CommandInvokeError(exc) from exc + finally: + if command._max_concurrency is not None: + await command._max_concurrency.release(ctx.message) + + await command.call_after_hooks(ctx) + return ret + + return wrapped + + +class _CaseInsensitiveDict(dict): + def __contains__(self, k): + return super().__contains__(k.casefold()) + + def __delitem__(self, k): + return super().__delitem__(k.casefold()) + + def __getitem__(self, k): + return super().__getitem__(k.casefold()) + + def get(self, k, default=None): + return super().get(k.casefold(), default) + + def pop(self, k, default=None): + return super().pop(k.casefold(), default) + + def __setitem__(self, k, v): + super().__setitem__(k.casefold(), v) + + +class _AttachmentIterator: + def __init__(self, data: List[discord.Attachment]): + self.data: List[discord.Attachment] = data + self.index: int = 0 + + def __iter__(self) -> Self: + return self + + def __next__(self) -> discord.Attachment: + try: + value = self.data[self.index] + except IndexError: + raise StopIteration + else: + self.index += 1 + return value + + def is_empty(self) -> bool: + return self.index >= len(self.data) + + +class Command(_BaseCommand, Generic[CogT, P, T]): + r"""A class that implements the protocol for a bot text command. + + These are not created manually, instead they are created via the + decorator or functional interface. + + Attributes + ----------- + name: :class:`str` + The name of the command. + callback: :ref:`coroutine ` + The coroutine that is executed when the command is called. + help: Optional[:class:`str`] + The long help text for the command. + brief: Optional[:class:`str`] + The short help text for the command. + usage: Optional[:class:`str`] + A replacement for arguments in the default help text. + aliases: Union[List[:class:`str`], Tuple[:class:`str`]] + The list of aliases the command can be invoked under. + enabled: :class:`bool` + A boolean that indicates if the command is currently enabled. + If the command is invoked while it is disabled, then + :exc:`.DisabledCommand` is raised to the :func:`.on_command_error` + event. Defaults to ``True``. + parent: Optional[:class:`Group`] + The parent group that this command belongs to. ``None`` if there + isn't one. + cog: Optional[:class:`Cog`] + The cog that this command belongs to. ``None`` if there isn't one. + checks: List[Callable[[:class:`.Context`], :class:`bool`]] + A list of predicates that verifies if the command could be executed + with the given :class:`.Context` as the sole parameter. If an exception + is necessary to be thrown to signal failure, then one inherited from + :exc:`.CommandError` should be used. Note that if the checks fail then + :exc:`.CheckFailure` exception is raised to the :func:`.on_command_error` + event. + description: :class:`str` + The message prefixed into the default help command. + hidden: :class:`bool` + If ``True``\, the default help command does not show this in the + help output. + rest_is_raw: :class:`bool` + If ``False`` and a keyword-only argument is provided then the keyword + only argument is stripped and handled as if it was a regular argument + that handles :exc:`.MissingRequiredArgument` and default values in a + regular matter rather than passing the rest completely raw. If ``True`` + then the keyword-only argument will pass in the rest of the arguments + in a completely raw matter. Defaults to ``False``. + invoked_subcommand: Optional[:class:`Command`] + The subcommand that was invoked, if any. + require_var_positional: :class:`bool` + If ``True`` and a variadic positional argument is specified, requires + the user to specify at least one argument. Defaults to ``False``. + + .. versionadded:: 1.5 + + ignore_extra: :class:`bool` + If ``True``\, ignores extraneous strings passed to a command if all its + requirements are met (e.g. ``?foo a b c`` when only expecting ``a`` + and ``b``). Otherwise :func:`.on_command_error` and local error handlers + are called with :exc:`.TooManyArguments`. Defaults to ``True``. + cooldown_after_parsing: :class:`bool` + If ``True``\, cooldown processing is done after argument parsing, + which calls converters. If ``False`` then cooldown processing is done + first and then the converters are called second. Defaults to ``False``. + extras: :class:`dict` + A dict of user provided extras to attach to the Command. + + .. note:: + This object may be copied by the library. + + + .. versionadded:: 2.0 + """ + __original_kwargs__: Dict[str, Any] + + def __new__(cls, *args: Any, **kwargs: Any) -> Self: + # if you're wondering why this is done, it's because we need to ensure + # we have a complete original copy of **kwargs even for classes that + # mess with it by popping before delegating to the subclass __init__. + # In order to do this, we need to control the instance creation and + # inject the original kwargs through __new__ rather than doing it + # inside __init__. + self = super().__new__(cls) + + # we do a shallow copy because it's probably the most common use case. + # this could potentially break if someone modifies a list or something + # while it's in movement, but for now this is the cheapest and + # fastest way to do what we want. + self.__original_kwargs__ = kwargs.copy() + return self + + def __init__( + self, + func: Union[ + Callable[Concatenate[CogT, Context[Any], P], Coro[T]], + Callable[Concatenate[Context[Any], P], Coro[T]], + ], + /, + **kwargs: Any, + ) -> None: + if not asyncio.iscoroutinefunction(func): + raise TypeError('Callback must be a coroutine.') + + name = kwargs.get('name') or func.__name__ + if not isinstance(name, str): + raise TypeError('Name of a command must be a string.') + self.name: str = name + + self.callback = func + self.enabled: bool = kwargs.get('enabled', True) + + help_doc = kwargs.get('help') + if help_doc is not None: + help_doc = inspect.cleandoc(help_doc) + else: + help_doc = extract_descriptions_from_docstring(func, self.params) + + self.help: Optional[str] = help_doc + + self.brief: Optional[str] = kwargs.get('brief') + self.usage: Optional[str] = kwargs.get('usage') + self.rest_is_raw: bool = kwargs.get('rest_is_raw', False) + self.aliases: Union[List[str], Tuple[str]] = kwargs.get('aliases', []) + self.extras: Dict[Any, Any] = kwargs.get('extras', {}) + + if not isinstance(self.aliases, (list, tuple)): + raise TypeError("Aliases of a command must be a list or a tuple of strings.") + + self.description: str = inspect.cleandoc(kwargs.get('description', '')) + self.hidden: bool = kwargs.get('hidden', False) + + try: + checks = func.__commands_checks__ + checks.reverse() + except AttributeError: + checks = kwargs.get('checks', []) + + self.checks: List[UserCheck[Context[Any]]] = checks + + try: + cooldown = func.__commands_cooldown__ + except AttributeError: + cooldown = kwargs.get('cooldown') + + if cooldown is None: + buckets = CooldownMapping(cooldown, BucketType.default) + elif isinstance(cooldown, CooldownMapping): + buckets: CooldownMapping[Context[Any]] = cooldown + else: + raise TypeError("Cooldown must be an instance of CooldownMapping or None.") + self._buckets: CooldownMapping[Context[Any]] = buckets + + try: + max_concurrency = func.__commands_max_concurrency__ + except AttributeError: + max_concurrency = kwargs.get('max_concurrency') + + self._max_concurrency: Optional[MaxConcurrency] = max_concurrency + + self.require_var_positional: bool = kwargs.get('require_var_positional', False) + self.ignore_extra: bool = kwargs.get('ignore_extra', True) + self.cooldown_after_parsing: bool = kwargs.get('cooldown_after_parsing', False) + self._cog: CogT = None # type: ignore # This breaks every other pyright release + + # bandaid for the fact that sometimes parent can be the bot instance + parent: Optional[GroupMixin[Any]] = kwargs.get('parent') + self.parent: Optional[GroupMixin[Any]] = parent if isinstance(parent, _BaseCommand) else None + + self._before_invoke: Optional[Hook] = None + try: + before_invoke = func.__before_invoke__ + except AttributeError: + pass + else: + self.before_invoke(before_invoke) + + self._after_invoke: Optional[Hook] = None + try: + after_invoke = func.__after_invoke__ + except AttributeError: + pass + else: + self.after_invoke(after_invoke) + + @property + def cog(self) -> CogT: + return self._cog + + @cog.setter + def cog(self, value: CogT) -> None: + self._cog = value + + @property + def callback( + self, + ) -> Union[Callable[Concatenate[CogT, Context[Any], P], Coro[T]], Callable[Concatenate[Context[Any], P], Coro[T]],]: + return self._callback + + @callback.setter + def callback( + self, + function: Union[ + Callable[Concatenate[CogT, Context[Any], P], Coro[T]], + Callable[Concatenate[Context[Any], P], Coro[T]], + ], + ) -> None: + self._callback = function + unwrap = unwrap_function(function) + self.module: str = unwrap.__module__ + + try: + globalns = unwrap.__globals__ + except AttributeError: + globalns = {} + + self.params: Dict[str, Parameter] = get_signature_parameters(function, globalns) + + def add_check(self, func: UserCheck[Context[Any]], /) -> None: + """Adds a check to the command. + + This is the non-decorator interface to :func:`.check`. + + .. versionadded:: 1.3 + + .. versionchanged:: 2.0 + + ``func`` parameter is now positional-only. + + .. seealso:: The :func:`~discord.ext.commands.check` decorator + + Parameters + ----------- + func + The function that will be used as a check. + """ + + self.checks.append(func) + + def remove_check(self, func: UserCheck[Context[Any]], /) -> None: + """Removes a check from the command. + + This function is idempotent and will not raise an exception + if the function is not in the command's checks. + + .. versionadded:: 1.3 + + .. versionchanged:: 2.0 + + ``func`` parameter is now positional-only. + + Parameters + ----------- + func + The function to remove from the checks. + """ + + try: + self.checks.remove(func) + except ValueError: + pass + + def update(self, **kwargs: Any) -> None: + """Updates :class:`Command` instance with updated attribute. + + This works similarly to the :func:`~discord.ext.commands.command` decorator in terms + of parameters in that they are passed to the :class:`Command` or + subclass constructors, sans the name and callback. + """ + cog = self.cog + self.__init__(self.callback, **dict(self.__original_kwargs__, **kwargs)) + self.cog = cog + + async def __call__(self, context: Context[BotT], /, *args: P.args, **kwargs: P.kwargs) -> T: + """|coro| + + Calls the internal callback that the command holds. + + .. note:: + + This bypasses all mechanisms -- including checks, converters, + invoke hooks, cooldowns, etc. You must take care to pass + the proper arguments and types to this function. + + .. versionadded:: 1.3 + + .. versionchanged:: 2.0 + + ``context`` parameter is now positional-only. + """ + if self.cog is not None: + return await self.callback(self.cog, context, *args, **kwargs) # type: ignore + else: + return await self.callback(context, *args, **kwargs) # type: ignore + + def _ensure_assignment_on_copy(self, other: Self) -> Self: + other._before_invoke = self._before_invoke + other._after_invoke = self._after_invoke + other.extras = self.extras + if self.checks != other.checks: + other.checks = self.checks.copy() + if self._buckets.valid and not other._buckets.valid: + other._buckets = self._buckets.copy() + if self._max_concurrency and self._max_concurrency != other._max_concurrency: + other._max_concurrency = self._max_concurrency.copy() + + try: + other.on_error = self.on_error + except AttributeError: + pass + return other + + def copy(self) -> Self: + """Creates a copy of this command. + + Returns + -------- + :class:`Command` + A new instance of this command. + """ + ret = self.__class__(self.callback, **self.__original_kwargs__) + return self._ensure_assignment_on_copy(ret) + + def _update_copy(self, kwargs: Dict[str, Any]) -> Self: + if kwargs: + kw = kwargs.copy() + kw.update(self.__original_kwargs__) + copy = self.__class__(self.callback, **kw) + return self._ensure_assignment_on_copy(copy) + else: + return self.copy() + + async def dispatch_error(self, ctx: Context[BotT], error: CommandError, /) -> None: + ctx.command_failed = True + cog = self.cog + try: + coro = self.on_error + except AttributeError: + pass + else: + injected = wrap_callback(coro) # type: ignore + if cog is not None: + await injected(cog, ctx, error) + else: + await injected(ctx, error) # type: ignore + + try: + if cog is not None: + local = Cog._get_overridden_method(cog.cog_command_error) + if local is not None: + wrapped = wrap_callback(local) + await wrapped(ctx, error) + finally: + ctx.bot.dispatch('command_error', ctx, error) + + async def transform(self, ctx: Context[BotT], param: Parameter, attachments: _AttachmentIterator, /) -> Any: + converter = param.converter + consume_rest_is_special = param.kind == param.KEYWORD_ONLY and not self.rest_is_raw + view = ctx.view + view.skip_ws() + + # The greedy converter is simple -- it keeps going until it fails in which case, + # it undos the view ready for the next parameter to use instead + if isinstance(converter, Greedy): + # Special case for Greedy[discord.Attachment] to consume the attachments iterator + if converter.converter is discord.Attachment: + return list(attachments) + + if param.kind in (param.POSITIONAL_OR_KEYWORD, param.POSITIONAL_ONLY): + return await self._transform_greedy_pos(ctx, param, param.required, converter.constructed_converter) + elif param.kind == param.VAR_POSITIONAL: + return await self._transform_greedy_var_pos(ctx, param, converter.constructed_converter) + else: + # if we're here, then it's a KEYWORD_ONLY param type + # since this is mostly useless, we'll helpfully transform Greedy[X] + # into just X and do the parsing that way. + converter = converter.constructed_converter + + # Try to detect Optional[discord.Attachment] or discord.Attachment special converter + if converter is discord.Attachment: + try: + return next(attachments) + except StopIteration: + raise MissingRequiredAttachment(param) + + if self._is_typing_optional(param.annotation) and param.annotation.__args__[0] is discord.Attachment: + if attachments.is_empty(): + # I have no idea who would be doing Optional[discord.Attachment] = 1 + # but for those cases then 1 should be returned instead of None + return None if param.default is param.empty else param.default + return next(attachments) + + if view.eof: + if param.kind == param.VAR_POSITIONAL: + raise RuntimeError() # break the loop + if param.required: + if self._is_typing_optional(param.annotation): + return None + if hasattr(converter, '__commands_is_flag__') and converter._can_be_constructible(): + return await converter._construct_default(ctx) + raise MissingRequiredArgument(param) + return await param.get_default(ctx) + + previous = view.index + if consume_rest_is_special: + ctx.current_argument = argument = view.read_rest().strip() + else: + try: + ctx.current_argument = argument = view.get_quoted_word() + except ArgumentParsingError as exc: + if self._is_typing_optional(param.annotation): + view.index = previous + return None if param.required else await param.get_default(ctx) + else: + raise exc + view.previous = previous + + # type-checker fails to narrow argument + return await run_converters(ctx, converter, argument, param) # type: ignore + + async def _transform_greedy_pos(self, ctx: Context[BotT], param: Parameter, required: bool, converter: Any) -> Any: + view = ctx.view + result = [] + while not view.eof: + # for use with a manual undo + previous = view.index + + view.skip_ws() + try: + ctx.current_argument = argument = view.get_quoted_word() + value = await run_converters(ctx, converter, argument, param) # type: ignore + except (CommandError, ArgumentParsingError): + view.index = previous + break + else: + result.append(value) + + if not result and not required: + return await param.get_default(ctx) + return result + + async def _transform_greedy_var_pos(self, ctx: Context[BotT], param: Parameter, converter: Any) -> Any: + view = ctx.view + previous = view.index + try: + ctx.current_argument = argument = view.get_quoted_word() + value = await run_converters(ctx, converter, argument, param) # type: ignore + except (CommandError, ArgumentParsingError): + view.index = previous + raise RuntimeError() from None # break loop + else: + return value + + @property + def clean_params(self) -> Dict[str, Parameter]: + """Dict[:class:`str`, :class:`Parameter`]: + Retrieves the parameter dictionary without the context or self parameters. + + Useful for inspecting signature. + """ + return self.params.copy() + + @property + def cooldown(self) -> Optional[Cooldown]: + """Optional[:class:`~discord.app_commands.Cooldown`]: The cooldown of a command when invoked + or ``None`` if the command doesn't have a registered cooldown. + + .. versionadded:: 2.0 + """ + return self._buckets._cooldown + + @property + def full_parent_name(self) -> str: + """:class:`str`: Retrieves the fully qualified parent command name. + + This the base command name required to execute it. For example, + in ``?one two three`` the parent name would be ``one two``. + """ + entries = [] + command = self + # command.parent is type-hinted as GroupMixin some attributes are resolved via MRO + while command.parent is not None: # type: ignore + command = command.parent # type: ignore + entries.append(command.name) # type: ignore + + return ' '.join(reversed(entries)) + + @property + def parents(self) -> List[Group[Any, ..., Any]]: + """List[:class:`Group`]: Retrieves the parents of this command. + + If the command has no parents then it returns an empty :class:`list`. + + For example in commands ``?a b c test``, the parents are ``[c, b, a]``. + + .. versionadded:: 1.1 + """ + entries = [] + command = self + while command.parent is not None: # type: ignore + command = command.parent # type: ignore + entries.append(command) + + return entries + + @property + def root_parent(self) -> Optional[Group[Any, ..., Any]]: + """Optional[:class:`Group`]: Retrieves the root parent of this command. + + If the command has no parents then it returns ``None``. + + For example in commands ``?a b c test``, the root parent is ``a``. + """ + if not self.parent: + return None + return self.parents[-1] + + @property + def qualified_name(self) -> str: + """:class:`str`: Retrieves the fully qualified command name. + + This is the full parent name with the command name as well. + For example, in ``?one two three`` the qualified name would be + ``one two three``. + """ + + parent = self.full_parent_name + if parent: + return parent + ' ' + self.name + else: + return self.name + + def __str__(self) -> str: + return self.qualified_name + + async def _parse_arguments(self, ctx: Context[BotT]) -> None: + ctx.args = [ctx] if self.cog is None else [self.cog, ctx] + ctx.kwargs = {} + args = ctx.args + kwargs = ctx.kwargs + attachments = _AttachmentIterator(ctx.message.attachments) + + view = ctx.view + iterator = iter(self.params.items()) + + for name, param in iterator: + ctx.current_parameter = param + if param.kind in (param.POSITIONAL_OR_KEYWORD, param.POSITIONAL_ONLY): + transformed = await self.transform(ctx, param, attachments) + args.append(transformed) + elif param.kind == param.KEYWORD_ONLY: + # kwarg only param denotes "consume rest" semantics + if self.rest_is_raw: + ctx.current_argument = argument = view.read_rest() + kwargs[name] = await run_converters(ctx, param.converter, argument, param) + else: + kwargs[name] = await self.transform(ctx, param, attachments) + break + elif param.kind == param.VAR_POSITIONAL: + if view.eof and self.require_var_positional: + raise MissingRequiredArgument(param) + while not view.eof: + try: + transformed = await self.transform(ctx, param, attachments) + args.append(transformed) + except RuntimeError: + break + + if not self.ignore_extra and not view.eof: + raise TooManyArguments('Too many arguments passed to ' + self.qualified_name) + + async def call_before_hooks(self, ctx: Context[BotT], /) -> None: + # now that we're done preparing we can call the pre-command hooks + # first, call the command local hook: + cog = self.cog + if self._before_invoke is not None: + # should be cog if @commands.before_invoke is used + instance = getattr(self._before_invoke, '__self__', cog) + # __self__ only exists for methods, not functions + # however, if @command.before_invoke is used, it will be a function + if instance: + await self._before_invoke(instance, ctx) # type: ignore + else: + await self._before_invoke(ctx) # type: ignore + + # call the cog local hook if applicable: + if cog is not None: + hook = Cog._get_overridden_method(cog.cog_before_invoke) + if hook is not None: + await hook(ctx) + + # call the bot global hook if necessary + hook = ctx.bot._before_invoke + if hook is not None: + await hook(ctx) + + async def call_after_hooks(self, ctx: Context[BotT], /) -> None: + cog = self.cog + if self._after_invoke is not None: + instance = getattr(self._after_invoke, '__self__', cog) + if instance: + await self._after_invoke(instance, ctx) # type: ignore + else: + await self._after_invoke(ctx) # type: ignore + + # call the cog local hook if applicable: + if cog is not None: + hook = Cog._get_overridden_method(cog.cog_after_invoke) + if hook is not None: + await hook(ctx) + + hook = ctx.bot._after_invoke + if hook is not None: + await hook(ctx) + + def _prepare_cooldowns(self, ctx: Context[BotT]) -> None: + if self._buckets.valid: + dt = ctx.message.edited_at or ctx.message.created_at + current = dt.replace(tzinfo=datetime.timezone.utc).timestamp() + bucket = self._buckets.get_bucket(ctx, current) + if bucket is not None: + retry_after = bucket.update_rate_limit(current) + if retry_after: + raise CommandOnCooldown(bucket, retry_after, self._buckets.type) # type: ignore + + async def prepare(self, ctx: Context[BotT], /) -> None: + ctx.command = self + + if not await self.can_run(ctx): + raise CheckFailure(f'The check functions for command {self.qualified_name} failed.') + + if self._max_concurrency is not None: + # For this application, context can be duck-typed as a Message + await self._max_concurrency.acquire(ctx) + + try: + if self.cooldown_after_parsing: + await self._parse_arguments(ctx) + self._prepare_cooldowns(ctx) + else: + self._prepare_cooldowns(ctx) + await self._parse_arguments(ctx) + + await self.call_before_hooks(ctx) + except: + if self._max_concurrency is not None: + await self._max_concurrency.release(ctx) + raise + + def is_on_cooldown(self, ctx: Context[BotT], /) -> bool: + """Checks whether the command is currently on cooldown. + + .. versionchanged:: 2.0 + + ``ctx`` parameter is now positional-only. + + Parameters + ----------- + ctx: :class:`.Context` + The invocation context to use when checking the commands cooldown status. + + Returns + -------- + :class:`bool` + A boolean indicating if the command is on cooldown. + """ + if not self._buckets.valid: + return False + + bucket = self._buckets.get_bucket(ctx) + if bucket is None: + return False + dt = ctx.message.edited_at or ctx.message.created_at + current = dt.replace(tzinfo=datetime.timezone.utc).timestamp() + return bucket.get_tokens(current) == 0 + + def reset_cooldown(self, ctx: Context[BotT], /) -> None: + """Resets the cooldown on this command. + + .. versionchanged:: 2.0 + + ``ctx`` parameter is now positional-only. + + Parameters + ----------- + ctx: :class:`.Context` + The invocation context to reset the cooldown under. + """ + if self._buckets.valid: + bucket = self._buckets.get_bucket(ctx) + if bucket is not None: + bucket.reset() + + def get_cooldown_retry_after(self, ctx: Context[BotT], /) -> float: + """Retrieves the amount of seconds before this command can be tried again. + + .. versionadded:: 1.4 + + .. versionchanged:: 2.0 + + ``ctx`` parameter is now positional-only. + + Parameters + ----------- + ctx: :class:`.Context` + The invocation context to retrieve the cooldown from. + + Returns + -------- + :class:`float` + The amount of time left on this command's cooldown in seconds. + If this is ``0.0`` then the command isn't on cooldown. + """ + if self._buckets.valid: + bucket = self._buckets.get_bucket(ctx) + if bucket is None: + return 0.0 + dt = ctx.message.edited_at or ctx.message.created_at + current = dt.replace(tzinfo=datetime.timezone.utc).timestamp() + return bucket.get_retry_after(current) + + return 0.0 + + async def invoke(self, ctx: Context[BotT], /) -> None: + await self.prepare(ctx) + + # terminate the invoked_subcommand chain. + # since we're in a regular command (and not a group) then + # the invoked subcommand is None. + ctx.invoked_subcommand = None + ctx.subcommand_passed = None + injected = hooked_wrapped_callback(self, ctx, self.callback) # type: ignore + await injected(*ctx.args, **ctx.kwargs) # type: ignore + + async def reinvoke(self, ctx: Context[BotT], /, *, call_hooks: bool = False) -> None: + ctx.command = self + await self._parse_arguments(ctx) + + if call_hooks: + await self.call_before_hooks(ctx) + + ctx.invoked_subcommand = None + try: + await self.callback(*ctx.args, **ctx.kwargs) # type: ignore + except: + ctx.command_failed = True + raise + finally: + if call_hooks: + await self.call_after_hooks(ctx) + + def error(self, coro: Error[CogT, ContextT], /) -> Error[CogT, ContextT]: + """A decorator that registers a coroutine as a local error handler. + + A local error handler is an :func:`.on_command_error` event limited to + a single command. However, the :func:`.on_command_error` is still + invoked afterwards as the catch-all. + + .. versionchanged:: 2.0 + + ``coro`` parameter is now positional-only. + + Parameters + ----------- + coro: :ref:`coroutine ` + The coroutine to register as the local error handler. + + Raises + ------- + TypeError + The coroutine passed is not actually a coroutine. + """ + + if not asyncio.iscoroutinefunction(coro): + raise TypeError('The error handler must be a coroutine.') + + self.on_error: Error[CogT, Any] = coro + return coro + + def has_error_handler(self) -> bool: + """:class:`bool`: Checks whether the command has an error handler registered. + + .. versionadded:: 1.7 + """ + return hasattr(self, 'on_error') + + def before_invoke(self, coro: Hook[CogT, ContextT], /) -> Hook[CogT, ContextT]: + """A decorator that registers a coroutine as a pre-invoke hook. + + A pre-invoke hook is called directly before the command is + called. This makes it a useful function to set up database + connections or any type of set up required. + + This pre-invoke hook takes a sole parameter, a :class:`.Context`. + + See :meth:`.Bot.before_invoke` for more info. + + .. versionchanged:: 2.0 + + ``coro`` parameter is now positional-only. + + Parameters + ----------- + coro: :ref:`coroutine ` + The coroutine to register as the pre-invoke hook. + + Raises + ------- + TypeError + The coroutine passed is not actually a coroutine. + """ + if not asyncio.iscoroutinefunction(coro): + raise TypeError('The pre-invoke hook must be a coroutine.') + + self._before_invoke = coro + return coro + + def after_invoke(self, coro: Hook[CogT, ContextT], /) -> Hook[CogT, ContextT]: + """A decorator that registers a coroutine as a post-invoke hook. + + A post-invoke hook is called directly after the command is + called. This makes it a useful function to clean-up database + connections or any type of clean up required. + + This post-invoke hook takes a sole parameter, a :class:`.Context`. + + See :meth:`.Bot.after_invoke` for more info. + + .. versionchanged:: 2.0 + + ``coro`` parameter is now positional-only. + + Parameters + ----------- + coro: :ref:`coroutine ` + The coroutine to register as the post-invoke hook. + + Raises + ------- + TypeError + The coroutine passed is not actually a coroutine. + """ + if not asyncio.iscoroutinefunction(coro): + raise TypeError('The post-invoke hook must be a coroutine.') + + self._after_invoke = coro + return coro + + @property + def cog_name(self) -> Optional[str]: + """Optional[:class:`str`]: The name of the cog this command belongs to, if any.""" + return type(self.cog).__cog_name__ if self.cog is not None else None + + @property + def short_doc(self) -> str: + """:class:`str`: Gets the "short" documentation of a command. + + By default, this is the :attr:`.brief` attribute. + If that lookup leads to an empty string then the first line of the + :attr:`.help` attribute is used instead. + """ + if self.brief is not None: + return self.brief + if self.help is not None: + return self.help.split('\n', 1)[0] + return '' + + def _is_typing_optional(self, annotation: Union[T, Optional[T]]) -> bool: + return getattr(annotation, '__origin__', None) is Union and type(None) in annotation.__args__ # type: ignore + + @property + def signature(self) -> str: + """:class:`str`: Returns a POSIX-like signature useful for help command output.""" + if self.usage is not None: + return self.usage + + params = self.clean_params + if not params: + return '' + + result = [] + for param in params.values(): + name = param.displayed_name or param.name + + greedy = isinstance(param.converter, Greedy) + optional = False # postpone evaluation of if it's an optional argument + + annotation: Any = param.converter.converter if greedy else param.converter + origin = getattr(annotation, '__origin__', None) + if not greedy and origin is Union: + none_cls = type(None) + union_args = annotation.__args__ + optional = union_args[-1] is none_cls + if len(union_args) == 2 and optional: + annotation = union_args[0] + origin = getattr(annotation, '__origin__', None) + + if annotation is discord.Attachment: + # For discord.Attachment we need to signal to the user that it's an attachment + # It's not exactly pretty but it's enough to differentiate + if optional: + result.append(f'[{name} (upload a file)]') + elif greedy: + result.append(f'[{name} (upload files)]...') + else: + result.append(f'<{name} (upload a file)>') + continue + + # for typing.Literal[...], typing.Optional[typing.Literal[...]], and Greedy[typing.Literal[...]], the + # parameter signature is a literal list of it's values + if origin is Literal: + name = '|'.join(f'"{v}"' if isinstance(v, str) else str(v) for v in annotation.__args__) + if not param.required: + # We don't want None or '' to trigger the [name=value] case and instead it should + # do [name] since [name=None] or [name=] are not exactly useful for the user. + if param.displayed_default: + result.append( + f'[{name}={param.displayed_default}]' if not greedy else f'[{name}={param.displayed_default}]...' + ) + continue + else: + result.append(f'[{name}]') + + elif param.kind == param.VAR_POSITIONAL: + if self.require_var_positional: + result.append(f'<{name}...>') + else: + result.append(f'[{name}...]') + elif greedy: + result.append(f'[{name}]...') + elif optional: + result.append(f'[{name}]') + else: + result.append(f'<{name}>') + + return ' '.join(result) + + async def can_run(self, ctx: Context[BotT], /) -> bool: + """|coro| + + Checks if the command can be executed by checking all the predicates + inside the :attr:`~Command.checks` attribute. This also checks whether the + command is disabled. + + .. versionchanged:: 1.3 + Checks whether the command is disabled or not + + .. versionchanged:: 2.0 + + ``ctx`` parameter is now positional-only. + + Parameters + ----------- + ctx: :class:`.Context` + The ctx of the command currently being invoked. + + Raises + ------- + :class:`CommandError` + Any command error that was raised during a check call will be propagated + by this function. + + Returns + -------- + :class:`bool` + A boolean indicating if the command can be invoked. + """ + + if not self.enabled: + raise DisabledCommand(f'{self.name} command is disabled') + + original = ctx.command + ctx.command = self + + try: + if not await ctx.bot.can_run(ctx): + raise CheckFailure(f'The global check functions for command {self.qualified_name} failed.') + + cog = self.cog + if cog is not None: + local_check = Cog._get_overridden_method(cog.cog_check) + if local_check is not None: + ret = await discord.utils.maybe_coroutine(local_check, ctx) + if not ret: + return False + + predicates = self.checks + if not predicates: + # since we have no checks, then we just return True. + return True + + return await discord.utils.async_all(predicate(ctx) for predicate in predicates) # type: ignore + finally: + ctx.command = original + + +class GroupMixin(Generic[CogT]): + """A mixin that implements common functionality for classes that behave + similar to :class:`.Group` and are allowed to register commands. + + Attributes + ----------- + all_commands: :class:`dict` + A mapping of command name to :class:`.Command` + objects. + case_insensitive: :class:`bool` + Whether the commands should be case insensitive. Defaults to ``False``. + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + case_insensitive = kwargs.get('case_insensitive', False) + self.all_commands: Dict[str, Command[CogT, ..., Any]] = _CaseInsensitiveDict() if case_insensitive else {} + self.case_insensitive: bool = case_insensitive + super().__init__(*args, **kwargs) + + @property + def commands(self) -> Set[Command[CogT, ..., Any]]: + """Set[:class:`.Command`]: A unique set of commands without aliases that are registered.""" + return set(self.all_commands.values()) + + def recursively_remove_all_commands(self) -> None: + for command in self.all_commands.copy().values(): + if isinstance(command, GroupMixin): + command.recursively_remove_all_commands() + self.remove_command(command.name) + + def add_command(self, command: Command[CogT, ..., Any], /) -> None: + """Adds a :class:`.Command` into the internal list of commands. + + This is usually not called, instead the :meth:`~.GroupMixin.command` or + :meth:`~.GroupMixin.group` shortcut decorators are used instead. + + .. versionchanged:: 1.4 + Raise :exc:`.CommandRegistrationError` instead of generic :exc:`.ClientException` + + .. versionchanged:: 2.0 + + ``command`` parameter is now positional-only. + + Parameters + ----------- + command: :class:`Command` + The command to add. + + Raises + ------- + CommandRegistrationError + If the command or its alias is already registered by different command. + TypeError + If the command passed is not a subclass of :class:`.Command`. + """ + + if not isinstance(command, Command): + raise TypeError('The command passed must be a subclass of Command') + + if isinstance(self, Command): + command.parent = self + + if command.name in self.all_commands: + raise CommandRegistrationError(command.name) + + self.all_commands[command.name] = command + for alias in command.aliases: + if alias in self.all_commands: + self.remove_command(command.name) + raise CommandRegistrationError(alias, alias_conflict=True) + self.all_commands[alias] = command + + def remove_command(self, name: str, /) -> Optional[Command[CogT, ..., Any]]: + """Remove a :class:`.Command` from the internal list + of commands. + + This could also be used as a way to remove aliases. + + .. versionchanged:: 2.0 + + ``name`` parameter is now positional-only. + + Parameters + ----------- + name: :class:`str` + The name of the command to remove. + + Returns + -------- + Optional[:class:`.Command`] + The command that was removed. If the name is not valid then + ``None`` is returned instead. + """ + command = self.all_commands.pop(name, None) + + # does not exist + if command is None: + return None + + if name in command.aliases: + # we're removing an alias so we don't want to remove the rest + return command + + # we're not removing the alias so let's delete the rest of them. + for alias in command.aliases: + cmd = self.all_commands.pop(alias, None) + # in the case of a CommandRegistrationError, an alias might conflict + # with an already existing command. If this is the case, we want to + # make sure the pre-existing command is not removed. + if cmd is not None and cmd != command: + self.all_commands[alias] = cmd + return command + + def walk_commands(self) -> Generator[Command[CogT, ..., Any], None, None]: + """An iterator that recursively walks through all commands and subcommands. + + .. versionchanged:: 1.4 + Duplicates due to aliases are no longer returned + + Yields + ------ + Union[:class:`.Command`, :class:`.Group`] + A command or group from the internal list of commands. + """ + for command in self.commands: + yield command + if isinstance(command, GroupMixin): + yield from command.walk_commands() + + def get_command(self, name: str, /) -> Optional[Command[CogT, ..., Any]]: + """Get a :class:`.Command` from the internal list + of commands. + + This could also be used as a way to get aliases. + + The name could be fully qualified (e.g. ``'foo bar'``) will get + the subcommand ``bar`` of the group command ``foo``. If a + subcommand is not found then ``None`` is returned just as usual. + + .. versionchanged:: 2.0 + + ``name`` parameter is now positional-only. + + Parameters + ----------- + name: :class:`str` + The name of the command to get. + + Returns + -------- + Optional[:class:`Command`] + The command that was requested. If not found, returns ``None``. + """ + + # fast path, no space in name. + if ' ' not in name: + return self.all_commands.get(name) + + names = name.split() + if not names: + return None + obj = self.all_commands.get(names[0]) + if not isinstance(obj, GroupMixin): + return obj + + for name in names[1:]: + try: + obj = obj.all_commands[name] # type: ignore + except (AttributeError, KeyError): + return None + + return obj + + @overload + def command( + self: GroupMixin[CogT], + name: str = ..., + *args: Any, + **kwargs: Any, + ) -> Callable[ + [ + Union[ + Callable[Concatenate[CogT, ContextT, P], Coro[T]], + Callable[Concatenate[ContextT, P], Coro[T]], + ] + ], + Command[CogT, P, T], + ]: + ... + + @overload + def command( + self: GroupMixin[CogT], + name: str = ..., + cls: Type[CommandT] = ..., # type: ignore # previous overload handles case where cls is not set + *args: Any, + **kwargs: Any, + ) -> Callable[ + [ + Union[ + Callable[Concatenate[CogT, ContextT, P], Coro[T]], + Callable[Concatenate[ContextT, P], Coro[T]], + ] + ], + CommandT, + ]: + ... + + def command( + self, + name: str = MISSING, + cls: Type[Command[Any, ..., Any]] = MISSING, + *args: Any, + **kwargs: Any, + ) -> Any: + """A shortcut decorator that invokes :func:`~discord.ext.commands.command` and adds it to + the internal command list via :meth:`~.GroupMixin.add_command`. + + Returns + -------- + Callable[..., :class:`Command`] + A decorator that converts the provided method into a Command, adds it to the bot, then returns it. + """ + + def decorator(func): + + kwargs.setdefault('parent', self) + result = command(name=name, cls=cls, *args, **kwargs)(func) + self.add_command(result) + return result + + return decorator + + @overload + def group( + self: GroupMixin[CogT], + name: str = ..., + *args: Any, + **kwargs: Any, + ) -> Callable[ + [ + Union[ + Callable[Concatenate[CogT, ContextT, P], Coro[T]], + Callable[Concatenate[ContextT, P], Coro[T]], + ] + ], + Group[CogT, P, T], + ]: + ... + + @overload + def group( + self: GroupMixin[CogT], + name: str = ..., + cls: Type[GroupT] = ..., # type: ignore # previous overload handles case where cls is not set + *args: Any, + **kwargs: Any, + ) -> Callable[ + [ + Union[ + Callable[Concatenate[CogT, ContextT, P], Coro[T]], + Callable[Concatenate[ContextT, P], Coro[T]], + ] + ], + GroupT, + ]: + ... + + def group( + self, + name: str = MISSING, + cls: Type[Group[Any, ..., Any]] = MISSING, + *args: Any, + **kwargs: Any, + ) -> Any: + """A shortcut decorator that invokes :func:`.group` and adds it to + the internal command list via :meth:`~.GroupMixin.add_command`. + + Returns + -------- + Callable[..., :class:`Group`] + A decorator that converts the provided method into a Group, adds it to the bot, then returns it. + """ + + def decorator(func): + kwargs.setdefault('parent', self) + result = group(name=name, cls=cls, *args, **kwargs)(func) + self.add_command(result) + return result + + return decorator + + +class Group(GroupMixin[CogT], Command[CogT, P, T]): + """A class that implements a grouping protocol for commands to be + executed as subcommands. + + This class is a subclass of :class:`.Command` and thus all options + valid in :class:`.Command` are valid in here as well. + + Attributes + ----------- + invoke_without_command: :class:`bool` + Indicates if the group callback should begin parsing and + invocation only if no subcommand was found. Useful for + making it an error handling function to tell the user that + no subcommand was found or to have different functionality + in case no subcommand was found. If this is ``False``, then + the group callback will always be invoked first. This means + that the checks and the parsing dictated by its parameters + will be executed. Defaults to ``False``. + case_insensitive: :class:`bool` + Indicates if the group's commands should be case insensitive. + Defaults to ``False``. + """ + + def __init__(self, *args: Any, **attrs: Any) -> None: + self.invoke_without_command: bool = attrs.pop('invoke_without_command', False) + super().__init__(*args, **attrs) + + def copy(self) -> Self: + """Creates a copy of this :class:`Group`. + + Returns + -------- + :class:`Group` + A new instance of this group. + """ + ret = super().copy() + for cmd in self.commands: + ret.add_command(cmd.copy()) + return ret + + async def invoke(self, ctx: Context[BotT], /) -> None: + ctx.invoked_subcommand = None + ctx.subcommand_passed = None + early_invoke = not self.invoke_without_command + if early_invoke: + await self.prepare(ctx) + + view = ctx.view + previous = view.index + view.skip_ws() + trigger = view.get_word() + + if trigger: + ctx.subcommand_passed = trigger + ctx.invoked_subcommand = self.all_commands.get(trigger, None) + + if early_invoke: + injected = hooked_wrapped_callback(self, ctx, self.callback) # type: ignore + await injected(*ctx.args, **ctx.kwargs) # type: ignore + + ctx.invoked_parents.append(ctx.invoked_with) # type: ignore + + if trigger and ctx.invoked_subcommand: + ctx.invoked_with = trigger + await ctx.invoked_subcommand.invoke(ctx) + elif not early_invoke: + # undo the trigger parsing + view.index = previous + view.previous = previous + await super().invoke(ctx) + + async def reinvoke(self, ctx: Context[BotT], /, *, call_hooks: bool = False) -> None: + ctx.invoked_subcommand = None + early_invoke = not self.invoke_without_command + if early_invoke: + ctx.command = self + await self._parse_arguments(ctx) + + if call_hooks: + await self.call_before_hooks(ctx) + + view = ctx.view + previous = view.index + view.skip_ws() + trigger = view.get_word() + + if trigger: + ctx.subcommand_passed = trigger + ctx.invoked_subcommand = self.all_commands.get(trigger, None) + + if early_invoke: + try: + await self.callback(*ctx.args, **ctx.kwargs) # type: ignore + except: + ctx.command_failed = True + raise + finally: + if call_hooks: + await self.call_after_hooks(ctx) + + ctx.invoked_parents.append(ctx.invoked_with) # type: ignore + + if trigger and ctx.invoked_subcommand: + ctx.invoked_with = trigger + await ctx.invoked_subcommand.reinvoke(ctx, call_hooks=call_hooks) + elif not early_invoke: + # undo the trigger parsing + view.index = previous + view.previous = previous + await super().reinvoke(ctx, call_hooks=call_hooks) + + +# Decorators + +if TYPE_CHECKING: + # Using a class to emulate a function allows for overloading the inner function in the decorator. + + class _CommandDecorator: + @overload + def __call__(self, func: Callable[Concatenate[CogT, ContextT, P], Coro[T]], /) -> Command[CogT, P, T]: + ... + + @overload + def __call__(self, func: Callable[Concatenate[ContextT, P], Coro[T]], /) -> Command[None, P, T]: + ... + + def __call__(self, func: Callable[..., Coro[T]], /) -> Any: + ... + + class _GroupDecorator: + @overload + def __call__(self, func: Callable[Concatenate[CogT, ContextT, P], Coro[T]], /) -> Group[CogT, P, T]: + ... + + @overload + def __call__(self, func: Callable[Concatenate[ContextT, P], Coro[T]], /) -> Group[None, P, T]: + ... + + def __call__(self, func: Callable[..., Coro[T]], /) -> Any: + ... + + +@overload +def command( + name: str = ..., + **attrs: Any, +) -> _CommandDecorator: + ... + + +@overload +def command( + name: str = ..., + cls: Type[CommandT] = ..., # type: ignore # previous overload handles case where cls is not set + **attrs: Any, +) -> Callable[ + [ + Union[ + Callable[Concatenate[ContextT, P], Coro[Any]], + Callable[Concatenate[CogT, ContextT, P], Coro[Any]], # type: ignore # CogT is used here to allow covariance + ] + ], + CommandT, +]: + ... + + +def command( + name: str = MISSING, + cls: Type[Command[Any, ..., Any]] = MISSING, + **attrs: Any, +) -> Any: + """A decorator that transforms a function into a :class:`.Command` + or if called with :func:`.group`, :class:`.Group`. + + By default the ``help`` attribute is received automatically from the + docstring of the function and is cleaned up with the use of + ``inspect.cleandoc``. If the docstring is ``bytes``, then it is decoded + into :class:`str` using utf-8 encoding. + + All checks added using the :func:`.check` & co. decorators are added into + the function. There is no way to supply your own checks through this + decorator. + + Parameters + ----------- + name: :class:`str` + The name to create the command with. By default this uses the + function name unchanged. + cls + The class to construct with. By default this is :class:`.Command`. + You usually do not change this. + attrs + Keyword arguments to pass into the construction of the class denoted + by ``cls``. + + Raises + ------- + TypeError + If the function is not a coroutine or is already a command. + """ + if cls is MISSING: + cls = Command + + def decorator(func): + if isinstance(func, Command): + raise TypeError('Callback is already a command.') + return cls(func, name=name, **attrs) + + return decorator + + +@overload +def group( + name: str = ..., + **attrs: Any, +) -> _GroupDecorator: + ... + + +@overload +def group( + name: str = ..., + cls: Type[GroupT] = ..., # type: ignore # previous overload handles case where cls is not set + **attrs: Any, +) -> Callable[ + [ + Union[ + Callable[Concatenate[CogT, ContextT, P], Coro[Any]], # type: ignore # CogT is used here to allow covariance + Callable[Concatenate[ContextT, P], Coro[Any]], + ] + ], + GroupT, +]: + ... + + +def group( + name: str = MISSING, + cls: Type[Group[Any, ..., Any]] = MISSING, + **attrs: Any, +) -> Any: + """A decorator that transforms a function into a :class:`.Group`. + + This is similar to the :func:`~discord.ext.commands.command` decorator but the ``cls`` + parameter is set to :class:`Group` by default. + + .. versionchanged:: 1.1 + The ``cls`` parameter can now be passed. + """ + if cls is MISSING: + cls = Group + + return command(name=name, cls=cls, **attrs) + + +def check(predicate: UserCheck[ContextT], /) -> Check[ContextT]: + r"""A decorator that adds a check to the :class:`.Command` or its + subclasses. These checks could be accessed via :attr:`.Command.checks`. + + These checks should be predicates that take in a single parameter taking + a :class:`.Context`. If the check returns a ``False``\-like value then + during invocation a :exc:`.CheckFailure` exception is raised and sent to + the :func:`.on_command_error` event. + + If an exception should be thrown in the predicate then it should be a + subclass of :exc:`.CommandError`. Any exception not subclassed from it + will be propagated while those subclassed will be sent to + :func:`.on_command_error`. + + A special attribute named ``predicate`` is bound to the value + returned by this decorator to retrieve the predicate passed to the + decorator. This allows the following introspection and chaining to be done: + + .. code-block:: python3 + + def owner_or_permissions(**perms): + original = commands.has_permissions(**perms).predicate + async def extended_check(ctx): + if ctx.guild is None: + return False + return ctx.guild.owner_id == ctx.author.id or await original(ctx) + return commands.check(extended_check) + + .. note:: + + The function returned by ``predicate`` is **always** a coroutine, + even if the original function was not a coroutine. + + .. versionchanged:: 1.3 + The ``predicate`` attribute was added. + + Examples + --------- + + Creating a basic check to see if the command invoker is you. + + .. code-block:: python3 + + def check_if_it_is_me(ctx): + return ctx.message.author.id == 85309593344815104 + + @bot.command() + @commands.check(check_if_it_is_me) + async def only_for_me(ctx): + await ctx.send('I know you!') + + Transforming common checks into its own decorator: + + .. code-block:: python3 + + def is_me(): + def predicate(ctx): + return ctx.message.author.id == 85309593344815104 + return commands.check(predicate) + + @bot.command() + @is_me() + async def only_me(ctx): + await ctx.send('Only you!') + + .. versionchanged:: 2.0 + + ``predicate`` parameter is now positional-only. + + Parameters + ----------- + predicate: Callable[[:class:`Context`], :class:`bool`] + The predicate to check if the command should be invoked. + """ + + def decorator(func: Union[Command[Any, ..., Any], CoroFunc]) -> Union[Command[Any, ..., Any], CoroFunc]: + if isinstance(func, Command): + func.checks.append(predicate) # type: ignore + else: + if not hasattr(func, '__commands_checks__'): + func.__commands_checks__ = [] + + func.__commands_checks__.append(predicate) + + return func + + if inspect.iscoroutinefunction(predicate): + decorator.predicate = predicate + else: + + @functools.wraps(predicate) + async def wrapper(ctx: ContextT): + return predicate(ctx) + + decorator.predicate = wrapper + + return decorator # type: ignore + + +def check_any(*checks: Check[ContextT]) -> Check[ContextT]: + r"""A :func:`check` that is added that checks if any of the checks passed + will pass, i.e. using logical OR. + + If all checks fail then :exc:`.CheckAnyFailure` is raised to signal the failure. + It inherits from :exc:`.CheckFailure`. + + .. note:: + + The ``predicate`` attribute for this function **is** a coroutine. + + .. versionadded:: 1.3 + + Parameters + ------------ + \*checks: Callable[[:class:`Context`], :class:`bool`] + An argument list of checks that have been decorated with + the :func:`check` decorator. + + Raises + ------- + TypeError + A check passed has not been decorated with the :func:`check` + decorator. + + Examples + --------- + + Creating a basic check to see if it's the bot owner or + the server owner: + + .. code-block:: python3 + + def is_guild_owner(): + def predicate(ctx): + return ctx.guild is not None and ctx.guild.owner_id == ctx.author.id + return commands.check(predicate) + + @bot.command() + @commands.check_any(commands.is_owner(), is_guild_owner()) + async def only_for_owners(ctx): + await ctx.send('Hello mister owner!') + """ + + unwrapped = [] + for wrapped in checks: + try: + pred = wrapped.predicate + except AttributeError: + raise TypeError(f'{wrapped!r} must be wrapped by commands.check decorator') from None + else: + unwrapped.append(pred) + + async def predicate(ctx: Context[BotT]) -> bool: + errors = [] + for func in unwrapped: + try: + value = await func(ctx) + except CheckFailure as e: + errors.append(e) + else: + if value: + return True + # if we're here, all checks failed + raise CheckAnyFailure(unwrapped, errors) + + return check(predicate) + + +def has_role(item: Union[int, str], /) -> Check[Any]: + """A :func:`.check` that is added that checks if the member invoking the + command has the role specified via the name or ID specified. + + If a string is specified, you must give the exact name of the role, including + caps and spelling. + + If an integer is specified, you must give the exact snowflake ID of the role. + + If the message is invoked in a private message context then the check will + return ``False``. + + This check raises one of two special exceptions, :exc:`.MissingRole` if the user + is missing a role, or :exc:`.NoPrivateMessage` if it is used in a private message. + Both inherit from :exc:`.CheckFailure`. + + .. versionchanged:: 1.1 + + Raise :exc:`.MissingRole` or :exc:`.NoPrivateMessage` + instead of generic :exc:`.CheckFailure` + + .. versionchanged:: 2.0 + + ``item`` parameter is now positional-only. + + Parameters + ----------- + item: Union[:class:`int`, :class:`str`] + The name or ID of the role to check. + """ + + def predicate(ctx: Context[BotT]) -> bool: + if ctx.guild is None: + raise NoPrivateMessage() + + # ctx.guild is None doesn't narrow ctx.author to Member + if isinstance(item, int): + role = ctx.author.get_role(item) # type: ignore + else: + role = discord.utils.get(ctx.author.roles, name=item) # type: ignore + if role is None: + raise MissingRole(item) + return True + + return check(predicate) + + +def has_any_role(*items: Union[int, str]) -> Callable[[T], T]: + r"""A :func:`.check` that is added that checks if the member invoking the + command has **any** of the roles specified. This means that if they have + one out of the three roles specified, then this check will return ``True``. + + Similar to :func:`.has_role`\, the names or IDs passed in must be exact. + + This check raises one of two special exceptions, :exc:`.MissingAnyRole` if the user + is missing all roles, or :exc:`.NoPrivateMessage` if it is used in a private message. + Both inherit from :exc:`.CheckFailure`. + + .. versionchanged:: 1.1 + + Raise :exc:`.MissingAnyRole` or :exc:`.NoPrivateMessage` + instead of generic :exc:`.CheckFailure` + + Parameters + ----------- + items: List[Union[:class:`str`, :class:`int`]] + An argument list of names or IDs to check that the member has roles wise. + + Example + -------- + + .. code-block:: python3 + + @bot.command() + @commands.has_any_role('Library Devs', 'Moderators', 492212595072434186) + async def cool(ctx): + await ctx.send('You are cool indeed') + """ + + def predicate(ctx): + if ctx.guild is None: + raise NoPrivateMessage() + + # ctx.guild is None doesn't narrow ctx.author to Member + if any( + ctx.author.get_role(item) is not None + if isinstance(item, int) + else discord.utils.get(ctx.author.roles, name=item) is not None + for item in items + ): + return True + raise MissingAnyRole(list(items)) + + return check(predicate) + + +def bot_has_role(item: int, /) -> Callable[[T], T]: + """Similar to :func:`.has_role` except checks if the bot itself has the + role. + + This check raises one of two special exceptions, :exc:`.BotMissingRole` if the bot + is missing the role, or :exc:`.NoPrivateMessage` if it is used in a private message. + Both inherit from :exc:`.CheckFailure`. + + .. versionchanged:: 1.1 + + Raise :exc:`.BotMissingRole` or :exc:`.NoPrivateMessage` + instead of generic :exc:`.CheckFailure` + + .. versionchanged:: 2.0 + + ``item`` parameter is now positional-only. + """ + + def predicate(ctx): + if ctx.guild is None: + raise NoPrivateMessage() + + if isinstance(item, int): + role = ctx.me.get_role(item) + else: + role = discord.utils.get(ctx.me.roles, name=item) + if role is None: + raise BotMissingRole(item) + return True + + return check(predicate) + + +def bot_has_any_role(*items: int) -> Callable[[T], T]: + """Similar to :func:`.has_any_role` except checks if the bot itself has + any of the roles listed. + + This check raises one of two special exceptions, :exc:`.BotMissingAnyRole` if the bot + is missing all roles, or :exc:`.NoPrivateMessage` if it is used in a private message. + Both inherit from :exc:`.CheckFailure`. + + .. versionchanged:: 1.1 + + Raise :exc:`.BotMissingAnyRole` or :exc:`.NoPrivateMessage` + instead of generic checkfailure + """ + + def predicate(ctx): + if ctx.guild is None: + raise NoPrivateMessage() + + me = ctx.me + if any( + me.get_role(item) is not None if isinstance(item, int) else discord.utils.get(me.roles, name=item) is not None + for item in items + ): + return True + raise BotMissingAnyRole(list(items)) + + return check(predicate) + + +def has_permissions(**perms: bool) -> Check[Any]: + """A :func:`.check` that is added that checks if the member has all of + the permissions necessary. + + Note that this check operates on the current channel permissions, not the + guild wide permissions. + + The permissions passed in must be exactly like the properties shown under + :class:`.discord.Permissions`. + + This check raises a special exception, :exc:`.MissingPermissions` + that is inherited from :exc:`.CheckFailure`. + + Parameters + ------------ + perms + An argument list of permissions to check for. + + Example + --------- + + .. code-block:: python3 + + @bot.command() + @commands.has_permissions(manage_messages=True) + async def test(ctx): + await ctx.send('You can manage messages.') + + """ + + invalid = set(perms) - set(discord.Permissions.VALID_FLAGS) + if invalid: + raise TypeError(f"Invalid permission(s): {', '.join(invalid)}") + + def predicate(ctx: Context[BotT]) -> bool: + permissions = ctx.permissions + + missing = [perm for perm, value in perms.items() if getattr(permissions, perm) != value] + + if not missing: + return True + + raise MissingPermissions(missing) + + return check(predicate) + + +def bot_has_permissions(**perms: bool) -> Check[Any]: + """Similar to :func:`.has_permissions` except checks if the bot itself has + the permissions listed. + + This check raises a special exception, :exc:`.BotMissingPermissions` + that is inherited from :exc:`.CheckFailure`. + """ + + invalid = set(perms) - set(discord.Permissions.VALID_FLAGS) + if invalid: + raise TypeError(f"Invalid permission(s): {', '.join(invalid)}") + + def predicate(ctx: Context[BotT]) -> bool: + permissions = ctx.bot_permissions + + missing = [perm for perm, value in perms.items() if getattr(permissions, perm) != value] + + if not missing: + return True + + raise BotMissingPermissions(missing) + + return check(predicate) + + +def has_guild_permissions(**perms: bool) -> Check[Any]: + """Similar to :func:`.has_permissions`, but operates on guild wide + permissions instead of the current channel permissions. + + If this check is called in a DM context, it will raise an + exception, :exc:`.NoPrivateMessage`. + + .. versionadded:: 1.3 + """ + + invalid = set(perms) - set(discord.Permissions.VALID_FLAGS) + if invalid: + raise TypeError(f"Invalid permission(s): {', '.join(invalid)}") + + def predicate(ctx: Context[BotT]) -> bool: + if not ctx.guild: + raise NoPrivateMessage + + permissions = ctx.author.guild_permissions # type: ignore + missing = [perm for perm, value in perms.items() if getattr(permissions, perm) != value] + + if not missing: + return True + + raise MissingPermissions(missing) + + return check(predicate) + + +def bot_has_guild_permissions(**perms: bool) -> Check[Any]: + """Similar to :func:`.has_guild_permissions`, but checks the bot + members guild permissions. + + .. versionadded:: 1.3 + """ + + invalid = set(perms) - set(discord.Permissions.VALID_FLAGS) + if invalid: + raise TypeError(f"Invalid permission(s): {', '.join(invalid)}") + + def predicate(ctx: Context[BotT]) -> bool: + if not ctx.guild: + raise NoPrivateMessage + + permissions = ctx.me.guild_permissions # type: ignore + missing = [perm for perm, value in perms.items() if getattr(permissions, perm) != value] + + if not missing: + return True + + raise BotMissingPermissions(missing) + + return check(predicate) + + +def dm_only() -> Check[Any]: + """A :func:`.check` that indicates this command must only be used in a + DM context. Only private messages are allowed when + using the command. + + This check raises a special exception, :exc:`.PrivateMessageOnly` + that is inherited from :exc:`.CheckFailure`. + + .. versionadded:: 1.1 + """ + + def predicate(ctx: Context[BotT]) -> bool: + if ctx.guild is not None: + raise PrivateMessageOnly() + return True + + return check(predicate) + + +def guild_only() -> Check[Any]: + """A :func:`.check` that indicates this command must only be used in a + guild context only. Basically, no private messages are allowed when + using the command. + + This check raises a special exception, :exc:`.NoPrivateMessage` + that is inherited from :exc:`.CheckFailure`. + + If used on hybrid commands, this will be equivalent to the + :func:`discord.app_commands.guild_only` decorator. In an unsupported + context, such as a subcommand, this will still fallback to applying the + check. + """ + + # Due to implementation quirks, this check has to be re-implemented completely + # to work with both app_commands and the command framework. + + def predicate(ctx: Context[BotT]) -> bool: + if ctx.guild is None: + raise NoPrivateMessage() + return True + + def decorator(func: Union[Command, CoroFunc]) -> Union[Command, CoroFunc]: + if isinstance(func, Command): + func.checks.append(predicate) + if hasattr(func, '__commands_is_hybrid__'): + app_command = getattr(func, 'app_command', None) + if app_command: + app_command.guild_only = True + else: + if not hasattr(func, '__commands_checks__'): + func.__commands_checks__ = [] + + func.__commands_checks__.append(predicate) + func.__discord_app_commands_guild_only__ = True + + return func + + if inspect.iscoroutinefunction(predicate): + decorator.predicate = predicate + else: + + @functools.wraps(predicate) + async def wrapper(ctx: Context[BotT]): + return predicate(ctx) + + decorator.predicate = wrapper + + return decorator # type: ignore + + +def is_owner() -> Check[Any]: + """A :func:`.check` that checks if the person invoking this command is the + owner of the bot. + + This is powered by :meth:`.Bot.is_owner`. + + This check raises a special exception, :exc:`.NotOwner` that is derived + from :exc:`.CheckFailure`. + """ + + async def predicate(ctx: Context[BotT]) -> bool: + if not await ctx.bot.is_owner(ctx.author): + raise NotOwner('You do not own this bot.') + return True + + return check(predicate) + + +def is_nsfw() -> Check[Any]: + """A :func:`.check` that checks if the channel is a NSFW channel. + + This check raises a special exception, :exc:`.NSFWChannelRequired` + that is derived from :exc:`.CheckFailure`. + + If used on hybrid commands, this will be equivalent to setting the + application command's ``nsfw`` attribute to ``True``. In an unsupported + context, such as a subcommand, this will still fallback to applying the + check. + + .. versionchanged:: 1.1 + + Raise :exc:`.NSFWChannelRequired` instead of generic :exc:`.CheckFailure`. + DM channels will also now pass this check. + """ + + # Due to implementation quirks, this check has to be re-implemented completely + # to work with both app_commands and the command framework. + + def predicate(ctx: Context[BotT]) -> bool: + ch = ctx.channel + if ctx.guild is None or ( + isinstance(ch, (discord.TextChannel, discord.Thread, discord.VoiceChannel)) and ch.is_nsfw() + ): + return True + raise NSFWChannelRequired(ch) # type: ignore + + def decorator(func: Union[Command, CoroFunc]) -> Union[Command, CoroFunc]: + if isinstance(func, Command): + func.checks.append(predicate) + if hasattr(func, '__commands_is_hybrid__'): + app_command = getattr(func, 'app_command', None) + if app_command: + app_command.nsfw = True + else: + if not hasattr(func, '__commands_checks__'): + func.__commands_checks__ = [] + + func.__commands_checks__.append(predicate) + func.__discord_app_commands_is_nsfw__ = True + + return func + + if inspect.iscoroutinefunction(predicate): + decorator.predicate = predicate + else: + + @functools.wraps(predicate) + async def wrapper(ctx: Context[BotT]): + return predicate(ctx) + + decorator.predicate = wrapper + + return decorator # type: ignore + + +def cooldown( + rate: int, + per: float, + type: Union[BucketType, Callable[[Context[Any]], Any]] = BucketType.default, +) -> Callable[[T], T]: + """A decorator that adds a cooldown to a :class:`.Command` + + A cooldown allows a command to only be used a specific amount + of times in a specific time frame. These cooldowns can be based + either on a per-guild, per-channel, per-user, per-role or global basis. + Denoted by the third argument of ``type`` which must be of enum + type :class:`.BucketType`. + + If a cooldown is triggered, then :exc:`.CommandOnCooldown` is triggered in + :func:`.on_command_error` and the local error handler. + + A command can only have a single cooldown. + + Parameters + ------------ + rate: :class:`int` + The number of times a command can be used before triggering a cooldown. + per: :class:`float` + The amount of seconds to wait for a cooldown when it's been triggered. + type: Union[:class:`.BucketType`, Callable[[:class:`.Context`], Any]] + The type of cooldown to have. If callable, should return a key for the mapping. + + .. versionchanged:: 1.7 + Callables are now supported for custom bucket types. + + .. versionchanged:: 2.0 + When passing a callable, it now needs to accept :class:`.Context` + rather than :class:`~discord.Message` as its only argument. + """ + + def decorator(func: Union[Command, CoroFunc]) -> Union[Command, CoroFunc]: + if isinstance(func, Command): + func._buckets = CooldownMapping(Cooldown(rate, per), type) + else: + func.__commands_cooldown__ = CooldownMapping(Cooldown(rate, per), type) + return func + + return decorator # type: ignore + + +def dynamic_cooldown( + cooldown: Callable[[Context[Any]], Optional[Cooldown]], + type: Union[BucketType, Callable[[Context[Any]], Any]], +) -> Callable[[T], T]: + """A decorator that adds a dynamic cooldown to a :class:`.Command` + + This differs from :func:`.cooldown` in that it takes a function that + accepts a single parameter of type :class:`.Context` and must + return a :class:`~discord.app_commands.Cooldown` or ``None``. + If ``None`` is returned then that cooldown is effectively bypassed. + + A cooldown allows a command to only be used a specific amount + of times in a specific time frame. These cooldowns can be based + either on a per-guild, per-channel, per-user, per-role or global basis. + Denoted by the third argument of ``type`` which must be of enum + type :class:`.BucketType`. + + If a cooldown is triggered, then :exc:`.CommandOnCooldown` is triggered in + :func:`.on_command_error` and the local error handler. + + A command can only have a single cooldown. + + .. versionadded:: 2.0 + + Parameters + ------------ + cooldown: Callable[[:class:`.Context`], Optional[:class:`~discord.app_commands.Cooldown`]] + A function that takes a message and returns a cooldown that will + apply to this invocation or ``None`` if the cooldown should be bypassed. + type: :class:`.BucketType` + The type of cooldown to have. + """ + if not callable(cooldown): + raise TypeError("A callable must be provided") + + if type is BucketType.default: + raise ValueError('BucketType.default cannot be used in dynamic cooldowns') + + def decorator(func: Union[Command, CoroFunc]) -> Union[Command, CoroFunc]: + if isinstance(func, Command): + func._buckets = DynamicCooldownMapping(cooldown, type) + else: + func.__commands_cooldown__ = DynamicCooldownMapping(cooldown, type) + return func + + return decorator # type: ignore + + +def max_concurrency(number: int, per: BucketType = BucketType.default, *, wait: bool = False) -> Callable[[T], T]: + """A decorator that adds a maximum concurrency to a :class:`.Command` or its subclasses. + + This enables you to only allow a certain number of command invocations at the same time, + for example if a command takes too long or if only one user can use it at a time. This + differs from a cooldown in that there is no set waiting period or token bucket -- only + a set number of people can run the command. + + .. versionadded:: 1.3 + + Parameters + ------------- + number: :class:`int` + The maximum number of invocations of this command that can be running at the same time. + per: :class:`.BucketType` + The bucket that this concurrency is based on, e.g. ``BucketType.guild`` would allow + it to be used up to ``number`` times per guild. + wait: :class:`bool` + Whether the command should wait for the queue to be over. If this is set to ``False`` + then instead of waiting until the command can run again, the command raises + :exc:`.MaxConcurrencyReached` to its error handler. If this is set to ``True`` + then the command waits until it can be executed. + """ + + def decorator(func: Union[Command, CoroFunc]) -> Union[Command, CoroFunc]: + value = MaxConcurrency(number, per=per, wait=wait) + if isinstance(func, Command): + func._max_concurrency = value + else: + func.__commands_max_concurrency__ = value + return func + + return decorator # type: ignore + + +def before_invoke(coro: Hook[CogT, ContextT], /) -> Callable[[T], T]: + """A decorator that registers a coroutine as a pre-invoke hook. + + This allows you to refer to one before invoke hook for several commands that + do not have to be within the same cog. + + .. versionadded:: 1.4 + + .. versionchanged:: 2.0 + + ``coro`` parameter is now positional-only. + + Example + --------- + + .. code-block:: python3 + + async def record_usage(ctx): + print(ctx.author, 'used', ctx.command, 'at', ctx.message.created_at) + + @bot.command() + @commands.before_invoke(record_usage) + async def who(ctx): # Output: used who at

    iF({mZnX5Y>h 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/member.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/member.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..69331d693e7a3814e92be7e88aa212770c7f26d2 GIT binary patch literal 54627 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/mentions.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/mentions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..65de7660145d5eb1fe07f61cfa9c3539a28e8ad4 GIT binary patch literal 7074 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/message.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/message.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6ef2022f5c752b1f6202c97a3b60a6bbdb4672a5 GIT binary patch literal 134855 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/mixins.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/mixins.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f067e6ad0d744d156d5c1edae41c710831dafe02 GIT binary patch literal 2326 zcmZuy&u`Oq6t@$n4K7fi0}Y9?@45*!liL6j6GCW`o4Ad))X8jzu03Em_BV~evBTF+ zvs6r~GZBb|#9`7-yA_pb5~saqCuOi%?fd%set+J3e);*t z36X>6r*CH4zvMXX54?;YxF^ryM{w+NF1NwC{05)lRya5FfOE4?GO5BwCgBOd%hAk} z?1-BkOcW;V8v@6PW}A{#)g)EVp+Q8+JX{K*SPHuX=54lPGVc_~)yr3|Ep!=;Xb=H*rEfWP&00Wn<#9>eVb8Gc8MKDq2t-$kGP@J>p*ln#&|8yrxBTtA@@0BWHDEe zLPQr|ZOFYzM+JkpULYcC3a(#i1K+| zR}4d}=|o+vS5*ags#dBt%Br?PmcUM{!6d6N!r;`b5eztTr78wGTUGQ@1w6}3YE?DY zC2?6bHSkH6!KqB@vTmxSMpf2Hy`k4@h63Ts;8s($WgVg@tBPhWLR8=p$gJK@nrbK#k#*I8RK;bz2JW$(V1YH$&`wiQ zFIeiNKt~+`6)ac-Kp*8&R^%%9g7#>yDKCnJ%~^>*k3+2vwB;R3nO-{P7M zgBF_vVT73x@^Y)#h+s7qVO=oV-*(zGC>jf&^a3wrMWf5`TmGzPvzW4C$skv*T`f8h z&}JA%3!5zLb*~q6OKu_7NpfFSDy@o?I* z>;N`TvgnaJ5jJtP4TWYH`fM6pGyM5ur;waPf+bAIJMa=A`I>ur>dcP%dw%Mxl>;H0 zySTS}z`^lD`~r{E7R_E8((#ZSUI59fA;l4OGgN40+$;=bZXgtL3`Z@^Bad#5rVTFW zCYeM6FS|HLaK8Dt{Pr=Nq(Vmf^Bf2Zd@?I=oPb+|{z!rji`a%w3VL*U{AodFQq}_M zVj*_8r_(dv_8<25<{o~zpTCeG)Cv>qGzi%lBr{0fLUI-fVtliZ2`D5Vz<-1W57I&& z2z+jK@4Xis9BJ`T3+H~)vf!r~+5|7~n*bx9bR+TfdYfM6Z>A&gF~b%i!U#Sl?jXza m{PWB?UO2d%oyzP?{(U^pUwqC1d2vqQXZNSy{fmP$iTe*!d1=`I literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/object.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/object.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..37ac54cc8efb93cf06a3974bdbeb16b6e986bd64 GIT binary patch literal 4896 zcmb7I+iw)t89%c(+hZF8=8_AzCnNzLGd#b4cYpQzHpc!*oz4^W8`{Rt(YV1ZR%DiDg=$(oR19g% z3R{s{xE?7+R6AOW)?>w3y{FiNzGlU0z4g9gUtKTi_5NaieV{m?F`>(0%=Od;i-XwT zTiaG2Dh^?MK=g_2Vu#pSi98E!#bK+jxGTg?F-yP3tbP%>8}_X!?hY}r+tPkDa90aP z_N?~A2aSmcV|t+~_&63pwo8cze|?4TzEis zCV1Vk>o(y(|L2px18bG}Lhi-nGiEhl96)ebbRj-;-{R zLH}%u=d&|~v&meFr}KOvmwhumotowcl6mwGB>35MVK%#1;8>AMW(wzcc7`W2=lGd) zW;(%BZ!P3f`MjRZ@$~${TsnoZbY^O9aXOtj#ZO{iCW}Z;BZMKekmaN>5S32lN!WZU zH#G~%$&=~1bm3e=pGg-okjZBtG|3l|xk7qsaW0wT3yZmhY(53`(-50UXJ&HHlA2Ft z3S-cUF`jx89iE>}&drf3J-G<$bI_CHQ`v=cx%8>o0-w#!O{Xw;G6l<$C+AYWDmXPY zmrTzm_;hkUd5Wyd@hqg|bXw+H$Is5DXo&PB@o%b-&SuDsscfc@LpK30bA|5Kv*~;) z!IQak9;WIuxh%vJoY+B_WoTa}Q zuC@D(1_DLprTZlj490qA4Ma`3CgP#?Hn-udRBFaWQS$7%X!p#g^JHE;((cc zy5Y443+EP6rK#D}6b}1TJ5pF}igt9df!NJJWY{R1_{6eh3Ut#aGXEX$oVM{6`Zt(h zMGedwvb17YM6A%yG^^JNUyBu^R-YBQ7AeLo-HPJdBYH3Fd|Z&bGLoB6owy zVn6tDKn|j7%z@)`BH%)o8+=(b1UQ9H+pg(I3)DsiBHB5g0+O-Wl1&H9+MzhJ23{k| zM6x1{oE5(6w5VfB0j}eR>R?90Ye{iP$+!f{qy#1bmf;y(2>_4S6}58(iAUR;N^FB) zXt^HpnWv}6_`HL5rPWZB=PGet)xdHb2eG8V-KH?@3hdt$t@zNFz)c7;YA$Fc*r8Zj zS)imD1c6F_+XMGOrt1mA8sixUJ*7)r5=6&NYq^RK{3h3di)j$6B6bJ`CCrBo#17AJ zS;VfyV?cw3e7y0+$<&Wt^F`gyfUQj-FUj6bX3^xNBBBLaMk75dfBd5>Bh; ziwflW{`v`744Jh_``ypz3L|Uid#` z(fR&wc~x-5;mfEwNLA;_2_yhwo{;jx;t*;KtPIRbdcke$2leRY;~%9p!6y{%6H9i( zTk6UN#7KWWNFlehrF*7E2D@)-U12FR%hhk zP(2kQ@t$@V?Y91=QEQ2ml#XooQ7{J0Qb{3QDz$q{r3Pf86|yZk1ViHCb_DfhMeadI zjko}h;dCEe8mE(R$5Dk!v9e}@zQ*&Tr(3vH<#@g+sYLv4%aE{ed@9e6zH)5bbn!+I zxTDL`X*FLP2U}hmui54C<||xuV`-*9_dgt@&Bd7mx?9Y>boc#36(!DcF>!*$NedSMfn(KCbeV~3n zOv@g*eNgdE|I6%`qshHtvl~7b?FQE*I{1->Ai99olh6AhD})akl)4V@cXGUn-SU=%+9pL{Bz zyMfE{S*+;h%;vhMXUE0EjOCfv%@M$(W#ZAcZo3`gQlTk#L6QQey$v-&nn;I!*a-`m z5l-zW2naDtR`39?Sg9o523mvNV4`jnE8JsvU1gv5?|x6*v_7>?!+USM`r}t`iVv%|s`rKut`8jid}#lA?|wOgZCj#(GDcBO0*x*3Jv9b8Nl$LB zr90Gz8cI-+JJx9|P4LHWvTiAi%S=^!sOvaw01xoR!qgZrAjJLP*@xESQKS0>qE#}y zwH*Nxn?nw*9>(h`dl+NeM}Writ>sUK4zBkeRPJWt5g+%V$I9+01Emg;$l9>F`nFto z=TW}Lq`HaQVXT9I16bOQIVz{+A?ifRj#Go()LGlnalDHF>gL_FOfQviPqu1ATmz*N zRTu${^^{8Zb&rhb!8%EQ%aHr&^&-6}swrLQ>L>DRN-B1|RryU!++oTwl~bxZS1*bP z_XJ+o*n`mFXz%@k#^$uV_BD$|-_SO;YtiEyv2b+czRtEk^XU-3H^i^bei0q~Din$y z+6c4Qwg=SmMN`cm*A#B?y>b*i@}$zD@*E~p)U;!D`!ZtOw>8@G?3(MJB01EK;dTSf zO3DmLtR(60N3x&hdOL8nnH-=|BoPvzyy^+J-A5loN@GnruHEHtjrfm z*^{U7gH9fy-4xUcj7PnbKG-MZcQ8iGqc|7jsA&&Ed$h>cN0|2Fzu3Niu$TWGiE5z@ zhS!5_EVAQok>S5bc7L(w`I~2M58oCapIhH|;@+OuuV(MZLj9quJr4)o(6mF>-+IXC U`(P%-cI>_R!cPZ&IH>gh7h2dwUH||9 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/oggparse.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/oggparse.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1ea75a84feb6eb9927bf06b8b6faf9e5653181c2 GIT binary patch literal 5363 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/opus.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/opus.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..38e63faa149498e96355f032c5ee187b998639d0 GIT binary patch literal 23494 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/partial_emoji.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/partial_emoji.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d9b33029bf6d41c05172caad4e07530aadd4f2dc GIT binary patch literal 11167 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/permissions.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/permissions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4568c0e49a3796fe9d957f8f9ade83e00bd7860f GIT binary patch literal 39775 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%0D0`){^?Yxf^? ze7j@u@Cyt67o1fXhAf$tp~B#H7w}B0g*5KmaXX$4=78FlCF@#CT*T>~+v=<`UNw0R zAJv~(S4=X9N@^10Xh(IEYmE{xWo#^8f$_uXY&T&93R#z@&U$06DM_ss z#uL}92lt^7HSxfNunBqGQ#iEg^{qlKcV4djFf@R7#^}Z$PiAaz3R~PSImt9Q_1@u1 z`pedtStRQ0WzrQL*^`_J;b42rY5I{;knBv6A&g6;d|WH0>xG0tjm9wJjI=pQ`e_O* zUh&~i@QPt|@X{B=Jtr2sP|7b8yQp|&PJ-%Kv*lh;UJT0FVC%f^exR9OJeLjNa;Nv3 zx6v7D_nO-mo7=O^xWd$17BU98`a9lNZ{80=LA|5hJ^o%Wv{ci0XZK&-Mj-E<(Yuen z7u>syu`NXBAT`{I&07Zs>WzUK2=`CEfBM~*C;EHKAqM7_PYRO@|jT4Sbq(JR!%DiW( zdHY9_yKJw}PCv`q$-}yMaL=+2sj#BAuzX^BTKRTU;~`%N`GR%x4#&n(8{&W0${|EV z+b0HFaUMe|J#XuSNX*4&9vs7n^RT7vab@(HMz^z4HxXuci|ptj=G97YA)HK$SKMPI zpMeU#N?Y@pHbWP`LVz&KWd|)Yv6Lv!v@KmX!q{zUUc!R8E|r_F=+dqEx4{GK$UGBD zh4&_5&teBn>Uf%!U}_>qi89i|7scH<4^DC9BLH;_@rXG;u9jp-I}0mD>Nkit$Yh3I z-bklkKT5{LY(T!-wHVmF;NR^$xHCa8f!8n%uXlLojy%!Nq1`c!yIyY)?wzJ7RTS@b z>W6Ypfg9F7l+)~p{4#Z+X}bRZ@tokCu8khgNgBAdhp`W$2Q#!X{fTB8wFyCBljo^5JhsBOQ%rtCcZM}!-9q{(dOg3Vde7^bz0 z=c!yad}V0qi%(rF)<%EQYLDTN^Fxa3?l#U}+SRL@GA{8?LT7K6?Rxs<%b{SN>y7$j z`qH0MfaM)Y-9iB=YNYQ-bn7vkIVkvF1lvxrRtkt+Rk}|i-_?UDITReA#`r37d;zW= zTjA;Pj8wCAuJ=Eb)-N^e$@=#!)wgB+ZSQaI$oe~$8h2&=yOtVuW^t=!)9x(pu-we@ za5#r-qWnwEd$az%OTlef+=t2GVxE>z)*sT}<)!h|ZS7fqyZ$aOdF%eHfBzB>Yqn?o z+m`}cv;M7mP58IOcllfV>m0siU)H}*{}zw)`s_NC^&eVlJ&^Su(7!0wpW`csv;MH2 zhu4|IcXVd`o%&n64q`pUuhh3@aq}my2`gd6Tk30Dsdf22<60?U(Mn&-@)qW3QsJx9 zoj)knT!DLTYt z%#o5>i6G}2OGK||DlMvVw<}uoQfnv)PGhJX9KLFJ!E6%>Jl=7hBkMY9BW2w~0qaw= zq{Q&dW7(hhpMtmkR6==1ZATXTleCu+EPGro*N5&#m-hz;B-hSAks|k`$a_-ckEG|a z(sRpRPlbD~^uuz=Tl4R{ZQu91T!DqAJ>Qq`yW%f#HGEhrxofhn+V8tBRk)gNg;pf` nMKieTmKo@y*~ZPT!19xlyX8mjNw=$GS)!0~w0y__tZDuasv=jO literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/player.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/player.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7b833a43777adbc0a31c50f709f261a47941d06c GIT binary patch literal 39928 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/poll.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/poll.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a6081da3453b8a03a535ed01c303b74987d87647 GIT binary patch literal 26053 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 PyGLENn)d_>8D9K9Usthw literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/presences.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/presences.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..50864c4ec73e118a8ee9335d36bcce49362d36c7 GIT binary patch literal 8327 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

    }rZQShd5dac&CPNt9vvVOt!lJ7| zFMzPM#f1|x<;9xfEDbaxZUZ*T~SlmDI@i#cn}qatH_v9KbU8zgdowE=X5nv-RQ1 zP9h234SvLquO>FSPpkz`JSq~hjod2y2|8bA6%?@|!ZP@lE_y7_8HNtq7^|gNC`y%h zS`Eu5+t3EY_(kLu$n0=SxcMae$g_Qv1s}Ohkt7Vqju)mwvvNi$=U$Da$D1^w@zYge zz6T9?m_G6_cb;179$X6!a-Ngn7H&x$Kg<JlGuw9K7Ep zwDkPe*B03Qz>nU2>fP@bTDpGg^93RV>$*?9`@tG)e;u~J4vW@d(K_t;I_&v6>|`Bw z@{6D^aM<1ZBNdjKHy0mJ2Ks1)ML~T9RgFMZ!jY4El>Y|$y{)iOc8?o{QWNSKCGCyQ zLe0n-d5L8$ikxM zRO#Rs2^1F=P+3Q<7Z~2om>bDP`1A#;ZE?z8sqH)7C8Z@^Yg&UN(@MlRk)&;*=vymy zd4$=RQPCBu`OePLMVOs!SS!jNS%}xyc3i5VgilrWo!H>DXWB>P>z2*)l2Xn5ZAq}v z7Bq{}6TtT(O*mA%SM~p|!jmhKS^*PveFREW;rz}F>K&!}8N4W4s#lMk9jc#xx{SK} ze0BD<=JVO2RzDrGoB4`qqSmHYQSV0;CBnuLZ=%*OdlfYnn@+H;pD*x}f)}#Z7IIB5 z3azXtR~ZVn6uYRhS=SEOY3M_h(QhyKMZ;G4uQPlN{9xn$Mgpp~W+MdB0YNbiDq4bu zj2=5RJIjCQ!S9tQpo27lpe3tsFPTlVGC;&g$K)Ka}zva73erwxit7}(uiA&%b%_xr+7++NP>S>;v0j_mMYWl&glSoP%jfO1 zR;lSlrADAijrkm=nv_=}*nJu=M^u~ug~_T#!eZ>Y>u!cISUR?I*}Ptt+o5Rl*O+IK zT)%RwHqk352UHD}GlXs*$ zuioug&8)Ly8~dN3-1d{FPkvzk>%=doLacjwmf z#`<^5A4jij9KV7o-Jcvj^}+5BmNpK*gi+__;M4a8Ppl7~c;Ei#H~;C)jlnpI5uti; zLzP&QYF(TIvzK~2OgWDpJRwCR<`gy4)VxAXiW*{Xd#FHell#s$(BU~Ig$g|g6$XW# zY4LjE3n>sdE4mJvkdxsjI7y0k<|~Mx5bv0z4o-_*EyHA)5|JeRGg1CS3{$()Rg?7C z3DEC7mYWAtM(hMCwx(NdK*UduE`!tK63eOAV4tXvZ@KXp^j9$HC{4OaTM}@(FaZ_f z`eIx)UM3t86~$mk=do4JaC5x$FnHRH+|HP<1D6bkHG}59Ulhg9ef^^JWke7U{--dy zE{y(KIP|G-@KfRRx^Vhe{$0P627fIb{-v}Zolm9g{T6?_?|SR+IufFI_;Z2UFE0A_ QiD$*zuYD=dn@jS40aA7_od5s; literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/raw_models.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/raw_models.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7d810fb4b2d8b7e9fc067744802654e41b990b90 GIT binary patch literal 22992 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 f_ER?8=67%Lh2LtTdc*Taw)hUdcJ3F5i=*d3 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 GuKxjeygK>- literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/role.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/role.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3b66cc19f18e53dd32a29ca488c871ad3cc40974 GIT binary patch literal 28037 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/scheduled_event.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/scheduled_event.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3c4fc530c6077f07e6d9155dbde92804286c381d GIT binary patch literal 27709 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/shard.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/shard.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..462d391b59a58843be5d292c41a7cba7fea59f05 GIT binary patch literal 33942 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 VfTR4Qc2|n$d--2;?1$m_zX2>8^(O!T literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/soundboard.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/soundboard.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..45d0fc1a6d25804b983ac792311f6bfb81562d0c GIT binary patch literal 13521 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 KTHqbN)qexTni%x} literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/state.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/state.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..afee3980b236d64f7d1afdb88a969efa7b4ab954 GIT binary patch literal 111286 zcmd?S34B!7nI~GiN~)5oB$f89kc1Yru?WNtLJP=%z)09o7|TMp1QJyezExt8g$<6o zyKqPlNhio1cP!6y2QhKla&N)!^>lEY#XafQsY^*Ixtf`$OuLtKPtTCx>300`mj8F| zR#mzJC%w%3{oV!DJ@?$R-|u|q+s=1>ke;5V!}ZSRN>2T_U9bB~dXO)R7|=iXbE8go zL&xbnI!@0Se0smZW6)FB=rekZxSM=Xvt{`JQ}#fu}$! zx6o6_$}RE~v3s$nn6q#xz7l__rxa-{oYhz6cYE9{oa$TQFZYzQaGI~eU+Jmzuk@^B z&o*C`zuHsH!ggPczt&UB!s)(M{yI+`3upN1{SBT57Iyd=zd^mWa86&Nzsb`i#jciO zGkt6PYdvdOY?g1GzuD8w!r8v{{tccDEbQ{N_&0hs`Zswt`8Rtuv$!1J7XMbyRu<0n zZS!yUZ1?Z*?C|gO>|}9yzE=M(&n_0u_qF-kJ@`&&MS-uw-|6XO;X>bT{~pgCf0w6= zJs0^N^Y8WSW#MAqKL38teiknAb^8x^4)_mx4zlM`-{by6o&|1r-o7OwC;3iDW=jmhbR$}a) z@jS!ARro&ro_-dt_MPw#cm`Ow#>e@+9xn^m`Ud?cJttXsmG6{)$TP&kb-rQ$Y0qgE zuJ`%;evjWj;u&Gj4ZczT8P6FOZuC9t=RLeX;0dtjCSTA$<{4w*)xNX-bDr}oyvBFI zKkj*sh1dEf023Ge&wE~A&+B}b027z-{a<9yrM}N#d|qPV6yL7_#(tfJn|;3lxCr^L zcwT1D>wTZ~4|=Y$@CM)K{Gaz+)9Va6Zx+|`b-g%?Jd@rGZ@;(CdwtMYfGE!w47%Mq zZsSWjZqwHdQkpL!k9AT%Tq8cm|9Zcql=Nk82edo;UrBc6+nM#*u zioM&0ciX*FN$*~{V65HQzuBbIrS+cjy7zbWy7vtYct-+WcMTqD)6&{T&s^Y#PM!+7 zYX)lFYgeyX-*ATa2D~Fd_o4nXXM*EtX$QT$e<%C2+y!XTf_es8gB>mD6+51i`fPkQU!!BKbr$OZQqFCRdL(G$V`p^>4HlkWbs0aQgPgQrkTV018e zuAlcJG3V|N1V#sj`ca;n8yy()qxSwF)i*fg^9I~CLA1TRN6JxNTc3tXIB&ntJv4&S zyl(lG``l3Q)aY2yjUEK~p#dtR9*G8gV;r?Xe(f9b4~aFTQFhk<0JVH9fF4jg>)rlQ zZfKD1Ue>KMV<&t=fm8KvZitFLF&0G107bIltWQHfnnrnd!0Yo-2}5W%>#N$jde&Fe zg0VsU(h#wF&z&0eQ%};Ao?wUu$M_Lci9w<6j$+7IjlTq}UxDOsW@I+U8N4vYcwFl4T_3kIT zdiNYS-0Mb)L#^GtN8JZH-L2h6-Fv&b+w0vOM-Cq9=;=v2aLC=Y|KPr^4#ahJx9vOJ z-qpR^y$kue4*-(80KzD=_kf!!l#1%==%K>)cN}WlgOXc!b?xiwJzAgE+11;PGTogh zwAFpE^-ynD+u?n!hujAbA3AuTrvufuquB1Q?#@G~rDK0bcW)zVMV!0i2|T!a_O$NX zM^&Y@9!BdAp`JtTwgU%`9_re?r`Nsbz`phlMDFT9%UXBs>kz9#r`q4y92tv32ez_jFJc)z^yuZM|Iwx~Us&2fBL?;jtdQJk+aXeX^^kqu$+m zsH+D}P3t^#0L9aAA_t9GH|6W@5KEzUlB zuuQE!X6qjTps;xv=&m)y%$)bxF>lOvfaib`xOPmpT4&5e_n7s-8G?;|Uo5@%=)sP@ zwmltf__VuYrrrx@yfO3P5xk9A+W=ktCw$(Rv32A^%(M?vE0#hjp6KUescoY?=JL>p zH)idjszwI9v6S835ie$T%-lP61{uxmtPv^uhJs!m)mZ`byl=Fh`w1aqwA#FTY{upi*xkChooZs}tw`@Mlc|4A=i=~v;$*$0F;GUE014fYQNM|r9;_fY@2gABP2 zcn_c9fbTlaQtkSfWxv;dg4Jm{H0tx#8e_ILF*_SCYmmRt=N%dI$1FYg0%OzwGls?& zKuTxpnKQsb?89{W`cDR8DP2I#Bf&t-DHhw-KXA&+UQtzDBNzc{r>k!W>43S<+`Bs8eIbMybzfdwP2hiZvlm z`V*tToCo>Q;OM}p4-wAxp}@c>&pqiq(KCvE&=)jy1-*XUZS5CE`u#%#>=E5-8}<9K zH1uMXjHUHr(G2+dF_x6$AdojkAWP~rhMaoM2BIV}P8^Sp^WFh`bT%-lJtL#%27Udf z=|fuSy#&^&?fd0^82CcWftXE#R0h-rz8GO6Yz69&-mhFA5eI<0?PDrbDj0{$Y6GlAMM zaW>A3yP30d7ThgdI+ucb$^~m}M$F!JYHZ~6A)5DrVDBx=gaLx@0khNsn)uWP{OKS3 z5o^PQenQtLz1Ha_40w`gH9VQ{BvEB}GU7?<0iMiw0`VkXL7N;Jw#y;)&go^UZP=m4 z%Av1I0hDKz<4)@El$!9wI5dj6fX~zY6DLBowwU!K;jq3TE@s6V&5I%6kx?IzUCiVg z9X-PzM$(vJ6qA1pK*o*wW5!e7^D*!q)j>3Plz&5Yl)dasSNT*kc~e| zKga0DLqAkhfH*=oyFM9fBG3smp;+E~ZX9Dh($v%N*cfm)-_&!4C-UR*F`z>)-_+LQ zUbB8}(?9^fCq{#ThLgbIXErtg&z)`Z4V`E@a{(0E$hyWgYnuXSO2e7{fz!YofhN#Z zG^d(?L4w}KGZ$jkKH#UJU|-*OPW%^dl%oUG%>DSeq`RM`E3FEduBI=PtYo*w4eZvm z4!6{WA~$Yn_X>+&TlLDS=|f*>j26}lh4qobMv7mkq^!1uE!#q-&)FZKK;3`>4|t&O z&tS;~n7M&(HcUy9u3-gc)E5&9MCd7(0!L~Jz8~=^>a!d|tO6x+94LMXW-l5h443p5 zbQAh^-SKTY-9_VsVOW7pHT{H93r>|%OcSQd=@X{m3^j)wx~#w2fHE`XXZ1c|l=JI# zS9h2Irx$d$^xd_o{4+=tvv|*A<>43ziNHhv7E3$n4fgrj5*IT7j8lh4v8;1_{lS>6 zub<*exuDsdsdPBsuI@Gb?aD^@| zICB>ZSNu$8OmCdD0G^^nbwW|yOy^r&x4I%l8z!v_*+t>(is|#w>P-UuZ(VQ|L|rQd z*UIU^c~`?vQ;_q%O=r*Ly=VYfV)dfFe1>q939);1`di(T zpMkvRIl%9ijW>+HZZ^xiFl2sRcmO@Jn^+bu$di4fj+W&%i1 z)ODl@JdK~f)qMaJ?X!StDfDL^4-}ECe9-EB2_hNU#=7bpk-{8;q$n3k792 zwl3P8*Y;i67qyoO_OfZqyuJFqS?6;9d};hI0`;ik#SOc3`ghE&Zrz{gTT4yfG9vV@ zp%{_xmg*_&E@|Cne0Q4>F$s`?Zz5uzGYI@LnCG7h6%+a%o%j_@;<`Y%mW@3hq|jOX zBn&f~;NtL)=Oqj_&3y62E0n1YKc8;A7aTdE^rf>!!N$*{q~*p0c(D<9Q9q&A!prjL z@cOGRq@ekibYU(@64CeD6Yoc^Pwd339TUm=1kYWS04xdEMQ z4j+rpc^s3MWnh`DwCIC;_V)F~()#)!f&o{6u)VME*|C0~_=e|DHvcUBoTs00`k`UH zrDKD^CO+RovFrzd0Cn^w-F>Gnujr=^r+NEgR?dAh?)NRa?A-e)6te0ZHTP2~l%~tB zzHg&YhR*4_Pw9~}E#pBZLJum_%#9E7E#{gBPNO;Zqco#g{06KtW%}w-p@P_H`ih7h z=oYv>5#8zmNq4@0X!ndWT^8F|+nFFSsI&*u7>PH*0J512LMN=7(u{cP|@)~)xAi2Fr= z#Go(gH|Sq7XX>u#9j2E}nYz#8`IQqvCKfUyWTB82Cqi-DR~WZp_FA}CIqOR%8DBup@!MP~ z_z)}j6x*wM?yH;~TuUnV8kdgPG;W&9z}?2Z&N*N#W?sqsBa%Xa1<8pA%;%;)exMy=STpsQ&v>_jDxWyHq4LQnFA)a!%f6o;m zO&<4kt{C@x?oF-)_X6%4Tq*8_-0yO4aqgGQ(5%dID-cu6z0H;5UV?iC?xkqY?{SrJ z?I}ad?{h2TV%*#xa8*dVf-B>y(UL#pYEXAM_eWeUVk>Z8g?lCPeUqz;%eN9Sx4HVb zm@34)!!^XkRCE6;*NEIT-2cWk;a-arf6T3pOR zt{L}6Jg>*SiF=pZfct9h+guCoYq<9yi8p!H;yZswg#hlm+$N02I_`Vi_aSjNdz!iT zxh+Vy9_juRJ>0r1@A@CPZ7-#GHmGGS4RJr;xbNiVxIMVHa`Rjl?z^}jagX8N z#znckxVLi)+&YMe%w9Wf8|c#evJDEZUFbE z@Qpa!k9(iyy!bcxs)74&+{u?L%1rE2-z1JU_usiw@#!!x$|!$Qs{7m!V6~6?DL0II zp5acvr1SKnRv(^Da6jYxxDRj-xDnhr?jvp#cQ5xpxHGs9a{tIZi~C9LpEw@(Q{2Z~ z0QVv8=Ufo?VeS)d4ENLA|H+-j-N*fcJBPcU`@gvJxQ}rEH+KQ|QSSfY#&JJ03Hb>3 z974|`q~|6O;t?`%7ZC~|WaOSlD2R}WdjX*_gv{I}gw7&l;VvU|4xtq8MTE{HWaU1C z&;^82xt9`yf zi_m3+GP$b=y@*g2_c??iPKE-G)b4mJqmRhbbKVnBKS7K)o|~9Kk~JO& zlS=6Zm~42wjwIa2KuXoSmE_0NIHI0FL=mlY{5a^DGyObCPZY|47AztzZM0~88O;BU zxOIP6S@DrVx*#M{Vwtdt*aCJ#xmn#<}7jLDq@diQm1g%xYUYB52IBo*Q4GsTKGo1Ex1CC<5FdI;YIy2HKfTY zE?Oommy3cGa^49`uu=}oZ3x(c)p8tXlXIeM3&z^thT+hKbTkx?~iMlC_~TBd&Jqgq3$sScAm)uxog&98&LNI^M`R zE?P%y!S!6{s0cj zfjq!+yPQV7CqS`FZpX4voD(t7B5ioDT!wmAYs6TlVO*-@cM~aiQfAeJ6;H&6uxla}Pqp$B z!(Xcsp6cW$?a}4!XblNJlP*3JqfYE-(uLX}vJkIjzIfilF`ztZC`p-@sOxFDRQ3Mw zaxmZA+I_O?&g*$QMlp5x8MQPylvuA`H-yxPTO+@}XbXDf@bI7@c};E>-7run2; za`(dSgx~%1Hr@)`%MD@wLe@ZV(!f zoInZV_KyXEls!pn9kW9C!}NsXYvfRJE~xTRAB=inj}osiZ;V+;F*6p3r4B)V92g?4 zeG2K1p=TanDFu>CLmRqS5;rUd+~a$8lO8Jovl7Y%QyH(HS-&6|v_GVh|+WSrvf zzkp#FgP9Uj2f>~PT2nGe2?U_^YmDU$kPfhqja~q1ggzwWgJWmLw}|xx8YLBiG8Wzu zRz4Zdu)J|)d=2N4irvovYs1O{0Dx7pF5}5S|PRBAC&DtO63&@&c{stA684tXykNgzkc@odY z(w^w|jd?qGeiXJ4_{x$#pD&@8sbq`5-toUh&kmS4&{yC^RcwIIr`VL>Xded(nI}{l zOBo#;^pOdN5d2AcMfxDkq^*MV)+Kkd*Q^++?kM%+lxep9x-w zKIlpj$@${`;5vP8B?QLz32-Uix$^)Bf?a_LsDf9v9{i%g&Du4K2m zwQp^?wPp7CJHbfZzL06oS^y>=ncir_cA;VWofUT*+7^(dea>F8Sl^7S z=?g78*sZG@x3q;-(8JDI^B2~&u=~A+wb6!lp`rcGli}{CBMp5NTXb*T#&2$W8#>xK zYw1Ew(_6M%ws7@4`sP+2zn4`MEWQxuO*59pI&j!mA$vPIcA6rDBr>~z5mv6XjisWt!*%oZM z)SALo(ZUv?u;q42q;Thzy&s}=r|0Un%w=z7&3kI@cz^hWKXQB|{M55yHy_Cjgq?v! zdtTIDE!eAPQs(Td7n=bIbJntj=B)sQjD@Ot-0TZ0Y8ZSpZ)A;IShJq)`P3n5VqLVn z`EGghLTP!lbfZwZG1Pwbz+!dd&F5Z!F1)Vm&({BN+n;WWR3D{0r3?gC2(}e(9KLz{ z_2YtV?LzJ9x5{png;#F8yR!TClhJM6!nSUL&hj5yQFBGuT0w1?Ja?~fg=i=+(;F#V zOZu2KR~`$sPgX8Cvah{x<%Oy9^NyN@`qh&uQ>LlMrw&b7U(0wUBa&Zp*I9cXx|uc5 zDWs-fOS_WxIr~yY7V*HCTlxn?_ARH#(&BVw)trI<6Xc9#LkBuMghgS1lU2)iI{T^*-?Q(?N6Do(DJF;b3J(xi*80Ewp&uO%>% z$v&lggQy25GLWfeHb6CFk}H5}#z^XxtH)(^3zRo`q_?g$c9UJ2d2p1637k2WewOUU zB(YH-mc}exn1qUd8Kv=e@DsC)jgYw_^kygM(aiEBs9LZxj0U_gf=NQtEV`J!%5%sm z>alYQqB+$BCd->9<}!*n5Y-Oul37h@Kr=lmF2F*EL; zKvkAr|4Ef3R75XvHQVI3EUhBW0(?TimV8|<4ic@! zF6|U=D%Kllhtj$W;<&^;LjefeI15-9pLc`|bBUON0hqV{H18dZWj~1kqxML22~5z> zUjX?-iC{wpGKi20C@C4GAWkB~NLT}^i9QtGl38d*Ujn4_G@hV8VHrlom$D&jAXcy> zs_(=FRwbizdHO1-Qs%g%Il_UNK>wadbu8{^ zrP!)?D(7Cy);sOd_QOK^;klM4LhYaHUToPyHxVZ)kcAde?*N7R2iUv>I6kSn2iY?cJY!%h_7pI+8LbC|Lfom@?+ME`-PKIhvLc0l8->NpFcb6# zL`y}Q_@e56fc}i>Sj~Enf`YAot(((&IM;))L9`oE2ekPIqPHDMGLN?8~d*B z`^|0&bYJhDUN`T8c>+oT@^%$Lr=Geh)VAPsMV*y`vvRseaMu3Rh)59vNnjyg3IxUw z!ypjC{a*nBH%bs_yl9%xUv|QVkV;Ov6e!Hc`;?@Yc#MM{!=s?^Dt0hU7$oR{g|1ec zCya^EV`k99{{yNLEn-xN5zP$6*#A!N@6*pu@sn&==we)1GC))&1B6zpE&>O#{CEgB z7*i`{aL5Y-7Fwbe>x7DRv*#lfI{*kb?APtTnL&Y!>lssld1uA_6lB4w`^$ZI!a|sL z`Ui&)xB&}?Wkyh6fcFY7w@qgY*(*csKeg)8Gbby<_7ziA5&MddKT6R#^J$)BeqeXP-Xt~ilK?HlFFFc! zzm-~L{2hIjF~Q=O#_Jl5*9Zct;f^NMX^xo|B`KNsJY*bI+ed@Q_WvWQj~_<~50BFijjo5)6$OY7Zd2!-h^>U?)nEjC6oXXaF}~-#j&NeFq!A?7S&cIIDWv zB4kyATf1wo{`t~T{6(M=g}kU=uYbu=rTe07z5c8EO4DnW_4==+t~I`8Sg(Iuzt;GB z#`TF-ji_B*2R9?I9OFZ_dk~@PwHY8zr!ql{D21m_Ba_hjv3O!3mO^&!kkY~~F^Pbd zUXW%sP>ce=*nm~;y3!TWe~_0SdiGlIN-%6KpW^Vdl*OSB$(C~t0qAh4TkO(mvW)DO zHPh8vru8b(8gGzUhgxDL*!6ow2GD$#WOj1zjWE`W?>`d{E$zD`usub6uRwv9bRTBq zT=QM=eRd>dl#HOGu4=(m9Wug#-jNkbTRH?LWMo6I2Z8t@0De*69IvEH%ZN=L7@1O# zzpD}38fc^C-y(0!!g?6s@8Thjr{#Zy=cSk;ffmK)Vfo{J=*XUI7yA@-H43gqn0H4U zYr@twOIJ$tO6(aSndM+qi%wH5qUD|#SReSWp`cqLlgCJz_-`c1YU3L|z9Jb~nK(B- z2~S-kjLjJGsH0qPlt&#^f}?8sd?b!9r@qLS(ywyFpkK?Z{}cMHcrRPH>RAtJjd66= z2Y4Nz!azZZ#8W1->Vha!Sg2_TnIv=TJ$J1umwpok+Nf>6+&58G zl(d@3>lK47;~Ch&TB#ibv2t%*5NeZYc|vQ)m#q6*sV-1i`6vtPzEv_Hk6OzFYuU7Q zrgGjYT8k#EH_BIOen`(i{eV`--VgnRLEXJ{)uz(R1~wtEdjdPI`_93@Qxqu}&IMwI zvjd5rE30peZ9qg1urG+VRtCn)mw?=oG!xXhQn7O+FQ^oK$Zllk(3)Ws)2Wq;fxkenlKVHO_&A@M^UOQ(Ya;pW=qN~>~baj0d_uOw`MPF|r&Kqi_^r!c+25XUbfP0}LGzlXS`tFx+DxI{xtLkEbgnO z4cm3w)NZf@$n^5w`>9CwNdRP^ZZe}x_gZbM&G>Gb9={2nNSS2CNSKJyF{p~YaSw1= zH=m29LexlN3>iBpgOC7j{I`*0d}T6xshy5fvV0bWKA>h^(%o}pPgPF$&N)_vtq)^o z9@SR9h&~O8%47`8gqiUZ-X?7`p)WUHl-$s`m!GGiO6bRnHY#I>FfADWa*GCoFG)$&DzFP`-eotp+7;sjL%Z?w5`!hi`Ul|)*9O@@$7HB3iS55Ps5U`C#3Y(9?$ls*dJh)ps2r2L2Y zk!Kf6Mk!)eCYvI?yIGV{QLC{I$++7lf)#tW^i#&Y{7o7il4fD1W#>)?r`oTNe{o01 zdat%|_VAs`_j~7R4~4CVLMGY?Go{Q|5x}~Iz-SfGDQFlQi?3WOB$whaU`U-OUbB&*S|$WMT!bc%AEWu*A(|k z;TQWtY4@78uz_ll1`3A#ljDN5eELZUI6@h0j&u*u=*X8cQfCo^Ror;FNShngq^{y6 zQ<_o$EgF+nOnEg>*MB4bH)uhuP+I7TAeQ#L_xYhBhY}k05=5`imUol5l$z)vmL>@( zX>>E<^9^wU>YfUUlD?R7Er;^y-D@H9u-yAy}~sXeMpmy6#^Y3$Y=}lZHs{Hf8jlQB)RnvL>r163zXDFWadW#C)NGm?~c+@1VolCyn-y5K@vB;JZ7 zwGUBu(yV9bKY88MBsn!#$A^hXWwKcAtVuK)N|(K&z%|AB3;bWB5j>o->6Y-x-^3f( zwkL@{M0L*F$ne081Xu(eE|H6zZoawo^{vs04MN3+NCgDco5I#j|H_z#wVvpmrOa3w zV|`h3mts-%-5*j<@>owuK|OJ0LXxmsBaYgzwU%|DR?o-`g>FM0l`Zk%VOijdU+$5P zE|u9ouMdDW3DOeFE={!y(t}RY%XAW`AVW9k9Y*^cK{k;9GKn9O4F&Zkmfa_lpCkQe z`-hmr9GTo!vL%q)F*h5PQC=gbsKpy!oeT|+%JB|HD$s!Th@@oV=-zdldGm0zp;Kt+ ze7`sR6c;`{I@fR}Yz1~l4rQtDlIe@(X#nuLv|oWwqKM&DxBgrncwdvO*NSq=+D% zj^Sf$4ctaBbu%OQ;p0TIViAd3k@OPTgeuBGW&lZaR=O;R5kK`3=8A1twhc_Igq!G{A5w zzvRaA*Po}vYeKszarc$(sJ&FMmrk8~ZTuCOiOt(rQ{pv0wdm5bM1VpglP;q1@xHsD6)#3gY1 z>)WFh8wIR?6`LcDEn(}HhxGOYvNMh9GWZOWitL;qz0;gPn$uNY_Mtr|J14~_gOR5N zoj--2SY|+Rg4M@@ir9}l_eoJ~@+7Pf{NpqtOJvMT3cE`~Lzo(LP)=SbZ6T-N#Sx5;wi6U$i=tO&+@C)zeIBxe8xAI8LPxIPBv#CTCnKKkGfU~u2nOe1=j{x4Z^A~Giomv?B!8=qhN2G8K1LnUdYZ5?fdv6o1{z6 z{~$Y$<~n4`qAtBr_q(Z^jqm6;s{&Ya*+F(H+wXYKFt7clFbz6nHtUZG!a$Kkr5LL=cvv)o}({9^G*Il^mSNl0_7XalbONfnYCmi#4-s}=%bNu zI>tYWGb(B=C#^@z&CRcGo(axbo9`)*zmQ)R&94>mYeQWNj{LBra>=y$=GM2j-f_)4 zJ23&AE8$DduA%HCu>hL^=Mne~{c>UlzFt+#X?@_3eh|9$m#lFgR}*C9HAep2J+Lol z0xPnXQZ8B~vPt4zj=-0eZPXQJkSx>fdWJ&bU`h{n#{R%bs8K|r%_U|@@`-h;uit-y z>)$@!m^^#faxJML8n^mJVeb~$j)0inK_7-R#~)wPO}E}`f4zOC^Y!jaB3Ta=&fnve zC^rmJ`gx`k{5W7%R0-^(Bsp{VuN+Vt>>4Kt5 z`aTLugK&%?E5d2$C@~E@*{0r-?0MKrCOM<>6fLT_`Y?G)AKP+C1`rzbB_Xt=RGBms zWhe~FLTAoY^K=lF%po%gTO3y$Q)b$grK(YByyc6+49G(WEC=G)gT5ZU(=-iaJJca1 z0{$V)m~?5$)=(O-2})BioSMn5vnz&%X8s+#p!FMDUcDSMz2m=2QDz?#wUJi5V5Vb8 zumYfkHNJc~odSiV?Z*gbVuVeaORz$YVl#wUsxMus4{ew*f@GEIm@o~BycHoscER)q zwjJu~q_s@}#DGyoV;9XF44koft3@{T0g1UfJEejc=@* z4$eF#RJTCG6WT*2p9iiVnBEg{LE;GxFt7M-?yhNb)V)D)Z5MTnq!wWBXEe7#$ZeS6W*>{>?to0xmH%=F?T9S+ zB#?=gO;)rP>)tJ1u}f!scZVLoitlc`RMjz$;bB=G3g8leKpCzwGyxFKh)gor0Qk)E z;sZzjXW(`n9wkLna~Sx+7ryvu$nP-o^$<(NhVXOP`b{<_KyY4;9DBlwm=eS17tQqK zuazwu)KT%+VUGRyfu$N?jYPHdy=u@^Qmo{X+A3uFz>&RR&te2%fnWvQJ$-oQu{moC zjCew}rPG>F9Yz86{mIkXpxW)rQ-CkVq$NaRUO4K5NE5s>DRn zlW}-%l*x}_oJB^E87mP$#ERu_E4qJ$y#qNakRVDnAThJZm?1bCv#@=($rd9nxfBLQ zQc)Vqu4I`RpK3J$(&y1UEW4mSPrO<^XDf%mHkwl<AaVoH)VLW zZ7$s%_coHVD%80MpS#bKuj|abE4vo$S&O#xYb{q=LOTGBi`KMjDOXaW)_TEOKXZ7_ zx^B^y8Mc*7SKX}pcXdc`ZSR%6QG2ssZ=O9oZ{Gr9wxSX58MwkqkhW$i^Be<4rW)cN zVM2k*9$|WubgAE%9A#pU#hQnnnE)fj;QWJcU zlHfb&vypI2+>K$;Wn@Lu-9oy1IzN)WDr8v5a7HuAgbbJu&zf%^et#(3$AvS>A{pMO z)qB_KmE>=A>-FEzuQUBFc3%uoBjk(7n$Hk!Ac{g7Wo@YxoFQqBZHh8~;jZhFO_ffm zCmz5ZmQp83DY@>ryEcJ^8Z~AsVl|jYd|QM3Z7;&D7E)!zRUif7n#j2{mLxhLXsp9v zR+29`ff8ZIqMaAyhlCduh?4xIgYY2RN_J^FvP&H%YANZGcRX;WH_bBcOfH%EQeT4| zLl)RMlVX}(TKk1T02QJg#Y!5YyOS=?!g`qUby_EI>2)tEmda;*nmu$Y?L9^Ql>)8Dw#b8)JbuYRjAv(6I+o} zB;QEmyL;gziF4CAUF3=#L@_I!&4&Oxqsz@^rh6sNj;mtx)4h^ospRVMT6(M81jJ0ohEwfyY>il;JX1xV-&GP=<18N!sOEjvN|{ zrOL=FGv6%woM4Q-O(|LlsEj?|gfg`#Ap?`{17PS<$~8&l8i9dHHj;D^W*Ai1HN9@6 z8C01D2IUNJ3zvHSX z$xItN`2^$`(_t8J{)ujwl1o?bLIYMv464y-jni+qj_tDyfw2c=khjUQ&Y6M z1p$StZLi>`QV%CeAO`da!c>C67NkvkQf#(ZU9yuwlj)Ujuch|J0 zkHd+4c~F-+p{d+ahfTdL+QVhyS*dN z{9PBN|8B0H!g(7J{+`p&nXUU?7Nz-Kc4}vt@q5LT=6j`j3YSsazE@tcyGr+cbN22c zclIZwk4AS~SRlc=uQg&1w(^(4}EM(uH~z5`a{soRRpGHx+N&%wMZQ zu8<}VwPvxb2|rk@G?r;%vXDMEAt`&fv>nVBT-H-<7mY!>u}h1gnJ^}J=~nuzx<%4j zD3L3Lij{kckyD5m)NG}9Fu}uO0g1G3c%@i>{4d0X$|zmUfw`S-xH|s57*@S{CwxN^ z-z8nhUzZexM;QX-y3kG~5p%OqEyOaM5ycf06wD}STpQ)Z`88Za$ zW8}7!SqMT|A)5Tx<}##DA}3l2*wPd;KR)J#{9^{iFo#O~M^rSCEMob8Ng;x4<~Ee+ z&G(*}hN)-+**- z++_QW-Pd=6b6TVdO9fkL*j9xty6Gc&xFww4CX}w3w0&gNRo6$Wwh2|+Zl8X?IZ}0S z(lqC+xVL3*bjy>%mM6nU2EyEF;fOD?#ZPal77I(K&cD(~7%m@VtEu z8C$Kzk^ql_=~vPxhv44wUQv0ps8J|toC!vob_z{9BTc&^MQtI|yfy#hk8*S_xND1F z0oYdiZ@bOyYjxjQo7%qJ_?>Nf{3akh@I<04xe5V>^f0c;mn!+8O;fO&Ah${ZoZHQT zyt;|hJbjG>Q~Y%Kd$D9o+1`ZLx9EeCbcda#L6Z#8YRJmjPDYJ*P47l==mz`K*8`=dskOtCI5NaJ?Kq9g){9df+eG8UnEeTIawt9V&6L#MLuUcYQG`Nb4lU!_Kf1^)R&kG?pQ1 zQ{ghes!EBS``^u{DnZH8IsU3DibW6_hU-71QmJj9U27 zA*XEY$i9l3jjuOGoNHhOQBoc z6as~5AiuNZh!Ejv7yaM1)sB1$5=06;3u1a_fb1xd+qK)Q*LY66#LH6Jx&9GKdjROu(A05ebMb0L1P>at)|u zNR^>Qn+)hMfr>d2K{z17FazIs(}5qzh%%PJU|4QXAZCOy)e^mQK_X%l8_ha0UYl&s zv~1El1l?c8hau>$o-su-8UWpdB46IVuzu4wpMLx4AC-7#s_&fp{`kA&;loFwhdJRe zcXv1UTPMRM-cYwt;$18$3w1A)))Vv>DbU|En>}Y;|ADPQf%vA`(mDIig}jyIYPN3D zxaf3|`@5)frQlpSJuvTFg>x^{>&Q&5@aI3X=}HIn0fL>cmFy}ty=yYzH-Vs0=EDd& z@h?LnsN5Tf2UDD@8G<+xFDG4Cm=&%{eI-L2JN<`?J6v1?pQ^4j$?4~WIqnQ5ot9Xa zGfpVVCE#d_rdhVKqXsEVntWc0dV&*rrtpqxA0YZoi8r(u$yz2|LVGy#gdPM-H-xe| za#`TgEX1WH@^LubN2et&9oA5Dsb>P={1WY4E9BbLJ5GI(I8#-GEv`-wNGiOnD%2e` zfHQMo#LQaU>qRSUi#!U)2BG7(FkNAG#|SMVZ(>eDB=WrXazjBJGa{~Ree5ZX9GAkm z8y#<8i}NnQc(K|{l|qYO6c00JPH~GOLoaX=c;*7nHtP{l4i~Xc@ylC6R z7`NZWd!ANO(e*(V9E!`WV(uPb0+TJ-93A8GV0$P-^viJ%(!;J-x~4}W#p^@+ z7gjWe+UD$~3hJt#fs1`C)`jBc8EhrRLT%Ait`oN>h4#n!M!O`ym>Me(n?Sj%yn$ku~u-bo!vC& zz~R84G~9yI9d$Mf&gR*pcT9Jl5_TS%clMA`@%H=aI=lO0Xz6lFUL6i+*Aib?w@_U6 zTK6m6Uq~hSVBIH-JABWY*`5oLTTy$n@jL7E_|-fIxR&2tk`t}}iK%Wr* zoRavA`W5Yi+$SI~a}s&1pg1)R+NhuwH8x>ExPa0XL7AE+PN!u6TG!ApVMzjku7xy} z@lC;dg^N_nhWTX`Bj~k|t7X`&rj$d=)FXXiAa5)0T4t0iSU9Y5ixh?+rJF|+z(OAC zXl?85I?&zM+TP9+T@8+v;ZUZ3CnHS}kwQ4cyqEXEOfLqx9m&j7++vE8 zWyl&@ZUmj+tc!_OoN}D#?3@rKb`qVSqFJY?&kRRmHz2bM=p%WUsFh)h229n(p7D#w zq=hOA6NxuDJ+)|j)x!zB__TkAZx=A5Ib^$C9CcO+&MMf6?tcAZ#JL{aOI}gPeARw0 z18&)7*3ULZGFn5%MI2au>iVgv^O4+|knICou53)&c5~nB`y#G2*eUFAg&ppDB^5J8 zw>#c<&6RXd8o!jbSh9lM3Q9t4S07Vo!kU?iIcp;jXLg=whA`cBv-|b#NY*-V>FgX7 zR1kGF39hDDbA)y*E|7YqUdRJ?KfC^R#kcC-sf*-w!m2epm)zRk&3*-S?GpBBw=AGLJW4dtSfxYY@+?5q$^bqb! z5+~tfDOVCVvy8E%77wK$25?@N_h8a#P?K7y@at0DK$qHiG_(bB9)<|CdclmP5+|<0 z$19M;9Ac9NoircWv&6?Ak|Nvaz$03petgZRoEvHu6GkQQESi+S>L;@Ei{u=WENGU3ZgEAlxIrjx zh!(FEiq}Spn?Xp}v&DV%QM)9lR!E9fGrMPx&)eJXr#u`S$%RQgIBGGzAaoO*_hRF-^3} zlGig>pR)B#ODINkghj4ZUeCZnDApiBa+Ap}#zG`*39mIvE1yGI`3`mLKk!6HESvZR zc|ssS+r?v!qzIfFMvEQ)_cUGpEB*Wf{UpvS{=XrP?P6eC&gCN5I>q0o^o)XklS0G~ z$QG}OOB55*@;{?Qi%7K8;mzr=HG}(THdOpp16kgjF$!G@&FHgq0nVvc8 znukorq;&-QBhowc3#3+AClrC|zP<8J_Vy3DiHZ9$G(kBPZ#)*xZqm@myxUmPma2O%)zMaD ze6LWC-vpZ5gx+Hm^bgiz%>QNQxIBBA1(g<5CyRQ2d3u{>cnzDs51-?p%b9(dRx1*O z2MTkpP_S`&5Ms`gXBIa2Fq$$yVIr{=Nut}}0WW@?5@TWTnK-3lg>ht~xOkD*BFz=d z4rK{eH?bsMol)_EJcZ~}XVenuUByG^l34usx?gHWiJ9CquU>ofysDXT&5T7d*2hh% z)w3YaHY`7>NDJC7PNF8Eh)A@e4U<+J%HS$irpU(IHS?}Enjpo*nqq>0HC=v!6ld-- z>Ar1p?8-HMJ4cV-gbAWZ`1qs=BB}Od^bJ*?xPOf^Li$vLWk-60VNfo%Jw_w`;agi^ z9yp|wZaNKn0KNgwlEnkrG!QRGbeJgLV#|_-v|Nkr#lk`cmiSA68aV{W3MB zvO4Lo9j%(QrZVb@U&N48gF@ue;`K++;@G`%A(~ff_z4Z(PY7xKgqkesTv7*c zBrToW36H6Ye5;QR0{sbnJ)XJXA+s^8IZYJtE&RYOKI7fug=)KUDG3B`jZ@c5xNUddH;>O#88em>m!*dyf?j zA6C-@`#xHWg)4W(ba1wLE_WlHoamUeT-iFc0VfhpbJ41ecdIsn*b~jNqW0B-ef4b7 zynP$&yC+B-SpDMf|9AhSBhZ}kY7H%MaXZ$PV$oKaLq=cWD`W{s;^k)Rbl(> zO?OVu+Yddego29ceL}$+$;?1>HcRKd&2-H^cjvJ=`vGYco%By1o7Xxcfq)8~)Iaz~ zjA8t`v}D?8Pc#x0)5lM`pk9nuPiiWaF0D}apJ_2Z5PuuA_K?Wy9nojn>MCtYR7+YC z&y+o~J(yUUWk`sI+7nb{Nt#;xc-fax+uB)118-X7e$u8|zF?Vgh8jUMjKZCv3KhjH zlOqj?NZE`_ZI-9LNTkBsV}MQ)kfhAxI}aY}=;`Qg>*zatu)Vdn1NIx@Sp&4=qkqJW zjnp`rcto_Hg|Y2sSlc$b+lK-JFup~a#!p>>C^XS1f{~~YzcYq$5s(J!S~}BLlo7Mj zym^wu#T-eEhbcq_;`#5;4=kx?p1A-TJGr>{ zg`YKs5 zUE2zU$s{G5ef^>>f10Ylr9at#W{2IuT2k?X^pBJ!p&nIQzuBb?Z{W4Eic! zqh17-GuC8_JKiT>TE?2H)sV=|$)|=aA~R3^*OuBiWs0964#JkY*jtjsLtn{_LYeW} zwM{Q?qEWypM3QSgPP8Sl=Pd2B3AvD4|KJG(;xVumVI%p(kuVN3FnJ{QWhNTzn1@(8 z9s5p)If7OWdLfN%K%LTQ+&HA(d#?Win9h0J#{X}Om8fjz-57JeoTfJcsj?9)aU8_7 zj~E9r(Fqj8ucSh~C@+B&PC*2Nh*$A?Ic2wM{ibQg0V$EZekg04AzoLL<`V-VN&orV3r8vq3s&C$v`Vc=Ow3$WGePk6zKm6xJDHIR00)jnk6j#J$z9lN&UE zDL8@FX=r9(P||}QU^N|9%MUF%A zq>jtg!!TVo46jhzA&26=1msxg(I)hW_WWv?3>#PayzDpuDLy@T3P=d9`9%YqOycVk zqH426Elw@kC)zAOk5G(x*OcmrIV4e<;>&|A^2EaMRrK=#%K?4SN$C)%m@}z40nvd6 z>p*7Tl9%M8Dpn}hBDOC;o(Sa@xFAmGWj$$EP1>+oi19pPdiiWqRr7U>79JAQ#q>C) zS1L7TkpiR_kX7gj8uY}GT~33Zm}(G+B(M@yVPS%X#Bts62Hb(P2=12KrrX02cUQ#u zSje1k9LR#rDcFkHfz#DOZuLxBBzGO$e>ie+G}(ePN3!8LIp=JYbS~l2=2<*$U(7DN zvGw}aH}*y=*9(>F|KPc3OSjO{9j-VaWFLUZT(o4JP_pi4I%Cdm{S;&i#jkCBW$R4K zTbplfj?f;T7182#Lh-t2af?vga$El`(>tcQ;%&;_pIvua=ZiaWcqX!ApAR+&6>b&^ zH{aeIDeRm~Su7=6qs$Zf$xcZ?G2Jw~Va~N#5m&6AYuOuZIU=+i2_Nl?v^+EK>W2{$ za@;S_;ZRPPB8hGe5^%A?ACY-_{OYXwt!1TM;mk=R2^JFc8bOomjKy*SxeId5C7Jq}lr{Bp}LH7;7(^Au2%>e{8#(q&+0 z=s#m*9yyLF5bP)|0RDw(5<_+jec|NegrmA;4z9IrPiuE~$G%4}a1!3o;J+Ffl8+_f zcgc=t$EPcutqodbWB-3OzL|)xzeXX3=FKPh(Xli9Q-mo=eF(L@SYe;|f+2ch0iFltOVH+`U(mQcIBQ{avY-!1oNiIejfh7kDid1i6 zs^|mr}TO@CL$ex6O^IqK|ZhsWu&@;C%n%gAgHq8PP zZ(*1?>?priTK?M5D?>9Wk5*{g)?RUp0#BiUQwjX+!1boDE7NA? zB2KBhdG_?3mU-vigo@`;vCNkq342b=+rf%puoG}DVN*u`ZpL`U<6Ou_5_F&PPLK)1 zrNTJusfCS6Y%J!Dn?EW&tc7urL%~|0d$n<|vIB(Z%F9hSuE+okfQ@phH4;oi&06%C zY7WZqtcGRe3v{$+n|vJgj{7L_y+lhA<3 zN{%aN;Nf*Fj|QxKIoc|2h}M|WAgRbKN1mlL{o|#>v6Mk5e@5X52(EgVNLro9qGPrc z!Tg-XA`3 zN;p0=XCEdx%BPxlKh7+D+edUg2u{~Qj2(OP^4uBK#pNSPE z6AE}8ke1h2K_V9y_o~*Wx>4j`033v?$pfN z_bO(?>u1m1vBHk{DJPI@LkD(q7QIeJjNi_rlJ65FKKJC)_l>TA7HJBAF^>KnRD7Lgy zB`xu)2xfd+?;fn~?R~%6`pdJWJ$=M`&Ij2BlMZt+Swtf~$84f}qK}-b)H>pDfjaqV z=P0vW!j5pbG!-+5TiR`G{gz^g&W~AuB*?w~9il4ioumAizfF`K@!uirvIJ)^Q4_-% z8$ray(oXdUq$-wR4M{93wOCr)mmK9NVJT4%B_{e~!W91j%>$-j$H_h>2OBWsPMOD%g@d5UQQJVHF-5mcle41sFMo`FD>989LI(V_sg zNK2BT^mf@6QG4PzC0Wv|pqXDy861lj^NQ@Vf@Q=m-frq0UG0_hR<@^=8x)kLkbL846C!>72Ig(KW>#ov@XlbKR z+Bg$<>*B48k$Z^bYTD!ziZx~J%(^*i(*pDQdM_*YM(y?5sm@4NMW_wfi}oi^ zVZ)Pq!I5+Ag_mDo;@(P}K0o~gyuZte-KLp!vzB>#3sl0>D`&>unz%IqKY=;B;UEgA zYsVLMuxxD0bk&@*R?gNilZzwtmZB!2EHDK62iq~i|35@cm6)U&yvwIT8wryX)Bp^S z8T%kp1MMCAI+o}7m*d9y2AV$gG#ApeCL!NU?`h8Q$LU9%ZL}|JsgHEFW-IgO5sS5` z5L!-$Dot@Q(O=Qb`NF^L%n|)1GmhLX*xl2)*d8cDc+<>=dHY(@BxoEsN^2Ga^BVmA z+k-iC-ejcZ3621;x%w1jZpT5C;_N6)JMmIU=PwwpIxun0993#LRCxjPiatk25 zfcHy$7sY3d{05AlhJ;eCA5@c3iy4#O>vczUllrT-sD~jjw#Tm8 z->8Djm>y@%P)l**qWA33=$OL(#PpolB{E18(J}MkNMBJ_CDUD$eC8(bJwBYY-WRwq zGB94HZGtYLTqWH{gmu4)MlYpT9>OBQ3Jv?JIS?7-op_gip{{8*U8vjsqrx52{jaW@ zdiJ+BgbR0s_Tq=U6|RhyH4A0Uv&SN3tzmod;?|wt+VjqyJ4eF@4@I{2{3xq;_Swlb zlfBnlraGdcQM+gj&oaKVE{Ee-%mfMy{#g2LB&if9^az9I#S9;_BZSPIs+d9sBQ5*sw z0TLuY0^G$#+$4&N7E+>iS>mFdvL(u!EHe}VNwg?ZJ|wj;bRsz$mAEmL%~azX(Z41! z)wD5vZ<^3;?u``3iSp8SizAQ$jY`){liru#>$|2r3J`lt6?Cig+%?j48hCoK1ER}NW%BS^;vO#YuI zH7A;`3mMIV<+?k8^6MA1m@Gf6wY69i-V&_1^HySA^Ct6K8wI34w%S|Ltv_}NNW=I^ zDvg$mdH?-yUb-zx_IIct>X;jp%K4?k(SrOd@S`5}w|Vcj=KTxsYh#jKgpdZC@24uhHVx#eIK&vBFHW;Dtn&;eGR8?qqv;5pM4xnI zD`gok$hOY%fhUHQvQgO_09D_|(ZYSK=S3a>Papl>zGHWG!P$2nuG?cMpZq7&nTBl#2M8XM#Q~nmun=_ z)UF!|yRza@ACacX2p?fGk_3UUvVk;f#ruvShmi{5P|Ar0Y?EbR;~0^j4y7f=98r~3 zlo4RWnM1=CFRU4I04t~j6MALzj!n-{dEsFYbjj%De)KYRC{^y!I`l|o{AleBr7Atb z7a7-X*9(e=9Os1>$nTp`Kaz*^ecu|RR7zNH+jImYNH&>xv%{yBLnhC{k=8;2tM~}8 zB@6*BR98$47)ph}7+QxMKlQ;!9kaSsZV(w5$_U3x#M$PwATu)ze<&O6dW`OhN9o*~ z78B)$$XP`jBmDOAkP)1D#f4)GAOADvn^UBWG9)TcBpeMVtq4vle+8O2LJuNXQyRkl z8Qu_2qBEjMgraa(B>$ZvtDKN|$S$L6d_C4|7;&hOhxuXTp*(zwGEr4r8Zo>uPEe-4 zLGw#khTn5uP{^(Y1}hYjuUu&cKzlbEPZ3?wJrX(M+560 z`+3ge6OX*SXzb{C$8_!rf6n8>sYqsOSG{)p>T!R=?i>39wGaQi;F0n4mpjK6|A(Xg zf=B$eJf!e?{!;a&YPhY)Lb!`WMgoF8cJAW2(d{>#2(OXFiN~=uQ?6yI`pc?`mTA|9 z*+nHIiC?lu(1od}WX@&Et0uCvfrS+1Rpk~1bE^>NZG2}Scg;wmTG`skQs`HLyC%8I zRei>_lNHmRtqS*_%L3j7(c19-d)cPkCxrJy1&^?>-amA?TP&6zuFGh#hkI2cnKffc zv|y4JRy2p)KTQ2b#Y!;tf&va^n_ouW(;y*K-UdL@#muEt)&kUK$c3vW6C~-mdMxE{ zP-=8A1>-%z=y0kj00NU6nr>alr1*$NyNK5^h#jaiL31R8{uprS!W{*HB21Jq;@0g4 zckXFwmkB~Rz`5T8Yb}g07~_mBb{5f)Sp2GU8778H=In7s>U|DRxi(xG<;JLRB9%h4 zJHjbYp_3Os3v9>bYZe_sVXZNekESx}yvP*;B08J{$=CP*n zJgKZcP`omQSIm)ITMX~`BY$0KNR2@zBsWP%}##s(37^4hb(CWn! z;um>sQV0X4{y{ZHT;P+?vWvLXr9_&lT@WD~IEMkSA`GX|6K}#Gwt4`ox&%>!dW6xM z!Xi+~6z#6sHfgXmfpjx#@-@_Bp#K}enl@S%Vb=aVxw`mQMns7Pqsq*zmC<9Qmr=do zGihbG_17#schJ?icHwLlZPONcTj_( zPtYp;9%_c60EE#WzxeUd{;`(JLjh;?u;mtsn8rPUv|3mm%0emgtBzM30auNxD(Zws zyAs$4_?<8efSEw)O;_pIvyyA+w5xPh6@q(TJ@(46KxQqNAkIv`bMZ_*+(&&0%BOfk zlQf|XO~9>cxZ&&vU+XK4KM45CqczB55_8GgB8A)7N$*kLM%=A^Hz8M02zEtG&V=6oGT)J~kQjdf zS_dZ9VMq$T6_^}(7W2W-Km=-fFkyNvvo`;TvVK^{;LmV3!Fq3L4 zQw`}1hStic{T#w_Ov;|2=;?D$4P-{k@!J@c`#6;&VnnZ)&&ixwdd`fni3AZT0x~zJ zj<$y~LU=O&>0S^XFWOBAZ!yM5vy6%&OPubJ77FEiDNx3mc?DSb9MdU?k;jccFZC7^|7cpM2!?!fW|A9=TpP<#~9Pu&*kx zSHBHMv18K?99uCV#tbq#p?=2n8OuwiizdoPUOI%Spgy^jf;c~GxoBAsaT*>TE*erv z6z~R&71(V)XGWiljt~Y+C{Sf|9FDj&X&q#6%PgjT72RmsM8lS0)6oR4`IF>=*g_IV zW$7zlc+sNKW$2Ls%gJlKi0#Apd$f3;y2FJ`*}%8huAK`pNZ4L)w5Y@4DPl30fbJ24 z1DP);U_KL!=JO&BY0CF0(YOV13FZ{16~=d9WXcg#!tJEbpJy^Bk-Yj0ZZKvZaB2k9 z(=%{b%ok_v#_rzEj_$tA$aI`M;_cY{MOv=3ZQMO?8m|vlZIG%qOg3Lz8K`PL4`WI^ z5O<@EklUa(Xf88?EaI3%<;7poo2v9JWbGd~)$M~9_Ks8hfMnGUNTJjtK7@+%apy~Y z%pn!SUCd+QM?jA~#06|&_$lnWV(Ba!bowHF@E@Xg@5ez<@ljDu!4=14$8hRQW(f(N z5EGsRPkS!z2|CDC%;>=@k6(U#tbf{3O>t>z;JzuR;N=5Ti<__Y-`H{eV}XK41KE#} zt58*YsA~M+#NKPGf3orV#%bHb|Be{I#rQXc7+Uytf1qt=7D{{~P)6|J$)V=p&A z2bpGRp`pEazx}g(hKf1$o3_&$OeK(86+{g}kDd`=&~F-l+FK{G_xS zGWn+hxrc!m(p1DyGd?iUdu`w+AG`jsY1^aGh=GncI4B77H<9^Jhp~l^S%%bt&LqK* zD(Eut|LB+jHYAAvaWO8A0lg4z(X0~$@8t_{>%pd-ZS8yZZEtUGZQK9E18U{h!r88s zDCoYBgWQKO%Ui6T`jkf=B(wyZtB6NXO4kInELH&{aSj{HjY;Gr9TnFK-cona-qV&SYfY zaoW<8hplrSIUt)qs}^xMZEK?8S7j!A7hU;RhF^XV4ri4caQkAy=$@?y+xE5Z-PhE- ze=Bp(zW?B!<_85)cFYX9^&qIY7fLh)t_B6Ju13L?g#j=o+yq)mR#uX|KU4kffN>vR z0u0m@cYZOvKgW6H&(OyF!TSIzpa0kifA?wW*qJHESpq6&-k4>)dD1iG+&pYiSy5Hv zZPT_@|2slYe9i(x3PxuTBj}OY7hk6x_Zvhx+&e(XOo00V2>!|s(1tipEk>Pn|JPsn z52hquYczLUFI#+&xs&z2?`Q7#D?h!5x%7eH%$2hgv3r3;?%cc1b<`%$TTXv*;%p>Pj(=;~QJY*!I@#kf5_0{=c*#P%;3 zF-Nq3s@??Hhf-)8RbGJC*zYIRW{jim&th8Ib=50KTU0Z?hY z{{sl3*ed=pCccI7p)uXxM7MNvPR~Ng+%E zSBxR2))Ky%idXR=(NUQ@kHf1g|DOLry`;n2uZi(CYfE{59(PR7Cs?#F>-X3p@eLHb z-}c|7_6eq0`v4NV<9+eZQBl}%&}oeg2gyA6aF8pCJ~(2)wBljpWi-_cC)3A8Tt@0F zKma6`h`7`ROztht>qS>arBR20G#>pm;6&rD>M37qbjbWC!ndsaH-&wF#-R7cJ>7_x zpgL`+(qjCEv01woHt`d1c|lH&zLM~g`O{V_KoSv=bMTgdy#HJBCq%vj1ZFW3y(#4n zm>Ntk)Z+gv0(Ate5!+CccnOmZ3Dp?onSkka$}z;oWbU*}h)+;*h!VEJjp7}#oqn>V zF^HTJoF;t1i0|T2L`a&2m(6bpY=49|IoKwe(z9;58b&?A+!a#piePSol-mHoIR%&@ zOM+m=GAUyj%*NMVT^q=#XAzR%L#Ck-`0gd!CEI8@acsuRUaP!XInnmL_Sf5QG~Y2N ztWBFkc+Irorl5n_qGi6C^Gc57ST_C`i@QWxYonZ*bB63eN2&uEn}Uu_e#fR?q&R1C zi%BH))xw~AiQlmV{{4c^#gcPzz**|ImCo5sshjVj8qd-X`pWPj&u`n*xJvlp7NN1$ z@}?;l`8RWg#ub(~^D-&FLO`mnNt8DcTr#9fu%WVh)FxUTuU%p3B;s7OK}%Z9)Ud$*J+AG%pxtx!NN#f3_n7I;mAKp??8Vd zy4qKS`k|-j%owQ~&E#5mH*;5vKReMZ<*W-h*ZXbj`Pl&9q+axm4DYmQc*jr--x?5UPz}K_tT^@d_oh_laYa zd=4WcPEx|~g`VlfkO2`z;>$?Fcdw9Jh9hv{+LiDH(T1xAh3o`zUqOQmJuoy-E@hOD z`2rcxGo7=T?N14}GIE0%B~k`7Z)D4c=0NHCYul$XAimk-ckIDt=*S)|N1RF7oXDRC z@yxWNPLUH=k6Vd{>oleA72dx^>$_BPLWNbJ+PNUepZlV z{;6**y7qj=wxzG2p5m zwld%T#ZpS~Smsp95*$^r4FlX#u+)Jfrc$bJQK-2h37V~zVDVb1c`S!r_;Rlyt3<$oB`JgMRW63&Y~;!%l5JIK+aMaBalKhQx9mHa+D~R zsl6WCiesJfVNdGr)q8%mEG`|wne+6!1}pMgFJ7BX^?mqrPxb0e2hP{wByE88BPJ^`4{t`d6UqNQR0^|BJ(C*R1q0NV1_5O3(Ga_py7n0f;R~oL53xp zOv-r%&oh*^wZDI2Q~Eb#(rIEFY7U`i@_4b6t^peM+QWNanatsRP=@daW&RSLY-tOn z%d4iR<8((?cgK-#Uzl1EEzUaPQ*1-#%Yu9~Hyws0!*g^D(7syDT}(Iu5fPm3yN86Y z2rmiHuz;ngj=NDQFr}MHb10#9g*c6Va3vgStGJl!8+~Bkc+A)1J9|ppJh(a@mgX#E zow||oS}U!cMX2&FqtR}fCOu&U`xZpqdBKJyX$2~UwQnp7l+{|%)T zG{W_-V`v$$qbb{HX!{ZWjuN77L?Q{rz4S#oj+?Ah6t)4$%<{N6fS1`!-$4L(H=I!# zh6Hr_jM}>9zC^JZaYo(P>Zz1U>_m&phnuGy1uD%6$v@)GD7(~)n=fwmrr|7FDt6Y@uZNw0oqZCv10|r+AfO`s0gON7uEW_#|4ciEwMo9Kw z#n&_HCkiZ?iV)P%FZA2j2(St(L~!+_WBVE zU?C57ZQt}Y4WuDY4Ke!{C7z>Ri~H&3jYcCE)*#!*0F20e>FVW(!kjS$ap zc96+kV!qVxk`j5%LJ=4^8KK^2rxt$blGOJJIy zGHzyMxB-nrE^a}{hJgf#Sx_X8qb4@(Dt}|3hvwX(W7WS&WoV|O2nqIP1PLKK{m`aY zwh)PH#6>gA%Xw*%A4X&0SR}%T3sVfo8uhOf&bYH*+Hz?Nj7Ab)*%)xI7;e%CiSh}k z7OjDoq>>dVABPP68#MRfChEZyi!ps>nm*Wjs00K}6mW#PezD3QGz3nBr%%;la2qE% z_wRdfWsHzT?Cti6&jFDsJ2Tyo~(z?Pu1LGn#d2&#?WL z(>+=~)-};T<=i-Ifve3Iofn;>mML3-s;yQzUO#O!a7Cx$h`Z>>hXcI}bz!t^1U>*G zB*D-{wq}Gw+<9Z1q0+DSaON>IIl{K1a`0krJE0^tJ&5)x6L}m0SeTnZJ+M9?38@E1 zxOeAxMgu|aU0MZGgPjauDBc?^%H-0*u*eGz5G<0icwATn^179kJ6bk+?(*_L*0SO4 za|zbeb&yF0vn!?S%JC(E>{V=c!pc~i@N+m%I| zS~lO*UQ6FvW4c~r-@49xeXW4hcvF*kM-O<&Vw+lrvTZG7=Vl1FVg7b-{8vHO$lNu; zUQNZa7;^d2xKHe0V@ywxlhUxwQ=_J0aE*)@0J6n410~K1(8IfY+SbGSgE9qd+U6ay zk@%bz6pL=cLlF|<)v*WkZb%vFcAEfxR)PAEjkpC=MYM;WXlyKh#=OwM2DuuySJUWZSfB+Z3V-y*VT4o*>b6CqN6BRCI3?#|QA!f)5 zpNo0uNfOK}EwH27g12o$HaYaQ9iA1L(I-3&CK;lEWThtNc1w6+v1Ta+zlR#ewJFk*G+ZLwr0 zI9Ami4sw-gGUfgjt>lxG5Ggje;$gA3)7RGr!BqzrRWV6bd0#O<&h-^{X#sReZpBZ0 zL=Ev{AAA>*yt1pu>pQD6_>^yR(I*MBVU*5noS2B4aT&^}4s{b1j}UKxl;OCftCVuN zgi+q3w^KD+C(Y}i$UcTnjO>e4{}W#5xrA)+M99Jg^BxbPs*r<1`KkB+9xwJ0U#eJt z8Q4k5L&2qG@$IC-ioQswY6HG2+RKb=sV)aJLX3wUmv)REfASqd*Gui z=&6!CRpWam%cebB;FSc5qkG3!2HZ6hg5+Ka#em0Oe|+*}VD%o!y$25K zZH}O=RI-(h?HKoxlbeY%f!ZzCvTrP%wjFr?y&{wQnDG94HdFl(feEOt+cTT$Ek8^w zXj&J;P0Sx+8b2geOmb;VSmZ^@ZVG;7R4q~B>@w!zf>enzq*u<(N(d9Z#f0L%Xcs?Y z?QCsp-p-ZZAJ|3;1Swl)Y{7+Z-Fohwtj1oXKOY(OYaNtr-+$?t9RcI*@QX~p1l%X4F#k!zT2P_Y2 zBylxShnH*7664!wc=@WH)?>UM)*W+acb|9^y$hx2Iu=dt<#6EAl~Fps)EKIwOTGqh znm>Y`Erdl`Sh!o6VAYMEzFHl~Y`EAm+&Gf{c3uIPJp)sDtA}^1tl`>;lxfFC72=-q zKYeuCaqNFzSQGEi{ul;iGF=`9WDj`05dVQT^4}u4CkT;Sz6S{5CEoyqi2q1U_y8th zr%)AFd>c=G2e_h8k1G@`!T9RxsS*vz7q*UYhDdx|Kq6y&1YL^wmlj+oi>Ma;x{!GW zVKeifoDSXc59PuY;7-k$uSp9V9Dx+VI36leV9tOdxo-vtK<@rMOfN6_CZ@Nq6(ezP z2p|Jt?*bVsDQbl4#l08z`tw#zG)_A-?ncbTuJYK5f!IDAHSu8VU5%-0sLY~|`bdHx z1DUGEoB&W-E)Y$lp05b7_yvJaIAGE;VV5Ca4?1_UIe;EK6?bx59&6sVW8c2r4@$1E z&~hQCVj8N@L)-4LTG@BHkqH+(xoC8dcG9TCm-4XPEEp>hNMQg?8=Mw{H4>mR`HmLZ z-E!mYETY(75-5KP^~WWRbgX1VB7NH5-X%RLdyf1Sd8?|HGONeiCN>5#A40&UjO<`W zsgzMVwkwdqe86P*QwmksuNr@B+Ob;Q=s3TkM>^a)?Z80@JqbgX>I(QZo_x3!px3j( z85U$IqYJzYf?t)A=65NDw-XgfYIjLb7m#ekYC}zWq`3f_&5-A;3Nu-xu}mJ5 z9dQTyJ9;`50mWeBfwryNo7)lcux)E=qoGYI&cV>_(~isQBSV#j!6S4J;4Yt({15?N zX|0bRe#2>Y#au!o2Gb(mqUB3xSblbu4f?~&C}dX*gMP!pZxgh3q3*cQO3dbhW#rxG zhG(jvb+~nAZOd>o+`vnYlCjOf(s~L1NDMDy4_yfCm$_ zW(<)%9~viLcn&b9VmdS=Uq(1DwuD68^Z|K*ag{-A1h-+>*lYy9nnGkuEg8fMLp}1! zVJFZuwdY0}(gfpNrlZ5w{qf%+3?F@JRoKr=2`zG6$VA$nh;?B=Au8*F!5H{S_=|;Q zgs`JlS)AIKxY(!?s8efL--dDH%9d)ht$4HyL;cBkCzL@f?C@0)xf2+#GkIL@ZJqJL ze?#l+3MO@-bv9E_5-g~b3hIId4N^hF_sx?{*F10R`U_{EUJzU# zG5)bY`DVYXWX4sfXmC=TEbhI~U%1-eu=B>|Y1fl#4D2rdiC+Jye(A)(wCnVJuTI;C zU!5D6a!3;$07-;dt|_>vTIyD+o3BDlCgTHFv^yg^#L;ror( zEZ5quC;!F1z~Vh4X;8UQgp#W#J~r)YF$P6VC>g0~vt;XP)AiK|<6{1yNkD46oBVfl z_e0V*>vTs!PTk1(_TMOV1B*kPCHp#$`@C?*;%)bxhOZQbEND8=xTCoV&NiCbn;(T^ z7$bJl{lViZ0>D)ml6xa*oDm(10M;-UE)hkQZ;0!{#rU0nB+xx}51@OiuzI2%{tF8m zhxg5_-%0dMspKdf+ZQZbBjKN;L8Wh2P3)U?G^t>#d0~uCasNAggK1!lj|FIzeuDUe$i7L-?cQmeETVDTjK&E^2$4ii z+=V9((S0pE{*DD_zk4HjC~)X%sc?0$aGg}R?)#;a-fQ)5Jo6XJ1BJV=6rF{B=dxQB z%P4;Fgfmd_kl%%{2Sq{G63Mk>+%n~=QAwUP{@d^V}<^Rpz8Y?vWyl!B8arZ zh*hXE8puC1dBcF5kvD8(2|po=nbG7;T)>s7ocjV?{!TgpE*%pVq}5{q?q6>9f5Z!7 zdusQoK;g51VdY@_fE&kmKRg`1^1Fb;u!Hf_VArTeV~m!3g&nJzCadz6@|UqK%fSXR zfLJgs@vU^lJS+pI!!_9#*h~yrn+v>?_y7lNgb6h`VB5G-Mkt5tKC9b@Oq(HEGY6y$8+i}fv(0hziCbP=Q^s;aDyX4_lN4egZw`)9U%3HaFD1M6O9sp7J8xKpH zpAM{V4-|ex+2m%j^Iv-I(sN%wFzy-ex>^({Ul$+~1*o(8-K8_0(x9hC^3;rbr#y9P z9G;Dny*K)&J#D{&O2)2ByZlAm1L0}u_?c*DNBW>f8rdzQBMOGb z&=J#)i=a?Sh(d|LK1&wFKJoxJ+&2Q^FIE!{`meu#9Q4|;tH-81Yg9b6WG?v1PMWG3w1cSvrLyzV&QV{$ zQ-;vFu#ifQ)5Mj5F;i9uy%f>2>RLU|@1SMiOwib@hl_W`^((Jxc|@o|m}#`lMF z_)Dz>$fWRpZ#XAAZ?t|aS<0^pWLFRGnDOKWJ++djcKmDro<9}$lH`G9jpSN0F)-sA%b@UB6iXmgvqS9zpby11+_rG%FA-TVm!(Tc?E9W!6qzB#Q0?}eA)vADvNFrTIAqPGLe9d$85xV3$tuY zWU7HiJhntVk@`Y|=G)A0i6Jnjwjf_J4$9P9Qu`;0(^&{e9s`4uRsy#H)cLpL$ zxNt{jRjRPWWJEV)CA&$n6;zACehzk`dcM}$QNJZ|DDlF|p+qB3q`DJXl4c`n6d1H$ z^&pIpqn1BWQK8Zb#1zH>J8@o9M)xUTn&)iK*(Y zB`zMa8GR{62hOU*4D_HV;uZWHvT1$naYK`l0+lb0Uk>A38ePJh2$wzSY~)eNOx| z#)!owjpVYV=+G3?TReoe#s5gjKU1fuD)ApF>7_~&c|fp`wc}_%!Zy*?&o(KZ@U2QV z)`;%=U<_l8=#oQ(vzDV1n%Kh{EN+mB5$kjEnLzQ*fNR&V^;WbRJDqb#Xb&foh>28r zsgis|vyi5wU<~KS^`rJnTi^nE?95Gsan4y3%&C=fK-|4{_UhR{&e{CfwFy) zWASjyNXsaWT`cx9yaa6c!iJgb#eVq9@C9qP+=PK@%TIP*-|2tk@taML&*l^abE>7B z>hVXXbLwYuOZ~aaXXsv~lv6ogF_p6tzB9RVja3sZlP%Ypr(L^bMyEf&!{2$#fBadg zQ=E47&6UG-R2(e+T};)&Se!66xdu|!wepua&{(YFXM&rFIAVHTd_x`uxRol7Vp_*4 z);1E&f?KJyuUpd!&k|c|Ho>K)!S3OZBO7nD`;H#__cj8>M?j+D4a2ndO1>is8iB)bwC#sgzne))Gjq8cvu= zNgduiDzVJ6X5HM@zI|?9(yFi!_*hX9zzF>SG0GSq16hBW3 z;-K*pLjusSMddpMQ%@UA>-K{jb4Ry?URk2=D({Akkzp(6E8y-UGr9&Xf)6p4MYoRh zgu9j@i-yn_ZsWpIkaDzFL|laOV~lEo5m~B{d@<@X5MdE5g6)9q1Z+E~;d14jhT)kR-t*QqWjHTQ}AbhnF= zZ&Ff537zdic5>1W`tjr`poSxKoAu;pRF#hsMoGPkTol(>_HxR5M+BzWKN!QyslLoN zX>re?B`of=MWbzjv=SWQ;Dm6~rA=e*SMy)VhnI|D^9#0_+yWkhW5N^2U2`#QIB6tv zHieA&ZaH&DmwbKQl(S~WokhMi{O%>=jj!#vx?^&CaAT{4f7PusMCVjUo(fqJq?7z= zOnVw;(zE>OC5$Sn0;?JC?Y_D@kiT}s{3YA0QeEjxNyV#6Us*c7Hc(POvit4ql3S&f z;~%|NcEbl>AEV}%ZL`h{3IybLLcNmFHKWJJlP28X%XvL#vhD|)-qY;@Jq|9CJhNGSj#Q?~_oOkti`%Y>K?eLvI0L~`;s_sA^O3{@KKiJE}ukN`b zQ;k9VMwk3P=6YT}uxIfYURi75P+d8&FB{)IZCm@VG%$R76zRMv9!9d@*Yg)*k^cIx z=OwS<>&1^y^}jdPPuR?JPV#+xpv|Q>+ZM1jN?&HBoMqI@CGpZN0WJMIkPhtuwI}^OLB#JdChq;Nou-jR|05aGIjeDVd zgiNB3nBtGNHzH6bESg zSwYD*N|+#%ZDGU-5!v4NS;~Ee5<20Bl1W0^(bIPZ><>MM`e#())0D8?Y!+q3PvU2^ z^9|Vs3|nF!nIVVuH&*O#!@@UcmwO8h(JoguhFxyiuvv{=SUFxdWm}GOy=9PhE2I4?QJ%&$6LaRgj7!`5GL``1Qlrnr@W-RnY`q2W4IRt8C){#RY!p78a} z_3K(fE^W#1TOy$v@g$Py)mF$w2hj^iR`aVh78b-RAEGt)<5+91dc1SWw(9q@=9+KR z{ndt_Zh)_f;FCus{M&sr;6A2bbN<2=6J?W@A2{D|-Z1}F>Q7SxYag9yx%+BTKaIOEQvL$k8q z2i*03M?D<)zWCh5=SCk3ILrOE@@N>Malv>C^EZ*vkFQanM`B_toF`(O_mO=NQ*k=L zBgE0Fi@1j5=Wq(3&JCObKn9{&<{1j;z=$`Zz4c*$$oVU8AHqes?aqWJOb4_`98gmt z@l(js({a)lvUT)yorHAEOEKp@L5qsXrk+O*N(`Fp>Q{J$yD=}Mmy^$Q^&jU#GsZDd zW|J{T$|Gkpl)+p?EA!?%+51da^yEgD`G0A0PoX_bE|GZ4B=@rMdayg(YldyVaAt$X z8%?~l(eEglvsmqE#3b2xY2%npa##8tm3MDBv)?nB?P<5%Mf_dRbEExN&R#w{o;=YU zC|VEKq+b7lCw|(EU@o4t_b34AoEa~C(C0*>SJG-t-(J17!hF44Kx(X-a25q2YcUM} z!vMm8XL>Y@@^sxdcvx}NLqJ0PRI&ic(8X0}OjKt{nU4xgg%~v-;@{KiiVBwjM)WbU z!wa$=tg5b#?shg&DIjJ09zvHPaDb2t+@xXK+sZb1ud*?kfj8d2t#+RzES#ula#zJUK3YBCsQC_mx2Mv@0Z z-CLd1VaRe`cp-ZT-eLvJ4XGvZ(KU-t(GY$Qof1EeoWkvAODN&gNq%A?Bo@Kx7s*#x zbUbPTa#@Jwp@HRGd}7nD#}G31eT9@-F(w95muc+#;hnRHD1PYDA%f>3sCs7Q2eYcB ztm^Uofvgq7+Y#|ra+b_w7k(k_-6WLYSPh+G7Yz*Y2-xt_^3`KCGFE_iPgMp-klKV+ zfDhxf(syx&C#eJ|K&9RdL)oD;IfS}Qeny9?4S&9vKA%_uSlrI6(YEo1NzasXv){Hk z8Yip3@g(cL3LN+qdC5~w8~}W8>7fFom$evPc4*raw}fvWx~|Enda~V{iaHD{Zz5Fx#Z)3v0W&iERN- z15@;soW+RF@C66WHWvlMU-ql0V=$w!qniaUJ5*a+TV1@h=iFg&oE{W3!OQibzJ9T~ zIJ(GT@hX*B6{}2RuZTFcT|K@-sF2mlt3G^K{03eWAEM+hDIue9@jN9LkRa+i%YU41 ze3EWh#9NeSH`pUqESa+}nCz_`&p$}r$B6BYZtC%2?tuJxdhzcK-nOui*n`RNd09ME z+}hjY)Ahh65;L893jZzTSP$>2x$~6M^;Oq2>N~7_K^2P0`9b%duD1}Q7Np%PvXS?=`O2?dx*${BubCD7v6~`#@K>_dtJF=LxmDy!;v}pU~P0$9JR>BCe#$8Hq@$(4zMy8aqi!wH*R@ALF+O$_!A=`{L(e!EK#34H5QVWIwB?SW+ct2j+joesVEN0c zi`$M(<0obI2qT5z&H8hIO7b_a&->1z`9x<=8#q=<+TQ78n0O#VHr? zvocKw)$DEdTzmTuSzpu-X7EZ~(c>+xh4a(`?FpC(wy;uWkYw8b7(+hv6VIZk_Zg z9Gk?gQY&_kwZ;8lnl#=ht>OdcdOBl30(~(rxYu{`h%$Lm$b3+%ke8Fc*|;D>mAqW+ zwLxR3E6CSHj9x~RjXOeWS+;$~pPPK85AtSxkEOQ`c)R-d^d4*O=@-xOS&bS9aR*Re z^xd6CcRz3|{fGh)MvmBYi2E!m7);%R1tfwxZxaW696f)a5r{{6d%NZRgYYw`IgOfO zucs-mw{&#($?uC_RX2-I7`?=|6-L0SB?njXjf?FRe7><`cJu+lS#=_z4;aGFS(5+C5Hc3t7PUl&n! z!Cvd?jXM@J5s&$f9PjNt5x=vvmJg73?wzv7;<(+7Djm1OQKjQ{d9gCk2NYj@Y)0bt zC&oK*dlloIxP2q?g28oo-)P^)Vu-?5gG9l^D9@Kg^eaS>@K@-pvyFUSu(M9A?!o##QR@DA&+L^J0GtL_sxT zYg1J8V$B;P`XkE5Z9SrF-1(qoZ=`xdTZY1UU>zWO{D4kA9JjZTh2wTNvaoS~6S*Gh zX6hF^GP8pib#t&lJxXcpq3U9JpH$DcZuykT$Q9*`O7DMA#9w0%RDP2Di`a6204884 zL}3m-V^|Ql%UDO+(Oo;k@(LplxpX3B=XmxJ?9iPSab~9eumfv!?YZh#M)5W-iJzkP zK26DIC?Vlq$k`4hsGeTHKW#wm?V^|NBK}`53_<(Pi2*7ZqU2|kyhq6$O5UgBpD6if zO1?(P&nY1*E-{6YG)ml*yh#s!NJ%mMB$=nUgpw*sR#CE=l690&&_8h#CEuerwo$Hy zlAV<7rDQiHdnkE?k~T^nrQ~r+n3Upa${nZV1SKaaVOnD6DEAyC&r`zG!bT`JO35pf zyhh0zl>BE(-lF9Hq~zz6{4FK(lzc#m3ETiNk&+Bb@+m2xq>PfKl&qsz}6K1#_2NGsHYNX&l0T#5dz6p@JWTqK ze2bFnbnh)nenQF5D7i_=G$k{X{5MK|Ny)D%`Ja@$N6812{C|`r5O%jxl0u1-k_<|+ zDaog#fRa*5mQYen39|xUO}TZHY^3BNN_JAxO38joo}i?il1@sFQqn_-NXc1BhA8oO&$ z&8M^M4znpS?Y#uSx^kX!b1au=w^q;PnJSk3#*|^*IKMR6x@=$+#4P6 zXsuH?##(rm)v;tApPYe)c^$g)Y8@NZIyTDptkyjF9_7+d@4PL+S}P9&>z*>C)Kj}P zcRnk@x?$dyY~3x)=UA-S^A4+ZyD*<7Sf4=wGrli5!P+BW&{~9D!kjtPdPJDaM|TRXR?mEz+q!YC+VqI7t?pIoX<+KR?cTQFqMn)tZl;l+8pcV`Fa}_^0=(c!hBg8<%?a`Rr6(8 z)=l#(5>O3BbGe+j@wxNMa;;urevK0VR^qnq!i{w6>iG%}8mLYM92Axy*&(D^^XH3; ztqt={LaMc9zAzmyR*`S*66V*ZSRWDQ^HQvjA$6fdnGJ7vB9auenkQfd5J=5z-{ton zy8~Esr~u$#PiEJw^B;KhU9;KhV53EU%j=+rfWO-wW`Aexy+qcXBx}xmh6f$1PNFeDwr0LM4Zu`v z!Dl$w7^hf!*~d|uO{2WZYCQw!vRRK~n0cB+`HU3nv%;OcBHXDOLnMQWCSZ;!d)|ns#SVk~Nq5QgjD%vE?_3Nmec| zWk`~+rFxP47MC#pJkrlVNbWN|DR@m!CU{eZO-G^V^GU~(X0OAW@JY*)7CY2?>?Ut2 zlyA&l%gYJ;w^8a%^IAWd^rY46^d{oXMAVRkze!$~*M`3~Z@SlxzjkkiHyMAEhfQaN zCsQDXcZc$}4)pgPIF9p+&l@30?!+#jUO@0BXsihHt;l>?(2MskLe>8d@MS|n7nE_o zE__}POvex#s~sC0zi{6~yO8deJQ5~V3&IL#d;=hkIHhFoqb|YBu`lF+kQ@y6_Wq8( z6Mdmn`4?=R`h9(%)Q+H1@wb%RrQ{kqt=Pw&=UWw#UW28vzq7U-v97xM+uN6ul)M_H z??PX|mU=NsvgM4H`E8YB6*p~_v#aWdEia_aZrC(znX={1Y<_6iGHsKs8TCU&8dvyO zVV>wGW+aUpkr#9bE<Z}03Nwgq76s81vjY@ecZ zGflCu_I!m;&}_8&Oja6mP! zS;!bk!d{UMj|Vl9t7g1wGJD#!_1#SB03-WaA+~;kMwp~-oeE?UJfYjBPY}F|$m})= z9Oh-{!!7lK7LZlvQzvOC$yk2|kP7#LLy52-mD~A*$!q#3*3?%LUNV2$YDF98Obw()sGNK*`bf1zF59EzMuokU`d=Q zWZ~s~Vl&MbiG_bn2xHD;O3MhQ7E7tcV>uH${Heu()J;&YN^=F%ilnrnG24W7^5Bgw zf4kS8Ruo9{1#P~YHs1#@}YRg1o0~GL3rE(FPWVoasnU}b}r}9kq*BC40 zqJ%LHQC2F(QHanHH4COEOy?5Ln9iD?Fu`Tgo9GVE>>r~SeCU3J8(d9u2aO-~R#8Zz zm_fYodPB(#dJ;)|e6 z`!)OtB_8YOKaP#`Dot4;?ugV+&RKYsa-?h1ao=S_k!se5(Y+G+L%3OwVM{0UyFW^VWWpd z_!TxQ4Ny_VcQxHZKWjn1Ef8k=vY~=b1cZpRQaeWJLN*Cc)-PeD}8G7Ms zG3GIBhF*Bx!uJgo8S%bQIwWi|^*Ave#mYT{IWmS7ILy+Z;G8LJOiPs7w7*Kd=Ts{J zhPvQh>#JA~E#e;`6~9i&Hz@fgl28gi1TgZyGK2d>xk69bX7o)|E`o-ZxsHr8NAM^9 zF%@BmZj5rY-gMr1+4j$9!+)T{e~PDI4IiOAd-QE8&cwH8=-$it8SQqVog+kD{|0Lo z#-F<4M+uAm6m@gjAz_)lZYDDuK6Em&<`Nz0TW*z921`~+C95XtgLTbPUGuf$Qr*5_ z-2tiYK%nlRzr8cqenx6PGgWdnxajOiGxkP!pUPe-Wv`qlpUPf4v!p7xq(NHJFloKk z>|fFlSh6d)c-Ls+OitmI)XS-31LH@>dZ%;N%#vrSYAL^Z!Ybvjo>^3UW$)#^{$(2` z4^A&?oaH~qt0%3~i#E>{ncUfEr{J7$7i^!B-NO5K?53QeV0M+1U4aaR;$Yq~DR0^Mn#qQ# zyvCrX@usKo?yc-XtxlAJ`|UlK_V^bgDsN}->2B%iZhuc-u;;YYbNc6=Gt}T&;REa{ zP+@kLN$#?7tK_ax{rr=IbkBxaRI>Nd-Z6aVv}es+HhMO<$efyqV%$T;*jdT5;_fYX zK0YK>i{ChxW=c(`i0z{_<2logRd?~puI!+*TymBZ5t9D4!$m|$`akvk2;lO(uziv6 zN%MBIX?RPc)pR{cXcR2hZ5GNqmf-gFI-${Qxn93D6+hk-1Uz`tEKuI+Zp=5onUg^I zJc080izvS~uPHa-M;Ss>X5x?BR?6p4`5)zOZqBp5l}+W}$`vS|w-)&yyHi^hn|@qO zWq!Qa-cn=!@iHp&<7$EOHPp8suW+NAKQX(v=bC?#l|XsaiF~dZ`LLaq=x^XIVLlny zBi32=LLTrC3PxT=)V)G7k*NuH4#sVX=#+|D3~oP{Kw$9|F$rCsQAGktGCoGx#T}8|bs}G}^AVPlhC@FGG1l z`-`2$qy18HybU9t1Lrp*c&*^I(kTEgujmiEjJ)OyS-gn~Hb-w%x}~2Shw!%yb~U_} zMAa%34c=5K4zz5eXV~9CX}}8G^h`OgNuO%|e+APEnHG%JGZp&hJTDS2gzUs3E*&hH zo~ep>h@W1&(lbU-8F7#n}#4Y^PAW3NpC7R&R|Nul#=gHSpr9SLB}G= zv4{t3opO|um0{AQO=IbBFfnYKO>vL(2eX$-_?NPjl`fDR1*69i{Uhk8#i@A8v4Y($ zmmK9|$EO_2@ycj@Fuz8^zm%F=RjXdxbam6WwhTAP$LX_@W9ct!j$8TV<4qI&lP#|g zP31TFZB5{4+DDpZi%N$rFQ!~f8EJZH`=#xYZP6@sw@^wc^ruwdWS-h1%oLW4ZITLC zj-=eNnbvFwuHGZ9-gDy+?CS%o+eZ-9vh>!5-N6lyNgE#XKi=v0o{%2z4s19{Pby~f z3P;aguB8og)$lH@=Wq$Pl6KEk*uCLAaPwz3vu9P3qiV`gqquJBnz9uuhs55ovs1Pe zzpAJSR;-gM;5;+9{t;>YBmVtQ2G$=6R6I3o3EFZcTkhym$yN#rXNPmRKjVd=8GjH9>9;5x)AWg%W{F?Hx`U2Bv!e^QZe@5@9>IslE zw0CxQ^!0W6;6SGxEXHdn&e$doakj}fs5~XLG*VwiwRb;h`b|P2q)YQIhZTbD5>r;r zOlHMqAEnP z;}mK6iNv}Pi5B8I8NZ<1Pbhhc5_WdWrrcL4p;LUw+;?JtJ71fndt`maHy5T`w1|q> z$Wt5ZJkdPxlcYCL7K!@N8N@KL0_~67JK)J)oCo_v2DhbDvX_!FNB2hjetFLF^ zWS>a%jktso?A<2uB^nX7ow5CrZD&NNh(v*irSx_U<-SU}TI52GF3qT+Pb88glr+#) zdm5H#;tDFtEZSIjNunIYWNM*~at%~RJ>`fX5GnSGxCXgUQU`>9_z1Cq?ysd=$sMHs z-HwUt6W7s=MDl^?>l4?rr+uo47uRY$LyZtE8Zvhr=@gl<)Moq?w@~s8N*+QIa-1fw zw^&%@6H(ks_xDkBJ@~^D=e6nQ|?ZkoPEYJC#gjJ*!nd zVh26lNe`U-L0?brnWNnuums#ichltJfK}LNoD+AmqFd#kvUZwMX(xBk%iKANU%*#} zlKJZc&?XI~kWQ(h&$gH9$&fYObPqx){0$!&tB4~sQdg)Vx!Zl*NKw2*_vE5n_Vh(v zDOp@3zCy3Jq9yUm^wi3#4ka8rqg2<)g9(VV`G{Ym(vMK?0!Ay8Bx}Wq2dJxdSPDbI z{}@=spQ0k4qvSXhJ+c4#PlyoBbz_t-kGSKbYEdByDqe@dBX^&wK7ld~cvINU- zR+xm+Uz*b1F)jORQ_5eP(teweE+qWc6qd}>&-pTw;6#C6n(TjT%DHVSxoukX4yDMK z-!?75&s(M}>}D;>ykjc6ZK}F$s(i;( zdE2!39n*4FNj|Hm;@w1(CH=Og^tPpnrNt~$dD~KO+p^>x%j(;fy#LGc@NLVo+m;Qt zEgRpl?0?7d*lo+U+m==DSUPT7%5GbFeqnQtm_O$@zjY?fJ+f!4*1xLB?`e|Kn$K_l zZQ^oa`MV}0b6&w@%RPT4n3QufDQ7e%kW_Ns0&O5+)19>Ea)pACW248Utcp7(`f=x> X`bQFkO=Cq9+0x>5zcJAdHq`$=5fKE6 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/sticker.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/sticker.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e094dab07cdabe586f418b58999c9a3a201f30fc GIT binary patch literal 21318 zcmeHvZEzGvnr2mZb*t6-XbA}n0z?7gLm(u;_)GY!kp#3sAC?+pH6yp0?viNe4{cQo zAz7YfZSNgi*k}7@c8qVvXA!Y`#^=3V9Q$EAVmAin$C`=#G2IqB($q3Bj<~&u+t~Yo zM>xjIuY2Cis_N=iOUB-roB6S2lgi4q_{KTOiCds=?b}$?vOiK7Ai}6LY`!Ks66Qn zd08GQQ4y+$xnk}_WwI(%g)~>JEK!~Gg?!1HPz`(cBx;i@LMxJWp}J&!s6M$ev@*FW zw2FNzPu!PW9a^1S6IzpO2sI$h8(OQl)F#v~CDw)3fnG&oeX=ps$nsYvHYDYc%;Hsv zjmb@+O)TzBY)&?Xwj{TPwk5ZRnv*+1JCiM;U83L+4hga9mxY*5se0eZ`y6UwsWnKg zRjQPl_a!5}m8GvhdY#g0<=)Ct>yf(Bmb#s#u0ra4%62R74wkwascUShEwQz+hL@#K z+oaUIF4B(byunk7+#LwYN8?c?r77}uyfk~g9qF-2H9mSOBX5s3%X@e4d0^L=s%T0o zBlkzf#xhf0Z=a$j?wo{aMvyi}a^U!#_fYv=*Bvqes(WAPFCtFUg3jh{@!wNou}EKa0Pj%SclqeRBe z7BBkImR4m=NhF9u9PMU(&9|%H>lrW5vzCNR60pL@mf6ri$=!P6siPMsJm&f zjMaEriDoE;T0W9aB+?VqwP-pOi&KBKb}t+2$jS6sh4qCGZz`QZQ+X3;09YgVs2ZQN zQxUZNq+&1(^~O_PN;12H-i@EsG8p(cct4g_S$)ObY(@QtyX1l1gTdqe{w_H%Aoun6 zJ`?Ed>XbM62k^eBMLr$~9_~FBl#!#~-xC~^dk@O~ox{wy=={S0+kCw=tA|KAlnn@IoOX{y1Ki1f~}|(X>!*y zc##JV`;Q)_s=WSVXnjBG>6bft`v&_1hYknj!@Wm4yO4OG3oY{>INHUlLZ>>8`UBl9 za;LxBe~4PwFZY5!ETzU7QNBnlZ>45o95T9Yd$Bwsdy+kAfD4r>7uutM{Kt zRyB)yMI?oZ!q%nMT&9;Djb{`!lF+MygMD4$j>BCY7`#KebQB9j_w!dj3JVpzMb?ahBmB*YA z=B}7GCgHDJDT`qXd|7(mpb_%KDr0VZDaYS3{Pj+Hnyb|N@Huh|wEGo9q-%0S);J^N zG4u{gRmRiWDxZb8rtyl!lvsPaytj3?^$C)NWVoUtod$r<0RGu19aFR@WTJu`5RTi= zVPByy=F_iaAj%-f1kJG#JSRW)m^@iPu;Y{xJ)_BS+DZzk&<3Ua z-Z-Qa1Y`u$6}#2FRO#&Fsdy|;A)d+GAGQQ6fKb9p@MFig*aJ) z0|m2^8l;^W4=>xOfg{J{Ky%!vdafMLGJ=fS=uDj7mh#1`wkLezhv${kxOLucN>NUmO(5nhk^a|T7(aXXo zA?y`3N^+VW2mXTh|plL*R@m@%js1Y$tg1ZxKBsH}*NLy8zn8Id|Y8%+~)Ht>gwQXQb zCFt|?ctpik)YdT|?|EQvTU0}MGM&+OjjHMKv4`8vDyg$=iTKI3u}PrA)cvh{_O@x* zympZYjEpK;8!%lot;X66=CzJZ>Yi{IxHS_FPt_0bxk=kWtC<={`xaIrI4{g^Yq=o3 zQZetTe9d>!cS-sO&-w*?5Te91^C?4wF>j11KN*v;U}H>NgO4Voz*PG;2Yq|NG41FS zUUNnrqo6v3q!*kSmq{9|H&iP#h5k-E|J3=u(SkP|udJ0&@&zZT8>$C#K;a?kNV8}a zw98f0E~}P|&#VbF+-5DH<1y1Sb!H5$vr^48s`GSB{>_a2X_<`{QzYpN>hKuttT1yH zw4mHps?y9ciT;YL&l5tkw@2NG59%fan1XE--%Y`03YsX`f}mOC*|s6B`}h(7kN_-! z_-L-uosbtiM*|g+DIk(IGSqKIORc5YRtkumx*b8Yq_$F=RZRu;GIP1os9?U!>K@9_ zf?#S@!MwB9OA_C-83gBrTlY0w+BYM;)&8B|#|$i+ue0fg8?m{bXs#!E^WhkMXqcCqW`=U|{q(Z>*4BqUlCqEY z&Tj3yAiY}oufMDkc29{K&8oK>58N+VVgv~S^^~my6%mLL;WVWdJ?BJqhbUx73b5xi zl`49cnD-^=nKNVnV?6bMxkoXmIo!_VJ|At;M3qcQ`HsP(F;uG%==EHF8KY-NOEw|i z6WJJRw21j=>TXVZYK473dD=PT(unMN;kH|-sef(y;`FD!V}I96b{oqUn7#lsNxBPX&?J(qnhob?T7J;RGx zLu0_E8ZFnQrrLm@?!ae^8*6WIQ_I5GU8$vYw*F%qV2S5ZaDhY)8tSWiZSvw|*0Y+m zqo>);#mqWE=T*JQE3>4y;Kj$8{K2- zSL$Pw=BJ<&!FvMh5tmG)Q!vHiVMMh32woOGcWiQbZXXuCweItQh1CvM>w?js2bW725FQd)=hY$TR%%>13u_bULZqva>CUpU z8L&D+nx855PEKYNZ5XCGvLqQQAniTSyP(uSiOW-`WP^oNK_o-il-1N8fnL)-Y<$dX z(yf?RnYc1ch#8!fqs(eRRwY%5#B8pB-zm~LaGQpV2o zM2gl9AwTLem)Ii_SPDU&a?sP0&KyjSr(#wDB@({p*(bn|n37Onam<$?LqM0RrqxA- zG=q&$R3b9(pqxQ&dv~~wYZW!rJnOxX`Bt*otb&0vTA6Rz)b3_`!R1Z7 zQJY#x?gTNpR6f0VvR-a=4JdmYI=n6sC5RTnBP0%({t2l-6Iwpc*ZLshQ#H0F)JlbD zRcN#_zx+SKm)N#ih02=O_Fvq8vtj34!`>YJuh@HQ#oFw;gR?6RWh)QeTG{Z%@i)Hp zo#*C!o3ozHS>NWn8sW#69`QTHzY+bS^tUd=3^Av>*z9aBQ;#5zdX$203VIRfzHr!P zgo5;0U|)b%k*JAf-nD2n6FuJKJb~R;-y3LmFs7v z^}mwVxSBo}5OA?X`J?z}J;qu$^&e9xSws}JZMx}KeF9wfDNzQSj1F>Seqwp>Nqd}HUe;3vngAHNp35zMaZztH*W;eXoD z^v={IIoR|6kC{ZZzJ&wu><+!KSjCkC^RhqCKVP*x`6tx1iR2?W&m zq(m%bhZ#9IoOqS4MTZC;Jqm8*F zir%%$!k0_qXhU%@VYFGN38XCw$VZ1a*1LIrVI{C5JG`i!PCwN9@wU&AAjXeO;r+Kq0yGn&wJF|5%{ zBla=DrMpIyO!U;0c`V3gD@&R~Hmx54hq{fz)*bJjxO`%6%LBPB56o@x=eGE-HGQ(} z`nK6EPt9$3>VkBO%oQ_dFSpFrwq0~za9()&XTBAe>fc%W*4iukZu)j-J-cta1o?=_ zG4PA``!|YzCHgl=f4u{-WsC;YCc|iuHw~x(Vu)cM*u}?TfU7DkP}>SlC|hJZ|A(5( zive~IXfc${O#*&;rA4f26fotP7AzO_gku?){qKlqO$f*gunuN`M}^vUSOFxD>s#VN zz34h7E|98!$6f2%!+|xGjpCp6K+w>0ucx2<>=VGcf&**CIQ2ADXyf#gP($QzmVnwz zqU=4b4|44ni1#;s@M%*YzbU|8`nYo$;`a)xfpC{O~zDH^*xmF_}3Y+(t1535F4~woiiPw2tu4R8YVE0Ua}hsyjhuDRft3 zh!+dlRbz8g@23)MH>YNpkEJDi3whoY3XYb(^2iHl*rJ8KnCSpWGem_Tk-bX%m zp!I9j6@bf2p$$U*Ut3oojlk-a$tFPnEf2nw&}HsXS131*w>E<&KW#cmu_y&G3KR-P z5CH$@QGY&rA^ulKDf=)5g#Xo36vPq0tB~8k`xq68!VQ_Xe+Ye^i_G?azAlFUHa+`0GIMaCBmRQ|5`s2GCss zy*tesX*LwB_mZ>zeQF^db|iPmG>-!ED&*7EYDRE8XCTlbvqu!hNOG@|DLXlW9t(D~ z0u0rFCg*bzi*+w60&lWNCO=v8Y4Gb6v^tbNFWkXdTqEc9tZ!@9vz76;1U#!Y*s}ymK=7;)@a#!Z zs11k&(AY7JiP9crAPq;5{J>`00-e`}ZBU7MO(jdxC9AI=GAyYn$aRj;%hqacH^t3>!ZNBX(jg zpXYiz18NOLrU4sZ>!m&L+bHrS5Syp!Vp+}u7o(dVd49v@nWMQ4dti@OdAVo9j!rjwwcE^pS)TrU^{s6O9kkqHACp{sn%s)XM9yVPGhKGSbv<#iVW49R| z4x}K1n_Q5 z`Rki_O>}Od-RPP8;UqDvqyg8q$1tYa?YC+Qvr(_HnQz0?HZC2RlhHY3uq&CmL>cJJ zqhRs1QtA*blqXSu+iAB8s~X-s@y3a{m0NNvx6G}4Ft_r-tCvjG*(SY(g{4on^UWEDW=2+$laeFYwf}+(RD)nm3yV@5sucW zTonJThxTkd;=+pvOQQ8k8(Od8Xx$;;o{7ucJ7d*kZ8i7CkVh$}|A6d0Kak3W;{Rg4 zSozEDkQd**KM-Rzu?oCZFx+1W++VA%MMEOPkWEYD{`~3%>>s7;HO3-?t@O8fUB$N4 z|J`Z}mqRX&zKI8f%^v%^Wwni*g*zGDOUpOwWICP5%e>>Klnh-hD%ftwJIpM|kUMJ_9Xh+KFp4fTG_FfdBiqMw@IyS>{R3|%N}8lf#2@4ZVhX#$w&%5 zDq$s=J{{NK!i5Wce2dnwanjzvzT}y`$aRH|5op(q$hi3tO~({og7=HS61%ZXE{f=k zL7P)qbn*~B=| z5I~PVc{8@D!I<(ExeTdI`cz4pmR>`ejJkFS6EgYQ6+QWDIVs#TL`{~%3tGW$eIU&` z3eS)x!k$v*XymLkzfTIy?jDuwy+QSLgz6g<`~d>oM$9WZq@%H1+!oDp%1DD6iUV6E zOe4dK{uj#06d@NI7&cILMTch#A)9%mYgcscV{_I3EjBIZ9okMc6e^+RymRiYb5|;^ z24^?4L!GIeB&jJX3EV(iJ{p@dG93KP#0NTxtGdH zJ9SI9xk6(=mPv9`X_^VXJ9v3;ru%CB)!2ulABj&;5R5(Qcytu4mRql}$k4E`2BB`>R$WTCkpnVEXV^1(L| zG3(p#5Whn*N+5;HB)cFY56HaaCUMu19!Ey_M3Z)rQb@Dl_A6Xlqud1bjh{APGz%d| z3GhQi>4D>rjK1Oy03mBumJd(y$b1jErdF`lo9lz+rtUHiS$OtV(}k4hFFrr#+miE< z`kB0(ob~O?diF8a_h2Dz1{r?hL`#*fGeq#K57u~)>?B9Kmq>oT4ANZxj0-Qgrp3J7 zXk1kBKJAK$)XZr|(H954IM^3w!Ixd-Uv)#sX^tLlzBx}@_99ebJTWJ%Lxx?7@}MSm zp8&JQvf`L|h0;fKrQ~bL+ijo;t5fka?V6U}CqChULz26|A<3N~H*WTnZqc+me`juh z>`|5^hds(E3WLHcXG{weE)wiunzbjg0Sly9v+lyrN7!!(*yjfG=EuZV3UD}0xW0&r ztr@p37dr^SQOHYK=vl@MfIbsWF?MZo1yClqYpvWp4qGUe2^9MTW>!Yt%YJ4AjyPJa|B_?uQFd7UrS4XBC|T4 ziJ?t+gJ!rlmkk5S1E_=YWsMDBzHtt)Z?XD=RD%KzaGCkagQK8aO)+-D&ij%wulZAR2 zz-S^8Rn+5DLZ*OOI_mk)$#9WuqF*kWH&Q0jhjHnlmEu;-DhXBfzak*3Ji9T*Zis0l z$*3cExCfg=Je#Vuuh~{g`b!e$pCC6kj2sk&x|J8oKCAG3cOqBOIN!MG!lBm>UhMs> zV$}~ua}`_Wx9mnjcdl~NXB9O+D9crBxb1LN?Y^~o^W5s~xz*dRtejol_PXn~M_AMN zPSsmgGtn#evy{&oHyf08wEp?d_jb#sEW%YQ?_x9B zG70<4KJ?|qEggb*W#xf3;cxw`5dBe|c;IpANA+td-d28Kzw<{AJ1E{RQhdLJIIi{* zAFZ7Ud|__vY-gg)@Hb}}h2*xRGAc42oRL5X(^Kq*imUP>WVMUQYDeT>(9~jC-N~*l zk-7t`A!Hkr*HI9ok1 z=Nb6aGjLZU)$PS6{N>_xQS_Hd*Bx%eO#^8`Wy@MeZI@YD1BaTuT92kS5T}{sBOH>@>L7oRSP~! z8xw_x_Ww$#a|OlES;#daYNI9R5ElqtLe_{2{|ynlV^041>a=yi<^>VR+&ZZ(rBt5T z4jyjMC^mBK$$82>dO>spnwe$8vyb~ z!7oNt8k;t|7Nfh^iMV|gsH9M{z<~~FG>>qqSy}(x6EiKdm2Ky{=F2L-TQOJDl&fj_ zw5;ituW`ne^=-*|w#=7Te|P8Hip{wdn?Ehzj1B72v8-=X*0brKe5)?GE_^%dSczK!aA|1Mc&IN=F}nfyH_XZ=H&^~HM`*apwJ_m9JZOK)zFX?rLsfKyVV}l zLD#xR#^H*OYuzgC9J(7m@eqkB4X;YJB9(?jC2XM50H|bGP>JE{+X!@bl73W6Q;Fre zi`|3e{(aRfVLTI0XewI{HB^RKX$a-0b?iI+IF`o8gp?9CMEIeYFt8tPlzU8PCflud zX8l=DdD+l45}7J;Osn~ngUYqnBS860>#*{ze+JS?0-VB0Sef_K20&g z0}KM)^*qXNy+5x01=6rQ1?|re06vJ~=Z;mP^u=yL-24lndrs)i3ElrFtoYx;x?c!Q zzYw1N2jSUY2>Wxw{@aqf!g0Rr^BO^_{YR5enN_7&-72YM6KU)1+@?YXO$V4s@)1^sUj%t;OgU}KsvY|+YKXydhpjO=$8$;GF>H_JcM zZrm0fNV79<-n^f0-n^ON?*|8E0m^T_|McqMEa)6g_59(sz(>A zo{~qzwpaI-yzrHDsp>2Fs{WF{8Yl%|%%}SGV70H*$J+s2uJ)Juc{`{NR0m6g)uGam zD9`{K1>Qb=xVo#fi;v6tNOiQdo45P*J=MLXz0j6R`#i#|pblIW)Ir*R)9cz+8f|z( zLrP2%1i7$E$y};H(prTY7A1$F6O!dAv({kR%BoEcS3+d`*zt*@HAXFJ*d(XaYWBJ; z&r?>_EK4&DqFH2>GP=|tD@-wLs)orjqm-D-q_V286&fbCNfe_&YLrt7t=OSl6nWt3k%;+fKcXfh7S(l>pn=`o*N$~z?ki{kY(Re# zBCdCB)vTf?a@!MtXt~Y|Pzj)*yCy)!HD06@8!2e{vZ?Fl8oE|74OK&bt(eT$T3IqL zQSOVoyoPCmsjdmQ0Ne<7RhvWBssgqz(I#M^S2JWJwcG*k>Pwal3$Fq8HIs3Dy>3Q8 ze=x%q590qUngY$lbN$$^%{Tq0A5 zfL5T9#2M(2d@`O+qbfOG1nYC4Cr75T^9#AuY_dR-+4OV*h^G@^S^RW5;i>|srqc1$ zT$oJ9=i;+yU5;cyN=`;L*E(`GnLrZii^JbkA(hRb8&la#AqU+sc$q7-r=Csa6JZk1 zrSf2^Jd?|Uc!U#XAZ8hymr1x%5NZxkdqsc+0V{&jZCj=j@ifSS<;gt29Faf6ToMwU ze#L-5;rr6cguITFhMnL9vo(wYMRx`Z3-gKcR5CFIi#Yq4=+5%hZB4gedN8R#fGz1X z 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/template.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/template.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5d332cdcfa5037e0a0d9d3b79dea5f74b8de7b3c GIT binary patch literal 13242 zcmeHOYit`=cAg=J6h%s;ACev0ax#94UYU$vNmhxsOG}i*Sf&(-N^E9RYQz~ywE5bZ zp=Ghk!pH`N)9w=}>IA!sO@IO$BU`NdtGhsf+P^l7qFAy@A(eH|09~NnUzJxaw#~18 z=gxxZ-0B|m_hbXf0NQtCcjR^^cd>Sz+1SBL7D4u!x^!ZaoRne5ZE>20sqF(lTClxi9(X>n478O-Phr*mLW%8N)f+%^@n2K8Jix@^L%>oEQ-!@vGvcSbTUuj9!_X zicU{^C#J;M<;n3_6lJma(D=-7EIuk;M8Eh1G&u$p#-ND_ktQ^Uibbbsu*=b@p)rgc zxfmOdC9V#5M`DRM#uP^|XhfWhOeJDNGvkpdadKvAa$-7)>4!0FJQg3B!Yt9t(Rd<+ zSy3iNU&f0#Jr)@sr>VS=8Bjlkd8WjniOH)|vC*-FI5sgp97W;9C@70u9FH1PfvKVK zNbK@}I2^eg871nb#0iWt<)vl@b>b^yQ7WSOBKS9yh)u+ajiHHnVhXPV;BqQqcYP%` z9UTxOQ?Y4~>K&Py!0;qa^dOnVsb4&5j6$Mj0GO-NufVA`f-I2swpSXiETQ{#~L z=VWt&e9b52p(t!$YC)mqjO3SVo{1vqfRwFuC$3ILQ$u6XAuQo&O&G^E`8iKLoi%S! zQZ*%|XL3rdH#N7cD_Tk~q~;_|dFEV7mUOAsaXB_kykH*JXepDGk?|yyTrmr)5XVbk zsF2S?^D)~rh)_@@%xH?5HY}o%(tLRM%{@r(a0-{?VYnSKpLEKOH@T#+>;&b9QX^_c z$;;X0F{m=<;grb^aAclnyXnTETLngBC0UlSzIrV%Bg`033s zv8#n)XH;dWoL*G&;ptN^mhzc`8lEnyWCUI+VSYso4^4}w&z}jWHKcO|T|2d)7D~nE z!Z(!sjc_(I7cMSi^8DG*=`&$1qbsM1Qu?~IplD%Ow{$_3!@4Q@P;t5DOQjYR$Xr)b zsq(2`DZEfa^Dt=F{77zb5B+_WgHx;i>56B16D3?c=&E^Asl1d^QmL9Zm4d}BWhvj4 zN`0{;WzCw-R7%T&iBwA6k8bKNN)Ax6kCL5MGJuTMjpR*keaEg_u}y(@C3vGHHEPln zb9wpAZ=j|@Q~WajrjT?h0_n>KsG}$8!n?EK-Hmsl;k^Uzu7-CH-rWuFow8rcCtmXnIp1^LB?DN88F9Pqtce=n$1wX zVwzKr;0+WX#ZS$LLrs-a=|U;5-{lz>8jUR)$`eGke5gI)4LzSjGmZ4_7WYYD_t#h6 zT3HL6s0L0{JSYD1NEZM`RP`iH-9RyEd3k?(imAg3ZAcZX0kPr{A4BRz^!iPtd`&=y zmdBF3lSy7BLTiqU+{!_%gKS$WBbN`h=fbT1Jo;;7a2sS!jI0HYR0BsUo+FQ8=Rc@4 zyK+iyPEk{7305{WpOqH0RxZ@jpsd{Ao`bF3hl!aM1qxLIp^7K8l?}8tbf1KLhg+tj zWyCOhE!t4qYmm4=CuT~yNywdWx&|}d&VGcpX+B2exsZ^odkl(f1A=0D*lsi_GWHlF zDd;p!1EZnlrjta`HR>&j#xBDq)C;PTQgVfBnQeDly~#NGZW`3A2X-6OwC?n6sJUwx zDwPzV$xQ8}BP?~J00^8)XL0)L_hgRLZVv5|9FA)K`3!;hKW zY%{g}#3WuO0-|f%jZ3Xso)sIhSliV!lwL+1Tf{A-tG|U&%Hm@vX8mT+N~3cE7T&Uw z$E$(k@2abTlNHa&t(s1&`uhZ|2qIj9(Z9njaMRo$JC}H7#SINJ4$PFI2+)fGhRO4ZqIFne>Fa&_FzbrP--JP4Bu?GK^joitJKdBG@+`eqW9(dS3Z2H za&ThRKUwiiGC{`yBi*W^!-=d3@j_k+3TlLAC0^ALB;`&5>8}FEzZTq~_EGUcN}in=)OGJzrym&Tv{n0tud)KSy`6q!qr6y$CILm}w`pcC-x29$H*w?pyF^YRXWKv%L; z-f4h8#iMv+&$k_&ob{i)3oy_PIJg@?5O7d2p`eA?lK$ncV2?_mR{Bd&GNqWY8BLVL zVFRj*HdOa|VR6M!NW1|*fxI$VR^-7!@pR~%QDwUs8f$r~{;>CSK~@IE!E_ekn88^@ zIc8Zg4Vpl#!I}r*09gsKDgX|x-XoLO>pjK_OJa@!LFDxz#?d&yqNE|rpyVmsA{!$S z)~}DWWp1jr;tUoYMn_rE(rSizp^xd`(5n3~X;qPM0@a6@0hX$BL;Raf9@AfuQ<7dE z0*3B)`7JUwY*f+7U5LuixS2A?2SPaK_-$>!D5Y;#)#<>NX+ZmWpS~Ph40Oj zIHRTH3~bz>XazG~wf4YVp^%+@&E5sCEW&43)aE52WiI6nPALeQhZ~I$7|Dj7t=sWT z=xJ6P^wtF0N;LxdT1_AwulX7@wbo&(T+M5)In=A>tuJ}4t5Ik*kHtyNZFq3DM@8o> z88ZCwo8*YKx{L6ysJ`V{aeTlVMLf4``&H8@Vlx2KndnbFPGtg#U88Zpx8YyWDN^2< zu!0GeFG!YO>qUYCc+Ua&g1&W6*Vlb-`Mxpy*PeY_ah81&{|xjH?J`fkf1|^TGKX1a z(u{fp>CG}5KcY-9%WRHU_-maQuH}(k7Wc0^Rvfn+GMC>EIeA-};q@9B=$5B0J5bqS zRq7OoV9z#lx~(~_U-Y(V`<1;rtX|eHdfW7Za}RO;x>G0Yz#f!!QkmV}DSOF-)Txj? z?K%Fw&+75Ipi?ZyXzN@NzHeVrU~YnSMooJOcgvi0Re{z4tMxJ$^vBf~@mlkh2rV1_ zyGo9MdYO_qB@CEPQmef%*03v?GAv=!mIySy!RKU-L6B$q3SZ%68isUNC9Dk)M02W_ zD6!|NIpH~|OzC~bHcVl^ss;(PG!1k(aRf4aqjpinOO&vYUCc>h^VPb{U2OzDcbXKM z9N<7?1Tk-n?1#CL2wRr}^^L?ls;{9?`x_+KM*9xFJ^v1cRXQn~tL_`H@>cQ5(EG1f zPhPk!eB^mzeeZ!gH@|uF-Okm$CvSJHho7&6hu+ga?D^?|pBz|=%~oTx6)CqG%Tt)< zXU|6NAN_IvgZ>X+SiN{<_1UW^3_NUC_(`8wIW$=9d%oh?_wewscjd}wUZ@_wuzL7& zD0us5)$`QD9mn1u{=ucYmpMbx&$9KA?xu7Rr4!mHk90N}m%5H)_8vT;hzfkV9(8YzaANM@ zi__IOpe}sMe=g{5)ls$;Y)xy8Q&4=44oAf28qKg#^d6|yXb-^c_aA&){%+=-%-gTM zfBat0pYHpUefNAnddagvk*=iW4JY3{&u=)LonB+{Y%7a-$c}%R7H=IH!{3wn*PSa40@ub<;#FTg zcv-iiXw`Pn+AUW*Yu3Iz5Dw^%@>0Y6*>#F5f0ehHkF z$F(HxOo4gw;_0UiD1;$VME480t1B!S5X`VtW`l;|>Ttw>D&!wnfP|SFBm}Z%XH{hZ zKE&*-Sd>)gDB{7QjoVd(a&8a=^;&&?y>Z#4W}aQ*;4T(7i+Okns+7TX^q_JxJvjTa zlr1UjB4!rMYPurHK#le+G~4WKEPn&GUXG{>?522jwt)_K;0CdVi$fh+yc{ZejJHA6 zB!EVbgCWj3H|#hvOU9)M^gYEo5*3 z6%sF(;7H(_c@lTIVC2Qg(S`+_ViAj0Vo%vKSkT_;npX?Cl(mHo zGfglcXdeEAC~5*prRFoQKIw&lf|ldn#0aK0RPMD-kB~VNWAb|#Px}HA7RcHd;kmsB zZu{1Kfj?NP`ks8aKYUME-GBb}rB8bI-Ffw!udekTtM(pS>m9824*u}mpMUm8pS>@C zcxkow%39#cZQ)^{=k25K%HO;G-t~_HXDXgE8%}P=RsK^Jw0Xne|ohDNCISKFQXR^Hz5MCntOmNRjS`57swa~XuV@=Z2?WGff)Crshi zzj9&U*$@v+OV+T(3;GCd3FW5InE9}_bUl)*+(h8CLGIfatvaig)v`8nvpHwyjk1KW zgehZd#s=!(tuRN0;2P`@`6Gt)>88*_-Rv+V7^2!2DIo-dyHIlY3`0YR*t(YysB5{~ zA}U0$Rn%*QDGjUg47X>0qxCpj?LB*Mc(lZmfE4?8Bo!4gMs!+M8GlB*>2J z1&+M_&h>l3M}hMd&v~*VGqxS^MEdy$UOsYMc;M?p9;DfhmTgmrL>npk;msR1B?HfO zg>OQNF2ZjzPabOvhIFksP~%`VZQX!&XzrTrr(;0#frV)U``ZD2v?O!i@-*Q~XA8cx zJzn%}OeM52&PgQEUlu{@83fv4*G^49=@)?S1? z&nrs|7uL6BL$t0<_>jWb_2?nt3)<-|12zoNuuyFwTb=IzH=QI+JimtNtXr74N~k30 zF;HBC2_>`pcoW)y;aCK!)=`v}vjs_R3*Q79u)(m>>px*?t&GGltm8blyZ3g-Cnj85 zfAa9{(Qk~rHL>p7^X-MI@7VgWr%`aZ+I6@EzinrMD>GkM?R{-6@Y*&;__u8%eC(o& ze{h1o=oB9G_aSc^UNT)an0p^D|C7NSLee~3ZWnX89n#luPPCfDVI>Q{waF+pY_b0? zTll|yYa1I=6yu0h)%RFHW{a`yE;|WzYxvHo<~G_l#5|3Hr?Ac%ef3~$qoW+YG`RlO z^)>&KRsWM~{!rB)dS71)f4&<2{91UZ8Xmfz`0>>TS6BTLYo3X}@=RDBjVH2;A(0(G zB5vfHHUXW*IAZxt5t+vX8M*H`5a4r^M=g9u7JsnG%8Mm6+n{t?5qe|vrQAbb+i8Pg z>pRR4j+`*!)eOtEipYtf%Uw2l!`oRBj&ZND(Z%gL4u>xDUgq6bD}mD$&uJEqqg7!* z(ht^*fV3S}o-|F`2vvZJ~ruQ|ajMq>bOiCWAfskvCZ!)Q%-2oR6; zWJt8J^<`9+yX`wS4E9>Rr5dHKftIflY8|N*{s#esG@n8>`$j>f$T<57*s$u0^qQrl zNQp+t7$qf2c2Pq26~^@x(ZnD!eK@HRmv3^990y#UjX~c|H$EZV?{Mwk^z3vE@tem5 zmlr~P{v!X+T)*q=W`gf?J+pC<=X(3rj}1KP4B^eq1$J$8P|m~cIkLgZyqtH}rVnMC zv-~dCB)`#*&l-N=aJkN~PZJ(d&LD|NXrH+tE3|cq_WEhFO{+=#d*rn3Xs$g8pMaS9=a@MpJDqk9PTMCEW(7KvSmI_ z-I#I=P>vv~@r~^v$~6n{Q_l;=N4uX>Z=n|2$7vKOK@gbdA365$!oNJt@kjoFJHN`E z|2ytNmAmjU_r!+V;d9*Tc;w}ToqsFr{#bbaW8wJ6!v0^n1wO$);wb&4Kghp?Jf*+9 Pf{!iuGr!;{Wup3bxfiNY literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/threads.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/threads.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8e48ec1a60e0f9e0802fb257028a9f8278007f6d GIT binary patch literal 40321 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�*p59SB^S?k)j23q-UA5rdmhf(yRbP(06q)z#n{)14qvsyLw^t>T z{mvxm-9v93NrMKqysd)+K^f`+wFTp9n9iFqQt1+mM)Q42U+HdO z8UH0hVuWR$ls*8kY*_H_NO*VLu)pfQ>7MsC&pDgdX#FPuH%A2A7+rFj>5m3Ozz!cNVc5b1^nuZd7%99-F-j&@Shquzp_Fcz$~wG7>qTk6 z3A^!=KF-M;{Ud>X_4f~{i3BSQ-iu1U*nYM1O6M2vyVg4MxjE;?m2IPG&QL@*Jgc`Y z6WBxXu$t;a`ih);~50BBWrAJbf%o$cXAqB8! zs%kVIAB(j#8p^7Mp=h{KM=`O+J91-f7FV-n>{llh-9N5{ggVOzxI;a=h4-vSDr&qD ze|75S)T@_oUcM2%^{HF&Z%@2FaVt3IJu&Azu|_waVBKuu6W|U(?-8XxnYf=<^f)UP z_LqT)A{!KeemV9tr&KG`M)S2m%QDQ0g&wni*^+{Wh4UaR_l$M1E*Ka_;;{xk<**cn z(Saf!OH>drq1=XXAT6;er=wWQ({1fY5v`0yCjuC*dY3Ukaavs>1dxfTc886UofPq0 zotn*XW-QY@V#;gFJYw%Kx|L!Z(Br_G1t77QN2jlxUMQ(al+?_Z)XjT$&N+9kG0Z>5 zr&pyB>GCRS!+){^1FsLL^(PZB#A%MQCzHzXB1C>IYg+ClCeui0`MpeYRIs9EM7wkz znu*J{>8uMvS7XMS8tTjTY5SA%v*nout7*FdjQa zFd-^wC;dMAFqsW6Egje>h(rzsrd*#u9J5d&Ta_fRvX){o!~)5Bq=KRu`=Zm@3oR-L&wH1fn{tvz|nR zC!TpiaDF*AbLPFf=bXFO045UnR+AXCZTC*KG9x7eY4l=U1qdU{e*{F(3TP>|EIN1z z^k7+Wy;pc+aP|?v3~0x%hND>70%rzes-8e7NNf7aaUwuqHsw`ECNsZGs=%ww3P{XI;cU84RUVfI*?DXdTo z(eUnbs2eg8DZlwT>eJ*)7YRJp1`5P(4ctYuhLj^f?AxVd@^N{g_1x{&b2D-4{8^|u zoTxcG?>#c-?4NtAAMP6SXf31+=0JYZZR$={*_ankAtsXq&gRPfs3qZ>Auvj0U2NzR z826MWQ=67|%*2LKu^|Fv>oEF*v4F`)=_pW)VVaG$2q)O0YNVA&_5_6EIEH6joW?95 zLFElRXf2#uM~Yn2OJ4y&X*Sgv@NjB{pk*;S%481jRGeitf}-mLRt6X`j)GRWl1}4G zL;XroRyCORYX}gcf|2?dfl&LrDcU?&eR#g;$eicMqPO(9&pne_ zEW0P7{xRX_zSZD|StYI*(Es;9DAmjymXr?>jMUu=j4XIJC%l{IoSRo-8RWrPKUzvyjaoB?{5$t#9>k1+44YKL4oFN* z)4EFp@xCL%Y}hJs8!cuvid|E{+ng)HB-Bk^{ljFkd!KUBAAvo}B(}Nj*#icU$k+t% z5J)38mo{+)6+#bmA;-|p6?olc+VY6yKQrh8b#wvmXp-a>yqgl@poE4z~famGoL zLVUIEG}ZH&5cD`~RG=LF6GQL8j0ankRqPHS`vxBe7S}t;f)-oTqKKbm)^CpoAsiDU z!ldOWI*e(QM*Xmy93

    z$HjjLqV__Vw9M<6woh5gQYWUR~s@IyXwO=VB$&uJ5x*3 z0!A`luW>(5w{k3kv3@;?7z;Cq)E>Gnk_0EFxPIZWg{lLIssnT019Q#;pX8vtagT!% z2|zc;+m|vTmT(#lvOHuO6@36GL?=Dm`j`UPH#!$%>Og`Gfd+#qYp`g>8_-qs1t~T_ zEV(V`DkI^hgsTlhj-HWFYv}LOs|-MMqN;gr6=krP6=Zg`+N>Z_q{`#+C0Q$g4TPL& zQNd7P5fd|YZ-dd@d;DPnTaah#P(&0Kq4)nij)nfwM;naT@Wd*E(G5K!u>(og*GRV# z_g_VH$_OCU(=-BG5y5l^f;aG%UhA9lZoci^KRe9UCAROMbMEJ}fd+v7=&|FEp{Qo$ zv+7`EO=qpfSH{J#%*g%zqHTPDR(Yy;H3wtkThdlR;7>`ko3vp1o9LVjd! zkoLryuok%(gE?9}4y{fT^qoPV`clG zKL*=z*ylsNoUYluj%cZPkyp;>yoeA&G8^>R3oA(}^vBSK9 zxXb$6-ulIDbu;a6d#V?=*3$3h#Z6o3cf+Exjee`xsy+Dn+uqIZlqw6Q^@-B@`O*d` zf;|P#o&2?v*Y>}7`1;{%yAqxqUpV<587VVL(0vmdh0!56%z+tb5m7*GnSs{lX_-G8 zA>3BlvcM#p9ILsKFf5F;VipAikU!;z=dv6ZNZbrn<%|v`T#)7u(Sq zw`uVTlQO;iq=0Fcp0f{Sjevxl2O*(#kW4MQlJ#tXUApW*{Jpm09~TvZN=k`_ zNV&^OZ)(OmDK>Q>$U>{BEVg4ZMU=B3e`DLCQ3hM91=~RjuaV%H*#sgR#ASY zgjj0!4-Pem6A9Ava8Ng}BPU2wwLlr)pGk`AiP7NDC`4KSBP}JH@MDTQ9MfgkX-GyD zD>(|Doar3c$m+Uu(bo-1FBYRQc4H`(Mpa4QHAdV(Mv^Z^=x(~u3_y(5>3~L>(G-v{ zn|eH|4YJK-q9m#d4YieDKrAIA7@F+Rxg5T1;8(EmNAVA_t)gZ% zx})*qv^16SF*quH0`Yd}Gs03HQyck1M5-tC#sXrg1@xTg>pLq>_zqj4FlePiFd(^q-Fny#ET@6fbCZLpk0;<)?cgnYTwuP&7OYSyXT$q%4;XS z^x2scKXK>JT>AAR*IIA8s}?;)DX;4`&u+e6`Qpaw8)r@~Lf+hYW#>Xsb)u+xp{OZQ z)P#*TJHEc-R?GK>=Zc!3CVnTeYdx7^=5K9}DxpWnOS>`gd(m%LKm zL-L*XJ<|50i_YFVF*3t>>X@xvmfv#7Z3pddWml8Grns%e{??%b@PB8I+;+eHJA1Rq z-$Jf-10VI>bS52alS9&h#pI!j$?U-ZxKW&F!*q;T^~b)p2o8QBoQm!A!$A#a;n)e+ zuwfF0og|==4Fuz%NXxN;hk`}}qOon-4tktDoipwHn*54x2AI@|6zw;bKhbbeoIezU#LaAj2qQqdtOZe|Q9kzY zvL#bX^ExhJ%Pn*RA`8PNV3*0pv>TWUXcWSx=uhl?7N5}+R|617N%q0Pcd47A83JIc zZYA7+eXFD33UIIqw}ES*9Xshc5p$&~M`)KXQv^`c8`w!pHEb3f0k*^XFwKM`tjyY! zs-%2IQd!OL4%Q50`UDVQ4Idb__Oj8Onpo`)%ULG($S|I70$7mM6hADJl5zBr#Ng>oW8@nKhtVbm1rtIte3= z^Q-WcA>SKyAQP4#&aHrwiY?J`g^ig7$9PS;JrG#N3T7%eyP8CdHMrno_ z88PZX{ie%LbQTnjlewrLeL+>_GD3#2xT{D(h&G*7{X0k$rhxT#V*R;^w4b4#7+S}S zcJGPzCN3nsJ%aTXoxh3_(yV=oohQ`etJ%h-s~dogah}Ws&M!3(w24Br-vbNQjn!US zEU3+89Jcli__g0B=bPkwi=12JyiU#^kVC9@jJPryY4-3_0UV4-imd?b?XQWmrro8S zvp$t2m2H9YZLz4F{ui&)-F4d*3rq3(L9wgM^*55Mz_lc~a>*%h-C;YzpQ_j_|CYST z{=8$ejJmR&RY#~cv;~mu-@_*QAdciy`9|0WD3~luQ&~`|Hc1AI1wAO#ctPp1Yg&#Y zfDYCb+Ch$;)|hp#+@H%UlP9mZTMj*RQz^MQ1Ns!W4fVruf^*gbt7YOVHe=3mqLe zABPsTjfE&Hze{J;vYjbLq=86;_5YfN0&F>lFU1PH!OSnf(GsV{IB*CpabS2lOJ-o8 z9zNs93D6m&!+WL^dmz(@ETNmwZ5_C=WI?UdRRUo3K<3ysDxLnU)dEoj z)pk6h*9>Hhmtg6tKGA=iRRen|(lZ-&TBkxwQ@+LS|Gpmi*b79%6@u zZY|HT9Vqc#j=!RG!W0F^yYb`}un=qQMvlB|*WxZL`BCDvGUIsg9y3GY40)j&FyKt@ zGZEGFGat=SLEIQj)2V;_#I=lvO#l*y2Hi^q(vII^aQsov=Au44Lnl^=L&_Ke*FP%xMxz0NBvgQojxi?8iZSG==E| zEAFFHtjNb^GCRr2I&)LcbXuc9y|gYcOs92YDvML|6gtfU>lJiNH-?lrSWOrR^C?Q_ ziW}z&ngdRiUwJ?vKMl}wC?D&`updY5jfeFky2he7jGI)~=(d4@Jx%*}qj_e=*1aGt zV4(Ry%0g-cM>ihs^N(cEQPTvbohHP`QZCr>l(Nf>>H?OCz>VuRfnb;>b07aqFPVLg zPGTy6R6W7k`(-{p|4V3%Qwj8mUh>CRsGC^t9@$@Erop<7Q4@j@qYG%L=~-RZ+#%|3 zeDyK7T|;u~V?Cd7HeyIQ1z1rx3vc)U$hgTMYCd{pJM{%)NapM(DY%Oq+W%bZ*2wfF zX@jW36aNuKy+jV_P`Tmz*C>gHYGAC8^Yg7)4*8sw&cLH;EH5&9)E*#5)FYWQ=AR5j z{VFf=DT<_evF+!)&kdI|+jc5j>{h3jR&cX1Tq?m??IoC?6_?KBV8_&#ClXLC(-|z! z2WL9Jc>I|&i|*nV4kX;wi`8`qIGONlT68O4%SpH!7aQAWI_FAuCOq|v?!p(!6K-Wu z*^Wdf5}v9>cgYK#3HO%8E%gX_FyT=a-Rr)JG&PI64$)_|2~VB)tfb=V$tx#kIu`5B29O~ zv*o?gJzwm*`q-7n7D~4zO1CYP?n#vHd9C?d2fltFQF`vy2%PT?-!473;5|2E{|PL+ znrGuLKk?ENI3J_#^}4sc9dpi(U%a0y?KmaB=RJ2PMh6%@b*!L$z5G_uhW29nTMb9y z|4zN!USa>vu6p=~boQ04_LG?KtF+o*f>7gRv5V=$xZW24tDo_zR?4PkS;mym7JOZ|*CcmcN!| zFuY)*ZB`~4EBk06V}Wgq1$HqO*zSMcwvq*IRdMJnAq}oiXWW5_jKy>nB=(-w+#Ct9 zJ+b0rQnRp~t{_+@q7qyqZAWJtUZL!^@|TP>kYsFK+%@P)gML_OKpgHTrp< zy67*;&!j8Y^)8m`5?N=*MO*8D9x|w*sh#CSi)u!+$@t7lhlp10OUnnm7(6>^F;!frberV$3VPyGzS zk$$E*k;Am65Ygs z>(K_0=5?ZEM1+~r=yv778*MMN&DvhhekuFK2NRVC^^+twZI-cLNRZI(TBp`d6`|TB zvvEHJ7GF$it-V2UjDlCfca!f?X4)a`Ns6LMv)t0G*l-}KURALH$q2Yg6&=TStfEWU zkF=|4q5f#1{^$?O@1N~`!FH|fE6%y{`)53G7M&#v&dLP-R~~$=`R&SsZ#xgZm%5z0 zGm*dZM*FLsH#@((<9qe<#~z*=7@o`DIiEkW;2cRfM}F~sj#Tl0470Y}QTYzrH~*CP zm{Yz|bWFDYc54N^Zyu75W!v98?1o7cxH%RP zG>|QQi+e`WW+jK2NSOg#*p-Lwq(|T4p3zV%lh!HIiDH?_rj_trAREiHC!PGJ5k)zT zD9Ra#qRszjXhynTs3#DntBL-RlSPoE|4&LlLo|J~Qe?)z2WrCd{RgEdMoT^tNnyas zs+ozXbZdW%SpyxsiEM3S(Xlk)h@)F({bRovn2c%P$4BXy)y=EN=z!R~X9@cw!mrox zA;+&R(rNiq^1`W4Cr*9(hfV!&^nPQ@YeTqdzSz6pabb>>Ll(2Am-iFJ(yaL zyYuO*S*J70NV;x7=*dhSPZzUDL6L@%Sy$U(<$U#mf zoKb)3^WA7-I*%sKBxfoGHx**+He<}nS-^_*3}`#05Q0Cw{Fr7*9g^``vM~*`>k|2O zI0pK_%>(oKdl#I0Z#(ziS*Dekr}iF^e_uXi|7P})f5dP)^-MaDo(fYw|i01Q~7o5$voy~W&+ZZje69In4%YUAD z`7h(;lfxvC21pB%_84s1UGPgN0~-Wkg)H)zYMIGup8%o(b8acZTwO9msnswJJ3>K6 zI${k&-;`*WYGC%mCTDfTWSB^p!YLYPmK>kh>o@lyG{%I28Sa ziKLx!w92Sl%%jj0F^>ZN7fo40#vH-crA^tUM809(+x+bVuLI4tEjZh5JKOFolZf%u z(N>6MlH3ZhOwNY?|GJs{R~a}3#v?NGS~fK4M+aF*@!k1`bcGpodC+{(P#f#pSP!#| zyvd<+RAMRYlbk%9F*SFEa;UNt{z=Rry-;eswWFzf_^Q<1rx6>fl!+wH5#yQMWh#~P zI`G*_9yc9zZU=2#MdWqV@1xJIrI4^ z7Mv$;J5Suv{tQKBo;)NYe3E2vHIj#G2gss`J#_5=ROrAJ^f2@ELdI&_{GZ7mz?aVeDOAEUnAK=pkX3AT=g zjjOchL}N^LAv>>-^)*b!=^RQfyjCFv)&tp2lN`#APMTq>Z~$2e`SPVVkM(d&alVx` zu#P~SPNnArW2;oQ-nx#3<*Ng??BC9LJ?D+``O>ZhZ`X|d9d9MB5m4V|N8>Kpq=J)> zE@_$OspeLf{7t#lY5!Icd?^AY>GVENY~UZl^U1;gD*#`5(iuKFi~@^aS^DA^YPskIm?=0isV|G|LWRv1cs>@!2{rc#S+@j!0cEoa4P_ZnX=r=L8|}@ ze(4k@@Yzqb57G zf>BZp&Rfx?DRW6btJaudrhMD2y@%0HnL7n8&X2= zrx`?3kI$g((z>b_-Phd<6*Y;9nuUr(i3(h;@a@jmJLfCf7mC`k&fR+Ahu*GRC13W; zw%>^Vu%P+2w`T=QyM7T^dzgc95_swz# zTrs@}GxhXmr}Y+OPkI2Ogul9v?IDLL)BNG_-y=)X|GR6 zgLYCw=wTZ&Qw1Dj-=x0i%Vr;r$|2&#EwqUdF-R89XP|9O;?REndX6R;S*h?zR-eX+ z?MmeDx}m;0a&zPsR-tyy=XWePJ8nBWbc5`D_sidskJxWz-@j6#LB{fOHFBnt&eg1t z6qYZ;egH2)ES9Tz9yoFRGi zJIFTeq=4-zmi)0{mS3<-HjLa()!ZgTmt8XBFJ=QkX1h3-Pv1@$+q-6my zfQ^I_IGa^WBt|dD*m^j%UMChA;=%;YCCK4P>BH?(ZvBtFRkP}iskgl?bIz8PCp=ME z_>-6S!-Er^RyjaC^MW{8v`^}H+-0$o&r{}KKcZ7*qJC0Ga85!jbXdZkHtW8)rFO>t zT;4NzUmU&~yb`?aR94oV2otM2S(2@GI#s5l!Ej`VxP;BPqff8@zeQF${z&HXngR^d zT7h+*6|FGCewA7Qg93~IZhU<1@-vqgyh_5W%&xo9KJRUsb2hQ2V4a@KGa$`6;g@sNjOxo#!TGZ|XN=SBG;O&{8*7^}n-)hSi|0eR=&2XOjL!N@Z zOzIby=|(YhYmA=%RGl~rm2d3>Ef^2$>FO2BF>>e68&#s?w2aRS#OJ4(Y+)ptDq@>> zH~^qJZ&&?cQut5?uSaVJlt00J>Wr;0?Vu_4ij!iH^J z;fy}}=V;4RF>gArX1zj(OP%L^NJj%un*tEX9@mHX}5pNg~$`dJFQ_Ma$pfE*Ue#8`XA-0T`d zwq{y}r|s;LKYkOSHQ%45EwrT#3%XP1AP?n7&#g_adIZe zVX_AGy!OlFz|uuxhX!kO#FX|NIscTLe@4z#a;}p@r$R7$UyVd)?JaWt4LSdwoCG;P zASX%AewE&VL3O?Eh!PG*%C zWqC7|8(ncve|NX2i$NFU(d`sk8 za_V9GMc953woioZ6JgCFtXYI@5@DP4Fo&Z{)&t4Al+Q}Zan$R9@GTXwFfVG%YXjd> zH4F2g+B^)tr41~s$T48#NZzFy7Fy^q%7zbTfK&Sl9o72R@abVW4n>r#EEi=v4lWmD zJN7LXR<}Hy5 zH!ksf%OqF%aybjd>V4^k#dXSJ`NqZdo5|g{ZSlZSsuikH-X}YblL?o%Xeo#Lol69!zD4)SwwId`ipOC$d=H+S^`nRIg(Jn7H6caeq6(h8+ z#Bowys+SHN`cNuE1D1D}Iu0#2$d0-XvSr5}4)X-=L--R97y^3aWx}0TrGVrE1LDh4 zWuHyW^4V3VYJ1x5bEvth9lzNswmsrEC*V}wYWCB1!yL<(JDF4KVF=291(T@9FbyT; zskqyXn-Fl;Mdy0Kmg6A*xIY-dVp)q4#Tj%=wG%T1K_tPcB{+d&Fn|=7=x~ThGZx&a z(nd!;Ksf@vD0VvQ5*jZCT%^y8W(#Woz?WjLCT64*AZUj|T=kQTU zLyM!Uudr>LKClP_sqF@p{z#b-QaAf}#mzCg=+kOkX27*)hQil4>~d8pXN8&<)hE?A zHIeuK>JpOqt>q&!lfcP`{$y!0d5o%s{^f*=DDzaQmClR%=6@dvnJ$ekJKf4| zDc!N_<;yQ!W?su>^IUEbbw!S(ueP*y)w|x;xbSS%yWX=@`&V+HPH=Qj73#OMbMBSh z(e5_k=E#&=A5Fl+5q|rdjVmv0sH|ou=PYV!vASXW$%_8qSFis8^+zMpqdy9(XPaL> z@X~?V+8c+ki1pd8e|B#F@i#8c^*prDGmyX~!=D35t9K(QFX>X!u@-~!O1Gn&`~QPH^LTr6?1Yg4I~?7_9Exc(-y z4O*uCDOSM6Wvf2RWveUm^cba>znQG!kf&%D@{AaH0t`4?yc^#q^Jy-c7Xz~iiR)Ph z5XT2TKt7rq$sE$>1G{Jp7TBCwN0AIF7~?sLSF2de@59!w2Ie5w!0(Tw+t>bxpyNyU zGEh>ZrwX&>#l9RHhH~qz6{5gKHK>-r<9vVG4=djZ1tt}&-Wvu8<$IOZMdP% z?QKgmw6mM8pUq!fzwz3{^<6XeFSvgGL8*S(Y8@`Rx_a@-#f7rkL>Z1k<+o1P{p|-} zX4qxa^@~-TUwrKPV=sRC`lk`yO-7LQcVgA3*VDzVZt1s*TlYzCy0^COvAx+Ole=&0 zu?@DjDrLArCyvwrNqq{hhi5g_13R04uc1uhSVX^`kt0aVM(FBv)M{RQL07Y~E>D|& zxIT;#cVn?l?`0nN@2H3A6agG0%Wi4K6-;x^^=x`|12MA<86!?wf@CqT4$nf@Gnm=| z?Y|?9p*W!X$IK{0)~BohJpThf+W#cyf06UQ$)VoiLJgB=m?$Gtn46q5*?`0}#?t&c zHGqJRWP^q=pJX0g&>L&uAQ0n%)-rw0x|NL_ z>3}qaa`W=Uu}E|RceP#&Xqzdji5!{&+Fz2hg`BPAY$InoIYf)K9pwBsa%#vSk(tZu zJK;;(={#($o&vkb*+tHmDJE}hd=OVe7}gS3DB^F(Nd<&E&cj?}KB`p$Oz>Zd{T>|5 zQCa?3R+()7aJM9H`7e^XAgMo))OV$-Ka)KFS=#U;>Ar+?-;bo4ccm@wN}Jx5w*E*u zHZL8+h0X4)Cv$%0lI(@=+PD9W-Qmbymf(EoksOWh+Bf{jetO=1`d$0RAK7>R$iC}c z`+6jMuVT}zdqFvnP!8OxT)3|%abM3|U;jd1B+(a{QzD6q=$yUugY3>cdC$ya*J?hH W$oE0t`VLvH{Nlk6CHiI1_D09m0Xl2Yl;b(bIv?^9TQO)vY(VAH8L@mpEqjjL_=)D#D-Yo zM58Du9(5na^hGzuHcf0oJy9-?HpQAInpm5P=;m1SL^I1*Mq6U76Rj-ok4mw&i8hw6 zinhl(COY)`TTp*1%U4IY#X2Xp#{v^OVml{xqO4}3%O(s7a_y^vTzA*TAu+LwmDQuH zLD_ZJu9tSR(hVqWRJzU59#*;$rJIy)#dm&^*S4nTr>wtt{;q@nod_&A0!^V_{Pd2` zD$=v>Q1IN*)FYqto$|5)G(#H9R;*ot+pQ?LUT|`;H7BA0B_M%X@Tqd<1<; zN6~4YbgFN3e7OJg@xD>%)alVvC&vac`~bQg86G)0ictnn433O)Yy)V9ya}0pVa*pHRiJa%;9MMB4nyVOp?$ltg|JYzZ&^eTIo{pn@ zXh?VqQhAVnCS=%}0}cFNTsKD)66ToON1L)T7bRj23X@Dz$jx z;&e20K?x=!F(p?YoLWdKS}>UiPK7k(v3)@qjdSi3!(#-LTy=0pNd`k&&}@f(9b-y# z8h<^gt57${mkpfgpT*jgD1JDH<|9!V8TScA(?T;;!QY?2TP94#uzn?A&-qS;K>VR7 zO)%$RX&s;ZfD%rq3`hf*PQa#a!m4xL{%8b3jVgu-oW`R|fARiil-v*$VM4?XX*-R5 zX~Hhs6o+g-h&Pbp&YUMm&BsGCcZ8fh5>MuA5qX4_2jiib5)9_N!62m8e3bI#!QhwY zLs9)rSum(Y6G;s({K23Fk-?zaiUID^gdQY&XaubXqD)mTroyvIyk~6J)AK-|+A}t% zlAQU2d8}Mfd-}(uJ&*3~32R8F(DSYtH8DSTpyx#;{$fuwGSxG;08t!&qENa*O3nHA)_nTP-CuDA_MdmXcal(q<{CW3AdPCG{vdAa__w z8d#kzmXZx9d0gIVDQRRS+bks;QPL}ST1qytlI@m~CY1EZ0ZYkdlsqBtu#_~jIy)^T zE%HIR3ovM1*cCXG^Be)66NLuKa}FYGwGDvERS-d`*wN#mWJ1mPW}=CyP?YgR&K(Rf zk%G(=vACM642Htkv6I0t6FxaRh&Sib7PO=i%T)x~HXjZ`&dg{zR}h#i9}T0Lv{92(n!fZO1dfOL1JkK z20y3nrWcPONwt_AmJ&1P)JIV%Oahi3(lkl3;GcM(Mz|qd7B34yRvJ!OjR4$ z>NbidP(iClaz$8aXu9fn-M8W?f1~_b`StOSJewG!n@d0~!H0ir3I7Hem=0LNc`7e@ zz6-v_8(qD&zWlCDw&RVi3>Up|;Eisa6ug0Xfj1s&8P8)J*Y|v5Lcl$esyJw@PKwBf z9=IeT$3qV)Bn$B!df=2mT!&H~iIdl%2jby?lT!&J8X}84LEI75LnzP)2YG0!%A8sR zOCE8i^uXDb%G&D# zH;yeHyWYEW_Llt4g|{!%x@xzVdDlXp(8{16M+O8`685rq0ccmt@wNo~ z$Ea0_avfvnxA^(4@I5;qY#+&qyB~-hAV6X#&SFQAvjWGBJuOMFsWNZ@N@FE5)qD&I z2+ikT_BCgG&9`bl^le$G-Eiaa#mCd-n^$TYZUhzs*PE95mgMD@-IE=CY|K7A` zFNcM7-b6tR7H5&UA&@D{pUYy>tY;W_mqc}=2!<;~cYp`=RrC-H#{~5W6obXQ5iJr2 zgT=!N-y7Rde#gd$Bj-#&?N>D#)L=PRFsOVPVDMYOKm`%h(Wvbe;bZ^CrLEs@%=&kH z=s$9M{)dn$zy&tomckL<9tcN%Ze-l?}Y1slk)RC|{!803l> zxbr=ftnDtSZHmTq`u50WmcGr=*QxE5eU{qHk3_Rsr*?TkZQ3B%vrg>_3zSH&WY2;S zs2s_8Nc%K(2rgyVF74742A8fclv~sVHCJxc4^+Y&lix?#j-G4aZHv`}Kt(AXA!mnu z!Zd^Y{-59Q^Vq-CrRO=2Q|$3qYo0MMGtD^ zxzJ{8V&za7gK^~|tV^cow4qg=$BOBlsl=pcGF6w;yFF(QN41=T*p#b91a?!+bV7Zf zTS!&rw>Hw>BUyjzRmZ1wjW>oDL0+$y(Z=7o*oiFB|8g@J z0CdP1V7X~$rfDbrBI>_!dGRu;G3qz6E$z!KdonG1IK^}FMjb}i7Zxud>nrNDbLVnr zf2OmaT5S2$UwhTJc2^@zGWvcUne}$H(yCNxg#x7}{h&+zL8(a*Mj7o>rD#+Z-*mAZ zG~iN6>ES!*bCm0%#8h4JK96E%$P~U`v+LHA#|Fk)BnBgm&>K7tM{%kpkIGW-7cr>T ziv*}`-27JAO#_i6QKE}c6Y7v-9F3$-K=^!C;jZ$o3hsxhxKE*Dt6Eo5dX!Y%j2#BB z5>o@c;V4|$y^}@WtI1wz9L`$4cSIK?Y!i`aXetW-E!mmOlS`10pnG%&>?-kl&KI0k z6S3fnq3FEA8RIC5Eef#u0)D6JO}JUNrtebKCL~vc&s{=Q>#~1G#=qnCzU7^VGCL1t z{fE<@!)xh~q!OdUZz8iE9lrc%UYjW?Lw`Nm!$`%Car!YPEQkSHNQBTftzQGe%!fF6 zu2&jWl5mr2@M}wj@8BC(8D#mUTnJ>Z7ovnc!*m{@kmH|$UxJHMnxBg%LNff{A>E!M zjKMM4B~4C_B;v~CBprmPY-C05w)VAgl=i-s2H@C06aEh1y+ z-cT~B_D<@rbbrHSzH2!8xY#6V3+EoA4L&RGLtrAdm_mqOEh;y!e+z{gc_6L`tCd1| z)f)$|9ZdT=KCW$CuHBlc-OA0wd;5O8|3~}Z9eDrvd&jf2!|C#2=)r4A#({nq$@~vw z)*~5Nd=VZJ2pV&9MP>bwZKSLx%?&YW3NC}SQYd*zj5j9pn^j3$)Tl4pd5fgEF_qk6 zg_7H`^7IRv^b6NDR4k9JzY;Iw>$D>sny0j3Y7_k*&I5uClO6YJ({n3SZpCc-mLUynvEiCQ_V=8`nRgzMdh z;evRpQ=_vv;w&8{IEXU1{3v9Bs?5wsLn=cK$y~57{y#sjF=maZ#Rx@{ydYrwZ|ShR zTY3?8IGuOMkQBYW(%$af=5Rn1+bZX<;58dyWg(MW(Zr{(qx?Uhu}1bB&{QQ<)sa5) zp??p#D@X-Nd-kjawJE`0d;x*i2&EQ|aG=xX!y;3*@r}1*If6 z4wh&q;QRrE8fP)6&hc4mB?Y2PDEO7G6p?!H&|!VVy@>l3k+lGX3a{)%T+!|lr+Lzhd z_rZZ|?eTQ^@sb!cS^JylWIYUC5f{Wf4*!3vX8~L4!!`I{qnR1%734GbsZh9wl0;m_ zG%+gIge`nsiWPTz^RgW8p`QoBa#H_L1h?OpQL40;}pY0 zlc2348VMoPhS>@zA(xcx53dwb}MoLv!raiBw z8uFsadhq#kG}X2sfjnwqJ4{Q)*OK;aV{{2W;c`PD(-6RsLE5upEgcf|Fr97_GV9SH z>20Aq{~X%-HAzeTSD-A_LKwdRVa=<*OOzE5)t7+KVwzH)N1?^lV4*PeS9qnLlz@<` zAko?~{d(CO8y}VPpN~n zC^FyItjw)9vm6NNC5UboG;-f#buOW%4#5CJi$m8RU+TO1wX~;YE#a7}ByXGXJifl$T1jQ=kp9L+Qppi&I* zI5JW#67%r5UBo`ly0W_Dz-4~StMmb|SFaunB~!KLHkmJ!2x_%x4o)iOkPzpW82r zEEb0eSp?+Rx_7Hn7{q!Gd4+|$Jt#Xkqr_oxsE1SAO#x!U454t{2cwB_D5@RqHfs(N zwNlXQul|qlt1H5XHT}1@T;F$N|KffwUp|5tzNY^lHKMCmI<~>flB?3Y3@UIsF5m&JeKaS)fhM%NStzev_H}&d>i`S= z%wLnO>A%;xy!S|E?~$L@^k@D3X-_|6qY)hb9Y!M_%1E&Z54N#b@8?fLe4Gj`&@oDv zWQmp5%g*IoTpZ*abe?j@rv3?aL;hj7*iPb4&Xt&=iw^w70eYcVl6WN=P5l-ntm(IT zDMJ%UY+gz^yy!CwB;LB{H6`eoET;uU%rm|cs`%1GVAv<_0ViU zik&e)9pxP=9bl>(C}HzuE0R>wAykrF>K012QbK36DtU_3rzjbs(ARfUQ@hH}gf2`$cOm0FT>SY4omL>|}pNyF#*(kqnv1|@$;$u&y; zn37gXIw>JaQAvqs2~9-%3sBHEgjHKbwd>08XDx!KexrMe~SY0=Zhty#}jy>{D^SA->4>p_gNqSMaO1V`J zEA#NmC__%K=XM?u^@@~Ttzk9Y&b?;gUcIc$Y>nJ%1FKi6%;$W@=#jECQOu{xxl`{E zxz#PKtkT)8mm#+*u`-ua(#w#88<^U<01mzumcJPbr#+VAL6I-Q1_bn`YBnB(!sqG8*L|(9m_eMdA z+b`kzp0PL5U%n|@Rb;BR?u;M`*Xbf3kpMLtS7T&EDr{G}XS#9zO==j-^E;a#SGmH#KjYdod4ESmCO(~WdI%U(K^9b^u;UmVTLqR1@p7URC4HPaUojBSj zQ3MPu1^5f-GVR5LN|eL<#{DoCUlDGz@LMe&W4$?_Wn{z~1urV03#u}Ws6A3oREnfi z=~9+T;Y8}6QX*0ECK6K@CsT^{3p?rJq!@f#gueiP`Ew07F#ZVA85dA&KQN;!=zi!B5@Scim?u@5#Y5w*;Sb-mTc5_1zRm_LtFxV=-kIch8JEgrKzy13r7{_bQ&&=Td zg!_9H*!?^sDgVLz%IPkOdIZ(feo6+Aq`W41A4*k77K9&SjwERCZB&=p-eyoAM?FJ0 zoika3&PW|Cf;PX8@(MwF9B=79N;5ZQmY%yceS7?e&)s?M_KA0!KS(YQoyiQHNgtiC z-bb0Z?f7BEor+suyBGUlV0mCXGcca+Kb=1PEZt5yD_X9n5UCjt(EvkM4w)j7!*w7| za(8v~vg;Ti!s3U%L|`0fBMu(@@dxH(soHjro~Q&G2m+v^%3lq?N{eXjYJ5X9O{@t2;Po?Dx4pUxr<$nkoG8P%O_*v>*=^(gO) zx5aG34pw4Bm*0Cd+w?evd2>e$rgj!1a07*m5mT(t6bZ(!kXY%$RJeg35ngiO(hXkl zXI@mD5G@W_q-9*T6})M9Q`OjU!m3+iSI(ZTNq!W(4DGG-$39!4!@~3mdR1d zbuP@#@WK}2Sl1UHHayx+&&Sy%czi|!r|`IqFR7sj*4C?B3inPvOM%LRs)|D{b2f=- zbCI-&$;sh3;+Z3IpE|=n^1LBLlm_>3 z5{!}K3KG@lVLc^OK1RkCeVr=zJ)8ne8YZgEQ!#WxPQv+7sk8pXJUr;&ib*4|7!}#U z8diW0spw&cRMmJ+Qcw$L4VxWP?h8AfP+ug}}i^j_zilENd82DW35+YIy7peEBs3ith-dycz{`4u9ajf+lk(>$-c1FIq@j@h!yM_WQ=-tZ z^{RWtSNrDvjIVvAeaF?I>rZFOTR-(xzqujflUDroX@A?tTONORTXsv|b@!6z!>YDV zw``|e2DvX-t$o`&JKx^9+`c!{zIVC($xQo`AGova$CfuAyXwGA+gpxzd~f^iZTYEx zf7-Ku)h;v-iw`skDExZgz9V(wPaYGG)Hr^!e>3u?x`Vf*&T^IZDP;cXGuKio$6Y{# zo-tf{P5m`}mgRW^>FmQM6wO6gW+!)~3c!y+LW+c{gzx{rfyO?P#0tN#Hb9|w`N%B3 z#bCQl!XIXgL|2pXP$bW)ADIY^7 zL*luBzv$qAuG`_mSuotUQsYu52&5i!7Nw&}^(H0vkl>pa+^!De!&Si`0)YMurOe`c ziu?I#7L0R`5vab7U%&c>@R@Cw)3f>|QK&vCUK##7cOCB4y;iwW)tvP-uhehMdN!_9 z)xPHYr9*V?x$lDi{+H!0XD{66?ST)5(lhbT>_vyqcILhQ9DeNW+;2@Y3*(>p5C`GmXM%aJHUF5-ghMWq?eIP0doQvBe_e`O z#)suBeq|3z%4L_OqzrZ4sOw$u;2Q5HbRPN$qm1VLR-xZJn#oE0dq;EL3%-tON`jXJ zEkxh%9nEXb|NnIz&7^8T_PqrLFW8gm&KdY!yg!G`zobv_du8zNxkgfD2Wg)v;o0Nv zJ4Z?PT}h{11$6}HD0kQSY!K$ODc}~y|w@5{-waJ$8eb|a3^rP+3JitlRoo8 z`dn!FoRT@Gq+gg$PtT0vm1| zUOb$w?O3kpxN2MRS6?lIrdGM-fktQdU$1Kwzaus~Zn#_5QPGa0)_O5sCBLmy(nFM2 z*Km9IZ`PbRm>;Gq4#L;hWc_X?DOk|jpox))p$Hy03zSRHlQfHFWjIf`j;5JrXBP`R z3?m+%16snac7i_XNzjz=xlhEfM0JbSRK)bV6eemWaXtoL3~U~FTy$SS-fV!YkJ$yA z8KUqpIoP&}fgOCyk6pvy)LcZqIjwhZkd1@`8l7+z-`}V^yiO!3kQl4RhmU1PA=sx3hJMu5pDuAK)Q9^Hs@k@#I>B4$UUaSrf`PRMiq^3 z25}vj)}q@}O!G_CFi;j~!%YND(p>?~I$_K9cb<6riRF&RG98aCcO1%e9Ljb)`Pcq) zOIts9bh&>l(?6CTKf65sd}jRlkNRKuW9Ntdb7{}Hf5acnhd$ns`uvWccpOLzWU476 z{xd3>G6MPHhvK+i#>YI?3y#ExK5V6|p!2^r&>@Ay0x4ui&$Nc3=d$SrW-_XtIa_TZ zFEry~XKO!2wZfc&TU7rlK%Siq8%yU_3xl#-F1Qw>yMA;9O}gBx(j&*VhJrDbvdUb<_fOktm7icbF@Cw?)+5EceF#224e^XW;>RQxuvkM z{{+A>GF6Gca`pJ0l}dg9&h>hj8l%!&C5$`>c7wz9lRq4FAgWi+9{?JseiFAz-b1&k zN=Ct^0O};_J%bnAAFxTNuD{`5^j~$Z_^Q&r%`3HySC4;MRd>U;=tEg&*E^}VQ_G!0 zna-jA=J=oP|L)Fqo?31@b=9##_p&-N{*GG%S$`ny31Dkz{{z#AclNc4KXHqF%^>au zpifSO_07YIt{yC#h1HOV&j}ExiE))L8apll}@=-609mQAU8uvfy((v z-^DjSyF*i9TzKF=)Ff3RCgX8uwDIPgN_;-1@hkEFj$W~EVK}j=L^U4C%{)xZ*F-Lr zTs5CSP`Q-EXRYCa(^MA!S4S`1IoY^Z8lN8JoEMdgJE;{rx=YI4g=ft{%94=En1j&o9?^W$L?rDNq^PTK^yW C%H;6? literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/utils.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/utils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aad0d589641ce1a627435262531c53233ea605e7 GIT binary patch literal 64183 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/voice_client.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/voice_client.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..782a60300629a5a2005cbe6ba3764588e748464f GIT binary patch literal 27890 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/__pycache__/widget.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/__pycache__/widget.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..94dd8415a07d7bb0c7c318b051d286f34bd846e2 GIT binary patch literal 13388 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 str: + return 'see-below' + + +_undefined: Any = _Undefined() + + +async def _single_delete_strategy(messages: Iterable[Message], *, reason: Optional[str] = None): + for m in messages: + try: + await m.delete() + except NotFound as exc: + if exc.code == 10008: + continue # bulk deletion ignores not found messages, single deletion does not. + # several other race conditions with deletion should fail without continuing, + # such as the channel being deleted and not found. + raise + + +async def _purge_helper( + channel: Union[Thread, TextChannel, VocalGuildChannel], + *, + limit: Optional[int] = 100, + check: Callable[[Message], bool] = MISSING, + before: Optional[SnowflakeTime] = None, + after: Optional[SnowflakeTime] = None, + around: Optional[SnowflakeTime] = None, + oldest_first: Optional[bool] = None, + bulk: bool = True, + reason: Optional[str] = None, +) -> List[Message]: + if check is MISSING: + check = lambda m: True + + iterator = channel.history(limit=limit, before=before, after=after, oldest_first=oldest_first, around=around) + ret: List[Message] = [] + count = 0 + + minimum_time = int((time.time() - 14 * 24 * 60 * 60) * 1000.0 - 1420070400000) << 22 + strategy = channel.delete_messages if bulk else _single_delete_strategy + + async for message in iterator: + if count == 100: + to_delete = ret[-100:] + await strategy(to_delete, reason=reason) + count = 0 + await asyncio.sleep(1) + + if not check(message): + continue + + if message.id < minimum_time: + # older than 14 days old + if count == 1: + await ret[-1].delete() + elif count >= 2: + to_delete = ret[-count:] + await strategy(to_delete, reason=reason) + + count = 0 + strategy = _single_delete_strategy + + count += 1 + ret.append(message) + + # Some messages remaining to poll + if count >= 2: + # more than 2 messages -> bulk delete + to_delete = ret[-count:] + await strategy(to_delete, reason=reason) + elif count == 1: + # delete a single message + await ret[-1].delete() + + return ret + + +@runtime_checkable +class Snowflake(Protocol): + """An ABC that details the common operations on a Discord model. + + Almost all :ref:`Discord models ` meet this + abstract base class. + + If you want to create a snowflake on your own, consider using + :class:`.Object`. + + Attributes + ----------- + id: :class:`int` + The model's unique ID. + """ + + id: int + + +@runtime_checkable +class User(Snowflake, Protocol): + """An ABC that details the common operations on a Discord user. + + The following implement this ABC: + + - :class:`~discord.User` + - :class:`~discord.ClientUser` + - :class:`~discord.Member` + + This ABC must also implement :class:`~discord.abc.Snowflake`. + + Attributes + ----------- + name: :class:`str` + The user's username. + discriminator: :class:`str` + The user's discriminator. This is a legacy concept that is no longer used. + global_name: Optional[:class:`str`] + The user's global nickname. + bot: :class:`bool` + If the user is a bot account. + system: :class:`bool` + If the user is a system account. + """ + + name: str + discriminator: str + global_name: Optional[str] + bot: bool + system: bool + + @property + def display_name(self) -> str: + """:class:`str`: Returns the user's display name.""" + raise NotImplementedError + + @property + def mention(self) -> str: + """:class:`str`: Returns a string that allows you to mention the given user.""" + raise NotImplementedError + + @property + def avatar(self) -> Optional[Asset]: + """Optional[:class:`~discord.Asset`]: Returns an Asset that represents the user's avatar, if present.""" + raise NotImplementedError + + @property + def avatar_decoration(self) -> Optional[Asset]: + """Optional[:class:`~discord.Asset`]: Returns an Asset that represents the user's avatar decoration, if present. + + .. versionadded:: 2.4 + """ + raise NotImplementedError + + @property + def avatar_decoration_sku_id(self) -> Optional[int]: + """Optional[:class:`int`]: Returns an integer that represents the user's avatar decoration SKU ID, if present. + + .. versionadded:: 2.4 + """ + raise NotImplementedError + + @property + def default_avatar(self) -> Asset: + """:class:`~discord.Asset`: Returns the default avatar for a given user.""" + raise NotImplementedError + + @property + def display_avatar(self) -> Asset: + """:class:`~discord.Asset`: Returns the user's display avatar. + + For regular users this is just their default avatar or uploaded avatar. + + .. versionadded:: 2.0 + """ + raise NotImplementedError + + def mentioned_in(self, message: Message) -> bool: + """Checks if the user is mentioned in the specified message. + + Parameters + ----------- + message: :class:`~discord.Message` + The message to check if you're mentioned in. + + Returns + ------- + :class:`bool` + Indicates if the user is mentioned in the message. + """ + raise NotImplementedError + + +class PrivateChannel: + """An ABC that details the common operations on a private Discord channel. + + The following implement this ABC: + + - :class:`~discord.DMChannel` + - :class:`~discord.GroupChannel` + + This ABC must also implement :class:`~discord.abc.Snowflake`. + + Attributes + ----------- + me: :class:`~discord.ClientUser` + The user presenting yourself. + """ + + __slots__ = () + + id: int + me: ClientUser + + +class _Overwrites: + __slots__ = ('id', 'allow', 'deny', 'type') + + ROLE = 0 + MEMBER = 1 + + def __init__(self, data: PermissionOverwritePayload) -> None: + self.id: int = int(data['id']) + self.allow: int = int(data.get('allow', 0)) + self.deny: int = int(data.get('deny', 0)) + self.type: OverwriteType = data['type'] + + def _asdict(self) -> PermissionOverwritePayload: + return { + 'id': self.id, + 'allow': str(self.allow), + 'deny': str(self.deny), + 'type': self.type, + } + + def is_role(self) -> bool: + return self.type == 0 + + def is_member(self) -> bool: + return self.type == 1 + + +class GuildChannel: + """An ABC that details the common operations on a Discord guild channel. + + The following implement this ABC: + + - :class:`~discord.TextChannel` + - :class:`~discord.VoiceChannel` + - :class:`~discord.CategoryChannel` + - :class:`~discord.StageChannel` + - :class:`~discord.ForumChannel` + + This ABC must also implement :class:`~discord.abc.Snowflake`. + + Attributes + ----------- + name: :class:`str` + The channel name. + guild: :class:`~discord.Guild` + The guild the channel belongs to. + position: :class:`int` + The position in the channel list. This is a number that starts at 0. + e.g. the top channel is position 0. + """ + + __slots__ = () + + id: int + name: str + guild: Guild + type: ChannelType + position: int + category_id: Optional[int] + _state: ConnectionState + _overwrites: List[_Overwrites] + + if TYPE_CHECKING: + + def __init__(self, *, state: ConnectionState, guild: Guild, data: GuildChannelPayload): + ... + + def __str__(self) -> str: + return self.name + + @property + def _sorting_bucket(self) -> int: + raise NotImplementedError + + def _update(self, guild: Guild, data: Dict[str, Any]) -> None: + raise NotImplementedError + + async def _move( + self, + position: int, + parent_id: Optional[Any] = None, + lock_permissions: bool = False, + *, + reason: Optional[str], + ) -> None: + if position < 0: + raise ValueError('Channel position cannot be less than 0.') + + http = self._state.http + bucket = self._sorting_bucket + channels: List[GuildChannel] = [c for c in self.guild.channels if c._sorting_bucket == bucket] + + channels.sort(key=lambda c: c.position) + + try: + # remove ourselves from the channel list + channels.remove(self) + except ValueError: + # not there somehow lol + return + else: + index = next((i for i, c in enumerate(channels) if c.position >= position), len(channels)) + # add ourselves at our designated position + channels.insert(index, self) + + payload = [] + for index, c in enumerate(channels): + d: Dict[str, Any] = {'id': c.id, 'position': index} + if parent_id is not _undefined and c.id == self.id: + d.update(parent_id=parent_id, lock_permissions=lock_permissions) + payload.append(d) + + await http.bulk_channel_update(self.guild.id, payload, reason=reason) + + async def _edit(self, options: Dict[str, Any], reason: Optional[str]) -> Optional[ChannelPayload]: + try: + parent = options.pop('category') + except KeyError: + parent_id = _undefined + else: + parent_id = parent and parent.id + + try: + options['rate_limit_per_user'] = options.pop('slowmode_delay') + except KeyError: + pass + + try: + options['default_thread_rate_limit_per_user'] = options.pop('default_thread_slowmode_delay') + except KeyError: + pass + + try: + rtc_region = options.pop('rtc_region') + except KeyError: + pass + else: + options['rtc_region'] = None if rtc_region is None else str(rtc_region) + + try: + video_quality_mode = options.pop('video_quality_mode') + except KeyError: + pass + else: + options['video_quality_mode'] = int(video_quality_mode) + + lock_permissions = options.pop('sync_permissions', False) + + try: + position = options.pop('position') + except KeyError: + if parent_id is not _undefined: + if lock_permissions: + category = self.guild.get_channel(parent_id) + if category: + options['permission_overwrites'] = [c._asdict() for c in category._overwrites] + options['parent_id'] = parent_id + elif lock_permissions and self.category_id is not None: + # if we're syncing permissions on a pre-existing channel category without changing it + # we need to update the permissions to point to the pre-existing category + category = self.guild.get_channel(self.category_id) + if category: + options['permission_overwrites'] = [c._asdict() for c in category._overwrites] + else: + await self._move(position, parent_id=parent_id, lock_permissions=lock_permissions, reason=reason) + + overwrites = options.get('overwrites', None) + if overwrites is not None: + perms = [] + for target, perm in overwrites.items(): + if not isinstance(perm, PermissionOverwrite): + raise TypeError(f'Expected PermissionOverwrite received {perm.__class__.__name__}') + + allow, deny = perm.pair() + payload = { + 'allow': allow.value, + 'deny': deny.value, + 'id': target.id, + } + + if isinstance(target, Role): + payload['type'] = _Overwrites.ROLE + elif isinstance(target, Object): + payload['type'] = _Overwrites.ROLE if target.type is Role else _Overwrites.MEMBER + else: + payload['type'] = _Overwrites.MEMBER + + perms.append(payload) + options['permission_overwrites'] = perms + + try: + ch_type = options['type'] + except KeyError: + pass + else: + if not isinstance(ch_type, ChannelType): + raise TypeError('type field must be of type ChannelType') + options['type'] = ch_type.value + + try: + status = options.pop('status') + except KeyError: + pass + else: + await self._state.http.edit_voice_channel_status(status, channel_id=self.id, reason=reason) + + if options: + return await self._state.http.edit_channel(self.id, reason=reason, **options) + + def _fill_overwrites(self, data: GuildChannelPayload) -> None: + self._overwrites = [] + everyone_index = 0 + everyone_id = self.guild.id + + for index, overridden in enumerate(data.get('permission_overwrites', [])): + overwrite = _Overwrites(overridden) + self._overwrites.append(overwrite) + + if overwrite.type == _Overwrites.MEMBER: + continue + + if overwrite.id == everyone_id: + # the @everyone role is not guaranteed to be the first one + # in the list of permission overwrites, however the permission + # resolution code kind of requires that it is the first one in + # the list since it is special. So we need the index so we can + # swap it to be the first one. + everyone_index = index + + # do the swap + tmp = self._overwrites + if tmp: + tmp[everyone_index], tmp[0] = tmp[0], tmp[everyone_index] + + @property + def changed_roles(self) -> List[Role]: + """List[:class:`~discord.Role`]: Returns a list of roles that have been overridden from + their default values in the :attr:`~discord.Guild.roles` attribute.""" + ret = [] + g = self.guild + for overwrite in filter(lambda o: o.is_role(), self._overwrites): + role = g.get_role(overwrite.id) + if role is None: + continue + + role = copy.copy(role) + role.permissions.handle_overwrite(overwrite.allow, overwrite.deny) + ret.append(role) + return ret + + @property + def mention(self) -> str: + """:class:`str`: The string that allows you to mention the channel.""" + return f'<#{self.id}>' + + @property + def jump_url(self) -> str: + """:class:`str`: Returns a URL that allows the client to jump to the channel. + + .. versionadded:: 2.0 + """ + return f'https://discord.com/channels/{self.guild.id}/{self.id}' + + @property + def created_at(self) -> datetime: + """:class:`datetime.datetime`: Returns the channel's creation time in UTC.""" + return utils.snowflake_time(self.id) + + def overwrites_for(self, obj: Union[Role, User, Object]) -> PermissionOverwrite: + """Returns the channel-specific overwrites for a member or a role. + + Parameters + ----------- + obj: Union[:class:`~discord.Role`, :class:`~discord.abc.User`, :class:`~discord.Object`] + The role or user denoting whose overwrite to get. + + Returns + --------- + :class:`~discord.PermissionOverwrite` + The permission overwrites for this object. + """ + + if isinstance(obj, User): + predicate = lambda p: p.is_member() + elif isinstance(obj, Role): + predicate = lambda p: p.is_role() + else: + predicate = lambda p: True + + for overwrite in filter(predicate, self._overwrites): + if overwrite.id == obj.id: + allow = Permissions(overwrite.allow) + deny = Permissions(overwrite.deny) + return PermissionOverwrite.from_pair(allow, deny) + + return PermissionOverwrite() + + @property + def overwrites(self) -> Dict[Union[Role, Member, Object], PermissionOverwrite]: + """Returns all of the channel's overwrites. + + This is returned as a dictionary where the key contains the target which + can be either a :class:`~discord.Role` or a :class:`~discord.Member` and the value is the + overwrite as a :class:`~discord.PermissionOverwrite`. + + .. versionchanged:: 2.0 + Overwrites can now be type-aware :class:`~discord.Object` in case of cache lookup failure + + Returns + -------- + Dict[Union[:class:`~discord.Role`, :class:`~discord.Member`, :class:`~discord.Object`], :class:`~discord.PermissionOverwrite`] + The channel's permission overwrites. + """ + ret = {} + for ow in self._overwrites: + allow = Permissions(ow.allow) + deny = Permissions(ow.deny) + overwrite = PermissionOverwrite.from_pair(allow, deny) + target = None + + if ow.is_role(): + target = self.guild.get_role(ow.id) + elif ow.is_member(): + target = self.guild.get_member(ow.id) + + if target is None: + target_type = Role if ow.is_role() else User + target = Object(id=ow.id, type=target_type) # type: ignore + + ret[target] = overwrite + return ret + + @property + def category(self) -> Optional[CategoryChannel]: + """Optional[:class:`~discord.CategoryChannel`]: The category this channel belongs to. + + If there is no category then this is ``None``. + """ + return self.guild.get_channel(self.category_id) # type: ignore # These are coerced into CategoryChannel + + @property + def permissions_synced(self) -> bool: + """:class:`bool`: Whether or not the permissions for this channel are synced with the + category it belongs to. + + If there is no category then this is ``False``. + + .. versionadded:: 1.3 + """ + if self.category_id is None: + return False + + category = self.guild.get_channel(self.category_id) + return bool(category and category.overwrites == self.overwrites) + + def _apply_implicit_permissions(self, base: Permissions) -> None: + # if you can't send a message in a channel then you can't have certain + # permissions as well + if not base.send_messages: + base.send_tts_messages = False + base.mention_everyone = False + base.embed_links = False + base.attach_files = False + + # if you can't read a channel then you have no permissions there + if not base.read_messages: + denied = Permissions.all_channel() + base.value &= ~denied.value + + def permissions_for(self, obj: Union[Member, Role], /) -> Permissions: + """Handles permission resolution for the :class:`~discord.Member` + or :class:`~discord.Role`. + + This function takes into consideration the following cases: + + - Guild owner + - Guild roles + - Channel overrides + - Member overrides + - Implicit permissions + - Member timeout + - User installed app + + If a :class:`~discord.Role` is passed, then it checks the permissions + someone with that role would have, which is essentially: + + - The default role permissions + - The permissions of the role used as a parameter + - The default role permission overwrites + - The permission overwrites of the role used as a parameter + + .. versionchanged:: 2.0 + The object passed in can now be a role object. + + .. versionchanged:: 2.0 + ``obj`` parameter is now positional-only. + + .. versionchanged:: 2.4 + User installed apps are now taken into account. + The permissions returned for a user installed app mirrors the + permissions Discord returns in :attr:`~discord.Interaction.app_permissions`, + though it is recommended to use that attribute instead. + + Parameters + ---------- + obj: Union[:class:`~discord.Member`, :class:`~discord.Role`] + The object to resolve permissions for. This could be either + a member or a role. If it's a role then member overwrites + are not computed. + + Returns + ------- + :class:`~discord.Permissions` + The resolved permissions for the member or role. + """ + + # The current cases can be explained as: + # Guild owner get all permissions -- no questions asked. Otherwise... + # The @everyone role gets the first application. + # After that, the applied roles that the user has in the channel + # (or otherwise) are then OR'd together. + # After the role permissions are resolved, the member permissions + # have to take into effect. + # After all that is done.. you have to do the following: + + # If manage permissions is True, then all permissions are set to True. + + # The operation first takes into consideration the denied + # and then the allowed. + + if self.guild.owner_id == obj.id: + return Permissions.all() + + default = self.guild.default_role + if default is None: + + if self._state.self_id == obj.id: + return Permissions._user_installed_permissions(in_guild=True) + else: + return Permissions.none() + + base = Permissions(default.permissions.value) + + # Handle the role case first + if isinstance(obj, Role): + base.value |= obj._permissions + + if base.administrator: + return Permissions.all() + + # Apply @everyone allow/deny first since it's special + try: + maybe_everyone = self._overwrites[0] + if maybe_everyone.id == self.guild.id: + base.handle_overwrite(allow=maybe_everyone.allow, deny=maybe_everyone.deny) + except IndexError: + pass + + if obj.is_default(): + return base + + overwrite = utils.get(self._overwrites, type=_Overwrites.ROLE, id=obj.id) + if overwrite is not None: + base.handle_overwrite(overwrite.allow, overwrite.deny) + + return base + + roles = obj._roles + get_role = self.guild.get_role + + # Apply guild roles that the member has. + for role_id in roles: + role = get_role(role_id) + if role is not None: + base.value |= role._permissions + + # Guild-wide Administrator -> True for everything + # Bypass all channel-specific overrides + if base.administrator: + return Permissions.all() + + # Apply @everyone allow/deny first since it's special + try: + maybe_everyone = self._overwrites[0] + if maybe_everyone.id == self.guild.id: + base.handle_overwrite(allow=maybe_everyone.allow, deny=maybe_everyone.deny) + remaining_overwrites = self._overwrites[1:] + else: + remaining_overwrites = self._overwrites + except IndexError: + remaining_overwrites = self._overwrites + + denies = 0 + allows = 0 + + # Apply channel specific role permission overwrites + for overwrite in remaining_overwrites: + if overwrite.is_role() and roles.has(overwrite.id): + denies |= overwrite.deny + allows |= overwrite.allow + + base.handle_overwrite(allow=allows, deny=denies) + + # Apply member specific permission overwrites + for overwrite in remaining_overwrites: + if overwrite.is_member() and overwrite.id == obj.id: + base.handle_overwrite(allow=overwrite.allow, deny=overwrite.deny) + break + + if obj.is_timed_out(): + # Timeout leads to every permission except VIEW_CHANNEL and READ_MESSAGE_HISTORY + # being explicitly denied + # N.B.: This *must* come last, because it's a conclusive mask + base.value &= Permissions._timeout_mask() + + return base + + async def delete(self, *, reason: Optional[str] = None) -> None: + """|coro| + + Deletes the channel. + + You must have :attr:`~discord.Permissions.manage_channels` to do this. + + Parameters + ----------- + reason: Optional[:class:`str`] + The reason for deleting this channel. + Shows up on the audit log. + + Raises + ------- + ~discord.Forbidden + You do not have proper permissions to delete the channel. + ~discord.NotFound + The channel was not found or was already deleted. + ~discord.HTTPException + Deleting the channel failed. + """ + await self._state.http.delete_channel(self.id, reason=reason) + + @overload + async def set_permissions( + self, + target: Union[Member, Role], + *, + overwrite: Optional[Union[PermissionOverwrite, _Undefined]] = ..., + reason: Optional[str] = ..., + ) -> None: + ... + + @overload + async def set_permissions( + self, + target: Union[Member, Role], + *, + reason: Optional[str] = ..., + **permissions: Optional[bool], + ) -> None: + ... + + async def set_permissions( + self, + target: Union[Member, Role], + *, + overwrite: Any = _undefined, + reason: Optional[str] = None, + **permissions: Optional[bool], + ) -> None: + r"""|coro| + + Sets the channel specific permission overwrites for a target in the + channel. + + The ``target`` parameter should either be a :class:`~discord.Member` or a + :class:`~discord.Role` that belongs to guild. + + The ``overwrite`` parameter, if given, must either be ``None`` or + :class:`~discord.PermissionOverwrite`. For convenience, you can pass in + keyword arguments denoting :class:`~discord.Permissions` attributes. If this is + done, then you cannot mix the keyword arguments with the ``overwrite`` + parameter. + + If the ``overwrite`` parameter is ``None``, then the permission + overwrites are deleted. + + You must have :attr:`~discord.Permissions.manage_roles` to do this. + + .. note:: + + This method *replaces* the old overwrites with the ones given. + + Examples + ---------- + + Setting allow and deny: :: + + await message.channel.set_permissions(message.author, read_messages=True, + send_messages=False) + + Deleting overwrites :: + + await channel.set_permissions(member, overwrite=None) + + Using :class:`~discord.PermissionOverwrite` :: + + overwrite = discord.PermissionOverwrite() + overwrite.send_messages = False + overwrite.read_messages = True + await channel.set_permissions(member, overwrite=overwrite) + + .. versionchanged:: 2.0 + This function will now raise :exc:`TypeError` instead of + ``InvalidArgument``. + + + Parameters + ----------- + target: Union[:class:`~discord.Member`, :class:`~discord.Role`] + The member or role to overwrite permissions for. + overwrite: Optional[:class:`~discord.PermissionOverwrite`] + The permissions to allow and deny to the target, or ``None`` to + delete the overwrite. + \*\*permissions + A keyword argument list of permissions to set for ease of use. + Cannot be mixed with ``overwrite``. + reason: Optional[:class:`str`] + The reason for doing this action. Shows up on the audit log. + + Raises + ------- + ~discord.Forbidden + You do not have permissions to edit channel specific permissions. + ~discord.HTTPException + Editing channel specific permissions failed. + ~discord.NotFound + The role or member being edited is not part of the guild. + TypeError + The ``overwrite`` parameter was invalid or the target type was not + :class:`~discord.Role` or :class:`~discord.Member`. + ValueError + The ``overwrite`` parameter and ``positions`` parameters were both + unset. + """ + + http = self._state.http + + if isinstance(target, User): + perm_type = _Overwrites.MEMBER + elif isinstance(target, Role): + perm_type = _Overwrites.ROLE + else: + raise ValueError('target parameter must be either Member or Role') + + if overwrite is _undefined: + if len(permissions) == 0: + raise ValueError('No overwrite provided.') + try: + overwrite = PermissionOverwrite(**permissions) + except (ValueError, TypeError): + raise TypeError('Invalid permissions given to keyword arguments.') + else: + if len(permissions) > 0: + raise TypeError('Cannot mix overwrite and keyword arguments.') + + if overwrite is None: + await http.delete_channel_permissions(self.id, target.id, reason=reason) + elif isinstance(overwrite, PermissionOverwrite): + (allow, deny) = overwrite.pair() + await http.edit_channel_permissions( + self.id, target.id, str(allow.value), str(deny.value), perm_type, reason=reason + ) + else: + raise TypeError('Invalid overwrite type provided.') + + async def _clone_impl( + self, + base_attrs: Dict[str, Any], + *, + name: Optional[str] = None, + category: Optional[CategoryChannel] = None, + reason: Optional[str] = None, + ) -> Self: + base_attrs['permission_overwrites'] = [x._asdict() for x in self._overwrites] + base_attrs['parent_id'] = self.category_id + base_attrs['name'] = name or self.name + if category is not None: + base_attrs['parent_id'] = category.id + + guild_id = self.guild.id + cls = self.__class__ + data = await self._state.http.create_channel(guild_id, self.type.value, reason=reason, **base_attrs) + obj = cls(state=self._state, guild=self.guild, data=data) + + # temporarily add it to the cache + self.guild._channels[obj.id] = obj # type: ignore # obj is a GuildChannel + return obj + + async def clone( + self, + *, + name: Optional[str] = None, + category: Optional[CategoryChannel] = None, + reason: Optional[str] = None, + ) -> Self: + """|coro| + + Clones this channel. This creates a channel with the same properties + as this channel. + + You must have :attr:`~discord.Permissions.manage_channels` to do this. + + .. versionadded:: 1.1 + + Parameters + ------------ + name: Optional[:class:`str`] + The name of the new channel. If not provided, defaults to this + channel name. + category: Optional[:class:`~discord.CategoryChannel`] + The category the new channel belongs to. + This parameter is ignored if cloning a category channel. + + .. versionadded:: 2.5 + reason: Optional[:class:`str`] + The reason for cloning this channel. Shows up on the audit log. + + Raises + ------- + ~discord.Forbidden + You do not have the proper permissions to create this channel. + ~discord.HTTPException + Creating the channel failed. + + Returns + -------- + :class:`.abc.GuildChannel` + The channel that was created. + """ + raise NotImplementedError + + @overload + async def move( + self, + *, + beginning: bool, + offset: int = MISSING, + category: Optional[Snowflake] = MISSING, + sync_permissions: bool = MISSING, + reason: Optional[str] = MISSING, + ) -> None: + ... + + @overload + async def move( + self, + *, + end: bool, + offset: int = MISSING, + category: Optional[Snowflake] = MISSING, + sync_permissions: bool = MISSING, + reason: str = MISSING, + ) -> None: + ... + + @overload + async def move( + self, + *, + before: Snowflake, + offset: int = MISSING, + category: Optional[Snowflake] = MISSING, + sync_permissions: bool = MISSING, + reason: str = MISSING, + ) -> None: + ... + + @overload + async def move( + self, + *, + after: Snowflake, + offset: int = MISSING, + category: Optional[Snowflake] = MISSING, + sync_permissions: bool = MISSING, + reason: str = MISSING, + ) -> None: + ... + + async def move(self, **kwargs: Any) -> None: + """|coro| + + A rich interface to help move a channel relative to other channels. + + If exact position movement is required, ``edit`` should be used instead. + + You must have :attr:`~discord.Permissions.manage_channels` to do this. + + .. note:: + + Voice channels will always be sorted below text channels. + This is a Discord limitation. + + .. versionadded:: 1.7 + + .. versionchanged:: 2.0 + This function will now raise :exc:`TypeError` or + :exc:`ValueError` instead of ``InvalidArgument``. + + Parameters + ------------ + beginning: :class:`bool` + Whether to move the channel to the beginning of the + channel list (or category if given). + This is mutually exclusive with ``end``, ``before``, and ``after``. + end: :class:`bool` + Whether to move the channel to the end of the + channel list (or category if given). + This is mutually exclusive with ``beginning``, ``before``, and ``after``. + before: :class:`~discord.abc.Snowflake` + Whether to move the channel before the given channel. + This is mutually exclusive with ``beginning``, ``end``, and ``after``. + after: :class:`~discord.abc.Snowflake` + Whether to move the channel after the given channel. + This is mutually exclusive with ``beginning``, ``end``, and ``before``. + offset: :class:`int` + The number of channels to offset the move by. For example, + an offset of ``2`` with ``beginning=True`` would move + it 2 after the beginning. A positive number moves it below + while a negative number moves it above. Note that this + number is relative and computed after the ``beginning``, + ``end``, ``before``, and ``after`` parameters. + category: Optional[:class:`~discord.abc.Snowflake`] + The category to move this channel under. + If ``None`` is given then it moves it out of the category. + This parameter is ignored if moving a category channel. + sync_permissions: :class:`bool` + Whether to sync the permissions with the category (if given). + reason: :class:`str` + The reason for the move. + + Raises + ------- + ValueError + An invalid position was given. + TypeError + A bad mix of arguments were passed. + Forbidden + You do not have permissions to move the channel. + HTTPException + Moving the channel failed. + """ + + if not kwargs: + return + + beginning, end = kwargs.get('beginning'), kwargs.get('end') + before, after = kwargs.get('before'), kwargs.get('after') + offset = kwargs.get('offset', 0) + if sum(bool(a) for a in (beginning, end, before, after)) > 1: + raise TypeError('Only one of [before, after, end, beginning] can be used.') + + bucket = self._sorting_bucket + parent_id = kwargs.get('category', MISSING) + # fmt: off + channels: List[GuildChannel] + if parent_id not in (MISSING, None): + parent_id = parent_id.id + channels = [ + ch + for ch in self.guild.channels + if ch._sorting_bucket == bucket + and ch.category_id == parent_id + ] + else: + channels = [ + ch + for ch in self.guild.channels + if ch._sorting_bucket == bucket + and ch.category_id == self.category_id + ] + # fmt: on + + channels.sort(key=lambda c: (c.position, c.id)) + + try: + # Try to remove ourselves from the channel list + channels.remove(self) + except ValueError: + # If we're not there then it's probably due to not being in the category + pass + + index = None + if beginning: + index = 0 + elif end: + index = len(channels) + elif before: + index = next((i for i, c in enumerate(channels) if c.id == before.id), None) + elif after: + index = next((i + 1 for i, c in enumerate(channels) if c.id == after.id), None) + + if index is None: + raise ValueError('Could not resolve appropriate move position') + + channels.insert(max((index + offset), 0), self) + payload: List[ChannelPositionUpdate] = [] + lock_permissions = kwargs.get('sync_permissions', False) + reason = kwargs.get('reason') + for index, channel in enumerate(channels): + d: ChannelPositionUpdate = {'id': channel.id, 'position': index} + if parent_id is not MISSING and channel.id == self.id: + d.update(parent_id=parent_id, lock_permissions=lock_permissions) + payload.append(d) + + await self._state.http.bulk_channel_update(self.guild.id, payload, reason=reason) + + async def create_invite( + self, + *, + reason: Optional[str] = None, + max_age: int = 0, + max_uses: int = 0, + temporary: bool = False, + unique: bool = True, + target_type: Optional[InviteTarget] = None, + target_user: Optional[User] = None, + target_application_id: Optional[int] = None, + ) -> Invite: + """|coro| + + Creates an instant invite from a text or voice channel. + + You must have :attr:`~discord.Permissions.create_instant_invite` to do this. + + Parameters + ------------ + max_age: :class:`int` + How long the invite should last in seconds. If it's 0 then the invite + doesn't expire. Defaults to ``0``. + max_uses: :class:`int` + How many uses the invite could be used for. If it's 0 then there + are unlimited uses. Defaults to ``0``. + temporary: :class:`bool` + Denotes that the invite grants temporary membership + (i.e. they get kicked after they disconnect). Defaults to ``False``. + unique: :class:`bool` + Indicates if a unique invite URL should be created. Defaults to True. + If this is set to ``False`` then it will return a previously created + invite. + reason: Optional[:class:`str`] + The reason for creating this invite. Shows up on the audit log. + target_type: Optional[:class:`.InviteTarget`] + The type of target for the voice channel invite, if any. + + .. versionadded:: 2.0 + + target_user: Optional[:class:`User`] + The user whose stream to display for this invite, required if ``target_type`` is :attr:`.InviteTarget.stream`. The user must be streaming in the channel. + + .. versionadded:: 2.0 + + target_application_id:: Optional[:class:`int`] + The id of the embedded application for the invite, required if ``target_type`` is :attr:`.InviteTarget.embedded_application`. + + .. versionadded:: 2.0 + + Raises + ------- + ~discord.HTTPException + Invite creation failed. + + ~discord.NotFound + The channel that was passed is a category or an invalid channel. + + Returns + -------- + :class:`~discord.Invite` + The invite that was created. + """ + if target_type is InviteTarget.unknown: + raise ValueError('Cannot create invite with an unknown target type') + + data = await self._state.http.create_invite( + self.id, + reason=reason, + max_age=max_age, + max_uses=max_uses, + temporary=temporary, + unique=unique, + target_type=target_type.value if target_type else None, + target_user_id=target_user.id if target_user else None, + target_application_id=target_application_id, + ) + return Invite.from_incomplete(data=data, state=self._state) + + async def invites(self) -> List[Invite]: + """|coro| + + Returns a list of all active instant invites from this channel. + + You must have :attr:`~discord.Permissions.manage_channels` to get this information. + + Raises + ------- + ~discord.Forbidden + You do not have proper permissions to get the information. + ~discord.HTTPException + An error occurred while fetching the information. + + Returns + ------- + List[:class:`~discord.Invite`] + The list of invites that are currently active. + """ + + state = self._state + data = await state.http.invites_from_channel(self.id) + guild = self.guild + return [Invite(state=state, data=invite, channel=self, guild=guild) for invite in data] + + +class Messageable: + """An ABC that details the common operations on a model that can send messages. + + The following classes implement this ABC: + + - :class:`~discord.TextChannel` + - :class:`~discord.VoiceChannel` + - :class:`~discord.StageChannel` + - :class:`~discord.DMChannel` + - :class:`~discord.GroupChannel` + - :class:`~discord.PartialMessageable` + - :class:`~discord.User` + - :class:`~discord.Member` + - :class:`~discord.ext.commands.Context` + - :class:`~discord.Thread` + """ + + __slots__ = () + _state: ConnectionState + + async def _get_channel(self) -> MessageableChannel: + raise NotImplementedError + + @overload + async def send( + self, + content: Optional[str] = ..., + *, + tts: bool = ..., + embed: Embed = ..., + file: File = ..., + stickers: Sequence[Union[GuildSticker, StickerItem]] = ..., + delete_after: float = ..., + nonce: Union[str, int] = ..., + allowed_mentions: AllowedMentions = ..., + reference: Union[Message, MessageReference, PartialMessage] = ..., + mention_author: bool = ..., + view: View = ..., + suppress_embeds: bool = ..., + silent: bool = ..., + poll: Poll = ..., + ) -> Message: + ... + + @overload + async def send( + self, + content: Optional[str] = ..., + *, + tts: bool = ..., + embed: Embed = ..., + files: Sequence[File] = ..., + stickers: Sequence[Union[GuildSticker, StickerItem]] = ..., + delete_after: float = ..., + nonce: Union[str, int] = ..., + allowed_mentions: AllowedMentions = ..., + reference: Union[Message, MessageReference, PartialMessage] = ..., + mention_author: bool = ..., + view: View = ..., + suppress_embeds: bool = ..., + silent: bool = ..., + poll: Poll = ..., + ) -> Message: + ... + + @overload + async def send( + self, + content: Optional[str] = ..., + *, + tts: bool = ..., + embeds: Sequence[Embed] = ..., + file: File = ..., + stickers: Sequence[Union[GuildSticker, StickerItem]] = ..., + delete_after: float = ..., + nonce: Union[str, int] = ..., + allowed_mentions: AllowedMentions = ..., + reference: Union[Message, MessageReference, PartialMessage] = ..., + mention_author: bool = ..., + view: View = ..., + suppress_embeds: bool = ..., + silent: bool = ..., + poll: Poll = ..., + ) -> Message: + ... + + @overload + async def send( + self, + content: Optional[str] = ..., + *, + tts: bool = ..., + embeds: Sequence[Embed] = ..., + files: Sequence[File] = ..., + stickers: Sequence[Union[GuildSticker, StickerItem]] = ..., + delete_after: float = ..., + nonce: Union[str, int] = ..., + allowed_mentions: AllowedMentions = ..., + reference: Union[Message, MessageReference, PartialMessage] = ..., + mention_author: bool = ..., + view: View = ..., + suppress_embeds: bool = ..., + silent: bool = ..., + poll: Poll = ..., + ) -> Message: + ... + + async def send( + self, + content: Optional[str] = None, + *, + tts: bool = False, + embed: Optional[Embed] = None, + embeds: Optional[Sequence[Embed]] = None, + file: Optional[File] = None, + files: Optional[Sequence[File]] = None, + stickers: Optional[Sequence[Union[GuildSticker, StickerItem]]] = None, + delete_after: Optional[float] = None, + nonce: Optional[Union[str, int]] = None, + allowed_mentions: Optional[AllowedMentions] = None, + reference: Optional[Union[Message, MessageReference, PartialMessage]] = None, + mention_author: Optional[bool] = None, + view: Optional[View] = None, + suppress_embeds: bool = False, + silent: bool = False, + poll: Optional[Poll] = None, + ) -> Message: + """|coro| + + Sends a message to the destination with the content given. + + The content must be a type that can convert to a string through ``str(content)``. + If the content is set to ``None`` (the default), then the ``embed`` parameter must + be provided. + + To upload a single file, the ``file`` parameter should be used with a + single :class:`~discord.File` object. To upload multiple files, the ``files`` + parameter should be used with a :class:`list` of :class:`~discord.File` objects. + **Specifying both parameters will lead to an exception**. + + To upload a single embed, the ``embed`` parameter should be used with a + single :class:`~discord.Embed` object. To upload multiple embeds, the ``embeds`` + parameter should be used with a :class:`list` of :class:`~discord.Embed` objects. + **Specifying both parameters will lead to an exception**. + + .. versionchanged:: 2.0 + This function will now raise :exc:`TypeError` or + :exc:`ValueError` instead of ``InvalidArgument``. + + Parameters + ------------ + content: Optional[:class:`str`] + The content of the message to send. + tts: :class:`bool` + Indicates if the message should be sent using text-to-speech. + embed: :class:`~discord.Embed` + The rich embed for the content. + embeds: List[:class:`~discord.Embed`] + A list of embeds to upload. Must be a maximum of 10. + + .. versionadded:: 2.0 + file: :class:`~discord.File` + The file to upload. + files: List[:class:`~discord.File`] + A list of files to upload. Must be a maximum of 10. + nonce: :class:`int` + The nonce to use for sending this message. If the message was successfully sent, + then the message will have a nonce with this value. + delete_after: :class:`float` + If provided, the number of seconds to wait in the background + before deleting the message we just sent. If the deletion fails, + then it is silently ignored. + allowed_mentions: :class:`~discord.AllowedMentions` + Controls the mentions being processed in this message. If this is + passed, then the object is merged with :attr:`~discord.Client.allowed_mentions`. + The merging behaviour only overrides attributes that have been explicitly passed + to the object, otherwise it uses the attributes set in :attr:`~discord.Client.allowed_mentions`. + If no object is passed at all then the defaults given by :attr:`~discord.Client.allowed_mentions` + are used instead. + + .. versionadded:: 1.4 + + reference: Union[:class:`~discord.Message`, :class:`~discord.MessageReference`, :class:`~discord.PartialMessage`] + A reference to the :class:`~discord.Message` to which you are referencing, this can be created using + :meth:`~discord.Message.to_reference` or passed directly as a :class:`~discord.Message`. + In the event of a replying reference, you can control whether this mentions the author of the referenced + message using the :attr:`~discord.AllowedMentions.replied_user` attribute of ``allowed_mentions`` or by + setting ``mention_author``. + + .. versionadded:: 1.6 + + mention_author: Optional[:class:`bool`] + If set, overrides the :attr:`~discord.AllowedMentions.replied_user` attribute of ``allowed_mentions``. + + .. versionadded:: 1.6 + view: :class:`discord.ui.View` + A Discord UI View to add to the message. + + .. versionadded:: 2.0 + stickers: Sequence[Union[:class:`~discord.GuildSticker`, :class:`~discord.StickerItem`]] + A list of stickers to upload. Must be a maximum of 3. + + .. versionadded:: 2.0 + suppress_embeds: :class:`bool` + Whether to suppress embeds for the message. This sends the message without any embeds if set to ``True``. + + .. versionadded:: 2.0 + silent: :class:`bool` + Whether to suppress push and desktop notifications for the message. This will increment the mention counter + in the UI, but will not actually send a notification. + + .. versionadded:: 2.2 + poll: :class:`~discord.Poll` + The poll to send with this message. + + .. versionadded:: 2.4 + + Raises + -------- + ~discord.HTTPException + Sending the message failed. + ~discord.Forbidden + You do not have the proper permissions to send the message. + ~discord.NotFound + You sent a message with the same nonce as one that has been explicitly + deleted shortly earlier. + ValueError + The ``files`` or ``embeds`` list is not of the appropriate size. + TypeError + You specified both ``file`` and ``files``, + or you specified both ``embed`` and ``embeds``, + or the ``reference`` object is not a :class:`~discord.Message`, + :class:`~discord.MessageReference` or :class:`~discord.PartialMessage`. + + Returns + --------- + :class:`~discord.Message` + The message that was sent. + """ + + channel = await self._get_channel() + state = self._state + content = str(content) if content is not None else None + previous_allowed_mention = state.allowed_mentions + + if stickers is not None: + sticker_ids: SnowflakeList = [sticker.id for sticker in stickers] + else: + sticker_ids = MISSING + + if reference is not None: + try: + reference_dict = reference.to_message_reference_dict() + except AttributeError: + raise TypeError('reference parameter must be Message, MessageReference, or PartialMessage') from None + else: + reference_dict = MISSING + + if view and not hasattr(view, '__discord_ui_view__'): + raise TypeError(f'view parameter must be View not {view.__class__.__name__}') + + if suppress_embeds or silent: + from .message import MessageFlags # circular import + + flags = MessageFlags._from_value(0) + flags.suppress_embeds = suppress_embeds + flags.suppress_notifications = silent + else: + flags = MISSING + + if nonce is None: + nonce = secrets.randbits(64) + + with handle_message_parameters( + content=content, + tts=tts, + file=file if file is not None else MISSING, + files=files if files is not None else MISSING, + embed=embed if embed is not None else MISSING, + embeds=embeds if embeds is not None else MISSING, + nonce=nonce, + allowed_mentions=allowed_mentions, + message_reference=reference_dict, + previous_allowed_mentions=previous_allowed_mention, + mention_author=mention_author, + stickers=sticker_ids, + view=view, + flags=flags, + poll=poll, + ) as params: + data = await state.http.send_message(channel.id, params=params) + + ret = state.create_message(channel=channel, data=data) + if view and not view.is_finished(): + state.store_view(view, ret.id) + + if poll: + poll._update(ret) + + if delete_after is not None: + await ret.delete(delay=delete_after) + return ret + + def typing(self) -> Typing: + """Returns an asynchronous context manager that allows you to send a typing indicator to + the destination for an indefinite period of time, or 10 seconds if the context manager + is called using ``await``. + + Example Usage: :: + + async with channel.typing(): + # simulate something heavy + await asyncio.sleep(20) + + await channel.send('Done!') + + Example Usage: :: + + await channel.typing() + # Do some computational magic for about 10 seconds + await channel.send('Done!') + + .. versionchanged:: 2.0 + This no longer works with the ``with`` syntax, ``async with`` must be used instead. + + .. versionchanged:: 2.0 + Added functionality to ``await`` the context manager to send a typing indicator for 10 seconds. + """ + return Typing(self) + + async def fetch_message(self, id: int, /) -> Message: + """|coro| + + Retrieves a single :class:`~discord.Message` from the destination. + + Parameters + ------------ + id: :class:`int` + The message ID to look for. + + Raises + -------- + ~discord.NotFound + The specified message was not found. + ~discord.Forbidden + You do not have the permissions required to get a message. + ~discord.HTTPException + Retrieving the message failed. + + Returns + -------- + :class:`~discord.Message` + The message asked for. + """ + + channel = await self._get_channel() + data = await self._state.http.get_message(channel.id, id) + return self._state.create_message(channel=channel, data=data) + + async def pins(self) -> List[Message]: + """|coro| + + Retrieves all messages that are currently pinned in the channel. + + .. note:: + + Due to a limitation with the Discord API, the :class:`.Message` + objects returned by this method do not contain complete + :attr:`.Message.reactions` data. + + Raises + ------- + ~discord.Forbidden + You do not have the permission to retrieve pinned messages. + ~discord.HTTPException + Retrieving the pinned messages failed. + + Returns + -------- + List[:class:`~discord.Message`] + The messages that are currently pinned. + """ + + channel = await self._get_channel() + state = self._state + data = await state.http.pins_from(channel.id) + return [state.create_message(channel=channel, data=m) for m in data] + + async def history( + self, + *, + limit: Optional[int] = 100, + before: Optional[SnowflakeTime] = None, + after: Optional[SnowflakeTime] = None, + around: Optional[SnowflakeTime] = None, + oldest_first: Optional[bool] = None, + ) -> AsyncIterator[Message]: + """Returns an :term:`asynchronous iterator` that enables receiving the destination's message history. + + You must have :attr:`~discord.Permissions.read_message_history` to do this. + + Examples + --------- + + Usage :: + + counter = 0 + async for message in channel.history(limit=200): + if message.author == client.user: + counter += 1 + + Flattening into a list: :: + + messages = [message async for message in channel.history(limit=123)] + # messages is now a list of Message... + + All parameters are optional. + + Parameters + ----------- + limit: Optional[:class:`int`] + The number of messages to retrieve. + If ``None``, retrieves every message in the channel. Note, however, + that this would make it a slow operation. + before: Optional[Union[:class:`~discord.abc.Snowflake`, :class:`datetime.datetime`]] + Retrieve messages before this date or message. + If a datetime is provided, it is recommended to use a UTC aware datetime. + If the datetime is naive, it is assumed to be local time. + after: Optional[Union[:class:`~discord.abc.Snowflake`, :class:`datetime.datetime`]] + Retrieve messages after this date or message. + If a datetime is provided, it is recommended to use a UTC aware datetime. + If the datetime is naive, it is assumed to be local time. + around: Optional[Union[:class:`~discord.abc.Snowflake`, :class:`datetime.datetime`]] + Retrieve messages around this date or message. + If a datetime is provided, it is recommended to use a UTC aware datetime. + If the datetime is naive, it is assumed to be local time. + When using this argument, the maximum limit is 101. Note that if the limit is an + even number then this will return at most limit + 1 messages. + oldest_first: Optional[:class:`bool`] + If set to ``True``, return messages in oldest->newest order. Defaults to ``True`` if + ``after`` is specified, otherwise ``False``. + + Raises + ------ + ~discord.Forbidden + You do not have permissions to get channel message history. + ~discord.HTTPException + The request to get message history failed. + + Yields + ------- + :class:`~discord.Message` + The message with the message data parsed. + """ + + async def _around_strategy(retrieve: int, around: Optional[Snowflake], limit: Optional[int]): + if not around: + return [], None, 0 + + around_id = around.id if around else None + data = await self._state.http.logs_from(channel.id, retrieve, around=around_id) + + return data, None, 0 + + async def _after_strategy(retrieve: int, after: Optional[Snowflake], limit: Optional[int]): + after_id = after.id if after else None + data = await self._state.http.logs_from(channel.id, retrieve, after=after_id) + + if data: + if limit is not None: + limit -= len(data) + + after = Object(id=int(data[0]['id'])) + + return data, after, limit + + async def _before_strategy(retrieve: int, before: Optional[Snowflake], limit: Optional[int]): + before_id = before.id if before else None + data = await self._state.http.logs_from(channel.id, retrieve, before=before_id) + + if data: + if limit is not None: + limit -= len(data) + + before = Object(id=int(data[-1]['id'])) + + return data, before, limit + + if isinstance(before, datetime): + before = Object(id=utils.time_snowflake(before, high=False)) + if isinstance(after, datetime): + after = Object(id=utils.time_snowflake(after, high=True)) + if isinstance(around, datetime): + around = Object(id=utils.time_snowflake(around)) + + if oldest_first is None: + reverse = after is not None + else: + reverse = oldest_first + + after = after or OLDEST_OBJECT + predicate = None + + if around: + if limit is None: + raise ValueError('history does not support around with limit=None') + if limit > 101: + raise ValueError("history max limit 101 when specifying around parameter") + + # Strange Discord quirk + limit = 100 if limit == 101 else limit + + strategy, state = _around_strategy, around + + if before and after: + predicate = lambda m: after.id < int(m['id']) < before.id + elif before: + predicate = lambda m: int(m['id']) < before.id + elif after: + predicate = lambda m: after.id < int(m['id']) + elif reverse: + strategy, state = _after_strategy, after + if before: + predicate = lambda m: int(m['id']) < before.id + else: + strategy, state = _before_strategy, before + if after and after != OLDEST_OBJECT: + predicate = lambda m: int(m['id']) > after.id + + channel = await self._get_channel() + + while True: + retrieve = 100 if limit is None else min(limit, 100) + if retrieve < 1: + return + + data, state, limit = await strategy(retrieve, state, limit) + + if reverse: + data = reversed(data) + if predicate: + data = filter(predicate, data) + + count = 0 + + for count, raw_message in enumerate(data, 1): + yield self._state.create_message(channel=channel, data=raw_message) + + if count < 100: + # There's no data left after this + break + + +class Connectable(Protocol): + """An ABC that details the common operations on a channel that can + connect to a voice server. + + The following implement this ABC: + + - :class:`~discord.VoiceChannel` + - :class:`~discord.StageChannel` + """ + + __slots__ = () + _state: ConnectionState + + def _get_voice_client_key(self) -> Tuple[int, str]: + raise NotImplementedError + + def _get_voice_state_pair(self) -> Tuple[int, int]: + raise NotImplementedError + + async def connect( + self, + *, + timeout: float = 30.0, + reconnect: bool = True, + cls: Callable[[Client, Connectable], T] = VoiceClient, + self_deaf: bool = False, + self_mute: bool = False, + ) -> T: + """|coro| + + Connects to voice and creates a :class:`~discord.VoiceClient` to establish + your connection to the voice server. + + This requires :attr:`~discord.Intents.voice_states`. + + Parameters + ----------- + timeout: :class:`float` + The timeout in seconds to wait the connection to complete. + reconnect: :class:`bool` + Whether the bot should automatically attempt + a reconnect if a part of the handshake fails + or the gateway goes down. + cls: Type[:class:`~discord.VoiceProtocol`] + A type that subclasses :class:`~discord.VoiceProtocol` to connect with. + Defaults to :class:`~discord.VoiceClient`. + self_mute: :class:`bool` + Indicates if the client should be self-muted. + + .. versionadded:: 2.0 + self_deaf: :class:`bool` + Indicates if the client should be self-deafened. + + .. versionadded:: 2.0 + + Raises + ------- + asyncio.TimeoutError + Could not connect to the voice channel in time. + ~discord.ClientException + You are already connected to a voice channel. + ~discord.opus.OpusNotLoaded + The opus library has not been loaded. + + Returns + -------- + :class:`~discord.VoiceProtocol` + A voice client that is fully connected to the voice server. + """ + + key_id, _ = self._get_voice_client_key() + state = self._state + + if state._get_voice_client(key_id): + raise ClientException('Already connected to a voice channel.') + + client = state._get_client() + voice: T = cls(client, self) + + if not isinstance(voice, VoiceProtocol): + raise TypeError('Type must meet VoiceProtocol abstract base class.') + + state._add_voice_client(key_id, voice) + + try: + await voice.connect(timeout=timeout, reconnect=reconnect, self_deaf=self_deaf, self_mute=self_mute) + except asyncio.TimeoutError: + try: + await voice.disconnect(force=True) + except Exception: + # we don't care if disconnect failed because connection failed + pass + raise # re-raise + + return voice diff --git a/venv/lib/python3.12/site-packages/discord/activity.py b/venv/lib/python3.12/site-packages/discord/activity.py new file mode 100644 index 00000000..324bea42 --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/activity.py @@ -0,0 +1,870 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from __future__ import annotations + +import datetime +from typing import Any, Dict, List, Optional, TYPE_CHECKING, Union, overload + +from .asset import Asset +from .enums import ActivityType, try_enum +from .colour import Colour +from .partial_emoji import PartialEmoji +from .utils import _get_as_snowflake + +__all__ = ( + 'BaseActivity', + 'Activity', + 'Streaming', + 'Game', + 'Spotify', + 'CustomActivity', +) + +"""If curious, this is the current schema for an activity. + +It's fairly long so I will document it here: + +All keys are optional. + +state: str (max: 128), +details: str (max: 128) +timestamps: dict + start: int (min: 1) + end: int (min: 1) +assets: dict + large_image: str (max: 32) + large_text: str (max: 128) + small_image: str (max: 32) + small_text: str (max: 128) +party: dict + id: str (max: 128), + size: List[int] (max-length: 2) + elem: int (min: 1) +secrets: dict + match: str (max: 128) + join: str (max: 128) + spectate: str (max: 128) +instance: bool +application_id: str +name: str (max: 128) +url: str +type: int +sync_id: str +session_id: str +flags: int +buttons: list[str (max: 32)] + +There are also activity flags which are mostly uninteresting for the library atm. + +t.ActivityFlags = { + INSTANCE: 1, + JOIN: 2, + SPECTATE: 4, + JOIN_REQUEST: 8, + SYNC: 16, + PLAY: 32 +} +""" + +if TYPE_CHECKING: + from .types.activity import ( + Activity as ActivityPayload, + ActivityTimestamps, + ActivityParty, + ActivityAssets, + ) + + from .state import ConnectionState + + +class BaseActivity: + """The base activity that all user-settable activities inherit from. + A user-settable activity is one that can be used in :meth:`Client.change_presence`. + + The following types currently count as user-settable: + + - :class:`Activity` + - :class:`Game` + - :class:`Streaming` + - :class:`CustomActivity` + + Note that although these types are considered user-settable by the library, + Discord typically ignores certain combinations of activity depending on + what is currently set. This behaviour may change in the future so there are + no guarantees on whether Discord will actually let you set these types. + + .. versionadded:: 1.3 + """ + + __slots__ = ('_created_at',) + + def __init__(self, **kwargs: Any) -> None: + self._created_at: Optional[float] = kwargs.pop('created_at', None) + + @property + def created_at(self) -> Optional[datetime.datetime]: + """Optional[:class:`datetime.datetime`]: When the user started doing this activity in UTC. + + .. versionadded:: 1.3 + """ + if self._created_at is not None: + return datetime.datetime.fromtimestamp(self._created_at / 1000, tz=datetime.timezone.utc) + + def to_dict(self) -> ActivityPayload: + raise NotImplementedError + + +class Activity(BaseActivity): + """Represents an activity in Discord. + + This could be an activity such as streaming, playing, listening + or watching. + + For memory optimisation purposes, some activities are offered in slimmed + down versions: + + - :class:`Game` + - :class:`Streaming` + + Attributes + ------------ + application_id: Optional[:class:`int`] + The application ID of the game. + name: Optional[:class:`str`] + The name of the activity. + url: Optional[:class:`str`] + A stream URL that the activity could be doing. + type: :class:`ActivityType` + The type of activity currently being done. + state: Optional[:class:`str`] + The user's current state. For example, "In Game". + details: Optional[:class:`str`] + The detail of the user's current activity. + platform: Optional[:class:`str`] + The user's current platform. + + .. versionadded:: 2.4 + timestamps: :class:`dict` + A dictionary of timestamps. It contains the following optional keys: + + - ``start``: Corresponds to when the user started doing the + activity in milliseconds since Unix epoch. + - ``end``: Corresponds to when the user will finish doing the + activity in milliseconds since Unix epoch. + + assets: :class:`dict` + A dictionary representing the images and their hover text of an activity. + It contains the following optional keys: + + - ``large_image``: A string representing the ID for the large image asset. + - ``large_text``: A string representing the text when hovering over the large image asset. + - ``small_image``: A string representing the ID for the small image asset. + - ``small_text``: A string representing the text when hovering over the small image asset. + + party: :class:`dict` + A dictionary representing the activity party. It contains the following optional keys: + + - ``id``: A string representing the party ID. + - ``size``: A list of up to two integer elements denoting (current_size, maximum_size). + buttons: List[:class:`str`] + A list of strings representing the labels of custom buttons shown in a rich presence. + + .. versionadded:: 2.0 + + emoji: Optional[:class:`PartialEmoji`] + The emoji that belongs to this activity. + """ + + __slots__ = ( + 'state', + 'details', + 'timestamps', + 'platform', + 'assets', + 'party', + 'flags', + 'sync_id', + 'session_id', + 'type', + 'name', + 'url', + 'application_id', + 'emoji', + 'buttons', + ) + + def __init__(self, **kwargs: Any) -> None: + super().__init__(**kwargs) + self.state: Optional[str] = kwargs.pop('state', None) + self.details: Optional[str] = kwargs.pop('details', None) + self.timestamps: ActivityTimestamps = kwargs.pop('timestamps', {}) + self.platform: Optional[str] = kwargs.pop('platform', None) + self.assets: ActivityAssets = kwargs.pop('assets', {}) + self.party: ActivityParty = kwargs.pop('party', {}) + self.application_id: Optional[int] = _get_as_snowflake(kwargs, 'application_id') + self.name: Optional[str] = kwargs.pop('name', None) + self.url: Optional[str] = kwargs.pop('url', None) + self.flags: int = kwargs.pop('flags', 0) + self.sync_id: Optional[str] = kwargs.pop('sync_id', None) + self.session_id: Optional[str] = kwargs.pop('session_id', None) + self.buttons: List[str] = kwargs.pop('buttons', []) + + activity_type = kwargs.pop('type', -1) + self.type: ActivityType = ( + activity_type if isinstance(activity_type, ActivityType) else try_enum(ActivityType, activity_type) + ) + + emoji = kwargs.pop('emoji', None) + self.emoji: Optional[PartialEmoji] = PartialEmoji.from_dict(emoji) if emoji is not None else None + + def __repr__(self) -> str: + attrs = ( + ('type', self.type), + ('name', self.name), + ('url', self.url), + ('platform', self.platform), + ('details', self.details), + ('application_id', self.application_id), + ('session_id', self.session_id), + ('emoji', self.emoji), + ) + inner = ' '.join('%s=%r' % t for t in attrs) + return f'' + + def to_dict(self) -> Dict[str, Any]: + ret: Dict[str, Any] = {} + for attr in self.__slots__: + value = getattr(self, attr, None) + if value is None: + continue + + if isinstance(value, dict) and len(value) == 0: + continue + + ret[attr] = value + ret['type'] = int(self.type) + if self.emoji: + ret['emoji'] = self.emoji.to_dict() + return ret + + @property + def start(self) -> Optional[datetime.datetime]: + """Optional[:class:`datetime.datetime`]: When the user started doing this activity in UTC, if applicable.""" + try: + timestamp = self.timestamps['start'] / 1000 # pyright: ignore[reportTypedDictNotRequiredAccess] + except KeyError: + return None + else: + return datetime.datetime.fromtimestamp(timestamp, tz=datetime.timezone.utc) + + @property + def end(self) -> Optional[datetime.datetime]: + """Optional[:class:`datetime.datetime`]: When the user will stop doing this activity in UTC, if applicable.""" + try: + timestamp = self.timestamps['end'] / 1000 # pyright: ignore[reportTypedDictNotRequiredAccess] + except KeyError: + return None + else: + return datetime.datetime.fromtimestamp(timestamp, tz=datetime.timezone.utc) + + @property + def large_image_url(self) -> Optional[str]: + """Optional[:class:`str`]: Returns a URL pointing to the large image asset of this activity, if applicable.""" + try: + large_image = self.assets['large_image'] # pyright: ignore[reportTypedDictNotRequiredAccess] + except KeyError: + return None + else: + return self._image_url(large_image) + + @property + def small_image_url(self) -> Optional[str]: + """Optional[:class:`str`]: Returns a URL pointing to the small image asset of this activity, if applicable.""" + try: + small_image = self.assets['small_image'] # pyright: ignore[reportTypedDictNotRequiredAccess] + except KeyError: + return None + else: + return self._image_url(small_image) + + def _image_url(self, image: str) -> Optional[str]: + if image.startswith('mp:'): + return f'https://media.discordapp.net/{image[3:]}' + elif self.application_id is not None: + return Asset.BASE + f'/app-assets/{self.application_id}/{image}.png' + + @property + def large_image_text(self) -> Optional[str]: + """Optional[:class:`str`]: Returns the large image asset hover text of this activity, if applicable.""" + return self.assets.get('large_text', None) + + @property + def small_image_text(self) -> Optional[str]: + """Optional[:class:`str`]: Returns the small image asset hover text of this activity, if applicable.""" + return self.assets.get('small_text', None) + + +class Game(BaseActivity): + """A slimmed down version of :class:`Activity` that represents a Discord game. + + This is typically displayed via **Playing** on the official Discord client. + + .. container:: operations + + .. describe:: x == y + + Checks if two games are equal. + + .. describe:: x != y + + Checks if two games are not equal. + + .. describe:: hash(x) + + Returns the game's hash. + + .. describe:: str(x) + + Returns the game's name. + + Parameters + ----------- + name: :class:`str` + The game's name. + + Attributes + ----------- + name: :class:`str` + The game's name. + platform: Optional[:class:`str`] + Where the user is playing from (ie. PS5, Xbox). + + .. versionadded:: 2.4 + + assets: :class:`dict` + A dictionary representing the images and their hover text of a game. + It contains the following optional keys: + + - ``large_image``: A string representing the ID for the large image asset. + - ``large_text``: A string representing the text when hovering over the large image asset. + - ``small_image``: A string representing the ID for the small image asset. + - ``small_text``: A string representing the text when hovering over the small image asset. + + .. versionadded:: 2.4 + """ + + __slots__ = ('name', '_end', '_start', 'platform', 'assets') + + def __init__(self, name: str, **extra: Any) -> None: + super().__init__(**extra) + self.name: str = name + self.platform: Optional[str] = extra.get('platform') + self.assets: ActivityAssets = extra.get('assets', {}) or {} + + try: + timestamps: ActivityTimestamps = extra['timestamps'] + except KeyError: + self._start = 0 + self._end = 0 + else: + self._start = timestamps.get('start', 0) + self._end = timestamps.get('end', 0) + + @property + def type(self) -> ActivityType: + """:class:`ActivityType`: Returns the game's type. This is for compatibility with :class:`Activity`. + + It always returns :attr:`ActivityType.playing`. + """ + return ActivityType.playing + + @property + def start(self) -> Optional[datetime.datetime]: + """Optional[:class:`datetime.datetime`]: When the user started playing this game in UTC, if applicable.""" + if self._start: + return datetime.datetime.fromtimestamp(self._start / 1000, tz=datetime.timezone.utc) + return None + + @property + def end(self) -> Optional[datetime.datetime]: + """Optional[:class:`datetime.datetime`]: When the user will stop playing this game in UTC, if applicable.""" + if self._end: + return datetime.datetime.fromtimestamp(self._end / 1000, tz=datetime.timezone.utc) + return None + + def __str__(self) -> str: + return str(self.name) + + def __repr__(self) -> str: + return f'' + + def to_dict(self) -> Dict[str, Any]: + timestamps: Dict[str, Any] = {} + if self._start: + timestamps['start'] = self._start + + if self._end: + timestamps['end'] = self._end + + return { + 'type': ActivityType.playing.value, + 'name': str(self.name), + 'timestamps': timestamps, + 'platform': str(self.platform) if self.platform else None, + 'assets': self.assets, + } + + def __eq__(self, other: object) -> bool: + return isinstance(other, Game) and other.name == self.name + + def __ne__(self, other: object) -> bool: + return not self.__eq__(other) + + def __hash__(self) -> int: + return hash(self.name) + + +class Streaming(BaseActivity): + """A slimmed down version of :class:`Activity` that represents a Discord streaming status. + + This is typically displayed via **Streaming** on the official Discord client. + + .. container:: operations + + .. describe:: x == y + + Checks if two streams are equal. + + .. describe:: x != y + + Checks if two streams are not equal. + + .. describe:: hash(x) + + Returns the stream's hash. + + .. describe:: str(x) + + Returns the stream's name. + + Attributes + ----------- + platform: Optional[:class:`str`] + Where the user is streaming from (ie. YouTube, Twitch). + + .. versionadded:: 1.3 + + name: Optional[:class:`str`] + The stream's name. + details: Optional[:class:`str`] + An alias for :attr:`name` + game: Optional[:class:`str`] + The game being streamed. + + .. versionadded:: 1.3 + + url: :class:`str` + The stream's URL. + assets: :class:`dict` + A dictionary comprising of similar keys than those in :attr:`Activity.assets`. + """ + + __slots__ = ('platform', 'name', 'game', 'url', 'details', 'assets') + + def __init__(self, *, name: Optional[str], url: str, **extra: Any) -> None: + super().__init__(**extra) + self.platform: Optional[str] = name + self.name: Optional[str] = extra.pop('details', name) + self.game: Optional[str] = extra.pop('state', None) + self.url: str = url + self.details: Optional[str] = extra.pop('details', self.name) # compatibility + self.assets: ActivityAssets = extra.pop('assets', {}) + + @property + def type(self) -> ActivityType: + """:class:`ActivityType`: Returns the game's type. This is for compatibility with :class:`Activity`. + + It always returns :attr:`ActivityType.streaming`. + """ + return ActivityType.streaming + + def __str__(self) -> str: + return str(self.name) + + def __repr__(self) -> str: + return f'' + + @property + def twitch_name(self) -> Optional[str]: + """Optional[:class:`str`]: If provided, the twitch name of the user streaming. + + This corresponds to the ``large_image`` key of the :attr:`Streaming.assets` + dictionary if it starts with ``twitch:``. Typically set by the Discord client. + """ + + try: + name = self.assets['large_image'] # pyright: ignore[reportTypedDictNotRequiredAccess] + except KeyError: + return None + else: + return name[7:] if name[:7] == 'twitch:' else None + + def to_dict(self) -> Dict[str, Any]: + ret: Dict[str, Any] = { + 'type': ActivityType.streaming.value, + 'name': str(self.name), + 'url': str(self.url), + 'assets': self.assets, + } + if self.details: + ret['details'] = self.details + return ret + + def __eq__(self, other: object) -> bool: + return isinstance(other, Streaming) and other.name == self.name and other.url == self.url + + def __ne__(self, other: object) -> bool: + return not self.__eq__(other) + + def __hash__(self) -> int: + return hash(self.name) + + +class Spotify: + """Represents a Spotify listening activity from Discord. This is a special case of + :class:`Activity` that makes it easier to work with the Spotify integration. + + .. container:: operations + + .. describe:: x == y + + Checks if two activities are equal. + + .. describe:: x != y + + Checks if two activities are not equal. + + .. describe:: hash(x) + + Returns the activity's hash. + + .. describe:: str(x) + + Returns the string 'Spotify'. + """ + + __slots__ = ('_state', '_details', '_timestamps', '_assets', '_party', '_sync_id', '_session_id', '_created_at') + + def __init__(self, **data: Any) -> None: + self._state: str = data.pop('state', '') + self._details: str = data.pop('details', '') + self._timestamps: ActivityTimestamps = data.pop('timestamps', {}) + self._assets: ActivityAssets = data.pop('assets', {}) + self._party: ActivityParty = data.pop('party', {}) + self._sync_id: str = data.pop('sync_id', '') + self._session_id: Optional[str] = data.pop('session_id') + self._created_at: Optional[float] = data.pop('created_at', None) + + @property + def type(self) -> ActivityType: + """:class:`ActivityType`: Returns the activity's type. This is for compatibility with :class:`Activity`. + + It always returns :attr:`ActivityType.listening`. + """ + return ActivityType.listening + + @property + def created_at(self) -> Optional[datetime.datetime]: + """Optional[:class:`datetime.datetime`]: When the user started listening in UTC. + + .. versionadded:: 1.3 + """ + if self._created_at is not None: + return datetime.datetime.fromtimestamp(self._created_at / 1000, tz=datetime.timezone.utc) + + @property + def colour(self) -> Colour: + """:class:`Colour`: Returns the Spotify integration colour, as a :class:`Colour`. + + There is an alias for this named :attr:`color`""" + return Colour(0x1DB954) + + @property + def color(self) -> Colour: + """:class:`Colour`: Returns the Spotify integration colour, as a :class:`Colour`. + + There is an alias for this named :attr:`colour`""" + return self.colour + + def to_dict(self) -> Dict[str, Any]: + return { + 'flags': 48, # SYNC | PLAY + 'name': 'Spotify', + 'assets': self._assets, + 'party': self._party, + 'sync_id': self._sync_id, + 'session_id': self._session_id, + 'timestamps': self._timestamps, + 'details': self._details, + 'state': self._state, + } + + @property + def name(self) -> str: + """:class:`str`: The activity's name. This will always return "Spotify".""" + return 'Spotify' + + def __eq__(self, other: object) -> bool: + return ( + isinstance(other, Spotify) + and other._session_id == self._session_id + and other._sync_id == self._sync_id + and other.start == self.start + ) + + def __ne__(self, other: object) -> bool: + return not self.__eq__(other) + + def __hash__(self) -> int: + return hash(self._session_id) + + def __str__(self) -> str: + return 'Spotify' + + def __repr__(self) -> str: + return f'' + + @property + def title(self) -> str: + """:class:`str`: The title of the song being played.""" + return self._details + + @property + def artists(self) -> List[str]: + """List[:class:`str`]: The artists of the song being played.""" + return self._state.split('; ') + + @property + def artist(self) -> str: + """:class:`str`: The artist of the song being played. + + This does not attempt to split the artist information into + multiple artists. Useful if there's only a single artist. + """ + return self._state + + @property + def album(self) -> str: + """:class:`str`: The album that the song being played belongs to.""" + return self._assets.get('large_text', '') + + @property + def album_cover_url(self) -> str: + """:class:`str`: The album cover image URL from Spotify's CDN.""" + large_image = self._assets.get('large_image', '') + if large_image[:8] != 'spotify:': + return '' + album_image_id = large_image[8:] + return 'https://i.scdn.co/image/' + album_image_id + + @property + def track_id(self) -> str: + """:class:`str`: The track ID used by Spotify to identify this song.""" + return self._sync_id + + @property + def track_url(self) -> str: + """:class:`str`: The track URL to listen on Spotify. + + .. versionadded:: 2.0 + """ + return f'https://open.spotify.com/track/{self.track_id}' + + @property + def start(self) -> datetime.datetime: + """:class:`datetime.datetime`: When the user started playing this song in UTC.""" + # the start key will be present here + return datetime.datetime.fromtimestamp(self._timestamps['start'] / 1000, tz=datetime.timezone.utc) # type: ignore + + @property + def end(self) -> datetime.datetime: + """:class:`datetime.datetime`: When the user will stop playing this song in UTC.""" + # the end key will be present here + return datetime.datetime.fromtimestamp(self._timestamps['end'] / 1000, tz=datetime.timezone.utc) # type: ignore + + @property + def duration(self) -> datetime.timedelta: + """:class:`datetime.timedelta`: The duration of the song being played.""" + return self.end - self.start + + @property + def party_id(self) -> str: + """:class:`str`: The party ID of the listening party.""" + return self._party.get('id', '') + + +class CustomActivity(BaseActivity): + """Represents a custom activity from Discord. + + .. container:: operations + + .. describe:: x == y + + Checks if two activities are equal. + + .. describe:: x != y + + Checks if two activities are not equal. + + .. describe:: hash(x) + + Returns the activity's hash. + + .. describe:: str(x) + + Returns the custom status text. + + .. versionadded:: 1.3 + + Attributes + ----------- + name: Optional[:class:`str`] + The custom activity's name. + emoji: Optional[:class:`PartialEmoji`] + The emoji to pass to the activity, if any. + """ + + __slots__ = ('name', 'emoji', 'state') + + def __init__( + self, name: Optional[str], *, emoji: Optional[Union[PartialEmoji, Dict[str, Any], str]] = None, **extra: Any + ) -> None: + super().__init__(**extra) + self.name: Optional[str] = name + self.state: Optional[str] = extra.pop('state', name) + if self.name == 'Custom Status': + self.name = self.state + + self.emoji: Optional[PartialEmoji] + if emoji is None: + self.emoji = emoji + elif isinstance(emoji, dict): + self.emoji = PartialEmoji.from_dict(emoji) + elif isinstance(emoji, str): + self.emoji = PartialEmoji(name=emoji) + elif isinstance(emoji, PartialEmoji): + self.emoji = emoji + else: + raise TypeError(f'Expected str, PartialEmoji, or None, received {type(emoji)!r} instead.') + + @property + def type(self) -> ActivityType: + """:class:`ActivityType`: Returns the activity's type. This is for compatibility with :class:`Activity`. + + It always returns :attr:`ActivityType.custom`. + """ + return ActivityType.custom + + def to_dict(self) -> Dict[str, Any]: + if self.name == self.state: + o = { + 'type': ActivityType.custom.value, + 'state': self.name, + 'name': 'Custom Status', + } + else: + o = { + 'type': ActivityType.custom.value, + 'name': self.name, + } + + if self.emoji: + o['emoji'] = self.emoji.to_dict() + return o + + def __eq__(self, other: object) -> bool: + return isinstance(other, CustomActivity) and other.name == self.name and other.emoji == self.emoji + + def __ne__(self, other: object) -> bool: + return not self.__eq__(other) + + def __hash__(self) -> int: + return hash((self.name, str(self.emoji))) + + def __str__(self) -> str: + if self.emoji: + if self.name: + return f'{self.emoji} {self.name}' + return str(self.emoji) + else: + return str(self.name) + + def __repr__(self) -> str: + return f'' + + +ActivityTypes = Union[Activity, Game, CustomActivity, Streaming, Spotify] + + +@overload +def create_activity(data: ActivityPayload, state: ConnectionState) -> ActivityTypes: + ... + + +@overload +def create_activity(data: None, state: ConnectionState) -> None: + ... + + +def create_activity(data: Optional[ActivityPayload], state: ConnectionState) -> Optional[ActivityTypes]: + if not data: + return None + + game_type = try_enum(ActivityType, data.get('type', -1)) + if game_type is ActivityType.playing: + if 'application_id' in data or 'session_id' in data: + return Activity(**data) + return Game(**data) + elif game_type is ActivityType.custom: + try: + name = data.pop('name') # type: ignore + except KeyError: + ret = Activity(**data) + else: + # we removed the name key from data already + ret = CustomActivity(name=name, **data) # type: ignore + elif game_type is ActivityType.streaming: + if 'url' in data: + # the url won't be None here + return Streaming(**data) # type: ignore + return Activity(**data) + elif game_type is ActivityType.listening and 'sync_id' in data and 'session_id' in data: + return Spotify(**data) + else: + ret = Activity(**data) + + if isinstance(ret.emoji, PartialEmoji): + ret.emoji._state = state + return ret diff --git a/venv/lib/python3.12/site-packages/discord/app_commands/__init__.py b/venv/lib/python3.12/site-packages/discord/app_commands/__init__.py new file mode 100644 index 00000000..a338cab7 --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/app_commands/__init__.py @@ -0,0 +1,21 @@ +""" +discord.app_commands +~~~~~~~~~~~~~~~~~~~~~ + +Application commands support for the Discord API + +:copyright: (c) 2015-present Rapptz +:license: MIT, see LICENSE for more details. + +""" + +from .commands import * +from .errors import * +from .models import * +from .tree import * +from .namespace import * +from .transformers import * +from .translator import * +from .installs import * +from . import checks as checks +from .checks import Cooldown as Cooldown diff --git a/venv/lib/python3.12/site-packages/discord/app_commands/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/app_commands/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..da021345ef2b2d0220a32368e0c18610e532ac94 GIT binary patch literal 683 zcmZvZzi$&U6vyrSYT~v7s`w=Y^4L@)CP9@@gpjJxAqXlUuw*%1?_P6O?`+F5Ks9I31ptXYPODd<0jE&eLVb!X|-9KePXe6 zk+yL=G$x32mW3*I?9Km-u{~o_8HHYI#aFT1O^ngj^CNA!Pk=wZOvv}14;br3+Dxq+ zC%(tGqbBd(>+H6S1qaIWmsr!!SPyf8a?sH}bV0h; zRG5J?VFdYxx1n-4L^K~Q6U!rse~%=BKq~2jplzn-^@ljuB!x$I3%j~lk=sG}Ri>2wE;VT7&ox4C c%*oZo+nN*PTXS-APOg6=cfONtdj-S)0*}tofB*mh literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/app_commands/__pycache__/checks.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/app_commands/__pycache__/checks.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6c5905bfb38f2e5c306f90dc3dce405d947f5afe GIT binary patch literal 22079 zcmeHvd2ke0nrCL+suH>-4hcxarNUAP33167TSx-b1_?{TZptvFRAovks6&%kLP(an zX-teoH$6blc7xZhVbk(GZ7QxiI|wNd;gf(*oa+K%Mp?*+`DwF_vn8%eSVSKCNn-bOG zYW7Y+d~;$;c#9~gJ~dC>qPo_i=Afv$RTut~2Ap(1;GlHTbBUMnG`v+Q3~zG?M+Bwl zvY-^d=RkG*!rPT~O37tcxJIc|N^uP;RZ1DIJ8&(>^|?I3{!dx2RG_R@-Jq<#E!yRj zQ#L4TE_=dtOP?tlm9;1jjk$u7-0TtrfA5eg9q;Isj>V#CQdgxK+ywpp*3|Hr78@K& zOEuA;)VQ-@ciph2>S{7Ab<4xU>2bgRgsLTCx*kgRYNHmFqVW-h#$Y~<#}YB#gP&e!^VezQBRXb4QSCvg`c%(lb(}!v$ zB}Ps6kEBskr$V-zwSLT_KBY;z8jn*8F^rqd)gE0fn=5+3+Ms`9iCDj*L#YJK#Ba?6 zOEfT|CDA1og{GUrlCd7os?ju+(8vc;@px*KrWQ>ll^D%eZ}ziqE%&F+t86a(^CnYi z43!UoJ^&j8|Ek6#eMrXG`&DDX&~Gg1ry_GYnB7Rfp2mldVeN-g8tZTAG(+hBXuH(Y zb-4GnmhN_`qenW?-SuimTYH;S-O_{m>RRcwj^3kPCwnE-=x*ukJtcJ=mRdSbNiTPF zw$)1QUp~>@-qYjn>Xtf=pE%ahjz2CEO1Gb?@zF`I9c`x~>aPX=xAt~) zb<#9iyE=Qjaa)U7cK2GZzShyxUMsb9cl2PW{=?l}Xr7i6Z_t``(tDllycJq%wm{Yw zK^0oClbEzMmbUhmV`vMXr*l!|kpE}Iv4UbYASba=7+vbYysWb&IhM_9O=+OFSW?Zp z+CXnv-%%Ocs6Vb|-6xaSjagqSb`UG@_Kpp!ugY51*ELKVM~-J#^`1J>9%((=-iq&j zr1NLQknf3EcXUXNo(p=iMV+Y=TI@U+!*NyDIoO>-7X`)*M#An(jC-45 z>Dlr_sq_lP#jUAC0wmj&Y)z%&N@_IuGvdvdrt74xYBb%PR)Wr~b5KoZy~jIxXvMRI z33;qvjYO^4i@o$}j~XAKS3AHOHJPy=%)&P$>k*9xoKHD$M}AjGcQzU7+0y=0IaYBf=l>((u zabI?aJ;)U)9^|~pc@^JnQ7KmPE_=g1r9|r*q9UTUu^Z5aaMl1F z=38_{4XYJa-(x-<6M~M;|6|?-y;)~0nbx+WAnRsJuhk&01u5A<$#Y0RA1(;K0alMy z&}lgMJdfV2CwkKBL2H^iIu6QC*7wwXX#~tctM3`sNOrw4B5NR+`qmz)VRvJFR7VO@ z(CY@lT!#16pI4LT>*KNh`r$E%_vEfnLu0)jORIIma`YUyf?f}y3|ds`fmlEtY}@Je zjEm@@;jyeQ5&;NFMzn=syd-o+bC;Kvoqfu`MCK+wpk8Kw&a+g1$?rYmeo{^dm**>`4c9GP=%_*D6L&hWeWgkRB~qX(Z|{%c0i zX}}JE63~@RQ8p>@Z48tE8V7R1PL~*(qVEV)fe#Rmsft1KM4%^RO-`uzyqvhH$fobQ zI*X8_Bbo->*DRUR;q}E7f5xgwO)#>LB?zmS^d~_s0N_CET#(e^RCI_yQdEvdN8&U} zW8iX{Q$008zm5S3QVqa{51i(ml$r-dlF{bAG&%@TQWNZ>$pIba&a7KyOJ$AAoR(E! zP5=~SGc4+qMsF{!IWmh~8H-Dwz+yM(9@7ChvsRcIqMybDmnZ9@k!GC<`2r_QMxu;Z ziF)rjwVk+Ry~a9cJ-l0!P&FcftRGU&;8f$K7OB{U{iviLL2^;}tV$?a{Yk~To3R_Q zKRY*dDZk!(^Yo3=cN%7jw@!H;1WJtiwjUh*?$Jzn?T-VsbLDGqp1N^r>hN4) z`P3?H7us4xK|}?Nf^H#06m$VJBnr<;McCmM9iai^XERdT>xy^|%c51G?h17FINBNq z<TS_WV zqzUMBzcEo*lQn5#i5RDiyqGEs8BM!>RED->5d|pWaZ5_A(2tRXR)?=2bZNVB(V8i- zCD&fuF5dZtw8=F!t&K(G0dTAFHH)@??h|?!>=ZOGUnP{T`*BIl?cR4!y?yGP*QdO5 z#pO3Q-q?6&^-OV)D4_WID_?(pu5|UyeK+>q8ogWg!>W5#nT@+MrF*9H_dF;pVFaM9 zLTf=$+mDMy3?%O@VhG{x*B}N$0@M!sVY^#0-z-~#F)Y$S-DegrjF`McHa4c15H5%- zw%{0FO>>Mqr6-UmxEdqTe0!{Bj*;jJf@}$i{%=hE9EmpqJA+AyQ88J19rekKXd}H1zXZW2z5IHqtjc{g5QEh)Rdj|zGjl8XYZ*4T|PhOEoi5VBrAHy3KMxpgAL z=9W8il+h0}wr0aij8b}g$n3EJv=*(j)O8h-iyLq@uoXleh~a_@J{93!}pv1cHdv^yT9Z8 zjt`W7ihmgY;E$$zPEVhaXV1hkXJXT*&rY8`H(eN?_Qlys20eTv^=OGB4a#LbU}#XN zvaZflQoSd3V!-=Q{;1I6hztpx(T>u4AtXi(?PV%prPL6br}ua%jh5Brk6!SfwC zdD;R-dDaQ5bugbaVc3w=NF?izL}20`iBmp568Ym1Ic_}hMk27nqZk`dk3$c~;x$r_ z3`8BE+(AlOC~2dFG=h5qTLwn++BPbs0v>I zyW-)_GI!~G?FRSW>F%D-1zZBDL?HUQOFIv_g{m@`E zP)cR+S!Nso+_m1VmBvydQes3;OM@|3_h}UB1sED7-WVSj^_S!I;A4`9p`63jg0|vu zj5enyxOHH!9E6SR+4|CxsnLPBd`_jI8$J%|(`d4nybEllK*TYf{2)or=|CncX=g!HhhFNAP~3D#Jog>Zg?q*oR?$9MRN1V_lwL0L3F1A=GBL zZcP5qRuMyj6KVh+H-It=fPo{jX~RFJkLhWZJV)57ZQKTip{LHr6f8Tl!jf4d%8d3_ z)24we1dR(lP$%?-&__&D<6}}h1*-|JhI0+=!P%D}j*Qt;Ur8uqwBeCc;;Ldb47Z>$ z2xH1iG+Wa^f~&FUYNDA8HmRg#>>*f+EnygYK?8lZ;is3(CN|aNY&}BIY|C*>$oK@f z0{f9PDkWG1C$#Ww@n()KVPz?nw&a%y5;T9>YqTc3XJjtr@R%!(w9k5OKoF+9tN=&O z2F#lF^@?T4ofMOs(xeWu-^$}VTVOu7uU8y@VcQ4A3GreeU2HzJTfZa{$m_fZR|TzO zFWfl(7;FI?jbvR!RT>mDK`Ww!q*2z#6l3yU3=+0xCK(#^A_wVBe|yS+1|jaS+}Ev>rs z`t16;%=)_7^}90bcfG&mqtX|r+8zW7rw)8lvi_DbQ?hwFfAd^nDU&YuT-s@LscoQy zWNy~g4@0p=D-8+yM^qd^qSFWMrPMN6u9ZD&~5BX$41sfn+gjyQs zlVr#jvI?^B4@y?)&4`}S)2}a5M}Jz_6u@iIL_(Il%^ar0767lidxqXhI$UpRl`+g1B#c@pg*XG zjKXVzme77_Irh~nzlqkZ8n5<4)6MIY>e*0ZBHzC?sgj)HIcvBRG ztFO9*G2uTtM@2Z8wUej}mG(7UxFSnY3)(44!jzC#7RbU8+R244N#{jy;!)m#K{csf z7}gGsH|B2F&~iv&7g_I=N%H;3;w0PaE=VvRQ%Tzu$TiKAQYpQQ{6a=Sz zL9TrFVMrzzicx+U7?P-zlK+Q)dIb^!Lx;tHd&g7I5G@giLR|O}GDMUhMT1~aVEs(o zZSU_D_w*CqB=^81u(7t@M)MS*de++GR%bbM@Q(237COHqDlSIgPS_Z7NZAg=fQ`W| zUxfnk+ed075GWeYz*DvssKcfhB|TLeGsHwElu1*dSjZ}cH<*zVdLzl1+y=;+0IhC} z@n0iSW(5Wv%6Z2`Wu%nl6h97jkzN^t$$<5&(OA+HBB>7{^hz25&(?U~hT>;-e!|jq zb-P1rN``$wUT#)+CaXej=PY>h`2y*~amg z)v-~)0Shg`D51h8V%XId?Jx^6!NBnZTvYeF0!B0s9uKY8AchbDNG24~Um%5LCHw;) zWcqiCf18byI-{&+Yu-^Y@;A?}gctzPDe#)plp=-yiwl<>^;W&K!7kIvklf z5cyWqbV=WoH&fF0)4~ck{XQ*_5J14h?=KeuLa8h+5X}1S>Xrh}-?@-zeYizrsq36N zrfX|(lMTFz_}#Y1;bSdFda`*GYTK@9DJ|~I0X)Obj%DJyd{Ddy0~?b_gz%Wd<&vh0K*{5UtdpRoBL=i|Rq@k#5VoudsJNAjB5;8sG_J zz-+)J3QMkU{l?kbyKcWRyKzruh0kUrEY7Ny1LLCd8G(xpE}1`VpxMGiwYZ=P^NHgAJ$_D)he-ZtS33@Vdu1Y@~h5UzS% zf^FKM6*Z;%n>Y#h2Il=8$4%#-xZU&y-Z@WNSitOO0#O5xt?!%gea$`LqkazHg$Z8| zzSe|$E%K9i)&q>euz+XMJu2)Kt~TOd71Qo#q-%b96M7YBzCi&{*mZ8HLa8ONX&`-xT}MO z(elURp$PBZI<*l|aQc9m&un5P9}BO4fr#NB(Im4=%ohmoZGaQ@$@kswG{#*O-eHRAwEIv z=HSsB40}n$u6vQ~I?mU5h{T_uSM4oI$UTI}j?L9S?gNmxzicqE^boY(f`u0qH z`)qwzroL;Y{*{@EZb*ed#dKf;!=M}Qc5GUFx7pD;nhtyJzD>Se@C_A0*0^r?wdU*e>??(r+E-Jq9fP3fyaIAM2h z*>>^BykDrPpW9J4x9`Qz0%h)sxpHaVi7SHnO192>Dd!UkYUcAO=NC%$%u_8G*Zfrr ztC0J=HqX8LVZ~BGg#ch;Ig0{-X-j~2iVLJxyd}Iv8kr-FJpYXdnhWtR!lX0l!|o(m zMS1MhN#~RZOO*o>%QxxDIa>m)%H*_=SuXi7jKD3>wGEcUtwuPZ1zQudr_<3m^0?7m z?s2Xb`zef4sZm~^yAM%4m4v|uE;klYA)5}rsKf(I8OS9&7BOQUaACx_M0wEX0G$~j zyo+c=t0Qy)BY(e4UcJ-+kJ~VeVSRmI$$fn|GRrrX83X~$+(EH4=5tt%=(L9sBEcgU z0JaeUlO{KXJQ7EsBbzO`!t3Jdd6ka88b^j`JXTX?S8OiK!h60rQLC5T!LdsQ(OlSWtiYSaBQ% zN3xC6m;3|KcQuZ18ZWX1Gv`dvA&5g7M05}x_GWAKB&TI7-z4_2N;){h=SHzW>?kvh z9&rY6fARnl4F~a96~nv5>znQ^!;I6TrkOEFX3<2z%hGP^;1AsyUNdXlFmhU3)(ETl z?YhX!o@yFurQM;Owe)RXh|7t7MV4aCQcWy0I1-C1kr`AQ`i~D$;)Y8yncFr?5S?wZ zByNy%ii`0wYtJ!KGZ~frRQSIv$n?3+fmNV zw(H=&6j@=?E)R^t9?dymXCBRd-HN_ii94OKo!e3TxdHt30Z48=B=<){rubgu@wS;T zvj=dVwuE^ZtZK21Hw~i|c{diX41Mj^C$cT`3?Fx5Fc$SVUT*Dps}Fj)uaAOrAwIzD zjHnUT3J(foj20M+{yGJ@V5I87c&cBHS1%dpBH&8UlNnM&$UM%Bx>B@ykHFNHdk&5K zgjq*SK}bE}kDPGkN4^7`(HtCKXHCR%dz#PwE5@)uj>U_@oi}E;@6BxAJG;F(v%UEu zkJMc>UR2}bCB$(Pj#@SfjbI0&#l%=n@7hfiKB?nr>ezuwUt6IgYM(7k6*Av;EONm+ z;0UMp@H3VHm}ndBaLj;~fGcX-k>jr5iw0DF+JHVH3|D~HfZ@JhbGPY!=}h%*V->K_ z>!@kMdO>$iF!`G($ofDq5t8%_pX!7iu}w@1#%6kvlH1h5E@a?zo$nU~U*PKC*S_*` zY4a7|TweZE<;SI)uJ|65R!sRmE!chW$ftp=cZTkJX9D}CUHf==7#d(dx>}&`5N@z{ z#1#Oa1AtF70G|VZPlP+t$(w+RoTGlTpyzj?qdpGg8Gls3+RR^oJ@)4y82J2G1NID% zYnYp`MNM={ERFF+fRHqg9EVVn?dQa!8CR5}6p>B*Z7G0d9%tgsPs6aReb$%-WX)Gr zj_z(XWMCh~!kJu{OR6PonKwxIk;e-n;LzlJG({Cb(vV9)>(DyJI1e{KB@5g(@jpet z_x0J!v>XpxXxId$Y-w}*vP9}11{}7AMnC}iiZ(`pm-zccOiO_F2H^ROo=`JTi*&vS znv0mt!8VnKkMpT`Feud>w9oG^0d*XpoLL;>6$2Wy1Hep}EWPl8v~TCmefxGd?Ag<> zr*Y5zeT_|vUnE#y>@pJGmSE2*U$K9J>kT_YI}O(;RsWSDBo4DAC3ISRzXTI59t%V+7Wdk-*sT#H7t_2Py|IWKq-D z?_ht-JV5c-Hd$H3k;7$8?_*9i3dR|UE6hSdQQSGbe4#y%CCFMwbMcvV$&_1vK-z=$ zZvX|g?;u%*+pCu{Fxv@XDh{Q<;My%}fgtU(stMY^{WZHQr|xc>-D&?0IpF=vRPZJx z?;_!N-^ATpsF;$E33t<wH&q4o)|dl}+}EuO+Z9~JUoZjb@~xL#W0*5yYTj``Id*{&>i;c7z*y!*w zTe)#olnua>(*awpf4{h^dW{^bbl7uX1m{q3*i&;-fd|Sq>=2rZs*_ryQ2>SpW3Zr+ zBTyr+mgc8~ymT7<6$W;?K8wFc#;m+L^Xq0k%z~ry14G4Bi&Rb)al`%BD#m$ZrY2?S_F~3X?BR8Bzx?#4M4>6)%NaL@0k3H_P(qq6k9BQ84jMK;9D7jvA#O=4)Au8V=S&no zb5w|~&vy#q=AXO#qT}ZRlFunwSR;t}|4XR+xx-7vNIowS#5F$=w*C*{U`9CjQ&(WB z_03}!#h*Hhe&X8p6W5LhtE=XGMc1FZ70r}XPZw{#bLy^szxDm%yKiK+K0jUje8zWR z@$*-vi??Nb+sT6${LJZGe>G-GJOBUy literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/app_commands/__pycache__/commands.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/app_commands/__pycache__/commands.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..feb87f3003e0419a55725428abd9aa2426204ff2 GIT binary patch literal 116506 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 z z7qt^?%z<_hMg!Ea&(bzsobMT9qygQ1la+A)ksY=_uG+Fxx{HhB?__E zaH*9ZF|Z|fzS1uGxm%QEVAw`C_{?h`a#P6)J`k?GtLb4ok}wU73g!fmqoWN96QTn- zGC*YiXMGfe91xrxi6;Q-gnt*W3+FT@H{I}XG+DbRTKkk-`&8uFuF1^6Sh9#Ea?f2D zTfZUVDSnXe|Hzh@)?&Y!WOAmhdEyREl!v0lAq^

    YDH=;qG<=mUGwx- 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 PM(!t1+qc=X8J+xpv5jep literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/app_commands/__pycache__/errors.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/app_commands/__pycache__/errors.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fe273635ac17c19d3bdffb4ffdc1773945538f3a GIT binary patch literal 24666 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 a&f&V}X8B8pECRoEa@}<8Z#mqsS^B@dNjgaY literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/app_commands/__pycache__/installs.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/app_commands/__pycache__/installs.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..de906c45d9d5e2e47a210373edf44e554ceb5be4 GIT binary patch literal 10724 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 A1ONa4 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/app_commands/__pycache__/models.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/app_commands/__pycache__/models.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0c2551f65f652e9d530982ebe3e53228504f6a31 GIT binary patch literal 48714 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 YaaB%%xv-S2*;)8q(XgG*Wi-S83y)7AZ2$lO literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/app_commands/__pycache__/translator.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/app_commands/__pycache__/translator.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..813a6c7b42cb9b912de70fb4d69f0b88ff258592 GIT binary patch literal 13297 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/app_commands/__pycache__/tree.cpython-312.pyc b/venv/lib/python3.12/site-packages/discord/app_commands/__pycache__/tree.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6c0c5ddd1ca4f8ff829a9279e26123f57ae8a4db GIT binary patch literal 56503 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/discord/app_commands/checks.py b/venv/lib/python3.12/site-packages/discord/app_commands/checks.py new file mode 100644 index 00000000..5c17b951 --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/app_commands/checks.py @@ -0,0 +1,537 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from __future__ import annotations + +from typing import ( + Any, + Coroutine, + Dict, + Hashable, + Union, + Callable, + TypeVar, + Optional, + TYPE_CHECKING, +) + +import time + +from .commands import check +from .errors import ( + NoPrivateMessage, + MissingRole, + MissingAnyRole, + MissingPermissions, + BotMissingPermissions, + CommandOnCooldown, +) + +from ..user import User +from ..permissions import Permissions +from ..utils import get as utils_get, MISSING, maybe_coroutine + +T = TypeVar('T') + +if TYPE_CHECKING: + from typing_extensions import Self + from ..interactions import Interaction + + CooldownFunction = Union[ + Callable[[Interaction[Any]], Coroutine[Any, Any, T]], + Callable[[Interaction[Any]], T], + ] + +__all__ = ( + 'has_role', + 'has_any_role', + 'has_permissions', + 'bot_has_permissions', + 'cooldown', + 'dynamic_cooldown', +) + + +class Cooldown: + """Represents a cooldown for a command. + + .. versionadded:: 2.0 + + Attributes + ----------- + rate: :class:`float` + The total number of tokens available per :attr:`per` seconds. + per: :class:`float` + The length of the cooldown period in seconds. + """ + + __slots__ = ('rate', 'per', '_window', '_tokens', '_last') + + def __init__(self, rate: float, per: float) -> None: + self.rate: int = int(rate) + self.per: float = float(per) + self._window: float = 0.0 + self._tokens: int = self.rate + self._last: float = 0.0 + + def get_tokens(self, current: Optional[float] = None) -> int: + """Returns the number of available tokens before rate limiting is applied. + + Parameters + ------------ + current: Optional[:class:`float`] + The time in seconds since Unix epoch to calculate tokens at. + If not supplied then :func:`time.time()` is used. + + Returns + -------- + :class:`int` + The number of tokens available before the cooldown is to be applied. + """ + if not current: + current = time.time() + + # the calculated tokens should be non-negative + tokens = max(self._tokens, 0) + + if current > self._window + self.per: + tokens = self.rate + return tokens + + def get_retry_after(self, current: Optional[float] = None) -> float: + """Returns the time in seconds until the cooldown will be reset. + + Parameters + ------------- + current: Optional[:class:`float`] + The current time in seconds since Unix epoch. + If not supplied, then :func:`time.time()` is used. + + Returns + ------- + :class:`float` + The number of seconds to wait before this cooldown will be reset. + """ + current = current or time.time() + tokens = self.get_tokens(current) + + if tokens == 0: + return self.per - (current - self._window) + + return 0.0 + + def update_rate_limit(self, current: Optional[float] = None, *, tokens: int = 1) -> Optional[float]: + """Updates the cooldown rate limit. + + Parameters + ------------- + current: Optional[:class:`float`] + The time in seconds since Unix epoch to update the rate limit at. + If not supplied, then :func:`time.time()` is used. + tokens: :class:`int` + The amount of tokens to deduct from the rate limit. + + Returns + ------- + Optional[:class:`float`] + The retry-after time in seconds if rate limited. + """ + current = current or time.time() + self._last = current + + self._tokens = self.get_tokens(current) + + # first token used means that we start a new rate limit window + if self._tokens == self.rate: + self._window = current + + # decrement tokens by specified number + self._tokens -= tokens + + # check if we are rate limited and return retry-after + if self._tokens < 0: + return self.per - (current - self._window) + + def reset(self) -> None: + """Reset the cooldown to its initial state.""" + self._tokens = self.rate + self._last = 0.0 + + def copy(self) -> Self: + """Creates a copy of this cooldown. + + Returns + -------- + :class:`Cooldown` + A new instance of this cooldown. + """ + return self.__class__(self.rate, self.per) + + def __repr__(self) -> str: + return f'' + + +def has_role(item: Union[int, str], /) -> Callable[[T], T]: + """A :func:`~discord.app_commands.check` that is added that checks if the member invoking the + command has the role specified via the name or ID specified. + + If a string is specified, you must give the exact name of the role, including + caps and spelling. + + If an integer is specified, you must give the exact snowflake ID of the role. + + This check raises one of two special exceptions, :exc:`~discord.app_commands.MissingRole` + if the user is missing a role, or :exc:`~discord.app_commands.NoPrivateMessage` if + it is used in a private message. Both inherit from :exc:`~discord.app_commands.CheckFailure`. + + .. versionadded:: 2.0 + + .. note:: + + This is different from the permission system that Discord provides for application + commands. This is done entirely locally in the program rather than being handled + by Discord. + + Parameters + ----------- + item: Union[:class:`int`, :class:`str`] + The name or ID of the role to check. + """ + + def predicate(interaction: Interaction) -> bool: + if isinstance(interaction.user, User): + raise NoPrivateMessage() + + if isinstance(item, int): + role = interaction.user.get_role(item) + else: + role = utils_get(interaction.user.roles, name=item) + + if role is None: + raise MissingRole(item) + return True + + return check(predicate) + + +def has_any_role(*items: Union[int, str]) -> Callable[[T], T]: + r"""A :func:`~discord.app_commands.check` that is added that checks if the member + invoking the command has **any** of the roles specified. This means that if they have + one out of the three roles specified, then this check will return ``True``. + + Similar to :func:`has_role`\, the names or IDs passed in must be exact. + + This check raises one of two special exceptions, :exc:`~discord.app_commands.MissingAnyRole` + if the user is missing all roles, or :exc:`~discord.app_commands.NoPrivateMessage` if + it is used in a private message. Both inherit from :exc:`~discord.app_commands.CheckFailure`. + + .. versionadded:: 2.0 + + .. note:: + + This is different from the permission system that Discord provides for application + commands. This is done entirely locally in the program rather than being handled + by Discord. + + Parameters + ----------- + items: List[Union[:class:`str`, :class:`int`]] + An argument list of names or IDs to check that the member has roles wise. + + Example + -------- + + .. code-block:: python3 + + @tree.command() + @app_commands.checks.has_any_role('Library Devs', 'Moderators', 492212595072434186) + async def cool(interaction: discord.Interaction): + await interaction.response.send_message('You are cool indeed') + """ + + def predicate(interaction: Interaction) -> bool: + if isinstance(interaction.user, User): + raise NoPrivateMessage() + + if any( + interaction.user.get_role(item) is not None + if isinstance(item, int) + else utils_get(interaction.user.roles, name=item) is not None + for item in items + ): + return True + raise MissingAnyRole(list(items)) + + return check(predicate) + + +def has_permissions(**perms: bool) -> Callable[[T], T]: + r"""A :func:`~discord.app_commands.check` that is added that checks if the member + has all of the permissions necessary. + + Note that this check operates on the permissions given by + :attr:`discord.Interaction.permissions`. + + The permissions passed in must be exactly like the properties shown under + :class:`discord.Permissions`. + + This check raises a special exception, :exc:`~discord.app_commands.MissingPermissions` + that is inherited from :exc:`~discord.app_commands.CheckFailure`. + + .. versionadded:: 2.0 + + .. note:: + + This is different from the permission system that Discord provides for application + commands. This is done entirely locally in the program rather than being handled + by Discord. + + Parameters + ------------ + \*\*perms: :class:`bool` + Keyword arguments denoting the permissions to check for. + + Example + --------- + + .. code-block:: python3 + + @tree.command() + @app_commands.checks.has_permissions(manage_messages=True) + async def test(interaction: discord.Interaction): + await interaction.response.send_message('You can manage messages.') + + """ + + invalid = perms.keys() - Permissions.VALID_FLAGS.keys() + if invalid: + raise TypeError(f"Invalid permission(s): {', '.join(invalid)}") + + def predicate(interaction: Interaction) -> bool: + permissions = interaction.permissions + + missing = [perm for perm, value in perms.items() if getattr(permissions, perm) != value] + + if not missing: + return True + + raise MissingPermissions(missing) + + return check(predicate) + + +def bot_has_permissions(**perms: bool) -> Callable[[T], T]: + """Similar to :func:`has_permissions` except checks if the bot itself has + the permissions listed. This relies on :attr:`discord.Interaction.app_permissions`. + + This check raises a special exception, :exc:`~discord.app_commands.BotMissingPermissions` + that is inherited from :exc:`~discord.app_commands.CheckFailure`. + + .. versionadded:: 2.0 + """ + + invalid = set(perms) - set(Permissions.VALID_FLAGS) + if invalid: + raise TypeError(f"Invalid permission(s): {', '.join(invalid)}") + + def predicate(interaction: Interaction) -> bool: + permissions = interaction.app_permissions + missing = [perm for perm, value in perms.items() if getattr(permissions, perm) != value] + + if not missing: + return True + + raise BotMissingPermissions(missing) + + return check(predicate) + + +def _create_cooldown_decorator( + key: CooldownFunction[Hashable], factory: CooldownFunction[Optional[Cooldown]] +) -> Callable[[T], T]: + + mapping: Dict[Any, Cooldown] = {} + + async def get_bucket( + interaction: Interaction, + *, + mapping: Dict[Any, Cooldown] = mapping, + key: CooldownFunction[Hashable] = key, + factory: CooldownFunction[Optional[Cooldown]] = factory, + ) -> Optional[Cooldown]: + current = interaction.created_at.timestamp() + dead_keys = [k for k, v in mapping.items() if current > v._last + v.per] + for k in dead_keys: + del mapping[k] + + k = await maybe_coroutine(key, interaction) + if k not in mapping: + bucket: Optional[Cooldown] = await maybe_coroutine(factory, interaction) + if bucket is not None: + mapping[k] = bucket + else: + bucket = mapping[k] + + return bucket + + async def predicate(interaction: Interaction) -> bool: + bucket = await get_bucket(interaction) + if bucket is None: + return True + + retry_after = bucket.update_rate_limit(interaction.created_at.timestamp()) + if retry_after is None: + return True + + raise CommandOnCooldown(bucket, retry_after) + + return check(predicate) + + +def cooldown( + rate: float, + per: float, + *, + key: Optional[CooldownFunction[Hashable]] = MISSING, +) -> Callable[[T], T]: + """A decorator that adds a cooldown to a command. + + A cooldown allows a command to only be used a specific amount + of times in a specific time frame. These cooldowns are based off + of the ``key`` function provided. If a ``key`` is not provided + then it defaults to a user-level cooldown. The ``key`` function + must take a single parameter, the :class:`discord.Interaction` and + return a value that is used as a key to the internal cooldown mapping. + + The ``key`` function can optionally be a coroutine. + + If a cooldown is triggered, then :exc:`~discord.app_commands.CommandOnCooldown` is + raised to the error handlers. + + Examples + --------- + + Setting a one per 5 seconds per member cooldown on a command: + + .. code-block:: python3 + + @tree.command() + @app_commands.checks.cooldown(1, 5.0, key=lambda i: (i.guild_id, i.user.id)) + async def test(interaction: discord.Interaction): + await interaction.response.send_message('Hello') + + @test.error + async def on_test_error(interaction: discord.Interaction, error: app_commands.AppCommandError): + if isinstance(error, app_commands.CommandOnCooldown): + await interaction.response.send_message(str(error), ephemeral=True) + + Parameters + ------------ + rate: :class:`int` + The number of times a command can be used before triggering a cooldown. + per: :class:`float` + The amount of seconds to wait for a cooldown when it's been triggered. + key: Optional[Callable[[:class:`discord.Interaction`], :class:`collections.abc.Hashable`]] + A function that returns a key to the mapping denoting the type of cooldown. + Can optionally be a coroutine. If not given then defaults to a user-level + cooldown. If ``None`` is passed then it is interpreted as a "global" cooldown. + """ + + if key is MISSING: + key_func = lambda interaction: interaction.user.id + elif key is None: + key_func = lambda i: None + else: + key_func = key + + factory = lambda interaction: Cooldown(rate, per) + + return _create_cooldown_decorator(key_func, factory) + + +def dynamic_cooldown( + factory: CooldownFunction[Optional[Cooldown]], + *, + key: Optional[CooldownFunction[Hashable]] = MISSING, +) -> Callable[[T], T]: + """A decorator that adds a dynamic cooldown to a command. + + A cooldown allows a command to only be used a specific amount + of times in a specific time frame. These cooldowns are based off + of the ``key`` function provided. If a ``key`` is not provided + then it defaults to a user-level cooldown. The ``key`` function + must take a single parameter, the :class:`discord.Interaction` and + return a value that is used as a key to the internal cooldown mapping. + + If a ``factory`` function is given, it must be a function that + accepts a single parameter of type :class:`discord.Interaction` and must + return a :class:`~discord.app_commands.Cooldown` or ``None``. + If ``None`` is returned then that cooldown is effectively bypassed. + + Both ``key`` and ``factory`` can optionally be coroutines. + + If a cooldown is triggered, then :exc:`~discord.app_commands.CommandOnCooldown` is + raised to the error handlers. + + Examples + --------- + + Setting a cooldown for everyone but the owner. + + .. code-block:: python3 + + def cooldown_for_everyone_but_me(interaction: discord.Interaction) -> Optional[app_commands.Cooldown]: + if interaction.user.id == 80088516616269824: + return None + return app_commands.Cooldown(1, 10.0) + + @tree.command() + @app_commands.checks.dynamic_cooldown(cooldown_for_everyone_but_me) + async def test(interaction: discord.Interaction): + await interaction.response.send_message('Hello') + + @test.error + async def on_test_error(interaction: discord.Interaction, error: app_commands.AppCommandError): + if isinstance(error, app_commands.CommandOnCooldown): + await interaction.response.send_message(str(error), ephemeral=True) + + Parameters + ------------ + factory: Optional[Callable[[:class:`discord.Interaction`], Optional[:class:`~discord.app_commands.Cooldown`]]] + A function that takes an interaction and returns a cooldown that will apply to that interaction + or ``None`` if the interaction should not have a cooldown. + key: Optional[Callable[[:class:`discord.Interaction`], :class:`collections.abc.Hashable`]] + A function that returns a key to the mapping denoting the type of cooldown. + Can optionally be a coroutine. If not given then defaults to a user-level + cooldown. If ``None`` is passed then it is interpreted as a "global" cooldown. + """ + + if key is MISSING: + key_func = lambda interaction: interaction.user.id + elif key is None: + key_func = lambda i: None + else: + key_func = key + + return _create_cooldown_decorator(key_func, factory) diff --git a/venv/lib/python3.12/site-packages/discord/app_commands/commands.py b/venv/lib/python3.12/site-packages/discord/app_commands/commands.py new file mode 100644 index 00000000..d5b8d93b --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/app_commands/commands.py @@ -0,0 +1,2886 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from __future__ import annotations +import inspect + +from typing import ( + Any, + Callable, + ClassVar, + Coroutine, + Dict, + Generator, + Generic, + List, + MutableMapping, + Optional, + Set, + TYPE_CHECKING, + Tuple, + Type, + TypeVar, + Union, + overload, +) + +import re +from copy import copy as shallow_copy + +from ..enums import AppCommandOptionType, AppCommandType, ChannelType, Locale +from .installs import AppCommandContext, AppInstallationType +from .models import Choice +from .transformers import annotation_to_parameter, CommandParameter, NoneType +from .errors import AppCommandError, CheckFailure, CommandInvokeError, CommandSignatureMismatch, CommandAlreadyRegistered +from .translator import TranslationContextLocation, TranslationContext, Translator, locale_str +from ..message import Message +from ..user import User +from ..member import Member +from ..permissions import Permissions +from ..utils import resolve_annotation, MISSING, is_inside_class, maybe_coroutine, async_all, _shorten, _to_kebab_case + +if TYPE_CHECKING: + from typing_extensions import ParamSpec, Concatenate + from ..interactions import Interaction + from ..abc import Snowflake + from .namespace import Namespace + from .models import ChoiceT + from .tree import CommandTree + from .._types import ClientT + + # Generally, these two libraries are supposed to be separate from each other. + # However, for type hinting purposes it's unfortunately necessary for one to + # reference the other to prevent type checking errors in callbacks + from discord.ext import commands + + ErrorFunc = Callable[[Interaction, AppCommandError], Coroutine[Any, Any, None]] + +__all__ = ( + 'Command', + 'ContextMenu', + 'Group', + 'Parameter', + 'context_menu', + 'command', + 'describe', + 'check', + 'rename', + 'choices', + 'autocomplete', + 'guilds', + 'guild_only', + 'dm_only', + 'private_channel_only', + 'allowed_contexts', + 'guild_install', + 'user_install', + 'allowed_installs', + 'default_permissions', +) + +if TYPE_CHECKING: + P = ParamSpec('P') +else: + P = TypeVar('P') + +T = TypeVar('T') +F = TypeVar('F', bound=Callable[..., Any]) +GroupT = TypeVar('GroupT', bound='Binding') +Coro = Coroutine[Any, Any, T] +UnboundError = Callable[['Interaction[Any]', AppCommandError], Coro[Any]] +Error = Union[ + Callable[[GroupT, 'Interaction[Any]', AppCommandError], Coro[Any]], + UnboundError, +] +Check = Callable[['Interaction[Any]'], Union[bool, Coro[bool]]] +Binding = Union['Group', 'commands.Cog'] + + +if TYPE_CHECKING: + CommandCallback = Union[ + Callable[Concatenate[GroupT, 'Interaction[Any]', P], Coro[T]], + Callable[Concatenate['Interaction[Any]', P], Coro[T]], + ] + + ContextMenuCallback = Union[ + # If groups end up support context menus these would be uncommented + # Callable[[GroupT, 'Interaction', Member], Coro[Any]], + # Callable[[GroupT, 'Interaction', User], Coro[Any]], + # Callable[[GroupT, 'Interaction', Message], Coro[Any]], + # Callable[[GroupT, 'Interaction', Union[Member, User]], Coro[Any]], + Callable[['Interaction[Any]', Member], Coro[Any]], + Callable[['Interaction[Any]', User], Coro[Any]], + Callable[['Interaction[Any]', Message], Coro[Any]], + Callable[['Interaction[Any]', Union[Member, User]], Coro[Any]], + ] + + AutocompleteCallback = Union[ + Callable[[GroupT, 'Interaction[Any]', str], Coro[List[Choice[ChoiceT]]]], + Callable[['Interaction[Any]', str], Coro[List[Choice[ChoiceT]]]], + ] +else: + CommandCallback = Callable[..., Coro[T]] + ContextMenuCallback = Callable[..., Coro[T]] + AutocompleteCallback = Callable[..., Coro[T]] + + +CheckInputParameter = Union['Command[Any, ..., Any]', 'ContextMenu', 'CommandCallback[Any, ..., Any]', ContextMenuCallback] + +# The re module doesn't support \p{} so we have to list characters from Thai and Devanagari manually. +THAI_COMBINING = r'\u0e31-\u0e3a\u0e47-\u0e4e' +DEVANAGARI_COMBINING = r'\u0900-\u0903\u093a\u093b\u093c\u093e\u093f\u0940-\u094f\u0955\u0956\u0957\u0962\u0963' +VALID_SLASH_COMMAND_NAME = re.compile(r'^[-_\w' + THAI_COMBINING + DEVANAGARI_COMBINING + r']{1,32}$') + +ARG_NAME_SUBREGEX = r'(?:\\?\*){0,2}(?P\w+)' + +ARG_DESCRIPTION_SUBREGEX = r'(?P(?:.|\n)+?(?:\Z|\r?\n(?=[\S\r\n])))' + +ARG_TYPE_SUBREGEX = r'(?:.+)' + +GOOGLE_DOCSTRING_ARG_REGEX = re.compile( + rf'^{ARG_NAME_SUBREGEX}[ \t]*(?:\({ARG_TYPE_SUBREGEX}\))?[ \t]*:[ \t]*{ARG_DESCRIPTION_SUBREGEX}', + re.MULTILINE, +) + +SPHINX_DOCSTRING_ARG_REGEX = re.compile( + rf'^:param {ARG_NAME_SUBREGEX}:[ \t]+{ARG_DESCRIPTION_SUBREGEX}', + re.MULTILINE, +) + +NUMPY_DOCSTRING_ARG_REGEX = re.compile( + rf'^{ARG_NAME_SUBREGEX}(?:[ \t]*:)?(?:[ \t]+{ARG_TYPE_SUBREGEX})?[ \t]*\r?\n[ \t]+{ARG_DESCRIPTION_SUBREGEX}', + re.MULTILINE, +) + + +def _parse_args_from_docstring(func: Callable[..., Any], params: Dict[str, CommandParameter]) -> Dict[str, str]: + docstring = inspect.getdoc(func) + + if docstring is None: + return {} + + # Extract the arguments + # Note: These are loose regexes, but they are good enough for our purposes + # For Google-style, look only at the lines that are indented + section_lines = inspect.cleandoc('\n'.join(line for line in docstring.splitlines() if line.startswith(' '))) + docstring_styles = ( + GOOGLE_DOCSTRING_ARG_REGEX.finditer(section_lines), + SPHINX_DOCSTRING_ARG_REGEX.finditer(docstring), + NUMPY_DOCSTRING_ARG_REGEX.finditer(docstring), + ) + + return { + m.group('name'): m.group('description') for matches in docstring_styles for m in matches if m.group('name') in params + } + + +def validate_name(name: str) -> str: + match = VALID_SLASH_COMMAND_NAME.match(name) + if match is None: + raise ValueError( + f'{name!r} must be between 1-32 characters and contain only lower-case letters, numbers, hyphens, or underscores.' + ) + + # Ideally, name.islower() would work instead but since certain characters + # are Lo (e.g. CJK) those don't pass the test. I'd use `casefold` instead as + # well, but chances are the server-side check is probably something similar to + # this code anyway. + if name.lower() != name: + raise ValueError(f'{name!r} must be all lower-case') + return name + + +def validate_context_menu_name(name: str) -> str: + if not name or len(name) > 32: + raise ValueError('context menu names must be between 1-32 characters') + return name + + +def validate_auto_complete_callback( + callback: AutocompleteCallback[GroupT, ChoiceT] +) -> AutocompleteCallback[GroupT, ChoiceT]: + # This function needs to ensure the following is true: + # If self.foo is passed then don't pass command.binding to the callback + # If Class.foo is passed then it is assumed command.binding has to be passed + # If free_function_foo is passed then no binding should be passed at all + # Passing command.binding is mandated by pass_command_binding + + binding = getattr(callback, '__self__', None) + pass_command_binding = binding is None and is_inside_class(callback) + + # 'method' objects can't have dynamic attributes + if binding is None: + callback.pass_command_binding = pass_command_binding + + required_parameters = 2 + pass_command_binding + params = inspect.signature(callback).parameters + if len(params) != required_parameters: + raise TypeError(f'autocomplete callback {callback.__qualname__!r} requires either 2 or 3 parameters to be passed') + + return callback + + +def _context_menu_annotation(annotation: Any, *, _none: type = NoneType) -> AppCommandType: + if annotation is Message: + return AppCommandType.message + + supported_types: Set[Any] = {Member, User} + if annotation in supported_types: + return AppCommandType.user + + # Check if there's an origin + origin = getattr(annotation, '__origin__', None) + if origin is not Union: + # Only Union is supported so bail early + msg = ( + f'unsupported type annotation {annotation!r}, must be either discord.Member, ' + 'discord.User, discord.Message, or a typing.Union of discord.Member and discord.User' + ) + raise TypeError(msg) + + # Only Union[Member, User] is supported + if not all(arg in supported_types for arg in annotation.__args__): + raise TypeError(f'unsupported types given inside {annotation!r}') + + return AppCommandType.user + + +def _populate_descriptions(params: Dict[str, CommandParameter], descriptions: Dict[str, Any]) -> None: + for name, param in params.items(): + description = descriptions.pop(name, MISSING) + if description is MISSING: + param.description = '…' + continue + + if not isinstance(description, (str, locale_str)): + raise TypeError('description must be a string') + + if isinstance(description, str): + param.description = _shorten(description) + else: + param.description = description + + if descriptions: + first = next(iter(descriptions)) + raise TypeError(f'unknown parameter given: {first}') + + +def _populate_renames(params: Dict[str, CommandParameter], renames: Dict[str, Union[str, locale_str]]) -> None: + rename_map: Dict[str, Union[str, locale_str]] = {} + + # original name to renamed name + + for name in params.keys(): + new_name = renames.pop(name, MISSING) + + if new_name is MISSING: + rename_map[name] = name + continue + + if name in rename_map: + raise ValueError(f'{new_name} is already used') + + if isinstance(new_name, str): + new_name = validate_name(new_name) + else: + validate_name(new_name.message) + + rename_map[name] = new_name + params[name]._rename = new_name + + if renames: + first = next(iter(renames)) + raise ValueError(f'unknown parameter given: {first}') + + +def _populate_choices(params: Dict[str, CommandParameter], all_choices: Dict[str, List[Choice]]) -> None: + for name, param in params.items(): + choices = all_choices.pop(name, MISSING) + if choices is MISSING: + continue + + if not isinstance(choices, list): + raise TypeError('choices must be a list of Choice') + + if not all(isinstance(choice, Choice) for choice in choices): + raise TypeError('choices must be a list of Choice') + + if param.type not in (AppCommandOptionType.string, AppCommandOptionType.number, AppCommandOptionType.integer): + raise TypeError('choices are only supported for integer, string, or number option types') + + if not all(param.type == choice._option_type for choice in choices): + raise TypeError('choices must all have the same inner option type as the parameter choice type') + + param.choices = choices + + if all_choices: + first = next(iter(all_choices)) + raise TypeError(f'unknown parameter given: {first}') + + +def _populate_autocomplete(params: Dict[str, CommandParameter], autocomplete: Dict[str, Any]) -> None: + for name, param in params.items(): + callback = autocomplete.pop(name, MISSING) + if callback is MISSING: + continue + + if not inspect.iscoroutinefunction(callback): + raise TypeError('autocomplete callback must be a coroutine function') + + if param.type not in (AppCommandOptionType.string, AppCommandOptionType.number, AppCommandOptionType.integer): + raise TypeError('autocomplete is only supported for integer, string, or number option types') + + if param.is_choice_annotation(): + raise TypeError( + 'Choice annotation unsupported for autocomplete parameters, consider using a regular annotation instead' + ) + + param.autocomplete = validate_auto_complete_callback(callback) + + if autocomplete: + first = next(iter(autocomplete)) + raise TypeError(f'unknown parameter given: {first}') + + +def _extract_parameters_from_callback(func: Callable[..., Any], globalns: Dict[str, Any]) -> Dict[str, CommandParameter]: + params = inspect.signature(func).parameters + cache = {} + required_params = is_inside_class(func) + 1 + if len(params) < required_params: + raise TypeError(f'callback {func.__qualname__!r} must have more than {required_params - 1} parameter(s)') + + iterator = iter(params.values()) + for _ in range(0, required_params): + next(iterator) + + parameters: List[CommandParameter] = [] + for parameter in iterator: + if parameter.annotation is parameter.empty: + raise TypeError(f'parameter {parameter.name!r} is missing a type annotation in callback {func.__qualname__!r}') + + resolved = resolve_annotation(parameter.annotation, globalns, globalns, cache) + param = annotation_to_parameter(resolved, parameter) + parameters.append(param) + + values = sorted(parameters, key=lambda a: a.required, reverse=True) + result = {v.name: v for v in values} + + descriptions = _parse_args_from_docstring(func, result) + + try: + descriptions.update(func.__discord_app_commands_param_description__) + except AttributeError: + for param in values: + if param.description is MISSING: + param.description = '…' + if descriptions: + _populate_descriptions(result, descriptions) + + try: + renames = func.__discord_app_commands_param_rename__ + except AttributeError: + pass + else: + _populate_renames(result, renames.copy()) + + try: + choices = func.__discord_app_commands_param_choices__ + except AttributeError: + pass + else: + _populate_choices(result, choices.copy()) + + try: + autocomplete = func.__discord_app_commands_param_autocomplete__ + except AttributeError: + pass + else: + _populate_autocomplete(result, autocomplete.copy()) + + return result + + +def _get_context_menu_parameter(func: ContextMenuCallback) -> Tuple[str, Any, AppCommandType]: + params = inspect.signature(func).parameters + if is_inside_class(func) and not hasattr(func, '__self__'): + raise TypeError('context menus cannot be defined inside a class') + + if len(params) != 2: + msg = ( + f'context menu callback {func.__qualname__!r} requires 2 parameters, ' + 'the first one being the interaction and the other one explicitly ' + 'annotated with either discord.Message, discord.User, discord.Member, ' + 'or a typing.Union of discord.Member and discord.User' + ) + raise TypeError(msg) + + iterator = iter(params.values()) + next(iterator) # skip interaction + parameter = next(iterator) + if parameter.annotation is parameter.empty: + msg = ( + f'second parameter of context menu callback {func.__qualname__!r} must be explicitly ' + 'annotated with either discord.Message, discord.User, discord.Member, or ' + 'a typing.Union of discord.Member and discord.User' + ) + raise TypeError(msg) + + resolved = resolve_annotation(parameter.annotation, func.__globals__, func.__globals__, {}) + type = _context_menu_annotation(resolved) + return (parameter.name, resolved, type) + + +def mark_overrideable(func: F) -> F: + func.__discord_app_commands_base_function__ = None + return func + + +class Parameter: + """A class that contains the parameter information of a :class:`Command` callback. + + .. versionadded:: 2.0 + + Attributes + ----------- + name: :class:`str` + The name of the parameter. This is the Python identifier for the parameter. + display_name: :class:`str` + The displayed name of the parameter on Discord. + description: :class:`str` + The description of the parameter. + autocomplete: :class:`bool` + Whether the parameter has an autocomplete handler. + locale_name: Optional[:class:`locale_str`] + The display name's locale string, if available. + locale_description: Optional[:class:`locale_str`] + The description's locale string, if available. + required: :class:`bool` + Whether the parameter is required + choices: List[:class:`~discord.app_commands.Choice`] + A list of choices this parameter takes, if any. + type: :class:`~discord.AppCommandOptionType` + The underlying type of this parameter. + channel_types: List[:class:`~discord.ChannelType`] + The channel types that are allowed for this parameter. + min_value: Optional[Union[:class:`int`, :class:`float`]] + The minimum supported value for this parameter. + max_value: Optional[Union[:class:`int`, :class:`float`]] + The maximum supported value for this parameter. + default: Any + The default value of the parameter, if given. + If not given then this is :data:`~discord.utils.MISSING`. + command: :class:`Command` + The command this parameter is attached to. + """ + + def __init__(self, parent: CommandParameter, command: Command[Any, ..., Any]) -> None: + self.__parent: CommandParameter = parent + self.__command: Command[Any, ..., Any] = command + + @property + def command(self) -> Command[Any, ..., Any]: + return self.__command + + @property + def name(self) -> str: + return self.__parent.name + + @property + def display_name(self) -> str: + return self.__parent.display_name + + @property + def required(self) -> bool: + return self.__parent.required + + @property + def description(self) -> str: + return str(self.__parent.description) + + @property + def locale_name(self) -> Optional[locale_str]: + if isinstance(self.__parent._rename, locale_str): + return self.__parent._rename + return None + + @property + def locale_description(self) -> Optional[locale_str]: + if isinstance(self.__parent.description, locale_str): + return self.__parent.description + return None + + @property + def autocomplete(self) -> bool: + return self.__parent.autocomplete is not None + + @property + def default(self) -> Any: + return self.__parent.default + + @property + def type(self) -> AppCommandOptionType: + return self.__parent.type + + @property + def choices(self) -> List[Choice[Union[int, float, str]]]: + choices = self.__parent.choices + if choices is MISSING: + return [] + return choices.copy() + + @property + def channel_types(self) -> List[ChannelType]: + channel_types = self.__parent.channel_types + if channel_types is MISSING: + return [] + return channel_types.copy() + + @property + def min_value(self) -> Optional[Union[int, float]]: + return self.__parent.min_value + + @property + def max_value(self) -> Optional[Union[int, float]]: + return self.__parent.max_value + + +class Command(Generic[GroupT, P, T]): + """A class that implements an application command. + + These are usually not created manually, instead they are created using + one of the following decorators: + + - :func:`~discord.app_commands.command` + - :meth:`Group.command ` + - :meth:`CommandTree.command ` + + .. versionadded:: 2.0 + + Parameters + ----------- + name: Union[:class:`str`, :class:`locale_str`] + The name of the application command. + description: Union[:class:`str`, :class:`locale_str`] + The description of the application command. This shows up in the UI to describe + the application command. + callback: :ref:`coroutine ` + The coroutine that is executed when the command is called. + auto_locale_strings: :class:`bool` + If this is set to ``True``, then all translatable strings will implicitly + be wrapped into :class:`locale_str` rather than :class:`str`. This could + avoid some repetition and be more ergonomic for certain defaults such + as default command names, command descriptions, and parameter names. + Defaults to ``True``. + nsfw: :class:`bool` + Whether the command is NSFW and should only work in NSFW channels. + Defaults to ``False``. + + Due to a Discord limitation, this does not work on subcommands. + parent: Optional[:class:`Group`] + The parent application command. ``None`` if there isn't one. + extras: :class:`dict` + A dictionary that can be used to store extraneous data. + The library will not touch any values or keys within this dictionary. + + Attributes + ------------ + name: :class:`str` + The name of the application command. + description: :class:`str` + The description of the application command. This shows up in the UI to describe + the application command. + checks + A list of predicates that take a :class:`~discord.Interaction` parameter + to indicate whether the command callback should be executed. If an exception + is necessary to be thrown to signal failure, then one inherited from + :exc:`AppCommandError` should be used. If all the checks fail without + propagating an exception, :exc:`CheckFailure` is raised. + default_permissions: Optional[:class:`~discord.Permissions`] + The default permissions that can execute this command on Discord. Note + that server administrators can override this value in the client. + Setting an empty permissions field will disallow anyone except server + administrators from using the command in a guild. + + Due to a Discord limitation, this does not work on subcommands. + guild_only: :class:`bool` + Whether the command should only be usable in guild contexts. + + Due to a Discord limitation, this does not work on subcommands. + allowed_contexts: Optional[:class:`~discord.app_commands.AppCommandContext`] + The contexts that the command is allowed to be used in. + Overrides ``guild_only`` if this is set. + + .. versionadded:: 2.4 + allowed_installs: Optional[:class:`~discord.app_commands.AppInstallationType`] + The installation contexts that the command is allowed to be installed + on. + + .. versionadded:: 2.4 + nsfw: :class:`bool` + Whether the command is NSFW and should only work in NSFW channels. + + Due to a Discord limitation, this does not work on subcommands. + parent: Optional[:class:`Group`] + The parent application command. ``None`` if there isn't one. + extras: :class:`dict` + A dictionary that can be used to store extraneous data. + The library will not touch any values or keys within this dictionary. + """ + + def __init__( + self, + *, + name: Union[str, locale_str], + description: Union[str, locale_str], + callback: CommandCallback[GroupT, P, T], + nsfw: bool = False, + parent: Optional[Group] = None, + guild_ids: Optional[List[int]] = None, + allowed_contexts: Optional[AppCommandContext] = None, + allowed_installs: Optional[AppInstallationType] = None, + auto_locale_strings: bool = True, + extras: Dict[Any, Any] = MISSING, + ): + name, locale = (name.message, name) if isinstance(name, locale_str) else (name, None) + self.name: str = validate_name(name) + self._locale_name: Optional[locale_str] = locale + description, locale = ( + (description.message, description) if isinstance(description, locale_str) else (description, None) + ) + self.description: str = description + self._locale_description: Optional[locale_str] = locale + self._attr: Optional[str] = None + self._callback: CommandCallback[GroupT, P, T] = callback + self.parent: Optional[Group] = parent + self.binding: Optional[GroupT] = None + self.on_error: Optional[Error[GroupT]] = None + self.module: Optional[str] = callback.__module__ + + # Unwrap __self__ for bound methods + try: + self.binding = callback.__self__ + self._callback = callback = callback.__func__ + except AttributeError: + pass + + self._params: Dict[str, CommandParameter] = _extract_parameters_from_callback(callback, callback.__globals__) + self.checks: List[Check] = getattr(callback, '__discord_app_commands_checks__', []) + self._guild_ids: Optional[List[int]] = guild_ids or getattr( + callback, '__discord_app_commands_default_guilds__', None + ) + self.default_permissions: Optional[Permissions] = getattr( + callback, '__discord_app_commands_default_permissions__', None + ) + self.guild_only: bool = getattr(callback, '__discord_app_commands_guild_only__', False) + self.allowed_contexts: Optional[AppCommandContext] = allowed_contexts or getattr( + callback, '__discord_app_commands_contexts__', None + ) + self.allowed_installs: Optional[AppInstallationType] = allowed_installs or getattr( + callback, '__discord_app_commands_installation_types__', None + ) + + self.nsfw: bool = nsfw + self.extras: Dict[Any, Any] = extras or {} + + if self._guild_ids is not None and self.parent is not None: + raise ValueError('child commands cannot have default guilds set, consider setting them in the parent instead') + + if auto_locale_strings: + self._convert_to_locale_strings() + + def _convert_to_locale_strings(self) -> None: + if self._locale_name is None: + self._locale_name = locale_str(self.name) + if self._locale_description is None: + self._locale_description = locale_str(self.description) + + for param in self._params.values(): + param._convert_to_locale_strings() + + def __set_name__(self, owner: Type[Any], name: str) -> None: + self._attr = name + + @property + def callback(self) -> CommandCallback[GroupT, P, T]: + """:ref:`coroutine `: The coroutine that is executed when the command is called.""" + return self._callback + + def _copy_with( + self, + *, + parent: Optional[Group], + binding: GroupT, + bindings: MutableMapping[GroupT, GroupT] = MISSING, + set_on_binding: bool = True, + ) -> Command: + bindings = {} if bindings is MISSING else bindings + + copy = shallow_copy(self) + copy._params = self._params.copy() + copy.parent = parent + copy.binding = bindings.get(self.binding) if self.binding is not None else binding + + if copy._attr and set_on_binding: + setattr(copy.binding, copy._attr, copy) + + return copy + + async def get_translated_payload(self, tree: CommandTree[ClientT], translator: Translator) -> Dict[str, Any]: + base = self.to_dict(tree) + name_localizations: Dict[str, str] = {} + description_localizations: Dict[str, str] = {} + + # Prevent creating these objects in a heavy loop + name_context = TranslationContext(location=TranslationContextLocation.command_name, data=self) + description_context = TranslationContext(location=TranslationContextLocation.command_description, data=self) + + for locale in Locale: + if self._locale_name: + translation = await translator._checked_translate(self._locale_name, locale, name_context) + if translation is not None: + name_localizations[locale.value] = translation + + if self._locale_description: + translation = await translator._checked_translate(self._locale_description, locale, description_context) + if translation is not None: + description_localizations[locale.value] = translation + + base['name_localizations'] = name_localizations + base['description_localizations'] = description_localizations + base['options'] = [ + await param.get_translated_payload(translator, Parameter(param, self)) for param in self._params.values() + ] + return base + + def to_dict(self, tree: CommandTree[ClientT]) -> Dict[str, Any]: + # If we have a parent then our type is a subcommand + # Otherwise, the type falls back to the specific command type (e.g. slash command or context menu) + option_type = AppCommandType.chat_input.value if self.parent is None else AppCommandOptionType.subcommand.value + base: Dict[str, Any] = { + 'name': self.name, + 'description': self.description, + 'type': option_type, + 'options': [param.to_dict() for param in self._params.values()], + } + + if self.parent is None: + base['nsfw'] = self.nsfw + base['dm_permission'] = not self.guild_only + base['default_member_permissions'] = None if self.default_permissions is None else self.default_permissions.value + base['contexts'] = tree.allowed_contexts._merge_to_array(self.allowed_contexts) + base['integration_types'] = tree.allowed_installs._merge_to_array(self.allowed_installs) + + return base + + async def _invoke_error_handlers(self, interaction: Interaction, error: AppCommandError) -> None: + # These type ignores are because the type checker can't narrow this type properly. + if self.on_error is not None: + if self.binding is not None: + await self.on_error(self.binding, interaction, error) # type: ignore + else: + await self.on_error(interaction, error) # type: ignore + + parent = self.parent + if parent is not None: + await parent.on_error(interaction, error) + + if parent.parent is not None: + await parent.parent.on_error(interaction, error) + + binding_error_handler = getattr(self.binding, '__discord_app_commands_error_handler__', None) + if binding_error_handler is not None: + await binding_error_handler(interaction, error) + + def _has_any_error_handlers(self) -> bool: + if self.on_error is not None: + return True + + parent = self.parent + if parent is not None: + # Check if the on_error is overridden + if not hasattr(parent.on_error, '__discord_app_commands_base_function__'): + return True + + if parent.parent is not None: + if not hasattr(parent.parent.on_error, '__discord_app_commands_base_function__'): + return True + + # Check if we have a bound error handler + if getattr(self.binding, '__discord_app_commands_error_handler__', None) is not None: + return True + + return False + + async def _transform_arguments(self, interaction: Interaction, namespace: Namespace) -> Dict[str, Any]: + values = namespace.__dict__ + transformed_values = {} + + for param in self._params.values(): + try: + value = values[param.display_name] + except KeyError: + if not param.required: + transformed_values[param.name] = param.default + else: + raise CommandSignatureMismatch(self) from None + else: + transformed_values[param.name] = await param.transform(interaction, value) + + return transformed_values + + async def _do_call(self, interaction: Interaction, params: Dict[str, Any]) -> T: + # These type ignores are because the type checker doesn't quite understand the narrowing here + # Likewise, it thinks we're missing positional arguments when there aren't any. + try: + if self.binding is not None: + return await self._callback(self.binding, interaction, **params) # type: ignore + return await self._callback(interaction, **params) # type: ignore + except TypeError as e: + # In order to detect mismatch from the provided signature and the Discord data, + # there are many ways it can go wrong yet all of them eventually lead to a TypeError + # from the Python compiler showcasing that the signature is incorrect. This lovely + # piece of code essentially checks the last frame of the caller and checks if the + # locals contains our `self` reference. + # + # This is because there is a possibility that a TypeError is raised within the body + # of the function, and in that case the locals wouldn't contain a reference to + # the command object under the name `self`. + frame = inspect.trace()[-1].frame + if frame.f_locals.get('self') is self: + raise CommandSignatureMismatch(self) from None + raise CommandInvokeError(self, e) from e + except AppCommandError: + raise + except Exception as e: + raise CommandInvokeError(self, e) from e + + async def _invoke_with_namespace(self, interaction: Interaction, namespace: Namespace) -> T: + if not await self._check_can_run(interaction): + raise CheckFailure(f'The check functions for command {self.name!r} failed.') + + transformed_values = await self._transform_arguments(interaction, namespace) + return await self._do_call(interaction, transformed_values) + + async def _invoke_autocomplete(self, interaction: Interaction, name: str, namespace: Namespace): + # The namespace contains the Discord provided names so this will be fine + # even if the name is renamed + value = namespace.__dict__[name] + + try: + param = self._params[name] + except KeyError: + # Slow case, it might be a rename + params = {param.display_name: param for param in self._params.values()} + try: + param = params[name] + except KeyError: + raise CommandSignatureMismatch(self) from None + + if param.autocomplete is None: + raise CommandSignatureMismatch(self) + + predicates = getattr(param.autocomplete, '__discord_app_commands_checks__', []) + if predicates: + try: + passed = await async_all(f(interaction) for f in predicates) # type: ignore + except Exception: + passed = False + + if not passed: + if not interaction.response.is_done(): + await interaction.response.autocomplete([]) + return + + if getattr(param.autocomplete, 'pass_command_binding', False): + binding = self.binding + if binding is not None: + choices = await param.autocomplete(binding, interaction, value) + else: + raise TypeError('autocomplete parameter expected a bound self parameter but one was not provided') + else: + choices = await param.autocomplete(interaction, value) + + if interaction.response.is_done(): + return + + await interaction.response.autocomplete(choices) + + def _get_internal_command(self, name: str) -> Optional[Union[Command, Group]]: + return None + + @property + def parameters(self) -> List[Parameter]: + """Returns a list of parameters for this command. + + This does not include the ``self`` or ``interaction`` parameters. + + Returns + -------- + List[:class:`Parameter`] + The parameters of this command. + """ + return [Parameter(p, self) for p in self._params.values()] + + def get_parameter(self, name: str) -> Optional[Parameter]: + """Retrieves a parameter by its name. + + The name must be the Python identifier rather than the renamed + one for display on Discord. + + Parameters + ----------- + name: :class:`str` + The parameter name in the callback function. + + Returns + -------- + Optional[:class:`Parameter`] + The parameter or ``None`` if not found. + """ + + parent = self._params.get(name) + if parent is not None: + return Parameter(parent, self) + return None + + @property + def root_parent(self) -> Optional[Group]: + """Optional[:class:`Group`]: The root parent of this command.""" + if self.parent is None: + return None + parent = self.parent + return parent.parent or parent + + @property + def qualified_name(self) -> str: + """:class:`str`: Returns the fully qualified command name. + + The qualified name includes the parent name as well. For example, + in a command like ``/foo bar`` the qualified name is ``foo bar``. + """ + # A B C + # ^ self + # ^ parent + # ^ grandparent + if self.parent is None: + return self.name + + names = [self.name, self.parent.name] + grandparent = self.parent.parent + if grandparent is not None: + names.append(grandparent.name) + + return ' '.join(reversed(names)) + + async def _check_can_run(self, interaction: Interaction) -> bool: + if self.parent is not None and self.parent is not self.binding: + # For commands with a parent which isn't the binding, i.e. + # + # + # + # The parent check needs to be called first + if not await maybe_coroutine(self.parent.interaction_check, interaction): + return False + + if self.binding is not None: + check: Optional[Check] = getattr(self.binding, 'interaction_check', None) + if check: + ret = await maybe_coroutine(check, interaction) + if not ret: + return False + + predicates = self.checks + if not predicates: + return True + + return await async_all(f(interaction) for f in predicates) # type: ignore + + def error(self, coro: Error[GroupT]) -> Error[GroupT]: + """A decorator that registers a coroutine as a local error handler. + + The local error handler is called whenever an exception is raised in the body + of the command or during handling of the command. The error handler must take + 2 parameters, the interaction and the error. + + The error passed will be derived from :exc:`AppCommandError`. + + Parameters + ----------- + coro: :ref:`coroutine ` + The coroutine to register as the local error handler. + + Raises + ------- + TypeError + The coroutine passed is not actually a coroutine. + """ + + if not inspect.iscoroutinefunction(coro): + raise TypeError('The error handler must be a coroutine.') + + self.on_error = coro + return coro + + def autocomplete( + self, name: str + ) -> Callable[[AutocompleteCallback[GroupT, ChoiceT]], AutocompleteCallback[GroupT, ChoiceT]]: + """A decorator that registers a coroutine as an autocomplete prompt for a parameter. + + The coroutine callback must have 2 parameters, the :class:`~discord.Interaction`, + and the current value by the user (the string currently being typed by the user). + + To get the values from other parameters that may be filled in, accessing + :attr:`.Interaction.namespace` will give a :class:`Namespace` object with those + values. + + Parent :func:`checks ` are ignored within an autocomplete. However, checks can be added + to the autocomplete callback and the ones added will be called. If the checks fail for any reason + then an empty list is sent as the interaction response. + + The coroutine decorator **must** return a list of :class:`~discord.app_commands.Choice` objects. + Only up to 25 objects are supported. + + .. warning:: + The choices returned from this coroutine are suggestions. The user may ignore them and input their own value. + + Example: + + .. code-block:: python3 + + @app_commands.command() + async def fruits(interaction: discord.Interaction, fruit: str): + await interaction.response.send_message(f'Your favourite fruit seems to be {fruit}') + + @fruits.autocomplete('fruit') + async def fruits_autocomplete( + interaction: discord.Interaction, + current: str, + ) -> List[app_commands.Choice[str]]: + fruits = ['Banana', 'Pineapple', 'Apple', 'Watermelon', 'Melon', 'Cherry'] + return [ + app_commands.Choice(name=fruit, value=fruit) + for fruit in fruits if current.lower() in fruit.lower() + ] + + + Parameters + ----------- + name: :class:`str` + The parameter name to register as autocomplete. + + Raises + ------- + TypeError + The coroutine passed is not actually a coroutine or + the parameter is not found or of an invalid type. + """ + + def decorator(coro: AutocompleteCallback[GroupT, ChoiceT]) -> AutocompleteCallback[GroupT, ChoiceT]: + if not inspect.iscoroutinefunction(coro): + raise TypeError('The autocomplete callback must be a coroutine function.') + + try: + param = self._params[name] + except KeyError: + raise TypeError(f'unknown parameter: {name!r}') from None + + if param.type not in (AppCommandOptionType.string, AppCommandOptionType.number, AppCommandOptionType.integer): + raise TypeError('autocomplete is only supported for integer, string, or number option types') + + if param.is_choice_annotation(): + raise TypeError( + 'Choice annotation unsupported for autocomplete parameters, consider using a regular annotation instead' + ) + + param.autocomplete = validate_auto_complete_callback(coro) + return coro + + return decorator + + def add_check(self, func: Check, /) -> None: + """Adds a check to the command. + + This is the non-decorator interface to :func:`check`. + + Parameters + ----------- + func + The function that will be used as a check. + """ + + self.checks.append(func) + + def remove_check(self, func: Check, /) -> None: + """Removes a check from the command. + + This function is idempotent and will not raise an exception + if the function is not in the command's checks. + + Parameters + ----------- + func + The function to remove from the checks. + """ + + try: + self.checks.remove(func) + except ValueError: + pass + + +class ContextMenu: + """A class that implements a context menu application command. + + These are usually not created manually, instead they are created using + one of the following decorators: + + - :func:`~discord.app_commands.context_menu` + - :meth:`CommandTree.context_menu ` + + .. versionadded:: 2.0 + + Parameters + ----------- + name: Union[:class:`str`, :class:`locale_str`] + The name of the context menu. + callback: :ref:`coroutine ` + The coroutine that is executed when the command is called. + type: :class:`.AppCommandType` + The type of context menu application command. By default, this is inferred + by the parameter of the callback. + auto_locale_strings: :class:`bool` + If this is set to ``True``, then all translatable strings will implicitly + be wrapped into :class:`locale_str` rather than :class:`str`. This could + avoid some repetition and be more ergonomic for certain defaults such + as default command names, command descriptions, and parameter names. + Defaults to ``True``. + nsfw: :class:`bool` + Whether the command is NSFW and should only work in NSFW channels. + Defaults to ``False``. + extras: :class:`dict` + A dictionary that can be used to store extraneous data. + The library will not touch any values or keys within this dictionary. + + Attributes + ------------ + name: :class:`str` + The name of the context menu. + type: :class:`.AppCommandType` + The type of context menu application command. By default, this is inferred + by the parameter of the callback. + default_permissions: Optional[:class:`~discord.Permissions`] + The default permissions that can execute this command on Discord. Note + that server administrators can override this value in the client. + Setting an empty permissions field will disallow anyone except server + administrators from using the command in a guild. + guild_only: :class:`bool` + Whether the command should only be usable in guild contexts. + Defaults to ``False``. + allowed_contexts: Optional[:class:`~discord.app_commands.AppCommandContext`] + The contexts that this context menu is allowed to be used in. + Overrides ``guild_only`` if set. + + .. versionadded:: 2.4 + allowed_installs: Optional[:class:`~discord.app_commands.AppInstallationType`] + The installation contexts that the command is allowed to be installed + on. + + .. versionadded:: 2.4 + nsfw: :class:`bool` + Whether the command is NSFW and should only work in NSFW channels. + Defaults to ``False``. + checks + A list of predicates that take a :class:`~discord.Interaction` parameter + to indicate whether the command callback should be executed. If an exception + is necessary to be thrown to signal failure, then one inherited from + :exc:`AppCommandError` should be used. If all the checks fail without + propagating an exception, :exc:`CheckFailure` is raised. + extras: :class:`dict` + A dictionary that can be used to store extraneous data. + The library will not touch any values or keys within this dictionary. + """ + + def __init__( + self, + *, + name: Union[str, locale_str], + callback: ContextMenuCallback, + type: AppCommandType = MISSING, + nsfw: bool = False, + guild_ids: Optional[List[int]] = None, + allowed_contexts: Optional[AppCommandContext] = None, + allowed_installs: Optional[AppInstallationType] = None, + auto_locale_strings: bool = True, + extras: Dict[Any, Any] = MISSING, + ): + name, locale = (name.message, name) if isinstance(name, locale_str) else (name, None) + self.name: str = validate_context_menu_name(name) + self._locale_name: Optional[locale_str] = locale + self._callback: ContextMenuCallback = callback + (param, annotation, actual_type) = _get_context_menu_parameter(callback) + if type is MISSING: + type = actual_type + + if actual_type != type: + raise ValueError(f'context menu callback implies a type of {actual_type} but {type} was passed.') + + self.type: AppCommandType = type + self._param_name = param + self._annotation = annotation + self.module: Optional[str] = callback.__module__ + self._guild_ids = guild_ids or getattr(callback, '__discord_app_commands_default_guilds__', None) + self.on_error: Optional[UnboundError] = None + self.default_permissions: Optional[Permissions] = getattr( + callback, '__discord_app_commands_default_permissions__', None + ) + self.nsfw: bool = nsfw + self.guild_only: bool = getattr(callback, '__discord_app_commands_guild_only__', False) + self.allowed_contexts: Optional[AppCommandContext] = allowed_contexts or getattr( + callback, '__discord_app_commands_contexts__', None + ) + self.allowed_installs: Optional[AppInstallationType] = allowed_installs or getattr( + callback, '__discord_app_commands_installation_types__', None + ) + self.checks: List[Check] = getattr(callback, '__discord_app_commands_checks__', []) + self.extras: Dict[Any, Any] = extras or {} + + if auto_locale_strings: + if self._locale_name is None: + self._locale_name = locale_str(self.name) + + @property + def callback(self) -> ContextMenuCallback: + """:ref:`coroutine `: The coroutine that is executed when the context menu is called.""" + return self._callback + + @property + def qualified_name(self) -> str: + """:class:`str`: Returns the fully qualified command name.""" + return self.name + + async def get_translated_payload(self, tree: CommandTree[ClientT], translator: Translator) -> Dict[str, Any]: + base = self.to_dict(tree) + context = TranslationContext(location=TranslationContextLocation.command_name, data=self) + if self._locale_name: + name_localizations: Dict[str, str] = {} + for locale in Locale: + translation = await translator._checked_translate(self._locale_name, locale, context) + if translation is not None: + name_localizations[locale.value] = translation + + base['name_localizations'] = name_localizations + return base + + def to_dict(self, tree: CommandTree[ClientT]) -> Dict[str, Any]: + return { + 'name': self.name, + 'type': self.type.value, + 'dm_permission': not self.guild_only, + 'contexts': tree.allowed_contexts._merge_to_array(self.allowed_contexts), + 'integration_types': tree.allowed_installs._merge_to_array(self.allowed_installs), + 'default_member_permissions': None if self.default_permissions is None else self.default_permissions.value, + 'nsfw': self.nsfw, + } + + async def _check_can_run(self, interaction: Interaction) -> bool: + predicates = self.checks + if not predicates: + return True + + return await async_all(f(interaction) for f in predicates) # type: ignore + + def _has_any_error_handlers(self) -> bool: + return self.on_error is not None + + async def _invoke(self, interaction: Interaction, arg: Any): + try: + if not await self._check_can_run(interaction): + raise CheckFailure(f'The check functions for context menu {self.name!r} failed.') + + await self._callback(interaction, arg) + except AppCommandError: + raise + except Exception as e: + raise CommandInvokeError(self, e) from e + + def error(self, coro: UnboundError) -> UnboundError: + """A decorator that registers a coroutine as a local error handler. + + The local error handler is called whenever an exception is raised in the body + of the command or during handling of the command. The error handler must take + 2 parameters, the interaction and the error. + + The error passed will be derived from :exc:`AppCommandError`. + + Parameters + ----------- + coro: :ref:`coroutine ` + The coroutine to register as the local error handler. + + Raises + ------- + TypeError + The coroutine passed is not actually a coroutine. + """ + + if not inspect.iscoroutinefunction(coro): + raise TypeError('The error handler must be a coroutine.') + + self.on_error = coro + return coro + + def add_check(self, func: Check, /) -> None: + """Adds a check to the command. + + This is the non-decorator interface to :func:`check`. + + Parameters + ----------- + func + The function that will be used as a check. + """ + + self.checks.append(func) + + def remove_check(self, func: Check, /) -> None: + """Removes a check from the command. + + This function is idempotent and will not raise an exception + if the function is not in the command's checks. + + Parameters + ----------- + func + The function to remove from the checks. + """ + + try: + self.checks.remove(func) + except ValueError: + pass + + +class Group: + """A class that implements an application command group. + + These are usually inherited rather than created manually. + + Decorators such as :func:`guild_only`, :func:`guilds`, and :func:`default_permissions` + will apply to the group if used on top of a subclass. For example: + + .. code-block:: python3 + + from discord import app_commands + + @app_commands.guild_only() + class MyGroup(app_commands.Group): + pass + + .. versionadded:: 2.0 + + Parameters + ----------- + name: Union[:class:`str`, :class:`locale_str`] + The name of the group. If not given, it defaults to a lower-case + kebab-case version of the class name. + description: Union[:class:`str`, :class:`locale_str`] + The description of the group. This shows up in the UI to describe + the group. If not given, it defaults to the docstring of the + class shortened to 100 characters. + auto_locale_strings: :class:`bool` + If this is set to ``True``, then all translatable strings will implicitly + be wrapped into :class:`locale_str` rather than :class:`str`. This could + avoid some repetition and be more ergonomic for certain defaults such + as default command names, command descriptions, and parameter names. + Defaults to ``True``. + default_permissions: Optional[:class:`~discord.Permissions`] + The default permissions that can execute this group on Discord. Note + that server administrators can override this value in the client. + Setting an empty permissions field will disallow anyone except server + administrators from using the command in a guild. + + Due to a Discord limitation, this does not work on subcommands. + guild_only: :class:`bool` + Whether the group should only be usable in guild contexts. + Defaults to ``False``. + + Due to a Discord limitation, this does not work on subcommands. + nsfw: :class:`bool` + Whether the command is NSFW and should only work in NSFW channels. + Defaults to ``False``. + + Due to a Discord limitation, this does not work on subcommands. + parent: Optional[:class:`Group`] + The parent application command. ``None`` if there isn't one. + extras: :class:`dict` + A dictionary that can be used to store extraneous data. + The library will not touch any values or keys within this dictionary. + + Attributes + ------------ + name: :class:`str` + The name of the group. + description: :class:`str` + The description of the group. This shows up in the UI to describe + the group. + default_permissions: Optional[:class:`~discord.Permissions`] + The default permissions that can execute this group on Discord. Note + that server administrators can override this value in the client. + Setting an empty permissions field will disallow anyone except server + administrators from using the command in a guild. + + Due to a Discord limitation, this does not work on subcommands. + guild_only: :class:`bool` + Whether the group should only be usable in guild contexts. + + Due to a Discord limitation, this does not work on subcommands. + allowed_contexts: Optional[:class:`~discord.app_commands.AppCommandContext`] + The contexts that this group is allowed to be used in. Overrides + guild_only if set. + + .. versionadded:: 2.4 + allowed_installs: Optional[:class:`~discord.app_commands.AppInstallationType`] + The installation contexts that the command is allowed to be installed + on. + + .. versionadded:: 2.4 + nsfw: :class:`bool` + Whether the command is NSFW and should only work in NSFW channels. + + Due to a Discord limitation, this does not work on subcommands. + parent: Optional[:class:`Group`] + The parent group. ``None`` if there isn't one. + extras: :class:`dict` + A dictionary that can be used to store extraneous data. + The library will not touch any values or keys within this dictionary. + """ + + __discord_app_commands_group_children__: ClassVar[List[Union[Command[Any, ..., Any], Group]]] = [] + __discord_app_commands_skip_init_binding__: bool = False + __discord_app_commands_group_name__: str = MISSING + __discord_app_commands_group_description__: str = MISSING + __discord_app_commands_group_locale_name__: Optional[locale_str] = None + __discord_app_commands_group_locale_description__: Optional[locale_str] = None + __discord_app_commands_group_nsfw__: bool = False + __discord_app_commands_guild_only__: bool = MISSING + __discord_app_commands_contexts__: Optional[AppCommandContext] = MISSING + __discord_app_commands_installation_types__: Optional[AppInstallationType] = MISSING + __discord_app_commands_default_permissions__: Optional[Permissions] = MISSING + __discord_app_commands_has_module__: bool = False + __discord_app_commands_error_handler__: Optional[ + Callable[[Interaction, AppCommandError], Coroutine[Any, Any, None]] + ] = None + + def __init_subclass__( + cls, + *, + name: Union[str, locale_str] = MISSING, + description: Union[str, locale_str] = MISSING, + guild_only: bool = MISSING, + nsfw: bool = False, + default_permissions: Optional[Permissions] = MISSING, + ) -> None: + if not cls.__discord_app_commands_group_children__: + children: List[Union[Command[Any, ..., Any], Group]] = [ + member for member in cls.__dict__.values() if isinstance(member, (Group, Command)) and member.parent is None + ] + + cls.__discord_app_commands_group_children__ = children + + found = set() + for child in children: + if child.name in found: + raise TypeError(f'Command {child.name!r} is a duplicate') + found.add(child.name) + + if len(children) > 25: + raise TypeError('groups cannot have more than 25 commands') + + if name is MISSING: + cls.__discord_app_commands_group_name__ = validate_name(_to_kebab_case(cls.__name__)) + elif isinstance(name, str): + cls.__discord_app_commands_group_name__ = validate_name(name) + else: + cls.__discord_app_commands_group_name__ = validate_name(name.message) + cls.__discord_app_commands_group_locale_name__ = name + + if description is MISSING: + if cls.__doc__ is None: + cls.__discord_app_commands_group_description__ = '…' + else: + cls.__discord_app_commands_group_description__ = _shorten(cls.__doc__) + elif isinstance(description, str): + cls.__discord_app_commands_group_description__ = description + else: + cls.__discord_app_commands_group_description__ = description.message + cls.__discord_app_commands_group_locale_description__ = description + + if guild_only is not MISSING: + cls.__discord_app_commands_guild_only__ = guild_only + + if default_permissions is not MISSING: + cls.__discord_app_commands_default_permissions__ = default_permissions + + if cls.__module__ != __name__: + cls.__discord_app_commands_has_module__ = True + cls.__discord_app_commands_group_nsfw__ = nsfw + + def __init__( + self, + *, + name: Union[str, locale_str] = MISSING, + description: Union[str, locale_str] = MISSING, + parent: Optional[Group] = None, + guild_ids: Optional[List[int]] = None, + guild_only: bool = MISSING, + allowed_contexts: Optional[AppCommandContext] = MISSING, + allowed_installs: Optional[AppInstallationType] = MISSING, + nsfw: bool = MISSING, + auto_locale_strings: bool = True, + default_permissions: Optional[Permissions] = MISSING, + extras: Dict[Any, Any] = MISSING, + ): + cls = self.__class__ + + if name is MISSING: + name, locale = cls.__discord_app_commands_group_name__, cls.__discord_app_commands_group_locale_name__ + elif isinstance(name, str): + name, locale = validate_name(name), None + else: + name, locale = validate_name(name.message), name + self.name: str = name + self._locale_name: Optional[locale_str] = locale + + if description is MISSING: + description, locale = ( + cls.__discord_app_commands_group_description__, + cls.__discord_app_commands_group_locale_description__, + ) + elif isinstance(description, str): + description, locale = description, None + else: + description, locale = description.message, description + self.description: str = description + self._locale_description: Optional[locale_str] = locale + + self._attr: Optional[str] = None + self._owner_cls: Optional[Type[Any]] = None + self._guild_ids: Optional[List[int]] = guild_ids or getattr(cls, '__discord_app_commands_default_guilds__', None) + + if default_permissions is MISSING: + if cls.__discord_app_commands_default_permissions__ is MISSING: + default_permissions = None + else: + default_permissions = cls.__discord_app_commands_default_permissions__ + + self.default_permissions: Optional[Permissions] = default_permissions + + if guild_only is MISSING: + if cls.__discord_app_commands_guild_only__ is MISSING: + guild_only = False + else: + guild_only = cls.__discord_app_commands_guild_only__ + + self.guild_only: bool = guild_only + + if allowed_contexts is MISSING: + if cls.__discord_app_commands_contexts__ is MISSING: + allowed_contexts = None + else: + allowed_contexts = cls.__discord_app_commands_contexts__ + + self.allowed_contexts: Optional[AppCommandContext] = allowed_contexts + + if allowed_installs is MISSING: + if cls.__discord_app_commands_installation_types__ is MISSING: + allowed_installs = None + else: + allowed_installs = cls.__discord_app_commands_installation_types__ + + self.allowed_installs: Optional[AppInstallationType] = allowed_installs + + if nsfw is MISSING: + nsfw = cls.__discord_app_commands_group_nsfw__ + + self.nsfw: bool = nsfw + + if not self.description: + raise TypeError('groups must have a description') + + if not self.name: + raise TypeError('groups must have a name') + + self.parent: Optional[Group] = parent + self.module: Optional[str] + if cls.__discord_app_commands_has_module__: + self.module = cls.__module__ + else: + try: + # This is pretty hacky + # It allows the module to be fetched if someone just constructs a bare Group object though. + self.module = inspect.currentframe().f_back.f_globals['__name__'] # type: ignore + except (AttributeError, IndexError, KeyError): + self.module = None + + self._children: Dict[str, Union[Command, Group]] = {} + self.extras: Dict[Any, Any] = extras or {} + + bindings: Dict[Group, Group] = {} + + for child in self.__discord_app_commands_group_children__: + # commands and groups created directly in this class (no parent) + copy = ( + child._copy_with(parent=self, binding=self, bindings=bindings, set_on_binding=False) + if not cls.__discord_app_commands_skip_init_binding__ + else child + ) + + self._children[copy.name] = copy + if copy._attr and not cls.__discord_app_commands_skip_init_binding__: + setattr(self, copy._attr, copy) + + if parent is not None: + if parent.parent is not None: + raise ValueError('groups can only be nested at most one level') + parent.add_command(self) + + if auto_locale_strings: + self._convert_to_locale_strings() + + def _convert_to_locale_strings(self) -> None: + if self._locale_name is None: + self._locale_name = locale_str(self.name) + if self._locale_description is None: + self._locale_description = locale_str(self.description) + + # I don't know if propagating to the children is the right behaviour here. + + def __set_name__(self, owner: Type[Any], name: str) -> None: + self._attr = name + self.module = owner.__module__ + self._owner_cls = owner + + def _copy_with( + self, + *, + parent: Optional[Group], + binding: Binding, + bindings: MutableMapping[Group, Group] = MISSING, + set_on_binding: bool = True, + ) -> Group: + bindings = {} if bindings is MISSING else bindings + + copy = shallow_copy(self) + copy.parent = parent + copy._children = {} + + bindings[self] = copy + + for child in self._children.values(): + child_copy = child._copy_with(parent=copy, binding=binding, bindings=bindings) + child_copy.parent = copy + copy._children[child_copy.name] = child_copy + + if isinstance(child_copy, Group) and child_copy._attr and set_on_binding: + if binding.__class__ is child_copy._owner_cls: + setattr(binding, child_copy._attr, child_copy) + elif child_copy._owner_cls is copy.__class__: + setattr(copy, child_copy._attr, child_copy) + + if copy._attr and set_on_binding: + setattr(parent or binding, copy._attr, copy) + + return copy + + async def get_translated_payload(self, tree: CommandTree[ClientT], translator: Translator) -> Dict[str, Any]: + base = self.to_dict(tree) + name_localizations: Dict[str, str] = {} + description_localizations: Dict[str, str] = {} + + # Prevent creating these objects in a heavy loop + name_context = TranslationContext(location=TranslationContextLocation.group_name, data=self) + description_context = TranslationContext(location=TranslationContextLocation.group_description, data=self) + for locale in Locale: + if self._locale_name: + translation = await translator._checked_translate(self._locale_name, locale, name_context) + if translation is not None: + name_localizations[locale.value] = translation + + if self._locale_description: + translation = await translator._checked_translate(self._locale_description, locale, description_context) + if translation is not None: + description_localizations[locale.value] = translation + + base['name_localizations'] = name_localizations + base['description_localizations'] = description_localizations + base['options'] = [await child.get_translated_payload(tree, translator) for child in self._children.values()] + return base + + def to_dict(self, tree: CommandTree[ClientT]) -> Dict[str, Any]: + # If this has a parent command then it's part of a subcommand group + # Otherwise, it's just a regular command + option_type = 1 if self.parent is None else AppCommandOptionType.subcommand_group.value + base: Dict[str, Any] = { + 'name': self.name, + 'description': self.description, + 'type': option_type, + 'options': [child.to_dict(tree) for child in self._children.values()], + } + + if self.parent is None: + base['nsfw'] = self.nsfw + base['dm_permission'] = not self.guild_only + base['default_member_permissions'] = None if self.default_permissions is None else self.default_permissions.value + base['contexts'] = tree.allowed_contexts._merge_to_array(self.allowed_contexts) + base['integration_types'] = tree.allowed_installs._merge_to_array(self.allowed_installs) + + return base + + @property + def root_parent(self) -> Optional[Group]: + """Optional[:class:`Group`]: The parent of this group.""" + return self.parent + + @property + def qualified_name(self) -> str: + """:class:`str`: Returns the fully qualified group name. + + The qualified name includes the parent name as well. For example, + in a group like ``/foo bar`` the qualified name is ``foo bar``. + """ + + if self.parent is None: + return self.name + return f'{self.parent.name} {self.name}' + + def _get_internal_command(self, name: str) -> Optional[Union[Command[Any, ..., Any], Group]]: + return self._children.get(name) + + @property + def commands(self) -> List[Union[Command[Any, ..., Any], Group]]: + """List[Union[:class:`Command`, :class:`Group`]]: The commands that this group contains.""" + return list(self._children.values()) + + def walk_commands(self) -> Generator[Union[Command[Any, ..., Any], Group], None, None]: + """An iterator that recursively walks through all commands that this group contains. + + Yields + --------- + Union[:class:`Command`, :class:`Group`] + The commands in this group. + """ + + for command in self._children.values(): + yield command + if isinstance(command, Group): + yield from command.walk_commands() + + @mark_overrideable + async def on_error(self, interaction: Interaction, error: AppCommandError, /) -> None: + """|coro| + + A callback that is called when a child's command raises an :exc:`AppCommandError`. + + To get the command that failed, :attr:`discord.Interaction.command` should be used. + + The default implementation does nothing. + + Parameters + ----------- + interaction: :class:`~discord.Interaction` + The interaction that is being handled. + error: :exc:`AppCommandError` + The exception that was raised. + """ + + pass + + def error(self, coro: ErrorFunc) -> ErrorFunc: + """A decorator that registers a coroutine as a local error handler. + + The local error handler is called whenever an exception is raised in a child command. + The error handler must take 2 parameters, the interaction and the error. + + The error passed will be derived from :exc:`AppCommandError`. + + Parameters + ----------- + coro: :ref:`coroutine ` + The coroutine to register as the local error handler. + + Raises + ------- + TypeError + The coroutine passed is not actually a coroutine, or is an invalid coroutine. + """ + + if not inspect.iscoroutinefunction(coro): + raise TypeError('The error handler must be a coroutine.') + + params = inspect.signature(coro).parameters + if len(params) != 2: + raise TypeError('The error handler must have 2 parameters.') + + self.on_error = coro # type: ignore + return coro + + async def interaction_check(self, interaction: Interaction, /) -> bool: + """|coro| + + A callback that is called when an interaction happens within the group + that checks whether a command inside the group should be executed. + + This is useful to override if, for example, you want to ensure that the + interaction author is a given user. + + The default implementation of this returns ``True``. + + .. note:: + + If an exception occurs within the body then the check + is considered a failure and error handlers such as + :meth:`on_error` is called. See :exc:`AppCommandError` + for more information. + + Parameters + ----------- + interaction: :class:`~discord.Interaction` + The interaction that occurred. + + Returns + --------- + :class:`bool` + Whether the view children's callbacks should be called. + """ + + return True + + def add_command(self, command: Union[Command[Any, ..., Any], Group], /, *, override: bool = False) -> None: + """Adds a command or group to this group's internal list of commands. + + Parameters + ----------- + command: Union[:class:`Command`, :class:`Group`] + The command or group to add. + override: :class:`bool` + Whether to override a pre-existing command or group with the same name. + If ``False`` then an exception is raised. + + Raises + ------- + CommandAlreadyRegistered + The command or group is already registered. Note that the :attr:`CommandAlreadyRegistered.guild_id` + attribute will always be ``None`` in this case. + ValueError + There are too many commands already registered or the group is too + deeply nested. + TypeError + The wrong command type was passed. + """ + + if not isinstance(command, (Command, Group)): + raise TypeError(f'expected Command or Group not {command.__class__.__name__}') + + if isinstance(command, Group) and self.parent is not None: + # In a tree like so: + # + # + # + # this needs to be forbidden + raise ValueError(f'{command.name!r} is too nested, groups can only be nested at most one level') + + if not override and command.name in self._children: + raise CommandAlreadyRegistered(command.name, guild_id=None) + + self._children[command.name] = command + command.parent = self + if len(self._children) > 25: + raise ValueError('maximum number of child commands exceeded') + + def remove_command(self, name: str, /) -> Optional[Union[Command[Any, ..., Any], Group]]: + """Removes a command or group from the internal list of commands. + + Parameters + ----------- + name: :class:`str` + The name of the command or group to remove. + + Returns + -------- + Optional[Union[:class:`~discord.app_commands.Command`, :class:`~discord.app_commands.Group`]] + The command that was removed. If nothing was removed + then ``None`` is returned instead. + """ + + self._children.pop(name, None) + + def get_command(self, name: str, /) -> Optional[Union[Command[Any, ..., Any], Group]]: + """Retrieves a command or group from its name. + + Parameters + ----------- + name: :class:`str` + The name of the command or group to retrieve. + + Returns + -------- + Optional[Union[:class:`~discord.app_commands.Command`, :class:`~discord.app_commands.Group`]] + The command or group that was retrieved. If nothing was found + then ``None`` is returned instead. + """ + return self._children.get(name) + + def command( + self, + *, + name: Union[str, locale_str] = MISSING, + description: Union[str, locale_str] = MISSING, + nsfw: bool = False, + auto_locale_strings: bool = True, + extras: Dict[Any, Any] = MISSING, + ) -> Callable[[CommandCallback[GroupT, P, T]], Command[GroupT, P, T]]: + """A decorator that creates an application command from a regular function under this group. + + Parameters + ------------ + name: Union[:class:`str`, :class:`locale_str`] + The name of the application command. If not given, it defaults to a lower-case + version of the callback name. + description: Union[:class:`str`, :class:`locale_str`] + The description of the application command. This shows up in the UI to describe + the application command. If not given, it defaults to the first line of the docstring + of the callback shortened to 100 characters. + nsfw: :class:`bool` + Whether the command is NSFW and should only work in NSFW channels. Defaults to ``False``. + auto_locale_strings: :class:`bool` + If this is set to ``True``, then all translatable strings will implicitly + be wrapped into :class:`locale_str` rather than :class:`str`. This could + avoid some repetition and be more ergonomic for certain defaults such + as default command names, command descriptions, and parameter names. + Defaults to ``True``. + extras: :class:`dict` + A dictionary that can be used to store extraneous data. + The library will not touch any values or keys within this dictionary. + """ + + def decorator(func: CommandCallback[GroupT, P, T]) -> Command[GroupT, P, T]: + if not inspect.iscoroutinefunction(func): + raise TypeError('command function must be a coroutine function') + + if description is MISSING: + if func.__doc__ is None: + desc = '…' + else: + desc = _shorten(func.__doc__) + else: + desc = description + + command = Command( + name=name if name is not MISSING else func.__name__, + description=desc, + callback=func, + nsfw=nsfw, + parent=self, + auto_locale_strings=auto_locale_strings, + extras=extras, + ) + self.add_command(command) + return command + + return decorator + + +def command( + *, + name: Union[str, locale_str] = MISSING, + description: Union[str, locale_str] = MISSING, + nsfw: bool = False, + auto_locale_strings: bool = True, + extras: Dict[Any, Any] = MISSING, +) -> Callable[[CommandCallback[GroupT, P, T]], Command[GroupT, P, T]]: + """Creates an application command from a regular function. + + Parameters + ------------ + name: :class:`str` + The name of the application command. If not given, it defaults to a lower-case + version of the callback name. + description: :class:`str` + The description of the application command. This shows up in the UI to describe + the application command. If not given, it defaults to the first line of the docstring + of the callback shortened to 100 characters. + nsfw: :class:`bool` + Whether the command is NSFW and should only work in NSFW channels. Defaults to ``False``. + + Due to a Discord limitation, this does not work on subcommands. + auto_locale_strings: :class:`bool` + If this is set to ``True``, then all translatable strings will implicitly + be wrapped into :class:`locale_str` rather than :class:`str`. This could + avoid some repetition and be more ergonomic for certain defaults such + as default command names, command descriptions, and parameter names. + Defaults to ``True``. + extras: :class:`dict` + A dictionary that can be used to store extraneous data. + The library will not touch any values or keys within this dictionary. + """ + + def decorator(func: CommandCallback[GroupT, P, T]) -> Command[GroupT, P, T]: + if not inspect.iscoroutinefunction(func): + raise TypeError('command function must be a coroutine function') + + if description is MISSING: + if func.__doc__ is None: + desc = '…' + else: + desc = _shorten(func.__doc__) + else: + desc = description + + return Command( + name=name if name is not MISSING else func.__name__, + description=desc, + callback=func, + parent=None, + nsfw=nsfw, + auto_locale_strings=auto_locale_strings, + extras=extras, + ) + + return decorator + + +def context_menu( + *, + name: Union[str, locale_str] = MISSING, + nsfw: bool = False, + auto_locale_strings: bool = True, + extras: Dict[Any, Any] = MISSING, +) -> Callable[[ContextMenuCallback], ContextMenu]: + """Creates an application command context menu from a regular function. + + This function must have a signature of :class:`~discord.Interaction` as its first parameter + and taking either a :class:`~discord.Member`, :class:`~discord.User`, or :class:`~discord.Message`, + or a :obj:`typing.Union` of ``Member`` and ``User`` as its second parameter. + + Examples + --------- + + .. code-block:: python3 + + @app_commands.context_menu() + async def react(interaction: discord.Interaction, message: discord.Message): + await interaction.response.send_message('Very cool message!', ephemeral=True) + + @app_commands.context_menu() + async def ban(interaction: discord.Interaction, user: discord.Member): + await interaction.response.send_message(f'Should I actually ban {user}...', ephemeral=True) + + Parameters + ------------ + name: Union[:class:`str`, :class:`locale_str`] + The name of the context menu command. If not given, it defaults to a title-case + version of the callback name. Note that unlike regular slash commands this can + have spaces and upper case characters in the name. + nsfw: :class:`bool` + Whether the command is NSFW and should only work in NSFW channels. Defaults to ``False``. + + Due to a Discord limitation, this does not work on subcommands. + auto_locale_strings: :class:`bool` + If this is set to ``True``, then all translatable strings will implicitly + be wrapped into :class:`locale_str` rather than :class:`str`. This could + avoid some repetition and be more ergonomic for certain defaults such + as default command names, command descriptions, and parameter names. + Defaults to ``True``. + extras: :class:`dict` + A dictionary that can be used to store extraneous data. + The library will not touch any values or keys within this dictionary. + """ + + def decorator(func: ContextMenuCallback) -> ContextMenu: + if not inspect.iscoroutinefunction(func): + raise TypeError('context menu function must be a coroutine function') + + actual_name = func.__name__.title() if name is MISSING else name + return ContextMenu( + name=actual_name, + nsfw=nsfw, + callback=func, + auto_locale_strings=auto_locale_strings, + extras=extras, + ) + + return decorator + + +def describe(**parameters: Union[str, locale_str]) -> Callable[[T], T]: + r'''Describes the given parameters by their name using the key of the keyword argument + as the name. + + Example: + + .. code-block:: python3 + + @app_commands.command(description='Bans a member') + @app_commands.describe(member='the member to ban') + async def ban(interaction: discord.Interaction, member: discord.Member): + await interaction.response.send_message(f'Banned {member}') + + Alternatively, you can describe parameters using Google, Sphinx, or Numpy style docstrings. + + Example: + + .. code-block:: python3 + + @app_commands.command() + async def ban(interaction: discord.Interaction, member: discord.Member): + """Bans a member + + Parameters + ----------- + member: discord.Member + the member to ban + """ + await interaction.response.send_message(f'Banned {member}') + + Parameters + ----------- + \*\*parameters: Union[:class:`str`, :class:`locale_str`] + The description of the parameters. + + Raises + -------- + TypeError + The parameter name is not found. + ''' + + def decorator(inner: T) -> T: + if isinstance(inner, Command): + _populate_descriptions(inner._params, parameters) + else: + try: + inner.__discord_app_commands_param_description__.update(parameters) # type: ignore # Runtime attribute access + except AttributeError: + inner.__discord_app_commands_param_description__ = parameters # type: ignore # Runtime attribute assignment + + return inner + + return decorator + + +def rename(**parameters: Union[str, locale_str]) -> Callable[[T], T]: + r"""Renames the given parameters by their name using the key of the keyword argument + as the name. + + This renames the parameter within the Discord UI. When referring to the parameter in other + decorators, the parameter name used in the function is used instead of the renamed one. + + Example: + + .. code-block:: python3 + + @app_commands.command() + @app_commands.rename(the_member_to_ban='member') + async def ban(interaction: discord.Interaction, the_member_to_ban: discord.Member): + await interaction.response.send_message(f'Banned {the_member_to_ban}') + + Parameters + ----------- + \*\*parameters: Union[:class:`str`, :class:`locale_str`] + The name of the parameters. + + Raises + -------- + ValueError + The parameter name is already used by another parameter. + TypeError + The parameter name is not found. + """ + + def decorator(inner: T) -> T: + if isinstance(inner, Command): + _populate_renames(inner._params, parameters) + else: + try: + inner.__discord_app_commands_param_rename__.update(parameters) # type: ignore # Runtime attribute access + except AttributeError: + inner.__discord_app_commands_param_rename__ = parameters # type: ignore # Runtime attribute assignment + + return inner + + return decorator + + +def choices(**parameters: List[Choice[ChoiceT]]) -> Callable[[T], T]: + r"""Instructs the given parameters by their name to use the given choices for their choices. + + Example: + + .. code-block:: python3 + + @app_commands.command() + @app_commands.describe(fruits='fruits to choose from') + @app_commands.choices(fruits=[ + Choice(name='apple', value=1), + Choice(name='banana', value=2), + Choice(name='cherry', value=3), + ]) + async def fruit(interaction: discord.Interaction, fruits: Choice[int]): + await interaction.response.send_message(f'Your favourite fruit is {fruits.name}.') + + .. note:: + + This is not the only way to provide choices to a command. There are two more ergonomic ways + of doing this. The first one is to use a :obj:`typing.Literal` annotation: + + .. code-block:: python3 + + @app_commands.command() + @app_commands.describe(fruits='fruits to choose from') + async def fruit(interaction: discord.Interaction, fruits: Literal['apple', 'banana', 'cherry']): + await interaction.response.send_message(f'Your favourite fruit is {fruits}.') + + The second way is to use an :class:`enum.Enum`: + + .. code-block:: python3 + + class Fruits(enum.Enum): + apple = 1 + banana = 2 + cherry = 3 + + @app_commands.command() + @app_commands.describe(fruits='fruits to choose from') + async def fruit(interaction: discord.Interaction, fruits: Fruits): + await interaction.response.send_message(f'Your favourite fruit is {fruits}.') + + + Parameters + ----------- + \*\*parameters + The choices of the parameters. + + Raises + -------- + TypeError + The parameter name is not found or the parameter type was incorrect. + """ + + def decorator(inner: T) -> T: + if isinstance(inner, Command): + _populate_choices(inner._params, parameters) + else: + try: + inner.__discord_app_commands_param_choices__.update(parameters) # type: ignore # Runtime attribute access + except AttributeError: + inner.__discord_app_commands_param_choices__ = parameters # type: ignore # Runtime attribute assignment + + return inner + + return decorator + + +def autocomplete(**parameters: AutocompleteCallback[GroupT, ChoiceT]) -> Callable[[T], T]: + r"""Associates the given parameters with the given autocomplete callback. + + Autocomplete is only supported on types that have :class:`str`, :class:`int`, or :class:`float` + values. + + :func:`Checks ` are supported, however they must be attached to the autocomplete + callback in order to work. Checks attached to the command are ignored when invoking the autocomplete + callback. + + For more information, see the :meth:`Command.autocomplete` documentation. + + .. warning:: + The choices returned from this coroutine are suggestions. The user may ignore them and input their own value. + + Example: + + .. code-block:: python3 + + async def fruit_autocomplete( + interaction: discord.Interaction, + current: str, + ) -> List[app_commands.Choice[str]]: + fruits = ['Banana', 'Pineapple', 'Apple', 'Watermelon', 'Melon', 'Cherry'] + return [ + app_commands.Choice(name=fruit, value=fruit) + for fruit in fruits if current.lower() in fruit.lower() + ] + + @app_commands.command() + @app_commands.autocomplete(fruit=fruit_autocomplete) + async def fruits(interaction: discord.Interaction, fruit: str): + await interaction.response.send_message(f'Your favourite fruit seems to be {fruit}') + + Parameters + ----------- + \*\*parameters + The parameters to mark as autocomplete. + + Raises + -------- + TypeError + The parameter name is not found or the parameter type was incorrect. + """ + + def decorator(inner: T) -> T: + if isinstance(inner, Command): + _populate_autocomplete(inner._params, parameters) + else: + try: + inner.__discord_app_commands_param_autocomplete__.update(parameters) # type: ignore # Runtime attribute access + except AttributeError: + inner.__discord_app_commands_param_autocomplete__ = parameters # type: ignore # Runtime attribute assignment + + return inner + + return decorator + + +def guilds(*guild_ids: Union[Snowflake, int]) -> Callable[[T], T]: + r"""Associates the given guilds with the command. + + When the command instance is added to a :class:`CommandTree`, the guilds that are + specified by this decorator become the default guilds that it's added to rather + than being a global command. + + .. note:: + + Due to an implementation quirk and Python limitation, if this is used in conjunction + with the :meth:`CommandTree.command` or :meth:`CommandTree.context_menu` decorator + then this must go below that decorator. + + .. note :: + + Due to a Discord limitation, this decorator cannot be used in conjunction with + contexts (e.g. :func:`.app_commands.allowed_contexts`) or installation types + (e.g. :func:`.app_commands.allowed_installs`). + + Example: + + .. code-block:: python3 + + MY_GUILD_ID = discord.Object(...) # Guild ID here + + @app_commands.command() + @app_commands.guilds(MY_GUILD_ID) + async def bonk(interaction: discord.Interaction): + await interaction.response.send_message('Bonk', ephemeral=True) + + Parameters + ----------- + \*guild_ids: Union[:class:`int`, :class:`~discord.abc.Snowflake`] + The guilds to associate this command with. The command tree will + use this as the default when added rather than adding it as a global + command. + """ + + defaults: List[int] = [g if isinstance(g, int) else g.id for g in guild_ids] + + def decorator(inner: T) -> T: + if isinstance(inner, (Group, ContextMenu)): + inner._guild_ids = defaults + elif isinstance(inner, Command): + if inner.parent is not None: + raise ValueError('child commands of a group cannot have default guilds set') + + inner._guild_ids = defaults + else: + # Runtime attribute assignment + inner.__discord_app_commands_default_guilds__ = defaults # type: ignore + + return inner + + return decorator + + +def check(predicate: Check) -> Callable[[T], T]: + r"""A decorator that adds a check to an application command. + + These checks should be predicates that take in a single parameter taking + a :class:`~discord.Interaction`. If the check returns a ``False``\-like value then + during invocation a :exc:`CheckFailure` exception is raised and sent to + the appropriate error handlers. + + These checks can be either a coroutine or not. + + Examples + --------- + + Creating a basic check to see if the command invoker is you. + + .. code-block:: python3 + + def check_if_it_is_me(interaction: discord.Interaction) -> bool: + return interaction.user.id == 85309593344815104 + + @tree.command() + @app_commands.check(check_if_it_is_me) + async def only_for_me(interaction: discord.Interaction): + await interaction.response.send_message('I know you!', ephemeral=True) + + Transforming common checks into its own decorator: + + .. code-block:: python3 + + def is_me(): + def predicate(interaction: discord.Interaction) -> bool: + return interaction.user.id == 85309593344815104 + return app_commands.check(predicate) + + @tree.command() + @is_me() + async def only_me(interaction: discord.Interaction): + await interaction.response.send_message('Only you!') + + Parameters + ----------- + predicate: Callable[[:class:`~discord.Interaction`], :class:`bool`] + The predicate to check if the command should be invoked. + """ + + def decorator(func: CheckInputParameter) -> CheckInputParameter: + if isinstance(func, (Command, ContextMenu)): + func.checks.append(predicate) + else: + if not hasattr(func, '__discord_app_commands_checks__'): + func.__discord_app_commands_checks__ = [] + + func.__discord_app_commands_checks__.append(predicate) + + return func + + return decorator # type: ignore + + +@overload +def guild_only(func: None = ...) -> Callable[[T], T]: + ... + + +@overload +def guild_only(func: T) -> T: + ... + + +def guild_only(func: Optional[T] = None) -> Union[T, Callable[[T], T]]: + """A decorator that indicates this command can only be used in a guild context. + + This is **not** implemented as a :func:`check`, and is instead verified by Discord server side. + Therefore, there is no error handler called when a command is used within a private message. + + This decorator can be called with or without parentheses. + + Due to a Discord limitation, this decorator does nothing in subcommands and is ignored. + + Examples + --------- + + .. code-block:: python3 + + @app_commands.command() + @app_commands.guild_only() + async def my_guild_only_command(interaction: discord.Interaction) -> None: + await interaction.response.send_message('I am only available in guilds!') + """ + + def inner(f: T) -> T: + if isinstance(f, (Command, Group, ContextMenu)): + f.guild_only = True + allowed_contexts = f.allowed_contexts or AppCommandContext() + f.allowed_contexts = allowed_contexts + else: + f.__discord_app_commands_guild_only__ = True # type: ignore # Runtime attribute assignment + + allowed_contexts = getattr(f, '__discord_app_commands_contexts__', None) or AppCommandContext() + f.__discord_app_commands_contexts__ = allowed_contexts # type: ignore # Runtime attribute assignment + + allowed_contexts.guild = True + + return f + + # Check if called with parentheses or not + if func is None: + # Called with parentheses + return inner + else: + return inner(func) + + +@overload +def private_channel_only(func: None = ...) -> Callable[[T], T]: + ... + + +@overload +def private_channel_only(func: T) -> T: + ... + + +def private_channel_only(func: Optional[T] = None) -> Union[T, Callable[[T], T]]: + """A decorator that indicates this command can only be used in the context of DMs and group DMs. + + This is **not** implemented as a :func:`check`, and is instead verified by Discord server side. + Therefore, there is no error handler called when a command is used within a guild. + + This decorator can be called with or without parentheses. + + Due to a Discord limitation, this decorator does nothing in subcommands and is ignored. + + .. versionadded:: 2.4 + + Examples + --------- + + .. code-block:: python3 + + @app_commands.command() + @app_commands.private_channel_only() + async def my_private_channel_only_command(interaction: discord.Interaction) -> None: + await interaction.response.send_message('I am only available in DMs and GDMs!') + """ + + def inner(f: T) -> T: + if isinstance(f, (Command, Group, ContextMenu)): + f.guild_only = False + allowed_contexts = f.allowed_contexts or AppCommandContext() + f.allowed_contexts = allowed_contexts + else: + allowed_contexts = getattr(f, '__discord_app_commands_contexts__', None) or AppCommandContext() + f.__discord_app_commands_contexts__ = allowed_contexts # type: ignore # Runtime attribute assignment + + allowed_contexts.private_channel = True + + return f + + # Check if called with parentheses or not + if func is None: + # Called with parentheses + return inner + else: + return inner(func) + + +@overload +def dm_only(func: None = ...) -> Callable[[T], T]: + ... + + +@overload +def dm_only(func: T) -> T: + ... + + +def dm_only(func: Optional[T] = None) -> Union[T, Callable[[T], T]]: + """A decorator that indicates this command can only be used in the context of bot DMs. + + This is **not** implemented as a :func:`check`, and is instead verified by Discord server side. + Therefore, there is no error handler called when a command is used within a guild or group DM. + + This decorator can be called with or without parentheses. + + Due to a Discord limitation, this decorator does nothing in subcommands and is ignored. + + Examples + --------- + + .. code-block:: python3 + + @app_commands.command() + @app_commands.dm_only() + async def my_dm_only_command(interaction: discord.Interaction) -> None: + await interaction.response.send_message('I am only available in DMs!') + """ + + def inner(f: T) -> T: + if isinstance(f, (Command, Group, ContextMenu)): + f.guild_only = False + allowed_contexts = f.allowed_contexts or AppCommandContext() + f.allowed_contexts = allowed_contexts + else: + allowed_contexts = getattr(f, '__discord_app_commands_contexts__', None) or AppCommandContext() + f.__discord_app_commands_contexts__ = allowed_contexts # type: ignore # Runtime attribute assignment + + allowed_contexts.dm_channel = True + return f + + # Check if called with parentheses or not + if func is None: + # Called with parentheses + return inner + else: + return inner(func) + + +def allowed_contexts(guilds: bool = MISSING, dms: bool = MISSING, private_channels: bool = MISSING) -> Callable[[T], T]: + """A decorator that indicates this command can only be used in certain contexts. + Valid contexts are guilds, DMs and private channels. + + This is **not** implemented as a :func:`check`, and is instead verified by Discord server side. + + Due to a Discord limitation, this decorator does nothing in subcommands and is ignored. + + .. versionadded:: 2.4 + + Examples + --------- + + .. code-block:: python3 + + @app_commands.command() + @app_commands.allowed_contexts(guilds=True, dms=False, private_channels=True) + async def my_command(interaction: discord.Interaction) -> None: + await interaction.response.send_message('I am only available in guilds and private channels!') + """ + + def inner(f: T) -> T: + if isinstance(f, (Command, Group, ContextMenu)): + f.guild_only = False + allowed_contexts = f.allowed_contexts or AppCommandContext() + f.allowed_contexts = allowed_contexts + else: + allowed_contexts = getattr(f, '__discord_app_commands_contexts__', None) or AppCommandContext() + f.__discord_app_commands_contexts__ = allowed_contexts # type: ignore # Runtime attribute assignment + + if guilds is not MISSING: + allowed_contexts.guild = guilds + + if dms is not MISSING: + allowed_contexts.dm_channel = dms + + if private_channels is not MISSING: + allowed_contexts.private_channel = private_channels + + return f + + return inner + + +@overload +def guild_install(func: None = ...) -> Callable[[T], T]: + ... + + +@overload +def guild_install(func: T) -> T: + ... + + +def guild_install(func: Optional[T] = None) -> Union[T, Callable[[T], T]]: + """A decorator that indicates this command should be installed in guilds. + + This is **not** implemented as a :func:`check`, and is instead verified by Discord server side. + + Due to a Discord limitation, this decorator does nothing in subcommands and is ignored. + + .. versionadded:: 2.4 + + Examples + --------- + + .. code-block:: python3 + + @app_commands.command() + @app_commands.guild_install() + async def my_guild_install_command(interaction: discord.Interaction) -> None: + await interaction.response.send_message('I am installed in guilds by default!') + """ + + def inner(f: T) -> T: + if isinstance(f, (Command, Group, ContextMenu)): + allowed_installs = f.allowed_installs or AppInstallationType() + f.allowed_installs = allowed_installs + else: + allowed_installs = getattr(f, '__discord_app_commands_installation_types__', None) or AppInstallationType() + f.__discord_app_commands_installation_types__ = allowed_installs # type: ignore # Runtime attribute assignment + + allowed_installs.guild = True + + return f + + # Check if called with parentheses or not + if func is None: + # Called with parentheses + return inner + else: + return inner(func) + + +@overload +def user_install(func: None = ...) -> Callable[[T], T]: + ... + + +@overload +def user_install(func: T) -> T: + ... + + +def user_install(func: Optional[T] = None) -> Union[T, Callable[[T], T]]: + """A decorator that indicates this command should be installed for users. + + This is **not** implemented as a :func:`check`, and is instead verified by Discord server side. + + Due to a Discord limitation, this decorator does nothing in subcommands and is ignored. + + .. versionadded:: 2.4 + + Examples + --------- + + .. code-block:: python3 + + @app_commands.command() + @app_commands.user_install() + async def my_user_install_command(interaction: discord.Interaction) -> None: + await interaction.response.send_message('I am installed in users by default!') + """ + + def inner(f: T) -> T: + if isinstance(f, (Command, Group, ContextMenu)): + allowed_installs = f.allowed_installs or AppInstallationType() + f.allowed_installs = allowed_installs + else: + allowed_installs = getattr(f, '__discord_app_commands_installation_types__', None) or AppInstallationType() + f.__discord_app_commands_installation_types__ = allowed_installs # type: ignore # Runtime attribute assignment + + allowed_installs.user = True + + return f + + # Check if called with parentheses or not + if func is None: + # Called with parentheses + return inner + else: + return inner(func) + + +def allowed_installs( + guilds: bool = MISSING, + users: bool = MISSING, +) -> Callable[[T], T]: + """A decorator that indicates this command should be installed in certain contexts. + Valid contexts are guilds and users. + + This is **not** implemented as a :func:`check`, and is instead verified by Discord server side. + + Due to a Discord limitation, this decorator does nothing in subcommands and is ignored. + + .. versionadded:: 2.4 + + Examples + --------- + + .. code-block:: python3 + + @app_commands.command() + @app_commands.allowed_installs(guilds=False, users=True) + async def my_command(interaction: discord.Interaction) -> None: + await interaction.response.send_message('I am installed in users by default!') + """ + + def inner(f: T) -> T: + if isinstance(f, (Command, Group, ContextMenu)): + allowed_installs = f.allowed_installs or AppInstallationType() + f.allowed_installs = allowed_installs + else: + allowed_installs = getattr(f, '__discord_app_commands_installation_types__', None) or AppInstallationType() + f.__discord_app_commands_installation_types__ = allowed_installs # type: ignore # Runtime attribute assignment + + if guilds is not MISSING: + allowed_installs.guild = guilds + + if users is not MISSING: + allowed_installs.user = users + + return f + + return inner + + +def default_permissions(perms_obj: Optional[Permissions] = None, /, **perms: bool) -> Callable[[T], T]: + r"""A decorator that sets the default permissions needed to execute this command. + + When this decorator is used, by default users must have these permissions to execute the command. + However, an administrator can change the permissions needed to execute this command using the official + client. Therefore, this only serves as a hint. + + Setting an empty permissions field, including via calling this with no arguments, will disallow anyone + except server administrators from using the command in a guild. + + This is sent to Discord server side, and is not a :func:`check`. Therefore, error handlers are not called. + + Due to a Discord limitation, this decorator does nothing in subcommands and is ignored. + + .. warning:: + + This serves as a *hint* and members are *not* required to have the permissions given to actually + execute this command. If you want to ensure that members have the permissions needed, consider using + :func:`~discord.app_commands.checks.has_permissions` instead. + + Parameters + ----------- + \*\*perms: :class:`bool` + Keyword arguments denoting the permissions to set as the default. + perms_obj: :class:`~discord.Permissions` + A permissions object as positional argument. This can be used in combination with ``**perms``. + + .. versionadded:: 2.5 + + Examples + --------- + + .. code-block:: python3 + + @app_commands.command() + @app_commands.default_permissions(manage_messages=True) + async def test(interaction: discord.Interaction): + await interaction.response.send_message('You may or may not have manage messages.') + + .. code-block:: python3 + + ADMIN_PERMS = discord.Permissions(administrator=True) + + @app_commands.command() + @app_commands.default_permissions(ADMIN_PERMS, manage_messages=True) + async def test(interaction: discord.Interaction): + await interaction.response.send_message('You may or may not have manage messages.') + """ + + if perms_obj is not None: + permissions = perms_obj | Permissions(**perms) + else: + permissions = Permissions(**perms) + + def decorator(func: T) -> T: + if isinstance(func, (Command, Group, ContextMenu)): + func.default_permissions = permissions + else: + func.__discord_app_commands_default_permissions__ = permissions # type: ignore # Runtime attribute assignment + + return func + + return decorator diff --git a/venv/lib/python3.12/site-packages/discord/app_commands/errors.py b/venv/lib/python3.12/site-packages/discord/app_commands/errors.py new file mode 100644 index 00000000..2efb4e5b --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/app_commands/errors.py @@ -0,0 +1,519 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from __future__ import annotations + +from typing import Any, TYPE_CHECKING, List, Optional, Sequence, Union + +from ..enums import AppCommandOptionType, AppCommandType, Locale +from ..errors import DiscordException, HTTPException, _flatten_error_dict, MissingApplicationID as MissingApplicationID +from ..utils import _human_join + +__all__ = ( + 'AppCommandError', + 'CommandInvokeError', + 'TransformerError', + 'TranslationError', + 'CheckFailure', + 'CommandAlreadyRegistered', + 'CommandSignatureMismatch', + 'CommandNotFound', + 'CommandLimitReached', + 'NoPrivateMessage', + 'MissingRole', + 'MissingAnyRole', + 'MissingPermissions', + 'BotMissingPermissions', + 'CommandOnCooldown', + 'MissingApplicationID', + 'CommandSyncFailure', +) + +if TYPE_CHECKING: + from .commands import Command, Group, ContextMenu, Parameter + from .transformers import Transformer + from .translator import TranslationContextTypes, locale_str + from ..types.snowflake import Snowflake, SnowflakeList + from .checks import Cooldown + + CommandTypes = Union[Command[Any, ..., Any], Group, ContextMenu] + + +class AppCommandError(DiscordException): + """The base exception type for all application command related errors. + + This inherits from :exc:`discord.DiscordException`. + + This exception and exceptions inherited from it are handled + in a special way as they are caught and passed into various error handlers + in this order: + + - :meth:`Command.error ` + - :meth:`Group.on_error ` + - :meth:`CommandTree.on_error ` + + .. versionadded:: 2.0 + """ + + pass + + +class CommandInvokeError(AppCommandError): + """An exception raised when the command being invoked raised an exception. + + This inherits from :exc:`~discord.app_commands.AppCommandError`. + + .. versionadded:: 2.0 + + Attributes + ----------- + original: :exc:`Exception` + The original exception that was raised. You can also get this via + the ``__cause__`` attribute. + command: Union[:class:`Command`, :class:`ContextMenu`] + The command that failed. + """ + + def __init__(self, command: Union[Command[Any, ..., Any], ContextMenu], e: Exception) -> None: + self.original: Exception = e + self.command: Union[Command[Any, ..., Any], ContextMenu] = command + super().__init__(f'Command {command.name!r} raised an exception: {e.__class__.__name__}: {e}') + + +class TransformerError(AppCommandError): + """An exception raised when a :class:`Transformer` or type annotation fails to + convert to its target type. + + This inherits from :exc:`~discord.app_commands.AppCommandError`. + + If an exception occurs while converting that does not subclass + :exc:`AppCommandError` then the exception is wrapped into this exception. + The original exception can be retrieved using the ``__cause__`` attribute. + Otherwise if the exception derives from :exc:`AppCommandError` then it will + be propagated as-is. + + .. versionadded:: 2.0 + + Attributes + ----------- + value: Any + The value that failed to convert. + type: :class:`~discord.AppCommandOptionType` + The type of argument that failed to convert. + transformer: :class:`Transformer` + The transformer that failed the conversion. + """ + + def __init__(self, value: Any, opt_type: AppCommandOptionType, transformer: Transformer): + self.value: Any = value + self.type: AppCommandOptionType = opt_type + self.transformer: Transformer = transformer + + super().__init__(f'Failed to convert {value} to {transformer._error_display_name!s}') + + +class TranslationError(AppCommandError): + """An exception raised when the library fails to translate a string. + + This inherits from :exc:`~discord.app_commands.AppCommandError`. + + If an exception occurs while calling :meth:`Translator.translate` that does + not subclass this then the exception is wrapped into this exception. + The original exception can be retrieved using the ``__cause__`` attribute. + Otherwise it will be propagated as-is. + + .. versionadded:: 2.0 + + Attributes + ----------- + string: Optional[Union[:class:`str`, :class:`locale_str`]] + The string that caused the error, if any. + locale: Optional[:class:`~discord.Locale`] + The locale that caused the error, if any. + context: :class:`~discord.app_commands.TranslationContext` + The context of the translation that triggered the error. + """ + + def __init__( + self, + *msg: str, + string: Optional[Union[str, locale_str]] = None, + locale: Optional[Locale] = None, + context: TranslationContextTypes, + ) -> None: + self.string: Optional[Union[str, locale_str]] = string + self.locale: Optional[Locale] = locale + self.context: TranslationContextTypes = context + + if msg: + super().__init__(*msg) + else: + ctx = context.location.name.replace('_', ' ') + fmt = f'Failed to translate {self.string!r} in a {ctx}' + if self.locale is not None: + fmt = f'{fmt} in the {self.locale.value} locale' + + super().__init__(fmt) + + +class CheckFailure(AppCommandError): + """An exception raised when check predicates in a command have failed. + + This inherits from :exc:`~discord.app_commands.AppCommandError`. + + .. versionadded:: 2.0 + """ + + pass + + +class NoPrivateMessage(CheckFailure): + """An exception raised when a command does not work in a direct message. + + This inherits from :exc:`~discord.app_commands.CheckFailure`. + + .. versionadded:: 2.0 + """ + + def __init__(self, message: Optional[str] = None) -> None: + super().__init__(message or 'This command cannot be used in direct messages.') + + +class MissingRole(CheckFailure): + """An exception raised when the command invoker lacks a role to run a command. + + This inherits from :exc:`~discord.app_commands.CheckFailure`. + + .. versionadded:: 2.0 + + Attributes + ----------- + missing_role: Union[:class:`str`, :class:`int`] + The required role that is missing. + This is the parameter passed to :func:`~discord.app_commands.checks.has_role`. + """ + + def __init__(self, missing_role: Snowflake) -> None: + self.missing_role: Snowflake = missing_role + message = f'Role {missing_role!r} is required to run this command.' + super().__init__(message) + + +class MissingAnyRole(CheckFailure): + """An exception raised when the command invoker lacks any of the roles + specified to run a command. + + This inherits from :exc:`~discord.app_commands.CheckFailure`. + + .. versionadded:: 2.0 + + Attributes + ----------- + missing_roles: List[Union[:class:`str`, :class:`int`]] + The roles that the invoker is missing. + These are the parameters passed to :func:`~discord.app_commands.checks.has_any_role`. + """ + + def __init__(self, missing_roles: SnowflakeList) -> None: + self.missing_roles: SnowflakeList = missing_roles + + fmt = _human_join([f"'{role}'" for role in missing_roles]) + message = f'You are missing at least one of the required roles: {fmt}' + super().__init__(message) + + +class MissingPermissions(CheckFailure): + """An exception raised when the command invoker lacks permissions to run a + command. + + This inherits from :exc:`~discord.app_commands.CheckFailure`. + + .. versionadded:: 2.0 + + Attributes + ----------- + missing_permissions: List[:class:`str`] + The required permissions that are missing. + """ + + def __init__(self, missing_permissions: List[str], *args: Any) -> None: + self.missing_permissions: List[str] = missing_permissions + + missing = [perm.replace('_', ' ').replace('guild', 'server').title() for perm in missing_permissions] + fmt = _human_join(missing, final='and') + message = f'You are missing {fmt} permission(s) to run this command.' + super().__init__(message, *args) + + +class BotMissingPermissions(CheckFailure): + """An exception raised when the bot's member lacks permissions to run a + command. + + This inherits from :exc:`~discord.app_commands.CheckFailure`. + + .. versionadded:: 2.0 + + Attributes + ----------- + missing_permissions: List[:class:`str`] + The required permissions that are missing. + """ + + def __init__(self, missing_permissions: List[str], *args: Any) -> None: + self.missing_permissions: List[str] = missing_permissions + + missing = [perm.replace('_', ' ').replace('guild', 'server').title() for perm in missing_permissions] + fmt = _human_join(missing, final='and') + message = f'Bot requires {fmt} permission(s) to run this command.' + super().__init__(message, *args) + + +class CommandOnCooldown(CheckFailure): + """An exception raised when the command being invoked is on cooldown. + + This inherits from :exc:`~discord.app_commands.CheckFailure`. + + .. versionadded:: 2.0 + + Attributes + ----------- + cooldown: :class:`~discord.app_commands.Cooldown` + The cooldown that was triggered. + retry_after: :class:`float` + The amount of seconds to wait before you can retry again. + """ + + def __init__(self, cooldown: Cooldown, retry_after: float) -> None: + self.cooldown: Cooldown = cooldown + self.retry_after: float = retry_after + super().__init__(f'You are on cooldown. Try again in {retry_after:.2f}s') + + +class CommandAlreadyRegistered(AppCommandError): + """An exception raised when a command is already registered. + + This inherits from :exc:`~discord.app_commands.AppCommandError`. + + .. versionadded:: 2.0 + + Attributes + ----------- + name: :class:`str` + The name of the command already registered. + guild_id: Optional[:class:`int`] + The guild ID this command was already registered at. + If ``None`` then it was a global command. + """ + + def __init__(self, name: str, guild_id: Optional[int]): + self.name: str = name + self.guild_id: Optional[int] = guild_id + super().__init__(f'Command {name!r} already registered.') + + +class CommandNotFound(AppCommandError): + """An exception raised when an application command could not be found. + + This inherits from :exc:`~discord.app_commands.AppCommandError`. + + .. versionadded:: 2.0 + + Attributes + ------------ + name: :class:`str` + The name of the application command not found. + parents: List[:class:`str`] + A list of parent command names that were previously found + prior to the application command not being found. + type: :class:`~discord.AppCommandType` + The type of command that was not found. + """ + + def __init__(self, name: str, parents: List[str], type: AppCommandType = AppCommandType.chat_input): + self.name: str = name + self.parents: List[str] = parents + self.type: AppCommandType = type + super().__init__(f'Application command {name!r} not found') + + +class CommandLimitReached(AppCommandError): + """An exception raised when the maximum number of application commands was reached + either globally or in a guild. + + This inherits from :exc:`~discord.app_commands.AppCommandError`. + + .. versionadded:: 2.0 + + Attributes + ------------ + type: :class:`~discord.AppCommandType` + The type of command that reached the limit. + guild_id: Optional[:class:`int`] + The guild ID that reached the limit or ``None`` if it was global. + limit: :class:`int` + The limit that was hit. + """ + + def __init__(self, guild_id: Optional[int], limit: int, type: AppCommandType = AppCommandType.chat_input): + self.guild_id: Optional[int] = guild_id + self.limit: int = limit + self.type: AppCommandType = type + + lookup = { + AppCommandType.chat_input: 'slash commands', + AppCommandType.message: 'message context menu commands', + AppCommandType.user: 'user context menu commands', + } + desc = lookup.get(type, 'application commands') + ns = 'globally' if self.guild_id is None else f'for guild ID {self.guild_id}' + super().__init__(f'maximum number of {desc} exceeded {limit} {ns}') + + +class CommandSignatureMismatch(AppCommandError): + """An exception raised when an application command from Discord has a different signature + from the one provided in the code. This happens because your command definition differs + from the command definition you provided Discord. Either your code is out of date or the + data from Discord is out of sync. + + This inherits from :exc:`~discord.app_commands.AppCommandError`. + + .. versionadded:: 2.0 + + Attributes + ------------ + command: Union[:class:`~.app_commands.Command`, :class:`~.app_commands.ContextMenu`, :class:`~.app_commands.Group`] + The command that had the signature mismatch. + """ + + def __init__(self, command: Union[Command[Any, ..., Any], ContextMenu, Group]): + self.command: Union[Command[Any, ..., Any], ContextMenu, Group] = command + msg = ( + f'The signature for command {command.name!r} is different from the one provided by Discord. ' + 'This can happen because either your code is out of date or you have not synced the ' + 'commands with Discord, causing the mismatch in data. It is recommended to sync the ' + 'command tree to fix this issue.' + ) + super().__init__(msg) + + +def _get_command_error( + index: str, + inner: Any, + objects: Sequence[Union[Parameter, CommandTypes]], + messages: List[str], + indent: int = 0, +) -> None: + # Import these here to avoid circular imports + from .commands import Command, Group, ContextMenu + + indentation = ' ' * indent + + # Top level errors are: + # : { : } + # The dicts could be nested, e.g. + # : { : { : } } + # Luckily, this is already handled by the flatten_error_dict utility + if not index.isdigit(): + errors = _flatten_error_dict(inner, index) + messages.extend(f'In {k}: {v}' for k, v in errors.items()) + return + + idx = int(index) + try: + obj = objects[idx] + except IndexError: + dedent_one_level = ' ' * (indent - 2) + errors = _flatten_error_dict(inner, index) + messages.extend(f'{dedent_one_level}In {k}: {v}' for k, v in errors.items()) + return + + children: Sequence[Union[Parameter, CommandTypes]] = [] + if isinstance(obj, Command): + messages.append(f'{indentation}In command {obj.qualified_name!r} defined in function {obj.callback.__qualname__!r}') + children = obj.parameters + elif isinstance(obj, Group): + messages.append(f'{indentation}In group {obj.qualified_name!r} defined in module {obj.module!r}') + children = obj.commands + elif isinstance(obj, ContextMenu): + messages.append( + f'{indentation}In context menu {obj.qualified_name!r} defined in function {obj.callback.__qualname__!r}' + ) + else: + messages.append(f'{indentation}In parameter {obj.name!r}') + + for key, remaining in inner.items(): + # Special case the 'options' key since they have well defined meanings + if key == 'options': + for index, d in remaining.items(): + _get_command_error(index, d, children, messages, indent=indent + 2) + elif key == '_errors': + errors = [x.get('message', '') for x in remaining] + + messages.extend(f'{indentation} {message}' for message in errors) + else: + if isinstance(remaining, dict): + try: + inner_errors = remaining['_errors'] + except KeyError: + errors = _flatten_error_dict(remaining, key=key) + else: + errors = {key: ' '.join(x.get('message', '') for x in inner_errors)} + + if isinstance(errors, dict): + messages.extend(f'{indentation} {k}: {v}' for k, v in errors.items()) + + +class CommandSyncFailure(AppCommandError, HTTPException): + """An exception raised when :meth:`CommandTree.sync` failed. + + This provides syncing failures in a slightly more readable format. + + This inherits from :exc:`~discord.app_commands.AppCommandError` + and :exc:`~discord.HTTPException`. + + .. versionadded:: 2.0 + """ + + def __init__(self, child: HTTPException, commands: List[CommandTypes]) -> None: + # Consume the child exception and make it seem as if we are that exception + self.__dict__.update(child.__dict__) + + messages = [f'Failed to upload commands to Discord (HTTP status {self.status}, error code {self.code})'] + + if self._errors: + # Handle case where the errors dict has no actual chain such as APPLICATION_COMMAND_TOO_LARGE + if len(self._errors) == 1 and '_errors' in self._errors: + errors = self._errors['_errors'] + if len(errors) == 1: + extra = errors[0].get('message') + if extra: + messages[0] += f': {extra}' + else: + messages.extend(f'Error {e.get("code", "")}: {e.get("message", "")}' for e in errors) + else: + for index, inner in self._errors.items(): + _get_command_error(index, inner, commands, messages) + + # Equivalent to super().__init__(...) but skips other constructors + self.args = ('\n'.join(messages),) diff --git a/venv/lib/python3.12/site-packages/discord/app_commands/installs.py b/venv/lib/python3.12/site-packages/discord/app_commands/installs.py new file mode 100644 index 00000000..5ac03324 --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/app_commands/installs.py @@ -0,0 +1,207 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from __future__ import annotations +from typing import TYPE_CHECKING, ClassVar, List, Optional, Sequence + +__all__ = ( + 'AppInstallationType', + 'AppCommandContext', +) + +if TYPE_CHECKING: + from typing_extensions import Self + from ..types.interactions import InteractionContextType, InteractionInstallationType + + +class AppInstallationType: + r"""Represents the installation location of an application command. + + .. versionadded:: 2.4 + + Parameters + ----------- + guild: Optional[:class:`bool`] + Whether the integration is a guild install. + user: Optional[:class:`bool`] + Whether the integration is a user install. + """ + + __slots__ = ('_guild', '_user') + + GUILD: ClassVar[int] = 0 + USER: ClassVar[int] = 1 + + def __init__(self, *, guild: Optional[bool] = None, user: Optional[bool] = None): + self._guild: Optional[bool] = guild + self._user: Optional[bool] = user + + @property + def guild(self) -> bool: + """:class:`bool`: Whether the integration is a guild install.""" + return bool(self._guild) + + @guild.setter + def guild(self, value: bool) -> None: + self._guild = bool(value) + + @property + def user(self) -> bool: + """:class:`bool`: Whether the integration is a user install.""" + return bool(self._user) + + @user.setter + def user(self, value: bool) -> None: + self._user = bool(value) + + def merge(self, other: AppInstallationType) -> AppInstallationType: + # Merging is similar to AllowedMentions where `self` is the base + # and the `other` is the override preference + guild = self._guild if other._guild is None else other._guild + user = self._user if other._user is None else other._user + return AppInstallationType(guild=guild, user=user) + + def _is_unset(self) -> bool: + return all(x is None for x in (self._guild, self._user)) + + def _merge_to_array(self, other: Optional[AppInstallationType]) -> Optional[List[InteractionInstallationType]]: + result = self.merge(other) if other is not None else self + if result._is_unset(): + return None + return result.to_array() + + @classmethod + def _from_value(cls, value: Sequence[InteractionInstallationType]) -> Self: + self = cls() + for x in value: + if x == cls.GUILD: + self._guild = True + elif x == cls.USER: + self._user = True + return self + + def to_array(self) -> List[InteractionInstallationType]: + values = [] + if self._guild: + values.append(self.GUILD) + if self._user: + values.append(self.USER) + return values + + +class AppCommandContext: + r"""Wraps up the Discord :class:`~discord.app_commands.Command` execution context. + + .. versionadded:: 2.4 + + Parameters + ----------- + guild: Optional[:class:`bool`] + Whether the context allows usage in a guild. + dm_channel: Optional[:class:`bool`] + Whether the context allows usage in a DM channel. + private_channel: Optional[:class:`bool`] + Whether the context allows usage in a DM or a GDM channel. + """ + + GUILD: ClassVar[int] = 0 + DM_CHANNEL: ClassVar[int] = 1 + PRIVATE_CHANNEL: ClassVar[int] = 2 + + __slots__ = ('_guild', '_dm_channel', '_private_channel') + + def __init__( + self, + *, + guild: Optional[bool] = None, + dm_channel: Optional[bool] = None, + private_channel: Optional[bool] = None, + ): + self._guild: Optional[bool] = guild + self._dm_channel: Optional[bool] = dm_channel + self._private_channel: Optional[bool] = private_channel + + @property + def guild(self) -> bool: + """:class:`bool`: Whether the context allows usage in a guild.""" + return bool(self._guild) + + @guild.setter + def guild(self, value: bool) -> None: + self._guild = bool(value) + + @property + def dm_channel(self) -> bool: + """:class:`bool`: Whether the context allows usage in a DM channel.""" + return bool(self._dm_channel) + + @dm_channel.setter + def dm_channel(self, value: bool) -> None: + self._dm_channel = bool(value) + + @property + def private_channel(self) -> bool: + """:class:`bool`: Whether the context allows usage in a DM or a GDM channel.""" + return bool(self._private_channel) + + @private_channel.setter + def private_channel(self, value: bool) -> None: + self._private_channel = bool(value) + + def merge(self, other: AppCommandContext) -> AppCommandContext: + guild = self._guild if other._guild is None else other._guild + dm_channel = self._dm_channel if other._dm_channel is None else other._dm_channel + private_channel = self._private_channel if other._private_channel is None else other._private_channel + return AppCommandContext(guild=guild, dm_channel=dm_channel, private_channel=private_channel) + + def _is_unset(self) -> bool: + return all(x is None for x in (self._guild, self._dm_channel, self._private_channel)) + + def _merge_to_array(self, other: Optional[AppCommandContext]) -> Optional[List[InteractionContextType]]: + result = self.merge(other) if other is not None else self + if result._is_unset(): + return None + return result.to_array() + + @classmethod + def _from_value(cls, value: Sequence[InteractionContextType]) -> Self: + self = cls() + for x in value: + if x == cls.GUILD: + self._guild = True + elif x == cls.DM_CHANNEL: + self._dm_channel = True + elif x == cls.PRIVATE_CHANNEL: + self._private_channel = True + return self + + def to_array(self) -> List[InteractionContextType]: + values = [] + if self._guild: + values.append(self.GUILD) + if self._dm_channel: + values.append(self.DM_CHANNEL) + if self._private_channel: + values.append(self.PRIVATE_CHANNEL) + return values diff --git a/venv/lib/python3.12/site-packages/discord/app_commands/models.py b/venv/lib/python3.12/site-packages/discord/app_commands/models.py new file mode 100644 index 00000000..e8a96784 --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/app_commands/models.py @@ -0,0 +1,1124 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from __future__ import annotations +from datetime import datetime + +from .errors import MissingApplicationID +from ..flags import AppCommandContext, AppInstallationType +from .translator import TranslationContextLocation, TranslationContext, locale_str, Translator +from ..permissions import Permissions +from ..enums import ( + AppCommandOptionType, + AppCommandType, + AppCommandPermissionType, + ChannelType, + Locale, + try_enum, +) +from ..mixins import Hashable +from ..utils import _get_as_snowflake, parse_time, snowflake_time, MISSING +from ..object import Object +from ..role import Role +from ..member import Member + +from typing import Any, Dict, Generic, List, TYPE_CHECKING, Optional, TypeVar, Union + +__all__ = ( + 'AppCommand', + 'AppCommandGroup', + 'AppCommandChannel', + 'AppCommandThread', + 'AppCommandPermissions', + 'GuildAppCommandPermissions', + 'Argument', + 'Choice', + 'AllChannels', +) + +ChoiceT = TypeVar('ChoiceT', str, int, float, Union[str, int, float]) + + +def is_app_command_argument_type(value: int) -> bool: + return 11 >= value >= 3 + + +if TYPE_CHECKING: + from ..types.command import ( + ApplicationCommand as ApplicationCommandPayload, + ApplicationCommandOption, + ApplicationCommandOptionChoice, + ApplicationCommandPermissions, + GuildApplicationCommandPermissions, + ) + from ..types.interactions import ( + PartialChannel, + PartialThread, + ) + from ..types.threads import ( + ThreadMetadata, + ThreadArchiveDuration, + ) + + from ..abc import Snowflake + from ..state import ConnectionState + from ..guild import GuildChannel, Guild + from ..channel import TextChannel + from ..threads import Thread + from ..user import User + + ApplicationCommandParent = Union['AppCommand', 'AppCommandGroup'] + + +class AllChannels: + """Represents all channels for application command permissions. + + .. versionadded:: 2.0 + + Attributes + ----------- + guild: :class:`~discord.Guild` + The guild the application command permission is for. + """ + + __slots__ = ('guild',) + + def __init__(self, guild: Guild): + self.guild: Guild = guild + + @property + def id(self) -> int: + """:class:`int`: The ID sentinel used to represent all channels. Equivalent to the guild's ID minus 1.""" + return self.guild.id - 1 + + def __repr__(self) -> str: + return f'' + + +def _to_locale_dict(data: Dict[str, str]) -> Dict[Locale, str]: + return {try_enum(Locale, key): value for key, value in data.items()} + + +class AppCommand(Hashable): + """Represents an application command. + + In common parlance this is referred to as a "Slash Command" or a + "Context Menu Command". + + .. versionadded:: 2.0 + + .. container:: operations + + .. describe:: x == y + + Checks if two application commands are equal. + + .. describe:: x != y + + Checks if two application commands are not equal. + + .. describe:: hash(x) + + Returns the application command's hash. + + .. describe:: str(x) + + Returns the application command's name. + + Attributes + ----------- + id: :class:`int` + The application command's ID. + application_id: :class:`int` + The application command's application's ID. + type: :class:`~discord.AppCommandType` + The application command's type. + name: :class:`str` + The application command's name. + description: :class:`str` + The application command's description. + name_localizations: Dict[:class:`~discord.Locale`, :class:`str`] + The localised names of the application command. Used for display purposes. + description_localizations: Dict[:class:`~discord.Locale`, :class:`str`] + The localised descriptions of the application command. Used for display purposes. + options: List[Union[:class:`Argument`, :class:`AppCommandGroup`]] + A list of options. + default_member_permissions: Optional[:class:`~discord.Permissions`] + The default member permissions that can run this command. + dm_permission: :class:`bool` + A boolean that indicates whether this command can be run in direct messages. + allowed_contexts: Optional[:class:`~discord.app_commands.AppCommandContext`] + The contexts that this command is allowed to be used in. Overrides the ``dm_permission`` attribute. + + .. versionadded:: 2.4 + allowed_installs: Optional[:class:`~discord.app_commands.AppInstallationType`] + The installation contexts that this command is allowed to be installed in. + + .. versionadded:: 2.4 + guild_id: Optional[:class:`int`] + The ID of the guild this command is registered in. A value of ``None`` + denotes that it is a global command. + nsfw: :class:`bool` + Whether the command is NSFW and should only work in NSFW channels. + """ + + __slots__ = ( + 'id', + 'type', + 'application_id', + 'name', + 'description', + 'name_localizations', + 'description_localizations', + 'guild_id', + 'options', + 'default_member_permissions', + 'dm_permission', + 'allowed_contexts', + 'allowed_installs', + 'nsfw', + '_state', + ) + + def __init__(self, *, data: ApplicationCommandPayload, state: ConnectionState) -> None: + self._state: ConnectionState = state + self._from_data(data) + + def _from_data(self, data: ApplicationCommandPayload) -> None: + self.id: int = int(data['id']) + self.application_id: int = int(data['application_id']) + self.name: str = data['name'] + self.description: str = data['description'] + self.guild_id: Optional[int] = _get_as_snowflake(data, 'guild_id') + self.type: AppCommandType = try_enum(AppCommandType, data.get('type', 1)) + self.options: List[Union[Argument, AppCommandGroup]] = [ + app_command_option_factory(data=d, parent=self, state=self._state) for d in data.get('options', []) + ] + self.default_member_permissions: Optional[Permissions] + permissions = data.get('default_member_permissions') + if permissions is None: + self.default_member_permissions = None + else: + self.default_member_permissions = Permissions(int(permissions)) + + dm_permission = data.get('dm_permission') + # For some reason this field can be explicit null and mean True + if dm_permission is None: + dm_permission = True + + self.dm_permission: bool = dm_permission + + allowed_contexts = data.get('contexts') + if allowed_contexts is None: + self.allowed_contexts: Optional[AppCommandContext] = None + else: + self.allowed_contexts = AppCommandContext._from_value(allowed_contexts) + + allowed_installs = data.get('integration_types') + if allowed_installs is None: + self.allowed_installs: Optional[AppInstallationType] = None + else: + self.allowed_installs = AppInstallationType._from_value(allowed_installs) + + self.nsfw: bool = data.get('nsfw', False) + self.name_localizations: Dict[Locale, str] = _to_locale_dict(data.get('name_localizations') or {}) + self.description_localizations: Dict[Locale, str] = _to_locale_dict(data.get('description_localizations') or {}) + + def to_dict(self) -> ApplicationCommandPayload: + return { + 'id': self.id, + 'type': self.type.value, + 'application_id': self.application_id, + 'name': self.name, + 'description': self.description, + 'name_localizations': {str(k): v for k, v in self.name_localizations.items()}, + 'description_localizations': {str(k): v for k, v in self.description_localizations.items()}, + 'contexts': self.allowed_contexts.to_array() if self.allowed_contexts is not None else None, + 'integration_types': self.allowed_installs.to_array() if self.allowed_installs is not None else None, + 'options': [opt.to_dict() for opt in self.options], + } # type: ignore # Type checker does not understand this literal. + + def __str__(self) -> str: + return self.name + + def __repr__(self) -> str: + return f'<{self.__class__.__name__} id={self.id!r} name={self.name!r} type={self.type!r}>' + + @property + def mention(self) -> str: + """:class:`str`: Returns a string that allows you to mention the given AppCommand.""" + return f'' + + @property + def guild(self) -> Optional[Guild]: + """Optional[:class:`~discord.Guild`]: Returns the guild this command is registered to + if it exists. + """ + return self._state._get_guild(self.guild_id) + + async def delete(self) -> None: + """|coro| + + Deletes the application command. + + Raises + ------- + NotFound + The application command was not found. + Forbidden + You do not have permission to delete this application command. + HTTPException + Deleting the application command failed. + MissingApplicationID + The client does not have an application ID. + """ + state = self._state + if not state.application_id: + raise MissingApplicationID + + if self.guild_id: + await state.http.delete_guild_command( + state.application_id, + self.guild_id, + self.id, + ) + else: + await state.http.delete_global_command( + state.application_id, + self.id, + ) + + async def edit( + self, + *, + name: str = MISSING, + description: str = MISSING, + default_member_permissions: Optional[Permissions] = MISSING, + dm_permission: bool = MISSING, + options: List[Union[Argument, AppCommandGroup]] = MISSING, + ) -> AppCommand: + """|coro| + + Edits the application command. + + Parameters + ----------- + name: :class:`str` + The new name for the application command. + description: :class:`str` + The new description for the application command. + default_member_permissions: Optional[:class:`~discord.Permissions`] + The new default permissions needed to use this application command. + Pass value of ``None`` to remove any permission requirements. + dm_permission: :class:`bool` + Indicates if the application command can be used in DMs. + options: List[Union[:class:`Argument`, :class:`AppCommandGroup`]] + List of new options for this application command. + + Raises + ------- + NotFound + The application command was not found. + Forbidden + You do not have permission to edit this application command. + HTTPException + Editing the application command failed. + MissingApplicationID + The client does not have an application ID. + + Returns + -------- + :class:`AppCommand` + The newly edited application command. + """ + state = self._state + if not state.application_id: + raise MissingApplicationID + + payload = {} + + if name is not MISSING: + payload['name'] = name + + if description is not MISSING: + payload['description'] = description + + if default_member_permissions is not MISSING: + if default_member_permissions is not None: + payload['default_member_permissions'] = default_member_permissions.value + else: + payload['default_member_permissions'] = None + + if self.guild_id is None and dm_permission is not MISSING: + payload['dm_permission'] = dm_permission + + if options is not MISSING: + payload['options'] = [option.to_dict() for option in options] + + if not payload: + return self + + if self.guild_id: + data = await state.http.edit_guild_command( + state.application_id, + self.guild_id, + self.id, + payload, + ) + else: + data = await state.http.edit_global_command( + state.application_id, + self.id, + payload, + ) + return AppCommand(data=data, state=state) + + async def fetch_permissions(self, guild: Snowflake) -> GuildAppCommandPermissions: + """|coro| + + Retrieves this command's permission in the guild. + + Parameters + ----------- + guild: :class:`~discord.abc.Snowflake` + The guild to retrieve the permissions from. + + Raises + ------- + Forbidden + You do not have permission to fetch the application command's permissions. + HTTPException + Fetching the application command's permissions failed. + MissingApplicationID + The client does not have an application ID. + NotFound + The application command's permissions could not be found. + This can also indicate that the permissions are synced with the guild + (i.e. they are unchanged from the default). + + Returns + -------- + :class:`GuildAppCommandPermissions` + An object representing the application command's permissions in the guild. + """ + state = self._state + if not state.application_id: + raise MissingApplicationID + + data = await state.http.get_application_command_permissions( + state.application_id, + guild.id, + self.id, + ) + return GuildAppCommandPermissions(data=data, state=state, command=self) + + +class Choice(Generic[ChoiceT]): + """Represents an application command argument choice. + + .. versionadded:: 2.0 + + .. container:: operations + + .. describe:: x == y + + Checks if two choices are equal. + + .. describe:: x != y + + Checks if two choices are not equal. + + .. describe:: hash(x) + + Returns the choice's hash. + + Parameters + ----------- + name: Union[:class:`str`, :class:`locale_str`] + The name of the choice. Used for display purposes. + Can only be up to 100 characters. + name_localizations: Dict[:class:`~discord.Locale`, :class:`str`] + The localised names of the choice. Used for display purposes. + value: Union[:class:`int`, :class:`str`, :class:`float`] + The value of the choice. If it's a string, it can only be + up to 100 characters long. + """ + + __slots__ = ('name', 'value', '_locale_name', 'name_localizations') + + def __init__(self, *, name: Union[str, locale_str], value: ChoiceT): + name, locale = (name.message, name) if isinstance(name, locale_str) else (name, None) + self.name: str = name + self._locale_name: Optional[locale_str] = locale + self.value: ChoiceT = value + self.name_localizations: Dict[Locale, str] = {} + + @classmethod + def from_dict(cls, data: ApplicationCommandOptionChoice) -> Choice[ChoiceT]: + self = cls.__new__(cls) + self.name = data['name'] + self.value = data['value'] # type: ignore # This seems to break every other pyright release + self.name_localizations = _to_locale_dict(data.get('name_localizations') or {}) + return self + + def __eq__(self, o: object) -> bool: + return isinstance(o, Choice) and self.name == o.name and self.value == o.value + + def __hash__(self) -> int: + return hash((self.name, self.value)) + + def __repr__(self) -> str: + return f'{self.__class__.__name__}(name={self.name!r}, value={self.value!r})' + + @property + def _option_type(self) -> AppCommandOptionType: + if isinstance(self.value, int): + return AppCommandOptionType.integer + elif isinstance(self.value, float): + return AppCommandOptionType.number + elif isinstance(self.value, str): + return AppCommandOptionType.string + else: + raise TypeError( + f'invalid Choice value type given, expected int, str, or float but received {self.value.__class__.__name__}' + ) + + async def get_translated_payload(self, translator: Translator) -> Dict[str, Any]: + base = self.to_dict() + name_localizations: Dict[str, str] = {} + context = TranslationContext(location=TranslationContextLocation.choice_name, data=self) + if self._locale_name: + for locale in Locale: + translation = await translator._checked_translate(self._locale_name, locale, context) + if translation is not None: + name_localizations[locale.value] = translation + + if name_localizations: + base['name_localizations'] = name_localizations + + return base + + async def get_translated_payload_for_locale(self, translator: Translator, locale: Locale) -> Dict[str, Any]: + base = self.to_dict() + if self._locale_name: + context = TranslationContext(location=TranslationContextLocation.choice_name, data=self) + translation = await translator._checked_translate(self._locale_name, locale, context) + if translation is not None: + base['name'] = translation + + return base + + def to_dict(self) -> Dict[str, Any]: + base = { + 'name': self.name, + 'value': self.value, + } + if self.name_localizations: + base['name_localizations'] = {str(k): v for k, v in self.name_localizations.items()} + return base + + +class AppCommandChannel(Hashable): + """Represents an application command partially resolved channel object. + + .. versionadded:: 2.0 + + .. container:: operations + + .. describe:: x == y + + Checks if two channels are equal. + + .. describe:: x != y + + Checks if two channels are not equal. + + .. describe:: hash(x) + + Returns the channel's hash. + + .. describe:: str(x) + + Returns the channel's name. + + Attributes + ----------- + id: :class:`int` + The ID of the channel. + type: :class:`~discord.ChannelType` + The type of channel. + name: :class:`str` + The name of the channel. + permissions: :class:`~discord.Permissions` + The resolved permissions of the user who invoked + the application command in that channel. + guild_id: :class:`int` + The guild ID this channel belongs to. + """ + + __slots__ = ( + 'id', + 'type', + 'name', + 'permissions', + 'guild_id', + '_state', + ) + + def __init__( + self, + *, + state: ConnectionState, + data: PartialChannel, + guild_id: int, + ): + self._state: ConnectionState = state + self.guild_id: int = guild_id + self.id: int = int(data['id']) + self.type: ChannelType = try_enum(ChannelType, data['type']) + self.name: str = data['name'] + self.permissions: Permissions = Permissions(int(data['permissions'])) + + def __str__(self) -> str: + return self.name + + def __repr__(self) -> str: + return f'<{self.__class__.__name__} id={self.id!r} name={self.name!r} type={self.type!r}>' + + @property + def guild(self) -> Optional[Guild]: + """Optional[:class:`~discord.Guild`]: The channel's guild, from cache, if found.""" + return self._state._get_guild(self.guild_id) + + def resolve(self) -> Optional[GuildChannel]: + """Resolves the application command channel to the appropriate channel + from cache if found. + + Returns + -------- + Optional[:class:`.abc.GuildChannel`] + The resolved guild channel or ``None`` if not found in cache. + """ + guild = self._state._get_guild(self.guild_id) + if guild is not None: + return guild.get_channel(self.id) + return None + + async def fetch(self) -> GuildChannel: + """|coro| + + Fetches the partial channel to a full :class:`.abc.GuildChannel`. + + Raises + -------- + NotFound + The channel was not found. + Forbidden + You do not have the permissions required to get a channel. + HTTPException + Retrieving the channel failed. + + Returns + -------- + :class:`.abc.GuildChannel` + The full channel. + """ + client = self._state._get_client() + return await client.fetch_channel(self.id) # type: ignore # This is explicit narrowing + + @property + def mention(self) -> str: + """:class:`str`: The string that allows you to mention the channel.""" + return f'<#{self.id}>' + + @property + def created_at(self) -> datetime: + """:class:`datetime.datetime`: An aware timestamp of when this channel was created in UTC.""" + return snowflake_time(self.id) + + +class AppCommandThread(Hashable): + """Represents an application command partially resolved thread object. + + .. versionadded:: 2.0 + + .. container:: operations + + .. describe:: x == y + + Checks if two thread are equal. + + .. describe:: x != y + + Checks if two thread are not equal. + + .. describe:: hash(x) + + Returns the thread's hash. + + .. describe:: str(x) + + Returns the thread's name. + + Attributes + ----------- + id: :class:`int` + The ID of the thread. + type: :class:`~discord.ChannelType` + The type of thread. + name: :class:`str` + The name of the thread. + parent_id: :class:`int` + The parent text channel ID this thread belongs to. + permissions: :class:`~discord.Permissions` + The resolved permissions of the user who invoked + the application command in that thread. + guild_id: :class:`int` + The guild ID this thread belongs to. + archived: :class:`bool` + Whether the thread is archived. + locked: :class:`bool` + Whether the thread is locked. + invitable: :class:`bool` + Whether non-moderators can add other non-moderators to this thread. + This is always ``True`` for public threads. + archiver_id: Optional[:class:`int`] + The user's ID that archived this thread. + auto_archive_duration: :class:`int` + The duration in minutes until the thread is automatically hidden from the channel list. + Usually a value of 60, 1440, 4320 and 10080. + archive_timestamp: :class:`datetime.datetime` + An aware timestamp of when the thread's archived status was last updated in UTC. + """ + + __slots__ = ( + 'id', + 'type', + 'name', + 'permissions', + 'guild_id', + 'parent_id', + 'archived', + 'archiver_id', + 'auto_archive_duration', + 'archive_timestamp', + 'locked', + 'invitable', + '_created_at', + '_state', + ) + + def __init__( + self, + *, + state: ConnectionState, + data: PartialThread, + guild_id: int, + ): + self._state: ConnectionState = state + self.guild_id: int = guild_id + self.id: int = int(data['id']) + self.parent_id: int = int(data['parent_id']) + self.type: ChannelType = try_enum(ChannelType, data['type']) + self.name: str = data['name'] + self.permissions: Permissions = Permissions(int(data['permissions'])) + self._unroll_metadata(data['thread_metadata']) + + def __str__(self) -> str: + return self.name + + def __repr__(self) -> str: + return f'<{self.__class__.__name__} id={self.id!r} name={self.name!r} archived={self.archived} type={self.type!r}>' + + @property + def guild(self) -> Optional[Guild]: + """Optional[:class:`~discord.Guild`]: The channel's guild, from cache, if found.""" + return self._state._get_guild(self.guild_id) + + def _unroll_metadata(self, data: ThreadMetadata) -> None: + self.archived: bool = data['archived'] + self.archiver_id: Optional[int] = _get_as_snowflake(data, 'archiver_id') + self.auto_archive_duration: ThreadArchiveDuration = data['auto_archive_duration'] + self.archive_timestamp: datetime = parse_time(data['archive_timestamp']) + self.locked: bool = data.get('locked', False) + self.invitable: bool = data.get('invitable', True) + self._created_at: Optional[datetime] = parse_time(data.get('create_timestamp')) + + @property + def parent(self) -> Optional[TextChannel]: + """Optional[:class:`~discord.TextChannel`]: The parent channel this thread belongs to.""" + return self.guild.get_channel(self.parent_id) # type: ignore + + @property + def mention(self) -> str: + """:class:`str`: The string that allows you to mention the thread.""" + return f'<#{self.id}>' + + @property + def created_at(self) -> Optional[datetime]: + """An aware timestamp of when the thread was created in UTC. + + .. note:: + + This timestamp only exists for threads created after 9 January 2022, otherwise returns ``None``. + """ + return self._created_at + + def resolve(self) -> Optional[Thread]: + """Resolves the application command channel to the appropriate channel + from cache if found. + + Returns + -------- + Optional[:class:`.abc.GuildChannel`] + The resolved guild channel or ``None`` if not found in cache. + """ + guild = self._state._get_guild(self.guild_id) + if guild is not None: + return guild.get_thread(self.id) + return None + + async def fetch(self) -> Thread: + """|coro| + + Fetches the partial channel to a full :class:`~discord.Thread`. + + Raises + -------- + NotFound + The thread was not found. + Forbidden + You do not have the permissions required to get a thread. + HTTPException + Retrieving the thread failed. + + Returns + -------- + :class:`~discord.Thread` + The full thread. + """ + client = self._state._get_client() + return await client.fetch_channel(self.id) # type: ignore # This is explicit narrowing + + +class Argument: + """Represents an application command argument. + + .. versionadded:: 2.0 + + Attributes + ------------ + type: :class:`~discord.AppCommandOptionType` + The type of argument. + name: :class:`str` + The name of the argument. + description: :class:`str` + The description of the argument. + name_localizations: Dict[:class:`~discord.Locale`, :class:`str`] + The localised names of the argument. Used for display purposes. + description_localizations: Dict[:class:`~discord.Locale`, :class:`str`] + The localised descriptions of the argument. Used for display purposes. + required: :class:`bool` + Whether the argument is required. + choices: List[:class:`Choice`] + A list of choices for the command to choose from for this argument. + parent: Union[:class:`AppCommand`, :class:`AppCommandGroup`] + The parent application command that has this argument. + channel_types: List[:class:`~discord.ChannelType`] + The channel types that are allowed for this parameter. + min_value: Optional[Union[:class:`int`, :class:`float`]] + The minimum supported value for this parameter. + max_value: Optional[Union[:class:`int`, :class:`float`]] + The maximum supported value for this parameter. + min_length: Optional[:class:`int`] + The minimum allowed length for this parameter. + max_length: Optional[:class:`int`] + The maximum allowed length for this parameter. + autocomplete: :class:`bool` + Whether the argument has autocomplete. + """ + + __slots__ = ( + 'type', + 'name', + 'description', + 'name_localizations', + 'description_localizations', + 'required', + 'choices', + 'channel_types', + 'min_value', + 'max_value', + 'min_length', + 'max_length', + 'autocomplete', + 'parent', + '_state', + ) + + def __init__( + self, *, parent: ApplicationCommandParent, data: ApplicationCommandOption, state: Optional[ConnectionState] = None + ) -> None: + self._state: Optional[ConnectionState] = state + self.parent: ApplicationCommandParent = parent + self._from_data(data) + + def __repr__(self) -> str: + return f'<{self.__class__.__name__} name={self.name!r} type={self.type!r} required={self.required}>' + + def _from_data(self, data: ApplicationCommandOption) -> None: + self.type: AppCommandOptionType = try_enum(AppCommandOptionType, data['type']) + self.name: str = data['name'] + self.description: str = data['description'] + self.required: bool = data.get('required', False) + self.min_value: Optional[Union[int, float]] = data.get('min_value') + self.max_value: Optional[Union[int, float]] = data.get('max_value') + self.min_length: Optional[int] = data.get('min_length') + self.max_length: Optional[int] = data.get('max_length') + self.autocomplete: bool = data.get('autocomplete', False) + self.channel_types: List[ChannelType] = [try_enum(ChannelType, d) for d in data.get('channel_types', [])] + self.choices: List[Choice[Union[int, float, str]]] = [Choice.from_dict(d) for d in data.get('choices', [])] + self.name_localizations: Dict[Locale, str] = _to_locale_dict(data.get('name_localizations') or {}) + self.description_localizations: Dict[Locale, str] = _to_locale_dict(data.get('description_localizations') or {}) + + def to_dict(self) -> ApplicationCommandOption: + return { + 'name': self.name, + 'type': self.type.value, + 'description': self.description, + 'required': self.required, + 'choices': [choice.to_dict() for choice in self.choices], + 'channel_types': [channel_type.value for channel_type in self.channel_types], + 'min_value': self.min_value, + 'max_value': self.max_value, + 'min_length': self.min_length, + 'max_length': self.max_length, + 'autocomplete': self.autocomplete, + 'options': [], + 'name_localizations': {str(k): v for k, v in self.name_localizations.items()}, + 'description_localizations': {str(k): v for k, v in self.description_localizations.items()}, + } # type: ignore # Type checker does not understand this literal. + + +class AppCommandGroup: + """Represents an application command subcommand. + + .. versionadded:: 2.0 + + Attributes + ------------ + type: :class:`~discord.AppCommandOptionType` + The type of subcommand. + name: :class:`str` + The name of the subcommand. + description: :class:`str` + The description of the subcommand. + name_localizations: Dict[:class:`~discord.Locale`, :class:`str`] + The localised names of the subcommand. Used for display purposes. + description_localizations: Dict[:class:`~discord.Locale`, :class:`str`] + The localised descriptions of the subcommand. Used for display purposes. + options: List[Union[:class:`Argument`, :class:`AppCommandGroup`]] + A list of options. + parent: Union[:class:`AppCommand`, :class:`AppCommandGroup`] + The parent application command. + """ + + __slots__ = ( + 'type', + 'name', + 'description', + 'name_localizations', + 'description_localizations', + 'options', + 'parent', + '_state', + ) + + def __init__( + self, *, parent: ApplicationCommandParent, data: ApplicationCommandOption, state: Optional[ConnectionState] = None + ) -> None: + self.parent: ApplicationCommandParent = parent + self._state: Optional[ConnectionState] = state + self._from_data(data) + + def __repr__(self) -> str: + return f'<{self.__class__.__name__} name={self.name!r} type={self.type!r}>' + + @property + def qualified_name(self) -> str: + """:class:`str`: Returns the fully qualified command name. + + The qualified name includes the parent name as well. For example, + in a command like ``/foo bar`` the qualified name is ``foo bar``. + """ + # A B C + # ^ self + # ^ parent + # ^ grandparent + names = [self.name, self.parent.name] + if isinstance(self.parent, AppCommandGroup): + names.append(self.parent.parent.name) + + return ' '.join(reversed(names)) + + @property + def mention(self) -> str: + """:class:`str`: Returns a string that allows you to mention the given AppCommandGroup.""" + if isinstance(self.parent, AppCommand): + base_command = self.parent + else: + base_command = self.parent.parent + return f'' # type: ignore + + def _from_data(self, data: ApplicationCommandOption) -> None: + self.type: AppCommandOptionType = try_enum(AppCommandOptionType, data['type']) + self.name: str = data['name'] + self.description: str = data['description'] + self.options: List[Union[Argument, AppCommandGroup]] = [ + app_command_option_factory(data=d, parent=self, state=self._state) for d in data.get('options', []) + ] + self.name_localizations: Dict[Locale, str] = _to_locale_dict(data.get('name_localizations') or {}) + self.description_localizations: Dict[Locale, str] = _to_locale_dict(data.get('description_localizations') or {}) + + def to_dict(self) -> 'ApplicationCommandOption': + return { + 'name': self.name, + 'type': self.type.value, + 'description': self.description, + 'options': [arg.to_dict() for arg in self.options], + 'name_localizations': {str(k): v for k, v in self.name_localizations.items()}, + 'description_localizations': {str(k): v for k, v in self.description_localizations.items()}, + } # type: ignore # Type checker does not understand this literal. + + +class AppCommandPermissions: + """Represents the permissions for an application command. + + .. versionadded:: 2.0 + + Attributes + ----------- + guild: :class:`~discord.Guild` + The guild associated with this permission. + id: :class:`int` + The ID of the permission target, such as a role, channel, or guild. + The special ``guild_id - 1`` sentinel is used to represent "all channels". + target: Any + The role, user, or channel associated with this permission. This could also be the :class:`AllChannels` sentinel type. + Falls back to :class:`~discord.Object` if the target could not be found in the cache. + type: :class:`.AppCommandPermissionType` + The type of permission. + permission: :class:`bool` + The permission value. ``True`` for allow, ``False`` for deny. + """ + + __slots__ = ('id', 'type', 'permission', 'target', 'guild', '_state') + + def __init__(self, *, data: ApplicationCommandPermissions, guild: Guild, state: ConnectionState) -> None: + self._state: ConnectionState = state + self.guild: Guild = guild + + self.id: int = int(data['id']) + self.type: AppCommandPermissionType = try_enum(AppCommandPermissionType, data['type']) + self.permission: bool = data['permission'] + + _object = None + _type = MISSING + + if self.type is AppCommandPermissionType.user: + _object = guild.get_member(self.id) or self._state.get_user(self.id) + _type = Member + elif self.type is AppCommandPermissionType.channel: + if self.id == (guild.id - 1): + _object = AllChannels(guild) + else: + _object = guild.get_channel(self.id) + elif self.type is AppCommandPermissionType.role: + _object = guild.get_role(self.id) + _type = Role + + if _object is None: + _object = Object(id=self.id, type=_type) + + self.target: Union[Object, User, Member, Role, AllChannels, GuildChannel] = _object + + def to_dict(self) -> ApplicationCommandPermissions: + return { + 'id': self.target.id, + 'type': self.type.value, + 'permission': self.permission, + } + + +class GuildAppCommandPermissions: + """Represents the permissions for an application command in a guild. + + .. versionadded:: 2.0 + + Attributes + ----------- + application_id: :class:`int` + The application ID. + command: :class:`.AppCommand` + The application command associated with the permissions. + id: :class:`int` + ID of the command or the application ID. + When this is the application ID instead of a command ID, + the permissions apply to all commands that do not contain explicit overwrites. + guild_id: :class:`int` + The guild ID associated with the permissions. + permissions: List[:class:`AppCommandPermissions`] + The permissions, this is a max of 100. + """ + + __slots__ = ('id', 'application_id', 'command', 'guild_id', 'permissions', '_state') + + def __init__(self, *, data: GuildApplicationCommandPermissions, state: ConnectionState, command: AppCommand) -> None: + self._state: ConnectionState = state + self.command: AppCommand = command + + self.id: int = int(data['id']) + self.application_id: int = int(data['application_id']) + self.guild_id: int = int(data['guild_id']) + guild = self.guild + self.permissions: List[AppCommandPermissions] = [ + AppCommandPermissions(data=value, guild=guild, state=self._state) for value in data['permissions'] + ] + + def to_dict(self) -> Dict[str, Any]: + return {'permissions': [p.to_dict() for p in self.permissions]} + + @property + def guild(self) -> Guild: + """:class:`~discord.Guild`: The guild associated with the permissions.""" + return self._state._get_or_create_unavailable_guild(self.guild_id) + + +def app_command_option_factory( + parent: ApplicationCommandParent, data: ApplicationCommandOption, *, state: Optional[ConnectionState] = None +) -> Union[Argument, AppCommandGroup]: + if is_app_command_argument_type(data['type']): + return Argument(parent=parent, data=data, state=state) + else: + return AppCommandGroup(parent=parent, data=data, state=state) diff --git a/venv/lib/python3.12/site-packages/discord/app_commands/namespace.py b/venv/lib/python3.12/site-packages/discord/app_commands/namespace.py new file mode 100644 index 00000000..3fa81712 --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/app_commands/namespace.py @@ -0,0 +1,263 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, Any, Dict, Iterable, Iterator, List, NamedTuple, Tuple +from ..member import Member +from ..object import Object +from ..role import Role +from ..message import Message, Attachment +from ..channel import PartialMessageable +from ..enums import AppCommandOptionType +from .models import AppCommandChannel, AppCommandThread + +if TYPE_CHECKING: + from ..interactions import Interaction + from ..types.interactions import ResolvedData, ApplicationCommandInteractionDataOption + +__all__ = ('Namespace',) + + +class ResolveKey(NamedTuple): + id: str + # CommandOptionType does not use 0 or negative numbers so those can be safe for library + # internal use, if necessary. Likewise, only 6, 7, 8, and 11 are actually in use. + type: int + + @classmethod + def any_with(cls, id: str) -> ResolveKey: + return ResolveKey(id=id, type=-1) + + def __eq__(self, o: object) -> bool: + if not isinstance(o, ResolveKey): + return NotImplemented + if self.type == -1 or o.type == -1: + return self.id == o.id + return (self.id, self.type) == (o.id, o.type) + + def __hash__(self) -> int: + # Most of the time an ID lookup is all that is necessary + # In case of collision then we look up both the ID and the type. + return hash(self.id) + + +class Namespace: + """An object that holds the parameters being passed to a command in a mostly raw state. + + This class is deliberately simple and just holds the option name and resolved value as a simple + key-pair mapping. These attributes can be accessed using dot notation. For example, an option + with the name of ``example`` can be accessed using ``ns.example``. If an attribute is not found, + then ``None`` is returned rather than an attribute error. + + .. warning:: + + The key names come from the raw Discord data, which means that if a parameter was renamed then the + renamed key is used instead of the function parameter name. + + .. versionadded:: 2.0 + + .. container:: operations + + .. describe:: x == y + + Checks if two namespaces are equal by checking if all attributes are equal. + .. describe:: x != y + + Checks if two namespaces are not equal. + .. describe:: x[key] + + Returns an attribute if it is found, otherwise raises + a :exc:`KeyError`. + .. describe:: key in x + + Checks if the attribute is in the namespace. + .. describe:: iter(x) + + Returns an iterator of ``(name, value)`` pairs. This allows it + to be, for example, constructed as a dict or a list of pairs. + + This namespace object converts resolved objects into their appropriate form depending on their + type. Consult the table below for conversion information. + + +-------------------------------------------+-------------------------------------------------------------------------------+ + | Option Type | Resolved Type | + +===========================================+===============================================================================+ + | :attr:`.AppCommandOptionType.string` | :class:`str` | + +-------------------------------------------+-------------------------------------------------------------------------------+ + | :attr:`.AppCommandOptionType.integer` | :class:`int` | + +-------------------------------------------+-------------------------------------------------------------------------------+ + | :attr:`.AppCommandOptionType.boolean` | :class:`bool` | + +-------------------------------------------+-------------------------------------------------------------------------------+ + | :attr:`.AppCommandOptionType.number` | :class:`float` | + +-------------------------------------------+-------------------------------------------------------------------------------+ + | :attr:`.AppCommandOptionType.user` | :class:`~discord.User` or :class:`~discord.Member` | + +-------------------------------------------+-------------------------------------------------------------------------------+ + | :attr:`.AppCommandOptionType.channel` | :class:`.AppCommandChannel` or :class:`.AppCommandThread` | + +-------------------------------------------+-------------------------------------------------------------------------------+ + | :attr:`.AppCommandOptionType.role` | :class:`~discord.Role` | + +-------------------------------------------+-------------------------------------------------------------------------------+ + | :attr:`.AppCommandOptionType.mentionable` | :class:`~discord.User` or :class:`~discord.Member`, or :class:`~discord.Role` | + +-------------------------------------------+-------------------------------------------------------------------------------+ + | :attr:`.AppCommandOptionType.attachment` | :class:`~discord.Attachment` | + +-------------------------------------------+-------------------------------------------------------------------------------+ + + .. note:: + + In autocomplete interactions, the namespace might not be validated or filled in. Discord does not + send the resolved data as well, so this means that certain fields end up just as IDs rather than + the resolved data. In these cases, a :class:`discord.Object` is returned instead. + + This is a Discord limitation. + """ + + def __init__( + self, + interaction: Interaction, + resolved: ResolvedData, + options: List[ApplicationCommandInteractionDataOption], + ): + completed = self._get_resolved_items(interaction, resolved) + for option in options: + opt_type = option['type'] + name = option['name'] + focused = option.get('focused', False) + if opt_type in (3, 4, 5): # string, integer, boolean + value = option['value'] # type: ignore # Key is there + self.__dict__[name] = value + elif opt_type == 10: # number + value = option['value'] # type: ignore # Key is there + # This condition is written this way because 0 can be a valid float + if value is None or value == '': + self.__dict__[name] = float('nan') + else: + if not focused: + self.__dict__[name] = float(value) + else: + # Autocomplete focused values tend to be garbage in + self.__dict__[name] = value + elif opt_type in (6, 7, 8, 9, 11): + # Remaining ones should be snowflake based ones with resolved data + snowflake: str = option['value'] # type: ignore # Key is there + if opt_type == 9: # Mentionable + # Mentionable is User | Role, these do not cause any conflict + key = ResolveKey.any_with(snowflake) + else: + # The remaining keys can conflict, for example, a role and a channel + # could end up with the same ID in very old guilds since they used to default + # to sharing the guild ID. Old general channels no longer exist, but some old + # servers will still have them so this needs to be handled. + key = ResolveKey(id=snowflake, type=opt_type) + + value = completed.get(key) or Object(id=int(snowflake)) + self.__dict__[name] = value + + @classmethod + def _get_resolved_items(cls, interaction: Interaction, resolved: ResolvedData) -> Dict[ResolveKey, Any]: + completed: Dict[ResolveKey, Any] = {} + state = interaction._state + members = resolved.get('members', {}) + guild_id = interaction.guild_id + guild = interaction.guild + type = AppCommandOptionType.user.value + for (user_id, user_data) in resolved.get('users', {}).items(): + try: + member_data = members[user_id] + except KeyError: + completed[ResolveKey(id=user_id, type=type)] = state.create_user(user_data) + else: + member_data['user'] = user_data + # Guild ID can't be None in this case. + # There's a type mismatch here that I don't actually care about + member = Member(state=state, guild=guild, data=member_data) # type: ignore + completed[ResolveKey(id=user_id, type=type)] = member + + type = AppCommandOptionType.role.value + completed.update( + { + # The guild ID can't be None in this case. + ResolveKey(id=role_id, type=type): Role(guild=guild, state=state, data=role_data) # type: ignore + for role_id, role_data in resolved.get('roles', {}).items() + } + ) + + type = AppCommandOptionType.channel.value + for (channel_id, channel_data) in resolved.get('channels', {}).items(): + key = ResolveKey(id=channel_id, type=type) + if channel_data['type'] in (10, 11, 12): + # The guild ID can't be none in this case + completed[key] = AppCommandThread(state=state, data=channel_data, guild_id=guild_id) # type: ignore + else: + # The guild ID can't be none in this case + completed[key] = AppCommandChannel(state=state, data=channel_data, guild_id=guild_id) # type: ignore + + type = AppCommandOptionType.attachment.value + completed.update( + { + ResolveKey(id=attachment_id, type=type): Attachment(data=attachment_data, state=state) + for attachment_id, attachment_data in resolved.get('attachments', {}).items() + } + ) + + for (message_id, message_data) in resolved.get('messages', {}).items(): + channel_id = int(message_data['channel_id']) + if guild is None: + channel = PartialMessageable(state=state, guild_id=guild_id, id=channel_id) + else: + channel = guild.get_channel_or_thread(channel_id) or PartialMessageable( + state=state, guild_id=guild_id, id=channel_id + ) + + # Type checker doesn't understand this due to failure to narrow + message = Message(state=state, channel=channel, data=message_data) # type: ignore + message.guild = guild + key = ResolveKey(id=message_id, type=-1) + completed[key] = message + + return completed + + def __repr__(self) -> str: + items = (f'{k}={v!r}' for k, v in self.__dict__.items()) + return '<{} {}>'.format(self.__class__.__name__, ' '.join(items)) + + def __eq__(self, other: object) -> bool: + if isinstance(self, Namespace) and isinstance(other, Namespace): + return self.__dict__ == other.__dict__ + return NotImplemented + + def __getitem__(self, key: str) -> Any: + return self.__dict__[key] + + def __contains__(self, key: str) -> Any: + return key in self.__dict__ + + def __getattr__(self, attr: str) -> Any: + return None + + def __iter__(self) -> Iterator[Tuple[str, Any]]: + yield from self.__dict__.items() + + def _update_with_defaults(self, defaults: Iterable[Tuple[str, Any]]) -> None: + for key, value in defaults: + self.__dict__.setdefault(key, value) diff --git a/venv/lib/python3.12/site-packages/discord/app_commands/transformers.py b/venv/lib/python3.12/site-packages/discord/app_commands/transformers.py new file mode 100644 index 00000000..c18485d8 --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/app_commands/transformers.py @@ -0,0 +1,878 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from __future__ import annotations +import inspect + +from dataclasses import dataclass +from enum import Enum +from typing import ( + TYPE_CHECKING, + Any, + Callable, + ClassVar, + Coroutine, + Dict, + Generic, + List, + Literal, + Optional, + Set, + Tuple, + Type, + TypeVar, + Union, +) + +from .errors import AppCommandError, TransformerError +from .models import AppCommandChannel, AppCommandThread, Choice +from .translator import TranslationContextLocation, TranslationContext, Translator, locale_str +from ..channel import StageChannel, VoiceChannel, TextChannel, CategoryChannel, ForumChannel +from ..abc import GuildChannel +from ..threads import Thread +from ..enums import Enum as InternalEnum, AppCommandOptionType, ChannelType, Locale +from ..utils import MISSING, maybe_coroutine +from ..user import User +from ..role import Role +from ..member import Member +from ..message import Attachment +from .._types import ClientT + +__all__ = ( + 'Transformer', + 'Transform', + 'Range', +) + +T = TypeVar('T') +FuncT = TypeVar('FuncT', bound=Callable[..., Any]) +ChoiceT = TypeVar('ChoiceT', str, int, float, Union[str, int, float]) +NoneType = type(None) + +if TYPE_CHECKING: + from ..interactions import Interaction + from .commands import Parameter + + +@dataclass +class CommandParameter: + # The name of the parameter is *always* the parameter name in the code + # Therefore, it can't be Union[str, locale_str] + name: str = MISSING + description: Union[str, locale_str] = MISSING + required: bool = MISSING + default: Any = MISSING + choices: List[Choice[Union[str, int, float]]] = MISSING + type: AppCommandOptionType = MISSING + channel_types: List[ChannelType] = MISSING + min_value: Optional[Union[int, float]] = None + max_value: Optional[Union[int, float]] = None + autocomplete: Optional[Callable[..., Coroutine[Any, Any, Any]]] = None + _rename: Union[str, locale_str] = MISSING + _annotation: Any = MISSING + + async def get_translated_payload(self, translator: Translator, data: Parameter) -> Dict[str, Any]: + base = self.to_dict() + + rename = self._rename + description = self.description + needs_name_translations = isinstance(rename, locale_str) + needs_description_translations = isinstance(description, locale_str) + name_localizations: Dict[str, str] = {} + description_localizations: Dict[str, str] = {} + + # Prevent creating these objects in a heavy loop + name_context = TranslationContext(location=TranslationContextLocation.parameter_name, data=data) + description_context = TranslationContext(location=TranslationContextLocation.parameter_description, data=data) + for locale in Locale: + if needs_name_translations: + translation = await translator._checked_translate(rename, locale, name_context) + if translation is not None: + name_localizations[locale.value] = translation + + if needs_description_translations: + translation = await translator._checked_translate(description, locale, description_context) + if translation is not None: + description_localizations[locale.value] = translation + + if self.choices: + base['choices'] = [await choice.get_translated_payload(translator) for choice in self.choices] + + if name_localizations: + base['name_localizations'] = name_localizations + + if description_localizations: + base['description_localizations'] = description_localizations + + return base + + def to_dict(self) -> Dict[str, Any]: + base = { + 'type': self.type.value, + 'name': self.display_name, + 'description': str(self.description), + 'required': self.required, + } + + if self.choices: + base['choices'] = [choice.to_dict() for choice in self.choices] + if self.channel_types: + base['channel_types'] = [t.value for t in self.channel_types] + if self.autocomplete: + base['autocomplete'] = True + + min_key, max_key = ( + ('min_value', 'max_value') if self.type is not AppCommandOptionType.string else ('min_length', 'max_length') + ) + if self.min_value is not None: + base[min_key] = self.min_value + if self.max_value is not None: + base[max_key] = self.max_value + + return base + + def _convert_to_locale_strings(self) -> None: + if self._rename is MISSING: + self._rename = locale_str(self.name) + elif isinstance(self._rename, str): + self._rename = locale_str(self._rename) + + if isinstance(self.description, str): + self.description = locale_str(self.description) + + if self.choices: + for choice in self.choices: + if choice._locale_name is None: + choice._locale_name = locale_str(choice.name) + + def is_choice_annotation(self) -> bool: + return getattr(self._annotation, '__discord_app_commands_is_choice__', False) + + async def transform(self, interaction: Interaction, value: Any, /) -> Any: + if hasattr(self._annotation, '__discord_app_commands_transformer__'): + # This one needs special handling for type safety reasons + if self._annotation.__discord_app_commands_is_choice__: + choice = next((c for c in self.choices if c.value == value), None) + if choice is None: + raise TransformerError(value, self.type, self._annotation) + return choice + + try: + return await maybe_coroutine(self._annotation.transform, interaction, value) + except AppCommandError: + raise + except Exception as e: + raise TransformerError(value, self.type, self._annotation) from e + + return value + + @property + def display_name(self) -> str: + """:class:`str`: The name of the parameter as it should be displayed to the user.""" + return self.name if self._rename is MISSING else str(self._rename) + + +class Transformer(Generic[ClientT]): + """The base class that allows a type annotation in an application command parameter + to map into a :class:`~discord.AppCommandOptionType` and transform the raw value into one + from this type. + + This class is customisable through the overriding of methods and properties in the class + and by using it as the second type parameter of the :class:`~discord.app_commands.Transform` + class. For example, to convert a string into a custom pair type: + + .. code-block:: python3 + + class Point(typing.NamedTuple): + x: int + y: int + + class PointTransformer(app_commands.Transformer): + async def transform(self, interaction: discord.Interaction, value: str) -> Point: + (x, _, y) = value.partition(',') + return Point(x=int(x.strip()), y=int(y.strip())) + + @app_commands.command() + async def graph( + interaction: discord.Interaction, + point: app_commands.Transform[Point, PointTransformer], + ): + await interaction.response.send_message(str(point)) + + If a class is passed instead of an instance to the second type parameter, then it is + constructed with no arguments passed to the ``__init__`` method. + + .. versionadded:: 2.0 + """ + + __discord_app_commands_transformer__: ClassVar[bool] = True + __discord_app_commands_is_choice__: ClassVar[bool] = False + + # This is needed to pass typing's type checks. + # e.g. Optional[MyTransformer] + def __call__(self) -> None: + pass + + def __or__(self, rhs: Any) -> Any: + return Union[self, rhs] + + @property + def type(self) -> AppCommandOptionType: + """:class:`~discord.AppCommandOptionType`: The option type associated with this transformer. + + This must be a :obj:`property`. + + Defaults to :attr:`~discord.AppCommandOptionType.string`. + """ + return AppCommandOptionType.string + + @property + def channel_types(self) -> List[ChannelType]: + """List[:class:`~discord.ChannelType`]: A list of channel types that are allowed to this parameter. + + Only valid if the :meth:`type` returns :attr:`~discord.AppCommandOptionType.channel`. + + This must be a :obj:`property`. + + Defaults to an empty list. + """ + return [] + + @property + def min_value(self) -> Optional[Union[int, float]]: + """Optional[:class:`int`]: The minimum supported value for this parameter. + + Only valid if the :meth:`type` returns :attr:`~discord.AppCommandOptionType.number` + :attr:`~discord.AppCommandOptionType.integer`, or :attr:`~discord.AppCommandOptionType.string`. + + This must be a :obj:`property`. + + Defaults to ``None``. + """ + return None + + @property + def max_value(self) -> Optional[Union[int, float]]: + """Optional[:class:`int`]: The maximum supported value for this parameter. + + Only valid if the :meth:`type` returns :attr:`~discord.AppCommandOptionType.number` + :attr:`~discord.AppCommandOptionType.integer`, or :attr:`~discord.AppCommandOptionType.string`. + + This must be a :obj:`property`. + + Defaults to ``None``. + """ + return None + + @property + def choices(self) -> Optional[List[Choice[Union[int, float, str]]]]: + """Optional[List[:class:`~discord.app_commands.Choice`]]: A list of up to 25 choices that are allowed to this parameter. + + Only valid if the :meth:`type` returns :attr:`~discord.AppCommandOptionType.number` + :attr:`~discord.AppCommandOptionType.integer`, or :attr:`~discord.AppCommandOptionType.string`. + + This must be a :obj:`property`. + + Defaults to ``None``. + """ + return None + + @property + def _error_display_name(self) -> str: + name = self.__class__.__name__ + if name.endswith('Transformer'): + return name[:-11] + else: + return name + + async def transform(self, interaction: Interaction[ClientT], value: Any, /) -> Any: + """|maybecoro| + + Transforms the converted option value into another value. + + The value passed into this transform function is the same as the + one in the :class:`conversion table `. + + Parameters + ----------- + interaction: :class:`~discord.Interaction` + The interaction being handled. + value: Any + The value of the given argument after being resolved. + See the :class:`conversion table ` + for how certain option types correspond to certain values. + """ + raise NotImplementedError('Derived classes need to implement this.') + + async def autocomplete( + self, interaction: Interaction[ClientT], value: Union[int, float, str], / + ) -> List[Choice[Union[int, float, str]]]: + """|coro| + + An autocomplete prompt handler to be automatically used by options using this transformer. + + .. note:: + + Autocomplete is only supported for options with a :meth:`~discord.app_commands.Transformer.type` + of :attr:`~discord.AppCommandOptionType.string`, :attr:`~discord.AppCommandOptionType.integer`, + or :attr:`~discord.AppCommandOptionType.number`. + + Parameters + ----------- + interaction: :class:`~discord.Interaction` + The autocomplete interaction being handled. + value: Union[:class:`str`, :class:`int`, :class:`float`] + The current value entered by the user. + + Returns + -------- + List[:class:`~discord.app_commands.Choice`] + A list of choices to be displayed to the user, a maximum of 25. + + """ + raise NotImplementedError('Derived classes can implement this.') + + +class IdentityTransformer(Transformer[ClientT]): + def __init__(self, type: AppCommandOptionType) -> None: + self._type = type + + @property + def type(self) -> AppCommandOptionType: + return self._type + + async def transform(self, interaction: Interaction[ClientT], value: Any, /) -> Any: + return value + + +class RangeTransformer(IdentityTransformer): + def __init__( + self, + opt_type: AppCommandOptionType, + *, + min: Optional[Union[int, float]] = None, + max: Optional[Union[int, float]] = None, + ) -> None: + if min and max and min > max: + raise TypeError('minimum cannot be larger than maximum') + + self._min: Optional[Union[int, float]] = min + self._max: Optional[Union[int, float]] = max + super().__init__(opt_type) + + @property + def min_value(self) -> Optional[Union[int, float]]: + return self._min + + @property + def max_value(self) -> Optional[Union[int, float]]: + return self._max + + +class LiteralTransformer(IdentityTransformer): + def __init__(self, values: Tuple[Any, ...]) -> None: + first = type(values[0]) + if first is int: + opt_type = AppCommandOptionType.integer + elif first is float: + opt_type = AppCommandOptionType.number + elif first is str: + opt_type = AppCommandOptionType.string + else: + raise TypeError(f'expected int, str, or float values not {first!r}') + + self._choices = [Choice(name=str(v), value=v) for v in values] + super().__init__(opt_type) + + @property + def choices(self): + return self._choices + + +class ChoiceTransformer(IdentityTransformer): + __discord_app_commands_is_choice__: ClassVar[bool] = True + + def __init__(self, inner_type: Any) -> None: + if inner_type is int: + opt_type = AppCommandOptionType.integer + elif inner_type is float: + opt_type = AppCommandOptionType.number + elif inner_type is str: + opt_type = AppCommandOptionType.string + else: + raise TypeError(f'expected int, str, or float values not {inner_type!r}') + + super().__init__(opt_type) + + +class EnumValueTransformer(Transformer): + def __init__(self, enum: Any) -> None: + super().__init__() + + values = list(enum) + if len(values) < 2: + raise TypeError('enum.Enum requires at least two values.') + + first = type(values[0].value) + if first is int: + opt_type = AppCommandOptionType.integer + elif first is float: + opt_type = AppCommandOptionType.number + elif first is str: + opt_type = AppCommandOptionType.string + else: + raise TypeError(f'expected int, str, or float values not {first!r}') + + self._type: AppCommandOptionType = opt_type + self._enum: Any = enum + self._choices = [Choice(name=v.name, value=v.value) for v in values] + + @property + def _error_display_name(self) -> str: + return self._enum.__name__ + + @property + def type(self) -> AppCommandOptionType: + return self._type + + @property + def choices(self): + return self._choices + + async def transform(self, interaction: Interaction, value: Any, /) -> Any: + return self._enum(value) + + +class EnumNameTransformer(Transformer): + def __init__(self, enum: Any) -> None: + super().__init__() + + values = list(enum) + if len(values) < 2: + raise TypeError('enum.Enum requires at least two values.') + + self._enum: Any = enum + self._choices = [Choice(name=v.name, value=v.name) for v in values] + + @property + def _error_display_name(self) -> str: + return self._enum.__name__ + + @property + def type(self) -> AppCommandOptionType: + return AppCommandOptionType.string + + @property + def choices(self): + return self._choices + + async def transform(self, interaction: Interaction, value: Any, /) -> Any: + return self._enum[value] + + +class InlineTransformer(Transformer[ClientT]): + def __init__(self, annotation: Any) -> None: + super().__init__() + self.annotation: Any = annotation + + @property + def _error_display_name(self) -> str: + return self.annotation.__name__ + + @property + def type(self) -> AppCommandOptionType: + return AppCommandOptionType.string + + async def transform(self, interaction: Interaction[ClientT], value: Any, /) -> Any: + return await self.annotation.transform(interaction, value) + + +if TYPE_CHECKING: + from typing_extensions import Annotated as Transform + from typing_extensions import Annotated as Range +else: + + class Transform: + """A type annotation that can be applied to a parameter to customise the behaviour of + an option type by transforming with the given :class:`Transformer`. This requires + the usage of two generic parameters, the first one is the type you're converting to and the second + one is the type of the :class:`Transformer` actually doing the transformation. + + During type checking time this is equivalent to :obj:`typing.Annotated` so type checkers understand + the intent of the code. + + For example usage, check :class:`Transformer`. + + .. versionadded:: 2.0 + """ + + def __class_getitem__(cls, items) -> Transformer: + if not isinstance(items, tuple): + raise TypeError(f'expected tuple for arguments, received {items.__class__.__name__} instead') + + if len(items) != 2: + raise TypeError('Transform only accepts exactly two arguments') + + _, transformer = items + + if inspect.isclass(transformer): + if not issubclass(transformer, Transformer): + raise TypeError(f'second argument of Transform must be a Transformer class not {transformer!r}') + transformer = transformer() + elif not isinstance(transformer, Transformer): + raise TypeError(f'second argument of Transform must be a Transformer not {transformer.__class__.__name__}') + + return transformer + + class Range: + """A type annotation that can be applied to a parameter to require a numeric or string + type to fit within the range provided. + + During type checking time this is equivalent to :obj:`typing.Annotated` so type checkers understand + the intent of the code. + + Some example ranges: + + - ``Range[int, 10]`` means the minimum is 10 with no maximum. + - ``Range[int, None, 10]`` means the maximum is 10 with no minimum. + - ``Range[int, 1, 10]`` means the minimum is 1 and the maximum is 10. + - ``Range[float, 1.0, 5.0]`` means the minimum is 1.0 and the maximum is 5.0. + - ``Range[str, 1, 10]`` means the minimum length is 1 and the maximum length is 10. + + .. versionadded:: 2.0 + + Examples + ---------- + + .. code-block:: python3 + + @app_commands.command() + async def range(interaction: discord.Interaction, value: app_commands.Range[int, 10, 12]): + await interaction.response.send_message(f'Your value is {value}', ephemeral=True) + """ + + def __class_getitem__(cls, obj) -> RangeTransformer: + if not isinstance(obj, tuple): + raise TypeError(f'expected tuple for arguments, received {obj.__class__.__name__} instead') + + if len(obj) == 2: + obj = (*obj, None) + elif len(obj) != 3: + raise TypeError('Range accepts either two or three arguments with the first being the type of range.') + + obj_type, min, max = obj + + if min is None and max is None: + raise TypeError('Range must not be empty') + + if min is not None and max is not None: + # At this point max and min are both not none + if type(min) != type(max): + raise TypeError('Both min and max in Range must be the same type') + + if obj_type is int: + opt_type = AppCommandOptionType.integer + elif obj_type is float: + opt_type = AppCommandOptionType.number + elif obj_type is str: + opt_type = AppCommandOptionType.string + else: + raise TypeError(f'expected int, float, or str as range type, received {obj_type!r} instead') + + if obj_type in (str, int): + cast = int + else: + cast = float + + transformer = RangeTransformer( + opt_type, + min=cast(min) if min is not None else None, + max=cast(max) if max is not None else None, + ) + return transformer + + +class MemberTransformer(Transformer[ClientT]): + @property + def type(self) -> AppCommandOptionType: + return AppCommandOptionType.user + + async def transform(self, interaction: Interaction[ClientT], value: Any, /) -> Member: + if not isinstance(value, Member): + raise TransformerError(value, self.type, self) + return value + + +class BaseChannelTransformer(Transformer[ClientT]): + def __init__(self, *channel_types: Type[Any]) -> None: + super().__init__() + if len(channel_types) == 1: + display_name = channel_types[0].__name__ + types = CHANNEL_TO_TYPES[channel_types[0]] + else: + display_name = '{}, and {}'.format(', '.join(t.__name__ for t in channel_types[:-1]), channel_types[-1].__name__) + types = [] + + for t in channel_types: + try: + types.extend(CHANNEL_TO_TYPES[t]) + except KeyError: + raise TypeError('Union type of channels must be entirely made up of channels') from None + + self._types: Tuple[Type[Any], ...] = channel_types + self._channel_types: List[ChannelType] = types + self._display_name = display_name + + @property + def _error_display_name(self) -> str: + return self._display_name + + @property + def type(self) -> AppCommandOptionType: + return AppCommandOptionType.channel + + @property + def channel_types(self) -> List[ChannelType]: + return self._channel_types + + async def transform(self, interaction: Interaction[ClientT], value: Any, /): + resolved = value.resolve() + if resolved is None or not isinstance(resolved, self._types): + raise TransformerError(value, AppCommandOptionType.channel, self) + return resolved + + +class RawChannelTransformer(BaseChannelTransformer[ClientT]): + async def transform(self, interaction: Interaction[ClientT], value: Any, /): + if not isinstance(value, self._types): + raise TransformerError(value, AppCommandOptionType.channel, self) + return value + + +class UnionChannelTransformer(BaseChannelTransformer[ClientT]): + async def transform(self, interaction: Interaction[ClientT], value: Any, /): + if isinstance(value, self._types): + return value + + resolved = value.resolve() + if resolved is None or not isinstance(resolved, self._types): + raise TransformerError(value, AppCommandOptionType.channel, self) + return resolved + + +CHANNEL_TO_TYPES: Dict[Any, List[ChannelType]] = { + AppCommandChannel: [ + ChannelType.stage_voice, + ChannelType.voice, + ChannelType.text, + ChannelType.news, + ChannelType.category, + ChannelType.forum, + ], + GuildChannel: [ + ChannelType.stage_voice, + ChannelType.voice, + ChannelType.text, + ChannelType.news, + ChannelType.category, + ChannelType.forum, + ], + AppCommandThread: [ChannelType.news_thread, ChannelType.private_thread, ChannelType.public_thread], + Thread: [ChannelType.news_thread, ChannelType.private_thread, ChannelType.public_thread], + StageChannel: [ChannelType.stage_voice], + VoiceChannel: [ChannelType.voice], + TextChannel: [ChannelType.text, ChannelType.news], + CategoryChannel: [ChannelType.category], + ForumChannel: [ChannelType.forum], +} + +BUILT_IN_TRANSFORMERS: Dict[Any, Transformer] = { + str: IdentityTransformer(AppCommandOptionType.string), + int: IdentityTransformer(AppCommandOptionType.integer), + float: IdentityTransformer(AppCommandOptionType.number), + bool: IdentityTransformer(AppCommandOptionType.boolean), + User: IdentityTransformer(AppCommandOptionType.user), + Member: MemberTransformer(), + Role: IdentityTransformer(AppCommandOptionType.role), + AppCommandChannel: RawChannelTransformer(AppCommandChannel), + AppCommandThread: RawChannelTransformer(AppCommandThread), + GuildChannel: BaseChannelTransformer(GuildChannel), + Thread: BaseChannelTransformer(Thread), + StageChannel: BaseChannelTransformer(StageChannel), + VoiceChannel: BaseChannelTransformer(VoiceChannel), + TextChannel: BaseChannelTransformer(TextChannel), + CategoryChannel: BaseChannelTransformer(CategoryChannel), + ForumChannel: BaseChannelTransformer(ForumChannel), + Attachment: IdentityTransformer(AppCommandOptionType.attachment), +} + +ALLOWED_DEFAULTS: Dict[AppCommandOptionType, Tuple[Type[Any], ...]] = { + AppCommandOptionType.string: (str, NoneType), + AppCommandOptionType.integer: (int, NoneType), + AppCommandOptionType.boolean: (bool, NoneType), + AppCommandOptionType.number: (float, NoneType), +} + + +def get_supported_annotation( + annotation: Any, + *, + _none: type = NoneType, + _mapping: Dict[Any, Transformer] = BUILT_IN_TRANSFORMERS, +) -> Tuple[Any, Any, bool]: + """Returns an appropriate, yet supported, annotation along with an optional default value. + + The third boolean element of the tuple indicates if default values should be validated. + + This differs from the built in mapping by supporting a few more things. + Likewise, this returns a "transformed" annotation that is ready to use with CommandParameter.transform. + """ + + try: + return (_mapping[annotation], MISSING, True) + except (KeyError, TypeError): + pass + + if isinstance(annotation, Transformer): + return (annotation, MISSING, False) + + if inspect.isclass(annotation): + if issubclass(annotation, Transformer): + return (annotation(), MISSING, False) + if issubclass(annotation, (Enum, InternalEnum)): + if all(isinstance(v.value, (str, int, float)) for v in annotation): + return (EnumValueTransformer(annotation), MISSING, False) + else: + return (EnumNameTransformer(annotation), MISSING, False) + if annotation is Choice: + raise TypeError('Choice requires a type argument of int, str, or float') + + # Check if a transform @classmethod is given to the class + # These flatten into simple "inline" transformers with implicit strings + transform_classmethod = annotation.__dict__.get('transform', None) + if isinstance(transform_classmethod, classmethod): + params = inspect.signature(transform_classmethod.__func__).parameters + if len(params) != 3: + raise TypeError('Inline transformer with transform classmethod requires 3 parameters') + if not inspect.iscoroutinefunction(transform_classmethod.__func__): + raise TypeError('Inline transformer with transform classmethod must be a coroutine') + return (InlineTransformer(annotation), MISSING, False) + + # Check if there's an origin + origin = getattr(annotation, '__origin__', None) + if origin is Literal: + args = annotation.__args__ + return (LiteralTransformer(args), MISSING, True) + + if origin is Choice: + arg = annotation.__args__[0] + return (ChoiceTransformer(arg), MISSING, True) + + if origin is not Union: + # Only Union/Optional is supported right now so bail early + raise TypeError(f'unsupported type annotation {annotation!r}') + + default = MISSING + args = annotation.__args__ + if args[-1] is _none: + if len(args) == 2: + underlying = args[0] + inner, _, validate_default = get_supported_annotation(underlying) + if inner is None: + raise TypeError(f'unsupported inner optional type {underlying!r}') + return (inner, None, validate_default) + else: + args = args[:-1] + default = None + + # Check for channel union types + if any(arg in CHANNEL_TO_TYPES for arg in args): + # If any channel type is given, then *all* must be channel types + return (UnionChannelTransformer(*args), default, True) + + # The only valid transformations here are: + # [Member, User] => user + # [Member, User, Role] => mentionable + # [Member | User, Role] => mentionable + supported_types: Set[Any] = {Role, Member, User} + if not all(arg in supported_types for arg in args): + raise TypeError(f'unsupported types given inside {annotation!r}') + if args == (User, Member) or args == (Member, User): + return (IdentityTransformer(AppCommandOptionType.user), default, True) + + return (IdentityTransformer(AppCommandOptionType.mentionable), default, True) + + +def annotation_to_parameter(annotation: Any, parameter: inspect.Parameter) -> CommandParameter: + """Returns the appropriate :class:`CommandParameter` for the given annotation. + + The resulting ``_annotation`` attribute might not match the one given here and might + be transformed in order to be easier to call from the ``transform`` asynchronous function + of a command parameter. + """ + + (inner, default, validate_default) = get_supported_annotation(annotation) + type = inner.type + + if default is MISSING or default is None: + param_default = parameter.default + if param_default is not parameter.empty: + default = param_default + + # Verify validity of the default parameter + if default is not MISSING and validate_default: + valid_types: Tuple[Any, ...] = ALLOWED_DEFAULTS.get(type, (NoneType,)) + if not isinstance(default, valid_types): + raise TypeError(f'invalid default parameter type given ({default.__class__}), expected {valid_types}') + + result = CommandParameter( + type=type, + _annotation=inner, + default=default, + required=default is MISSING, + name=parameter.name, + ) + + choices = inner.choices + if choices is not None: + result.choices = choices + + # These methods should be duck typed + if type in (AppCommandOptionType.number, AppCommandOptionType.string, AppCommandOptionType.integer): + result.min_value = inner.min_value + result.max_value = inner.max_value + + if type is AppCommandOptionType.channel: + result.channel_types = inner.channel_types + + if parameter.kind in (parameter.POSITIONAL_ONLY, parameter.VAR_KEYWORD, parameter.VAR_POSITIONAL): + raise TypeError(f'unsupported parameter kind in callback: {parameter.kind!s}') + + # Check if the method is overridden + if inner.autocomplete.__func__ is not Transformer.autocomplete: + from .commands import validate_auto_complete_callback + + result.autocomplete = validate_auto_complete_callback(inner.autocomplete) + + return result diff --git a/venv/lib/python3.12/site-packages/discord/app_commands/translator.py b/venv/lib/python3.12/site-packages/discord/app_commands/translator.py new file mode 100644 index 00000000..4b6e01d4 --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/app_commands/translator.py @@ -0,0 +1,305 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from __future__ import annotations +from typing import TYPE_CHECKING, Any, Generic, Literal, Optional, TypeVar, Union, overload +from .errors import TranslationError +from ..enums import Enum, Locale + + +if TYPE_CHECKING: + from .commands import Command, ContextMenu, Group, Parameter + from .models import Choice + + +__all__ = ( + 'TranslationContextLocation', + 'TranslationContextTypes', + 'TranslationContext', + 'Translator', + 'locale_str', +) + + +class TranslationContextLocation(Enum): + command_name = 0 + command_description = 1 + group_name = 2 + group_description = 3 + parameter_name = 4 + parameter_description = 5 + choice_name = 6 + other = 7 + + +_L = TypeVar('_L', bound=TranslationContextLocation) +_D = TypeVar('_D') + + +class TranslationContext(Generic[_L, _D]): + """A class that provides context for the :class:`locale_str` being translated. + + This is useful to determine where exactly the string is located and aid in looking + up the actual translation. + + Attributes + ----------- + location: :class:`TranslationContextLocation` + The location where this string is located. + data: Any + The extraneous data that is being translated. + """ + + __slots__ = ('location', 'data') + + @overload + def __init__( + self, location: Literal[TranslationContextLocation.command_name], data: Union[Command[Any, ..., Any], ContextMenu] + ) -> None: + ... + + @overload + def __init__( + self, location: Literal[TranslationContextLocation.command_description], data: Command[Any, ..., Any] + ) -> None: + ... + + @overload + def __init__( + self, + location: Literal[TranslationContextLocation.group_name, TranslationContextLocation.group_description], + data: Group, + ) -> None: + ... + + @overload + def __init__( + self, + location: Literal[TranslationContextLocation.parameter_name, TranslationContextLocation.parameter_description], + data: Parameter, + ) -> None: + ... + + @overload + def __init__(self, location: Literal[TranslationContextLocation.choice_name], data: Choice[Any]) -> None: + ... + + @overload + def __init__(self, location: Literal[TranslationContextLocation.other], data: Any) -> None: + ... + + def __init__(self, location: _L, data: _D) -> None: # type: ignore # pyright doesn't like the overloads + self.location: _L = location + self.data: _D = data + + +# For type checking purposes, it makes sense to allow the user to leverage type narrowing +# So code like this works as expected: +# +# if context.type == TranslationContextLocation.command_name: +# reveal_type(context.data) # Revealed type is Command | ContextMenu +# +# This requires a union of types +CommandNameTranslationContext = TranslationContext[ + Literal[TranslationContextLocation.command_name], Union['Command[Any, ..., Any]', 'ContextMenu'] +] +CommandDescriptionTranslationContext = TranslationContext[ + Literal[TranslationContextLocation.command_description], 'Command[Any, ..., Any]' +] +GroupTranslationContext = TranslationContext[ + Literal[TranslationContextLocation.group_name, TranslationContextLocation.group_description], 'Group' +] +ParameterTranslationContext = TranslationContext[ + Literal[TranslationContextLocation.parameter_name, TranslationContextLocation.parameter_description], 'Parameter' +] +ChoiceTranslationContext = TranslationContext[Literal[TranslationContextLocation.choice_name], 'Choice[Any]'] +OtherTranslationContext = TranslationContext[Literal[TranslationContextLocation.other], Any] + +TranslationContextTypes = Union[ + CommandNameTranslationContext, + CommandDescriptionTranslationContext, + GroupTranslationContext, + ParameterTranslationContext, + ChoiceTranslationContext, + OtherTranslationContext, +] + + +class Translator: + """A class that handles translations for commands, parameters, and choices. + + Translations are done lazily in order to allow for async enabled translations as well + as supporting a wide array of translation systems such as :mod:`gettext` and + `Project Fluent `_. + + In order for a translator to be used, it must be set using the :meth:`CommandTree.set_translator` + method. The translation flow for a string is as follows: + + 1. Use :class:`locale_str` instead of :class:`str` in areas of a command you want to be translated. + - Currently, these are command names, command descriptions, parameter names, parameter descriptions, and choice names. + - This can also be used inside the :func:`~discord.app_commands.describe` decorator. + 2. Call :meth:`CommandTree.set_translator` to the translator instance that will handle the translations. + 3. Call :meth:`CommandTree.sync` + 4. The library will call :meth:`Translator.translate` on all the relevant strings being translated. + + .. versionadded:: 2.0 + """ + + async def load(self) -> None: + """|coro| + + An asynchronous setup function for loading the translation system. + + The default implementation does nothing. + + This is invoked when :meth:`CommandTree.set_translator` is called. + """ + pass + + async def unload(self) -> None: + """|coro| + + An asynchronous teardown function for unloading the translation system. + + The default implementation does nothing. + + This is invoked when :meth:`CommandTree.set_translator` is called + if a tree already has a translator or when :meth:`discord.Client.close` is called. + """ + pass + + async def _checked_translate( + self, string: locale_str, locale: Locale, context: TranslationContextTypes + ) -> Optional[str]: + try: + return await self.translate(string, locale, context) + except TranslationError: + raise + except Exception as e: + raise TranslationError(string=string, locale=locale, context=context) from e + + async def translate(self, string: locale_str, locale: Locale, context: TranslationContextTypes) -> Optional[str]: + """|coro| + + Translates the given string to the specified locale. + + If the string cannot be translated, ``None`` should be returned. + + The default implementation returns ``None``. + + If an exception is raised in this method, it should inherit from :exc:`TranslationError`. + If it doesn't, then when this is called the exception will be chained with it instead. + + Parameters + ------------ + string: :class:`locale_str` + The string being translated. + locale: :class:`~discord.Locale` + The locale being requested for translation. + context: :class:`TranslationContext` + The translation context where the string originated from. + For better type checking ergonomics, the ``TranslationContextTypes`` + type can be used instead to aid with type narrowing. It is functionally + equivalent to :class:`TranslationContext`. + """ + + return None + + +class locale_str: + """Marks a string as ready for translation. + + This is done lazily and is not actually translated until :meth:`CommandTree.sync` is called. + + The sync method then ultimately defers the responsibility of translating to the :class:`Translator` + instance used by the :class:`CommandTree`. For more information on the translation flow, see the + :class:`Translator` documentation. + + .. container:: operations + + .. describe:: str(x) + + Returns the message passed to the string. + + .. describe:: x == y + + Checks if the string is equal to another string. + + .. describe:: x != y + + Checks if the string is not equal to another string. + + .. describe:: hash(x) + + Returns the hash of the string. + + .. versionadded:: 2.0 + + Attributes + ------------ + message: :class:`str` + The message being translated. Once set, this cannot be changed. + + .. warning:: + + This must be the default "message" that you send to Discord. + Discord sends this message back to the library and the library + uses it to access the data in order to dispatch commands. + + For example, in a command name context, if the command + name is ``foo`` then the message *must* also be ``foo``. + For other translation systems that require a message ID such + as Fluent, consider using a keyword argument to pass it in. + extras: :class:`dict` + A dict of user provided extras to attach to the translated string. + This can be used to add more context, information, or any metadata necessary + to aid in actually translating the string. + + Since these are passed via keyword arguments, the keys are strings. + """ + + __slots__ = ('__message', 'extras') + + def __init__(self, message: str, /, **kwargs: Any) -> None: + self.__message: str = message + self.extras: dict[str, Any] = kwargs + + @property + def message(self) -> str: + return self.__message + + def __str__(self) -> str: + return self.__message + + def __repr__(self) -> str: + kwargs = ', '.join(f'{k}={v!r}' for k, v in self.extras.items()) + if kwargs: + return f'{self.__class__.__name__}({self.__message!r}, {kwargs})' + return f'{self.__class__.__name__}({self.__message!r})' + + def __eq__(self, obj: object) -> bool: + return isinstance(obj, locale_str) and self.message == obj.message + + def __hash__(self) -> int: + return hash(self.__message) diff --git a/venv/lib/python3.12/site-packages/discord/app_commands/tree.py b/venv/lib/python3.12/site-packages/discord/app_commands/tree.py new file mode 100644 index 00000000..3099071c --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/app_commands/tree.py @@ -0,0 +1,1317 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from __future__ import annotations +import logging +import inspect + +from typing import ( + Any, + TYPE_CHECKING, + Callable, + Coroutine, + Dict, + Generator, + Generic, + List, + Literal, + Optional, + Sequence, + Set, + Tuple, + Union, + overload, +) +from collections import Counter + + +from .namespace import Namespace, ResolveKey +from .models import AppCommand +from .commands import Command, ContextMenu, Group +from .errors import ( + AppCommandError, + CommandAlreadyRegistered, + CommandNotFound, + CommandSignatureMismatch, + CommandLimitReached, + CommandSyncFailure, + MissingApplicationID, +) +from .installs import AppCommandContext, AppInstallationType +from .translator import Translator, locale_str +from ..errors import ClientException, HTTPException +from ..enums import AppCommandType, InteractionType +from ..utils import MISSING, _get_as_snowflake, _is_submodule, _shorten +from .._types import ClientT + + +if TYPE_CHECKING: + from ..types.interactions import ApplicationCommandInteractionData, ApplicationCommandInteractionDataOption + from ..interactions import Interaction + from ..abc import Snowflake + from .commands import ContextMenuCallback, CommandCallback, P, T + + ErrorFunc = Callable[ + [Interaction[ClientT], AppCommandError], + Coroutine[Any, Any, Any], + ] + +__all__ = ('CommandTree',) + +_log = logging.getLogger(__name__) + + +def _retrieve_guild_ids( + command: Any, guild: Optional[Snowflake] = MISSING, guilds: Sequence[Snowflake] = MISSING +) -> Optional[Set[int]]: + if guild is not MISSING and guilds is not MISSING: + raise TypeError('cannot mix guild and guilds keyword arguments') + + # guilds=[] or guilds=[...] + if guild is MISSING: + # If no arguments are given then it should default to the ones + # given to the guilds(...) decorator or None for global. + if guilds is MISSING: + return getattr(command, '_guild_ids', None) + + # guilds=[] is the same as global + if len(guilds) == 0: + return None + + return {g.id for g in guilds} + + # At this point it should be... + # guild=None or guild=Object + if guild is None: + return None + return {guild.id} + + +class CommandTree(Generic[ClientT]): + """Represents a container that holds application command information. + + Parameters + ----------- + client: :class:`~discord.Client` + The client instance to get application command information from. + fallback_to_global: :class:`bool` + If a guild-specific command is not found when invoked, then try falling back into + a global command in the tree. For example, if the tree locally has a ``/ping`` command + under the global namespace but the guild has a guild-specific ``/ping``, instead of failing + to find the guild-specific ``/ping`` command it will fall back to the global ``/ping`` command. + This has the potential to raise more :exc:`~discord.app_commands.CommandSignatureMismatch` errors + than usual. Defaults to ``True``. + allowed_contexts: :class:`~discord.app_commands.AppCommandContext` + The default allowed contexts that applies to all commands in this tree. + Note that you can override this on a per command basis. + + .. versionadded:: 2.4 + allowed_installs: :class:`~discord.app_commands.AppInstallationType` + The default allowed install locations that apply to all commands in this tree. + Note that you can override this on a per command basis. + + .. versionadded:: 2.4 + """ + + def __init__( + self, + client: ClientT, + *, + fallback_to_global: bool = True, + allowed_contexts: AppCommandContext = MISSING, + allowed_installs: AppInstallationType = MISSING, + ): + self.client: ClientT = client + self._http = client.http + self._state = client._connection + + if self._state._command_tree is not None: + raise ClientException('This client already has an associated command tree.') + + self._state._command_tree = self + self.fallback_to_global: bool = fallback_to_global + self.allowed_contexts = AppCommandContext() if allowed_contexts is MISSING else allowed_contexts + self.allowed_installs = AppInstallationType() if allowed_installs is MISSING else allowed_installs + self._guild_commands: Dict[int, Dict[str, Union[Command, Group]]] = {} + self._global_commands: Dict[str, Union[Command, Group]] = {} + # (name, guild_id, command_type): Command + # The above two mappings can use this structure too but we need fast retrieval + # by name and guild_id in the above case while here it isn't as important since + # it's uncommon and N=5 anyway. + self._context_menus: Dict[Tuple[str, Optional[int], int], ContextMenu] = {} + + async def fetch_command(self, command_id: int, /, *, guild: Optional[Snowflake] = None) -> AppCommand: + """|coro| + + Fetches an application command from the application. + + Parameters + ----------- + command_id: :class:`int` + The ID of the command to fetch. + guild: Optional[:class:`~discord.abc.Snowflake`] + The guild to fetch the command from. If not passed then the global command + is fetched instead. + + Raises + ------- + HTTPException + Fetching the command failed. + MissingApplicationID + The application ID could not be found. + NotFound + The application command was not found. + This could also be because the command is a guild command + and the guild was not specified and vice versa. + + Returns + -------- + :class:`~discord.app_commands.AppCommand` + The application command. + """ + if self.client.application_id is None: + raise MissingApplicationID + + if guild is None: + command = await self._http.get_global_command(self.client.application_id, command_id) + else: + command = await self._http.get_guild_command(self.client.application_id, guild.id, command_id) + + return AppCommand(data=command, state=self._state) + + async def fetch_commands(self, *, guild: Optional[Snowflake] = None) -> List[AppCommand]: + """|coro| + + Fetches the application's current commands. + + If no guild is passed then global commands are fetched, otherwise + the guild's commands are fetched instead. + + .. note:: + + This includes context menu commands. + + Parameters + ----------- + guild: Optional[:class:`~discord.abc.Snowflake`] + The guild to fetch the commands from. If not passed then global commands + are fetched instead. + + Raises + ------- + HTTPException + Fetching the commands failed. + MissingApplicationID + The application ID could not be found. + + Returns + -------- + List[:class:`~discord.app_commands.AppCommand`] + The application's commands. + """ + if self.client.application_id is None: + raise MissingApplicationID + + if guild is None: + commands = await self._http.get_global_commands(self.client.application_id) + else: + commands = await self._http.get_guild_commands(self.client.application_id, guild.id) + + return [AppCommand(data=data, state=self._state) for data in commands] + + def copy_global_to(self, *, guild: Snowflake) -> None: + """Copies all global commands to the specified guild. + + This method is mainly available for development purposes, as it allows you + to copy your global commands over to a testing guild easily. + + Note that this method will *override* pre-existing guild commands that would conflict. + + Parameters + ----------- + guild: :class:`~discord.abc.Snowflake` + The guild to copy the commands to. + + Raises + -------- + CommandLimitReached + The maximum number of commands was reached for that guild. + This is currently 100 for slash commands and 5 for context menu commands. + """ + + try: + mapping = self._guild_commands[guild.id].copy() + except KeyError: + mapping = {} + + mapping.update(self._global_commands) + if len(mapping) > 100: + raise CommandLimitReached(guild_id=guild.id, limit=100) + + ctx_menu: Dict[Tuple[str, Optional[int], int], ContextMenu] = { + (name, guild.id, cmd_type): cmd + for ((name, g, cmd_type), cmd) in self._context_menus.items() + if g is None or g == guild.id + } + + counter = Counter(cmd_type for _, _, cmd_type in ctx_menu) + for cmd_type, count in counter.items(): + if count > 5: + as_enum = AppCommandType(cmd_type) + raise CommandLimitReached(guild_id=guild.id, limit=5, type=as_enum) + + self._context_menus.update(ctx_menu) + self._guild_commands[guild.id] = mapping + + def add_command( + self, + command: Union[Command[Any, ..., Any], ContextMenu, Group], + /, + *, + guild: Optional[Snowflake] = MISSING, + guilds: Sequence[Snowflake] = MISSING, + override: bool = False, + ) -> None: + """Adds an application command to the tree. + + This only adds the command locally -- in order to sync the commands + and enable them in the client, :meth:`sync` must be called. + + The root parent of the command is added regardless of the type passed. + + Parameters + ----------- + command: Union[:class:`Command`, :class:`Group`] + The application command or group to add. + guild: Optional[:class:`~discord.abc.Snowflake`] + The guild to add the command to. If not given or ``None`` then it + becomes a global command instead. + + .. note :: + + Due to a Discord limitation, this keyword argument cannot be used in conjunction with + contexts (e.g. :func:`.app_commands.allowed_contexts`) or installation types + (e.g. :func:`.app_commands.allowed_installs`). + + guilds: List[:class:`~discord.abc.Snowflake`] + The list of guilds to add the command to. This cannot be mixed + with the ``guild`` parameter. If no guilds are given at all + then it becomes a global command instead. + + .. note :: + + Due to a Discord limitation, this keyword argument cannot be used in conjunction with + contexts (e.g. :func:`.app_commands.allowed_contexts`) or installation types + (e.g. :func:`.app_commands.allowed_installs`). + + override: :class:`bool` + Whether to override a command with the same name. If ``False`` + an exception is raised. Default is ``False``. + + Raises + -------- + ~discord.app_commands.CommandAlreadyRegistered + The command was already registered and no override was specified. + TypeError + The application command passed is not a valid application command. + Or, ``guild`` and ``guilds`` were both given. + CommandLimitReached + The maximum number of commands was reached globally or for that guild. + This is currently 100 for slash commands and 5 for context menu commands. + """ + + guild_ids = _retrieve_guild_ids(command, guild, guilds) + if isinstance(command, ContextMenu): + type = command.type.value + name = command.name + + def _context_menu_add_helper( + guild_id: Optional[int], + data: Dict[Tuple[str, Optional[int], int], ContextMenu], + name: str = name, + type: int = type, + ) -> None: + key = (name, guild_id, type) + found = key in self._context_menus + if found and not override: + raise CommandAlreadyRegistered(name, guild_id) + + # If the key is found and overridden then it shouldn't count as an extra addition + # read as `0 if override and found else 1` if confusing + to_add = not (override and found) + total = sum(1 for _, g, t in self._context_menus if g == guild_id and t == type) + if total + to_add > 5: + raise CommandLimitReached(guild_id=guild_id, limit=5, type=AppCommandType(type)) + data[key] = command + + if guild_ids is None: + _context_menu_add_helper(None, self._context_menus) + else: + current: Dict[Tuple[str, Optional[int], int], ContextMenu] = {} + for guild_id in guild_ids: + _context_menu_add_helper(guild_id, current) + + # Update at the end in order to make sure the update is atomic. + # An error during addition could end up making the context menu mapping + # have a partial state + self._context_menus.update(current) + return + elif not isinstance(command, (Command, Group)): + raise TypeError(f'Expected an application command, received {command.__class__.__name__} instead') + + # todo: validate application command groups having children (required) + + root = command.root_parent or command + name = root.name + if guild_ids is not None: + # Validate that the command can be added first, before actually + # adding it into the mapping. This ensures atomicity. + for guild_id in guild_ids: + commands = self._guild_commands.get(guild_id, {}) + found = name in commands + if found and not override: + raise CommandAlreadyRegistered(name, guild_id) + + to_add = not (override and found) + if len(commands) + to_add > 100: + raise CommandLimitReached(guild_id=guild_id, limit=100) + + # Actually add the command now that it has been verified to be okay. + for guild_id in guild_ids: + commands = self._guild_commands.setdefault(guild_id, {}) + commands[name] = root + else: + found = name in self._global_commands + if found and not override: + raise CommandAlreadyRegistered(name, None) + + to_add = not (override and found) + if len(self._global_commands) + to_add > 100: + raise CommandLimitReached(guild_id=None, limit=100) + self._global_commands[name] = root + + @overload + def remove_command( + self, + command: str, + /, + *, + guild: Optional[Snowflake] = ..., + type: Literal[AppCommandType.message, AppCommandType.user], + ) -> Optional[ContextMenu]: + ... + + @overload + def remove_command( + self, + command: str, + /, + *, + guild: Optional[Snowflake] = ..., + type: Literal[AppCommandType.chat_input] = ..., + ) -> Optional[Union[Command[Any, ..., Any], Group]]: + ... + + @overload + def remove_command( + self, + command: str, + /, + *, + guild: Optional[Snowflake] = ..., + type: AppCommandType, + ) -> Optional[Union[Command[Any, ..., Any], ContextMenu, Group]]: + ... + + def remove_command( + self, + command: str, + /, + *, + guild: Optional[Snowflake] = None, + type: AppCommandType = AppCommandType.chat_input, + ) -> Optional[Union[Command[Any, ..., Any], ContextMenu, Group]]: + """Removes an application command from the tree. + + This only removes the command locally -- in order to sync the commands + and remove them in the client, :meth:`sync` must be called. + + Parameters + ----------- + command: :class:`str` + The name of the root command to remove. + guild: Optional[:class:`~discord.abc.Snowflake`] + The guild to remove the command from. If not given or ``None`` then it + removes a global command instead. + type: :class:`~discord.AppCommandType` + The type of command to remove. Defaults to :attr:`~discord.AppCommandType.chat_input`, + i.e. slash commands. + + Returns + --------- + Optional[Union[:class:`Command`, :class:`ContextMenu`, :class:`Group`]] + The application command that got removed. + If nothing was removed then ``None`` is returned instead. + """ + + if type is AppCommandType.chat_input: + if guild is None: + return self._global_commands.pop(command, None) + else: + try: + commands = self._guild_commands[guild.id] + except KeyError: + return None + else: + return commands.pop(command, None) + elif type in (AppCommandType.user, AppCommandType.message): + guild_id = None if guild is None else guild.id + key = (command, guild_id, type.value) + return self._context_menus.pop(key, None) + + def clear_commands(self, *, guild: Optional[Snowflake], type: Optional[AppCommandType] = None) -> None: + """Clears all application commands from the tree. + + This only removes the commands locally -- in order to sync the commands + and remove them in the client, :meth:`sync` must be called. + + Parameters + ----------- + guild: Optional[:class:`~discord.abc.Snowflake`] + The guild to remove the commands from. If ``None`` then it + removes all global commands instead. + type: :class:`~discord.AppCommandType` + The type of command to clear. If not given or ``None`` then it removes all commands + regardless of the type. + """ + + if type is None or type is AppCommandType.chat_input: + if guild is None: + self._global_commands.clear() + else: + try: + commands = self._guild_commands[guild.id] + except KeyError: + pass + else: + commands.clear() + + guild_id = None if guild is None else guild.id + if type is None: + self._context_menus = { + (name, _guild_id, value): cmd + for (name, _guild_id, value), cmd in self._context_menus.items() + if _guild_id != guild_id + } + elif type in (AppCommandType.user, AppCommandType.message): + self._context_menus = { + (name, _guild_id, value): cmd + for (name, _guild_id, value), cmd in self._context_menus.items() + if _guild_id != guild_id or value != type.value + } + + @overload + def get_command( + self, + command: str, + /, + *, + guild: Optional[Snowflake] = ..., + type: Literal[AppCommandType.message, AppCommandType.user], + ) -> Optional[ContextMenu]: + ... + + @overload + def get_command( + self, + command: str, + /, + *, + guild: Optional[Snowflake] = ..., + type: Literal[AppCommandType.chat_input] = ..., + ) -> Optional[Union[Command[Any, ..., Any], Group]]: + ... + + @overload + def get_command( + self, + command: str, + /, + *, + guild: Optional[Snowflake] = ..., + type: AppCommandType, + ) -> Optional[Union[Command[Any, ..., Any], ContextMenu, Group]]: + ... + + def get_command( + self, + command: str, + /, + *, + guild: Optional[Snowflake] = None, + type: AppCommandType = AppCommandType.chat_input, + ) -> Optional[Union[Command[Any, ..., Any], ContextMenu, Group]]: + """Gets an application command from the tree. + + Parameters + ----------- + command: :class:`str` + The name of the root command to get. + guild: Optional[:class:`~discord.abc.Snowflake`] + The guild to get the command from. If not given or ``None`` then it + gets a global command instead. + type: :class:`~discord.AppCommandType` + The type of command to get. Defaults to :attr:`~discord.AppCommandType.chat_input`, + i.e. slash commands. + + Returns + --------- + Optional[Union[:class:`Command`, :class:`ContextMenu`, :class:`Group`]] + The application command that was found. + If nothing was found then ``None`` is returned instead. + """ + + if type is AppCommandType.chat_input: + if guild is None: + return self._global_commands.get(command) + else: + try: + commands = self._guild_commands[guild.id] + except KeyError: + return None + else: + return commands.get(command) + elif type in (AppCommandType.user, AppCommandType.message): + guild_id = None if guild is None else guild.id + key = (command, guild_id, type.value) + return self._context_menus.get(key) + + @overload + def get_commands( + self, + *, + guild: Optional[Snowflake] = ..., + type: Literal[AppCommandType.message, AppCommandType.user], + ) -> List[ContextMenu]: + ... + + @overload + def get_commands( + self, + *, + guild: Optional[Snowflake] = ..., + type: Literal[AppCommandType.chat_input], + ) -> List[Union[Command[Any, ..., Any], Group]]: + ... + + @overload + def get_commands( + self, + *, + guild: Optional[Snowflake] = ..., + type: AppCommandType, + ) -> Union[List[Union[Command[Any, ..., Any], Group]], List[ContextMenu]]: + ... + + @overload + def get_commands( + self, + *, + guild: Optional[Snowflake] = ..., + type: Optional[AppCommandType] = ..., + ) -> List[Union[Command[Any, ..., Any], Group, ContextMenu]]: + ... + + def get_commands( + self, + *, + guild: Optional[Snowflake] = None, + type: Optional[AppCommandType] = None, + ) -> Union[ + List[ContextMenu], + List[Union[Command[Any, ..., Any], Group]], + List[Union[Command[Any, ..., Any], Group, ContextMenu]], + ]: + """Gets all application commands from the tree. + + Parameters + ----------- + guild: Optional[:class:`~discord.abc.Snowflake`] + The guild to get the commands from, not including global commands. + If not given or ``None`` then only global commands are returned. + type: Optional[:class:`~discord.AppCommandType`] + The type of commands to get. When not given or ``None``, then all + command types are returned. + + Returns + --------- + List[Union[:class:`ContextMenu`, :class:`Command`, :class:`Group`]] + The application commands from the tree. + """ + if type is None: + return self._get_all_commands(guild=guild) + + if type is AppCommandType.chat_input: + if guild is None: + return list(self._global_commands.values()) + else: + try: + commands = self._guild_commands[guild.id] + except KeyError: + return [] + else: + return list(commands.values()) + else: + guild_id = None if guild is None else guild.id + value = type.value + return [command for ((_, g, t), command) in self._context_menus.items() if g == guild_id and t == value] + + @overload + def walk_commands( + self, + *, + guild: Optional[Snowflake] = ..., + type: Literal[AppCommandType.message, AppCommandType.user], + ) -> Generator[ContextMenu, None, None]: + ... + + @overload + def walk_commands( + self, + *, + guild: Optional[Snowflake] = ..., + type: Literal[AppCommandType.chat_input] = ..., + ) -> Generator[Union[Command[Any, ..., Any], Group], None, None]: + ... + + @overload + def walk_commands( + self, + *, + guild: Optional[Snowflake] = ..., + type: AppCommandType, + ) -> Union[Generator[Union[Command[Any, ..., Any], Group], None, None], Generator[ContextMenu, None, None]]: + ... + + def walk_commands( + self, + *, + guild: Optional[Snowflake] = None, + type: AppCommandType = AppCommandType.chat_input, + ) -> Union[Generator[Union[Command[Any, ..., Any], Group], None, None], Generator[ContextMenu, None, None]]: + """An iterator that recursively walks through all application commands and child commands from the tree. + + Parameters + ----------- + guild: Optional[:class:`~discord.abc.Snowflake`] + The guild to iterate the commands from, not including global commands. + If not given or ``None`` then only global commands are iterated. + type: :class:`~discord.AppCommandType` + The type of commands to iterate over. Defaults to :attr:`~discord.AppCommandType.chat_input`, + i.e. slash commands. + + Yields + --------- + Union[:class:`ContextMenu`, :class:`Command`, :class:`Group`] + The application commands from the tree. + """ + + if type is AppCommandType.chat_input: + if guild is None: + for cmd in self._global_commands.values(): + yield cmd + if isinstance(cmd, Group): + yield from cmd.walk_commands() + else: + try: + commands = self._guild_commands[guild.id] + except KeyError: + return + else: + for cmd in commands.values(): + yield cmd + if isinstance(cmd, Group): + yield from cmd.walk_commands() + else: + guild_id = None if guild is None else guild.id + value = type.value + for (_, g, t), command in self._context_menus.items(): + if g == guild_id and t == value: + yield command + + def _get_all_commands( + self, *, guild: Optional[Snowflake] = None + ) -> List[Union[Command[Any, ..., Any], Group, ContextMenu]]: + if guild is None: + base: List[Union[Command[Any, ..., Any], Group, ContextMenu]] = list(self._global_commands.values()) + base.extend(cmd for ((_, g, _), cmd) in self._context_menus.items() if g is None) + return base + else: + try: + commands = self._guild_commands[guild.id] + except KeyError: + guild_id = guild.id + return [cmd for ((_, g, _), cmd) in self._context_menus.items() if g == guild_id] + else: + base: List[Union[Command[Any, ..., Any], Group, ContextMenu]] = list(commands.values()) + guild_id = guild.id + base.extend(cmd for ((_, g, _), cmd) in self._context_menus.items() if g == guild_id) + return base + + def _remove_with_module(self, name: str) -> None: + remove: List[Any] = [] + for key, cmd in self._context_menus.items(): + if cmd.module is not None and _is_submodule(name, cmd.module): + remove.append(key) + + for key in remove: + del self._context_menus[key] + + remove = [] + for key, cmd in self._global_commands.items(): + if cmd.module is not None and _is_submodule(name, cmd.module): + remove.append(key) + + for key in remove: + del self._global_commands[key] + + for mapping in self._guild_commands.values(): + remove = [] + for key, cmd in mapping.items(): + if cmd.module is not None and _is_submodule(name, cmd.module): + remove.append(key) + + for key in remove: + del mapping[key] + + async def on_error(self, interaction: Interaction[ClientT], error: AppCommandError, /) -> None: + """|coro| + + A callback that is called when any command raises an :exc:`AppCommandError`. + + The default implementation logs the exception using the library logger + if the command does not have any error handlers attached to it. + + To get the command that failed, :attr:`discord.Interaction.command` should + be used. + + Parameters + ----------- + interaction: :class:`~discord.Interaction` + The interaction that is being handled. + error: :exc:`AppCommandError` + The exception that was raised. + """ + + command = interaction.command + if command is not None: + if command._has_any_error_handlers(): + return + + _log.error('Ignoring exception in command %r', command.name, exc_info=error) + else: + _log.error('Ignoring exception in command tree', exc_info=error) + + def error(self, coro: ErrorFunc[ClientT]) -> ErrorFunc[ClientT]: + """A decorator that registers a coroutine as a local error handler. + + This must match the signature of the :meth:`on_error` callback. + + The error passed will be derived from :exc:`AppCommandError`. + + Parameters + ----------- + coro: :ref:`coroutine ` + The coroutine to register as the local error handler. + + Raises + ------- + TypeError + The coroutine passed is not actually a coroutine or does + not match the signature. + """ + + if not inspect.iscoroutinefunction(coro): + raise TypeError('The error handler must be a coroutine.') + + params = inspect.signature(coro).parameters + if len(params) != 2: + raise TypeError('error handler must have 2 parameters') + + self.on_error = coro # type: ignore + return coro + + def command( + self, + *, + name: Union[str, locale_str] = MISSING, + description: Union[str, locale_str] = MISSING, + nsfw: bool = False, + guild: Optional[Snowflake] = MISSING, + guilds: Sequence[Snowflake] = MISSING, + auto_locale_strings: bool = True, + extras: Dict[Any, Any] = MISSING, + ) -> Callable[[CommandCallback[Group, P, T]], Command[Group, P, T]]: + """A decorator that creates an application command from a regular function directly under this tree. + + Parameters + ------------ + name: Union[:class:`str`, :class:`locale_str`] + The name of the application command. If not given, it defaults to a lower-case + version of the callback name. + description: Union[:class:`str`, :class:`locale_str`] + The description of the application command. This shows up in the UI to describe + the application command. If not given, it defaults to the first line of the docstring + of the callback shortened to 100 characters. + nsfw: :class:`bool` + Whether the command is NSFW and should only work in NSFW channels. Defaults to ``False``. + + Due to a Discord limitation, this does not work on subcommands. + guild: Optional[:class:`~discord.abc.Snowflake`] + The guild to add the command to. If not given or ``None`` then it + becomes a global command instead. + + .. note :: + + Due to a Discord limitation, this keyword argument cannot be used in conjunction with + contexts (e.g. :func:`.app_commands.allowed_contexts`) or installation types + (e.g. :func:`.app_commands.allowed_installs`). + + guilds: List[:class:`~discord.abc.Snowflake`] + The list of guilds to add the command to. This cannot be mixed + with the ``guild`` parameter. If no guilds are given at all + then it becomes a global command instead. + + .. note :: + + Due to a Discord limitation, this keyword argument cannot be used in conjunction with + contexts (e.g. :func:`.app_commands.allowed_contexts`) or installation types + (e.g. :func:`.app_commands.allowed_installs`). + + auto_locale_strings: :class:`bool` + If this is set to ``True``, then all translatable strings will implicitly + be wrapped into :class:`locale_str` rather than :class:`str`. This could + avoid some repetition and be more ergonomic for certain defaults such + as default command names, command descriptions, and parameter names. + Defaults to ``True``. + extras: :class:`dict` + A dictionary that can be used to store extraneous data. + The library will not touch any values or keys within this dictionary. + """ + + def decorator(func: CommandCallback[Group, P, T]) -> Command[Group, P, T]: + if not inspect.iscoroutinefunction(func): + raise TypeError('command function must be a coroutine function') + + if description is MISSING: + if func.__doc__ is None: + desc = '…' + else: + desc = _shorten(func.__doc__) + else: + desc = description + + command = Command( + name=name if name is not MISSING else func.__name__, + description=desc, + callback=func, + nsfw=nsfw, + parent=None, + auto_locale_strings=auto_locale_strings, + extras=extras, + ) + self.add_command(command, guild=guild, guilds=guilds) + return command + + return decorator + + def context_menu( + self, + *, + name: Union[str, locale_str] = MISSING, + nsfw: bool = False, + guild: Optional[Snowflake] = MISSING, + guilds: Sequence[Snowflake] = MISSING, + auto_locale_strings: bool = True, + extras: Dict[Any, Any] = MISSING, + ) -> Callable[[ContextMenuCallback], ContextMenu]: + """A decorator that creates an application command context menu from a regular function directly under this tree. + + This function must have a signature of :class:`~discord.Interaction` as its first parameter + and taking either a :class:`~discord.Member`, :class:`~discord.User`, or :class:`~discord.Message`, + or a :obj:`typing.Union` of ``Member`` and ``User`` as its second parameter. + + Examples + --------- + + .. code-block:: python3 + + @app_commands.context_menu() + async def react(interaction: discord.Interaction, message: discord.Message): + await interaction.response.send_message('Very cool message!', ephemeral=True) + + @app_commands.context_menu() + async def ban(interaction: discord.Interaction, user: discord.Member): + await interaction.response.send_message(f'Should I actually ban {user}...', ephemeral=True) + + Parameters + ------------ + name: Union[:class:`str`, :class:`locale_str`] + The name of the context menu command. If not given, it defaults to a title-case + version of the callback name. Note that unlike regular slash commands this can + have spaces and upper case characters in the name. + nsfw: :class:`bool` + Whether the command is NSFW and should only work in NSFW channels. Defaults to ``False``. + + Due to a Discord limitation, this does not work on subcommands. + guild: Optional[:class:`~discord.abc.Snowflake`] + The guild to add the command to. If not given or ``None`` then it + becomes a global command instead. + + .. note :: + + Due to a Discord limitation, this keyword argument cannot be used in conjunction with + contexts (e.g. :func:`.app_commands.allowed_contexts`) or installation types + (e.g. :func:`.app_commands.allowed_installs`). + + guilds: List[:class:`~discord.abc.Snowflake`] + The list of guilds to add the command to. This cannot be mixed + with the ``guild`` parameter. If no guilds are given at all + then it becomes a global command instead. + + .. note :: + + Due to a Discord limitation, this keyword argument cannot be used in conjunction with + contexts (e.g. :func:`.app_commands.allowed_contexts`) or installation types + (e.g. :func:`.app_commands.allowed_installs`). + + auto_locale_strings: :class:`bool` + If this is set to ``True``, then all translatable strings will implicitly + be wrapped into :class:`locale_str` rather than :class:`str`. This could + avoid some repetition and be more ergonomic for certain defaults such + as default command names, command descriptions, and parameter names. + Defaults to ``True``. + extras: :class:`dict` + A dictionary that can be used to store extraneous data. + The library will not touch any values or keys within this dictionary. + """ + + def decorator(func: ContextMenuCallback) -> ContextMenu: + if not inspect.iscoroutinefunction(func): + raise TypeError('context menu function must be a coroutine function') + + actual_name = func.__name__.title() if name is MISSING else name + context_menu = ContextMenu( + name=actual_name, + nsfw=nsfw, + callback=func, + auto_locale_strings=auto_locale_strings, + extras=extras, + ) + self.add_command(context_menu, guild=guild, guilds=guilds) + return context_menu + + return decorator + + @property + def translator(self) -> Optional[Translator]: + """Optional[:class:`Translator`]: The translator, if any, responsible for handling translation of commands. + + To change the translator, use :meth:`set_translator`. + """ + return self._state._translator + + async def set_translator(self, translator: Optional[Translator]) -> None: + """|coro| + + Sets the translator to use for translating commands. + + If a translator was previously set, it will be unloaded using its + :meth:`Translator.unload` method. + + When a translator is set, it will be loaded using its :meth:`Translator.load` method. + + Parameters + ------------ + translator: Optional[:class:`Translator`] + The translator to use. If ``None`` then the translator is just removed and unloaded. + + Raises + ------- + TypeError + The translator was not ``None`` or a :class:`Translator` instance. + """ + + if translator is not None and not isinstance(translator, Translator): + raise TypeError(f'expected None or Translator instance, received {translator.__class__.__name__} instead') + + old_translator = self._state._translator + if old_translator is not None: + await old_translator.unload() + + if translator is None: + self._state._translator = None + else: + await translator.load() + self._state._translator = translator + + async def sync(self, *, guild: Optional[Snowflake] = None) -> List[AppCommand]: + """|coro| + + Syncs the application commands to Discord. + + This also runs the translator to get the translated strings necessary for + feeding back into Discord. + + This must be called for the application commands to show up. + + Parameters + ----------- + guild: Optional[:class:`~discord.abc.Snowflake`] + The guild to sync the commands to. If ``None`` then it + syncs all global commands instead. + + Raises + ------- + HTTPException + Syncing the commands failed. + CommandSyncFailure + Syncing the commands failed due to a user related error, typically because + the command has invalid data. This is equivalent to an HTTP status code of + 400. + Forbidden + The client does not have the ``applications.commands`` scope in the guild. + MissingApplicationID + The client does not have an application ID. + TranslationError + An error occurred while translating the commands. + + Returns + -------- + List[:class:`AppCommand`] + The application's commands that got synced. + """ + + if self.client.application_id is None: + raise MissingApplicationID + + commands = self._get_all_commands(guild=guild) + + translator = self.translator + if translator: + payload = [await command.get_translated_payload(self, translator) for command in commands] + else: + payload = [command.to_dict(self) for command in commands] + + try: + if guild is None: + data = await self._http.bulk_upsert_global_commands(self.client.application_id, payload=payload) + else: + data = await self._http.bulk_upsert_guild_commands(self.client.application_id, guild.id, payload=payload) + except HTTPException as e: + if e.status == 400 and e.code == 50035: + raise CommandSyncFailure(e, commands) from None + raise + + return [AppCommand(data=d, state=self._state) for d in data] + + async def _dispatch_error(self, interaction: Interaction[ClientT], error: AppCommandError, /) -> None: + command = interaction.command + interaction.command_failed = True + try: + if isinstance(command, Command): + await command._invoke_error_handlers(interaction, error) + finally: + await self.on_error(interaction, error) + + def _from_interaction(self, interaction: Interaction[ClientT]) -> None: + async def wrapper(): + try: + await self._call(interaction) + except AppCommandError as e: + await self._dispatch_error(interaction, e) + + self.client.loop.create_task(wrapper(), name='CommandTree-invoker') + + def _get_context_menu(self, data: ApplicationCommandInteractionData) -> Optional[ContextMenu]: + name = data['name'] + guild_id = _get_as_snowflake(data, 'guild_id') + t = data.get('type', 1) + cmd = self._context_menus.get((name, guild_id, t)) + if cmd is None and self.fallback_to_global: + return self._context_menus.get((name, None, t)) + return cmd + + def _get_app_command_options( + self, data: ApplicationCommandInteractionData + ) -> Tuple[Command[Any, ..., Any], List[ApplicationCommandInteractionDataOption]]: + parents: List[str] = [] + name = data['name'] + + command_guild_id = _get_as_snowflake(data, 'guild_id') + if command_guild_id: + try: + guild_commands = self._guild_commands[command_guild_id] + except KeyError: + command = None if not self.fallback_to_global else self._global_commands.get(name) + else: + command = guild_commands.get(name) + if command is None and self.fallback_to_global: + command = self._global_commands.get(name) + else: + command = self._global_commands.get(name) + + # If it's not found at this point then it's not gonna be found at any point + if command is None: + raise CommandNotFound(name, parents) + + # This could be done recursively but it'd be a bother due to the state needed + # to be tracked above like the parents, the actual command type, and the + # resulting options we care about + searching = True + options: List[ApplicationCommandInteractionDataOption] = data.get('options', []) + while searching: + for option in options: + # Find subcommands + if option.get('type', 0) in (1, 2): + parents.append(name) + name = option['name'] + command = command._get_internal_command(name) + if command is None: + raise CommandNotFound(name, parents) + options = option.get('options', []) + break + else: + searching = False + break + else: + break + + if isinstance(command, Group): + # Right now, groups can't be invoked. This is a Discord limitation in how they + # do slash commands. So if we're here and we have a Group rather than a Command instance + # then something in the code is out of date from the data that Discord has. + raise CommandSignatureMismatch(command) + + return (command, options) + + async def _call_context_menu( + self, interaction: Interaction[ClientT], data: ApplicationCommandInteractionData, type: int + ) -> None: + name = data['name'] + guild_id = _get_as_snowflake(data, 'guild_id') + ctx_menu = self._context_menus.get((name, guild_id, type)) + if ctx_menu is None and self.fallback_to_global: + ctx_menu = self._context_menus.get((name, None, type)) + + # Pre-fill the cached slot to prevent re-computation + interaction._cs_command = ctx_menu + + if ctx_menu is None: + raise CommandNotFound(name, [], AppCommandType(type)) + + resolved = Namespace._get_resolved_items(interaction, data.get('resolved', {})) + + # This is annotated as str | int but realistically this will always be str + target_id: Optional[Union[str, int]] = data.get('target_id') + # Right now, the only types are message and user + # Therefore, there's no conflict with snowflakes + + # This will always work at runtime + key = ResolveKey.any_with(target_id) # type: ignore + value = resolved.get(key) + if ctx_menu.type.value != type: + raise CommandSignatureMismatch(ctx_menu) + + if value is None: + raise AppCommandError('This should not happen if Discord sent well-formed data.') + + # I assume I don't have to type check here. + try: + await ctx_menu._invoke(interaction, value) + except AppCommandError as e: + if ctx_menu.on_error is not None: + await ctx_menu.on_error(interaction, e) + await self.on_error(interaction, e) + else: + self.client.dispatch('app_command_completion', interaction, ctx_menu) + + async def interaction_check(self, interaction: Interaction[ClientT], /) -> bool: + """|coro| + + A global check to determine if an :class:`~discord.Interaction` should + be processed by the tree. + + The default implementation returns True (all interactions are processed), + but can be overridden if custom behaviour is desired. + """ + return True + + async def _call(self, interaction: Interaction[ClientT]) -> None: + if not await self.interaction_check(interaction): + interaction.command_failed = True + return + + data: ApplicationCommandInteractionData = interaction.data # type: ignore + type = data.get('type', 1) + if type != 1: + # Context menu command... + await self._call_context_menu(interaction, data, type) + return + + command, options = self._get_app_command_options(data) + + # Pre-fill the cached slot to prevent re-computation + interaction._cs_command = command + + # At this point options refers to the arguments of the command + # and command refers to the class type we care about + namespace = Namespace(interaction, data.get('resolved', {}), options) + + # Same pre-fill as above + interaction._cs_namespace = namespace + + # Auto complete handles the namespace differently... so at this point this is where we decide where that is. + if interaction.type is InteractionType.autocomplete: + focused = next((opt['name'] for opt in options if opt.get('focused')), None) + if focused is None: + raise AppCommandError('This should not happen, but there is no focused element. This is a Discord bug.') + + try: + await command._invoke_autocomplete(interaction, focused, namespace) + except Exception: + # Suppress exception since it can't be handled anyway. + _log.exception('Ignoring exception in autocomplete for %r', command.qualified_name) + + return + + try: + await command._invoke_with_namespace(interaction, namespace) + except AppCommandError as e: + interaction.command_failed = True + await command._invoke_error_handlers(interaction, e) + await self.on_error(interaction, e) + else: + if not interaction.command_failed: + self.client.dispatch('app_command_completion', interaction, command) diff --git a/venv/lib/python3.12/site-packages/discord/appinfo.py b/venv/lib/python3.12/site-packages/discord/appinfo.py new file mode 100644 index 00000000..990c7c2f --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/appinfo.py @@ -0,0 +1,645 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from __future__ import annotations + +from typing import List, TYPE_CHECKING, Literal, Optional + +from . import utils +from .asset import Asset +from .flags import ApplicationFlags +from .permissions import Permissions +from .utils import MISSING + +if TYPE_CHECKING: + from typing import Dict, Any + + from .guild import Guild + from .types.appinfo import ( + AppInfo as AppInfoPayload, + PartialAppInfo as PartialAppInfoPayload, + Team as TeamPayload, + InstallParams as InstallParamsPayload, + AppIntegrationTypeConfig as AppIntegrationTypeConfigPayload, + ) + from .user import User + from .state import ConnectionState + +__all__ = ( + 'AppInfo', + 'PartialAppInfo', + 'AppInstallParams', + 'IntegrationTypeConfig', +) + + +class AppInfo: + """Represents the application info for the bot provided by Discord. + + + Attributes + ------------- + id: :class:`int` + The application ID. + name: :class:`str` + The application name. + owner: :class:`User` + The application owner. + team: Optional[:class:`Team`] + The application's team. + + .. versionadded:: 1.3 + + description: :class:`str` + The application description. + bot_public: :class:`bool` + Whether the bot can be invited by anyone or if it is locked + to the application owner. + bot_require_code_grant: :class:`bool` + Whether the bot requires the completion of the full oauth2 code + grant flow to join. + rpc_origins: Optional[List[:class:`str`]] + A list of RPC origin URLs, if RPC is enabled. + + verify_key: :class:`str` + The hex encoded key for verification in interactions and the + GameSDK's :ddocs:`GetTicket `. + + .. versionadded:: 1.3 + + guild_id: Optional[:class:`int`] + If this application is a game sold on Discord, + this field will be the guild to which it has been linked to. + + .. versionadded:: 1.3 + + primary_sku_id: Optional[:class:`int`] + If this application is a game sold on Discord, + this field will be the id of the "Game SKU" that is created, + if it exists. + + .. versionadded:: 1.3 + + slug: Optional[:class:`str`] + If this application is a game sold on Discord, + this field will be the URL slug that links to the store page. + + .. versionadded:: 1.3 + + terms_of_service_url: Optional[:class:`str`] + The application's terms of service URL, if set. + + .. versionadded:: 2.0 + + privacy_policy_url: Optional[:class:`str`] + The application's privacy policy URL, if set. + + .. versionadded:: 2.0 + + tags: List[:class:`str`] + The list of tags describing the functionality of the application. + + .. versionadded:: 2.0 + + custom_install_url: List[:class:`str`] + The custom authorization URL for the application, if enabled. + + .. versionadded:: 2.0 + + install_params: Optional[:class:`AppInstallParams`] + The settings for custom authorization URL of application, if enabled. + + .. versionadded:: 2.0 + role_connections_verification_url: Optional[:class:`str`] + The application's connection verification URL which will render the application as + a verification method in the guild's role verification configuration. + + .. versionadded:: 2.2 + interactions_endpoint_url: Optional[:class:`str`] + The interactions endpoint url of the application to receive interactions over this endpoint rather than + over the gateway, if configured. + + .. versionadded:: 2.4 + redirect_uris: List[:class:`str`] + A list of authentication redirect URIs. + + .. versionadded:: 2.4 + approximate_guild_count: :class:`int` + The approximate count of the guilds the bot was added to. + + .. versionadded:: 2.4 + approximate_user_install_count: Optional[:class:`int`] + The approximate count of the user-level installations the bot has. + + .. versionadded:: 2.5 + """ + + __slots__ = ( + '_state', + 'description', + 'id', + 'name', + 'rpc_origins', + 'bot_public', + 'bot_require_code_grant', + 'owner', + '_icon', + 'verify_key', + 'team', + 'guild_id', + 'primary_sku_id', + 'slug', + '_cover_image', + '_flags', + 'terms_of_service_url', + 'privacy_policy_url', + 'tags', + 'custom_install_url', + 'install_params', + 'role_connections_verification_url', + 'interactions_endpoint_url', + 'redirect_uris', + 'approximate_guild_count', + 'approximate_user_install_count', + '_integration_types_config', + ) + + def __init__(self, state: ConnectionState, data: AppInfoPayload): + from .team import Team + + self._state: ConnectionState = state + self.id: int = int(data['id']) + self.name: str = data['name'] + self.description: str = data['description'] + self._icon: Optional[str] = data['icon'] + self.rpc_origins: Optional[List[str]] = data.get('rpc_origins') + self.bot_public: bool = data['bot_public'] + self.bot_require_code_grant: bool = data['bot_require_code_grant'] + self.owner: User = state.create_user(data['owner']) + + team: Optional[TeamPayload] = data.get('team') + self.team: Optional[Team] = Team(state, team) if team else None + + self.verify_key: str = data['verify_key'] + + self.guild_id: Optional[int] = utils._get_as_snowflake(data, 'guild_id') + + self.primary_sku_id: Optional[int] = utils._get_as_snowflake(data, 'primary_sku_id') + self.slug: Optional[str] = data.get('slug') + self._flags: int = data.get('flags', 0) + self._cover_image: Optional[str] = data.get('cover_image') + self.terms_of_service_url: Optional[str] = data.get('terms_of_service_url') + self.privacy_policy_url: Optional[str] = data.get('privacy_policy_url') + self.tags: List[str] = data.get('tags', []) + self.custom_install_url: Optional[str] = data.get('custom_install_url') + self.role_connections_verification_url: Optional[str] = data.get('role_connections_verification_url') + + params = data.get('install_params') + self.install_params: Optional[AppInstallParams] = AppInstallParams(params) if params else None + self.interactions_endpoint_url: Optional[str] = data.get('interactions_endpoint_url') + self.redirect_uris: List[str] = data.get('redirect_uris', []) + self.approximate_guild_count: int = data.get('approximate_guild_count', 0) + self.approximate_user_install_count: Optional[int] = data.get('approximate_user_install_count') + self._integration_types_config: Dict[Literal['0', '1'], AppIntegrationTypeConfigPayload] = data.get( + 'integration_types_config', {} + ) + + def __repr__(self) -> str: + return ( + f'<{self.__class__.__name__} id={self.id} name={self.name!r} ' + f'description={self.description!r} public={self.bot_public} ' + f'owner={self.owner!r}>' + ) + + @property + def icon(self) -> Optional[Asset]: + """Optional[:class:`.Asset`]: Retrieves the application's icon asset, if any.""" + if self._icon is None: + return None + return Asset._from_icon(self._state, self.id, self._icon, path='app') + + @property + def cover_image(self) -> Optional[Asset]: + """Optional[:class:`.Asset`]: Retrieves the cover image on a store embed, if any. + + This is only available if the application is a game sold on Discord. + """ + if self._cover_image is None: + return None + return Asset._from_cover_image(self._state, self.id, self._cover_image) + + @property + def guild(self) -> Optional[Guild]: + """Optional[:class:`Guild`]: If this application is a game sold on Discord, + this field will be the guild to which it has been linked + + .. versionadded:: 1.3 + """ + return self._state._get_guild(self.guild_id) + + @property + def flags(self) -> ApplicationFlags: + """:class:`ApplicationFlags`: The application's flags. + + .. versionadded:: 2.0 + """ + return ApplicationFlags._from_value(self._flags) + + @property + def guild_integration_config(self) -> Optional[IntegrationTypeConfig]: + """Optional[:class:`IntegrationTypeConfig`]: The default settings for the + application's installation context in a guild. + + .. versionadded:: 2.5 + """ + if not self._integration_types_config: + return None + + try: + return IntegrationTypeConfig(self._integration_types_config['0']) + except KeyError: + return None + + @property + def user_integration_config(self) -> Optional[IntegrationTypeConfig]: + """Optional[:class:`IntegrationTypeConfig`]: The default settings for the + application's installation context as a user. + + .. versionadded:: 2.5 + """ + if not self._integration_types_config: + return None + + try: + return IntegrationTypeConfig(self._integration_types_config['1']) + except KeyError: + return None + + async def edit( + self, + *, + reason: Optional[str] = MISSING, + custom_install_url: Optional[str] = MISSING, + description: Optional[str] = MISSING, + role_connections_verification_url: Optional[str] = MISSING, + install_params_scopes: Optional[List[str]] = MISSING, + install_params_permissions: Optional[Permissions] = MISSING, + flags: Optional[ApplicationFlags] = MISSING, + icon: Optional[bytes] = MISSING, + cover_image: Optional[bytes] = MISSING, + interactions_endpoint_url: Optional[str] = MISSING, + tags: Optional[List[str]] = MISSING, + guild_install_scopes: Optional[List[str]] = MISSING, + guild_install_permissions: Optional[Permissions] = MISSING, + user_install_scopes: Optional[List[str]] = MISSING, + user_install_permissions: Optional[Permissions] = MISSING, + ) -> AppInfo: + r"""|coro| + + Edits the application info. + + .. versionadded:: 2.4 + + Parameters + ---------- + custom_install_url: Optional[:class:`str`] + The new custom authorization URL for the application. Can be ``None`` to remove the URL. + description: Optional[:class:`str`] + The new application description. Can be ``None`` to remove the description. + role_connections_verification_url: Optional[:class:`str`] + The new application’s connection verification URL which will render the application + as a verification method in the guild’s role verification configuration. Can be ``None`` to remove the URL. + install_params_scopes: Optional[List[:class:`str`]] + The new list of :ddocs:`OAuth2 scopes ` of + the :attr:`~install_params`. Can be ``None`` to remove the scopes. + install_params_permissions: Optional[:class:`Permissions`] + The new permissions of the :attr:`~install_params`. Can be ``None`` to remove the permissions. + flags: Optional[:class:`ApplicationFlags`] + The new application’s flags. Only limited intent flags (:attr:`~ApplicationFlags.gateway_presence_limited`, + :attr:`~ApplicationFlags.gateway_guild_members_limited`, :attr:`~ApplicationFlags.gateway_message_content_limited`) + can be edited. Can be ``None`` to remove the flags. + + .. warning:: + + Editing the limited intent flags leads to the termination of the bot. + + icon: Optional[:class:`bytes`] + The new application’s icon as a :term:`py:bytes-like object`. Can be ``None`` to remove the icon. + cover_image: Optional[:class:`bytes`] + The new application’s cover image as a :term:`py:bytes-like object` on a store embed. + The cover image is only available if the application is a game sold on Discord. + Can be ``None`` to remove the image. + interactions_endpoint_url: Optional[:class:`str`] + The new interactions endpoint url of the application to receive interactions over this endpoint rather than + over the gateway. Can be ``None`` to remove the URL. + tags: Optional[List[:class:`str`]] + The new list of tags describing the functionality of the application. Can be ``None`` to remove the tags. + guild_install_scopes: Optional[List[:class:`str`]] + The new list of :ddocs:`OAuth2 scopes ` of + the default guild installation context. Can be ``None`` to remove the scopes. + + .. versionadded: 2.5 + guild_install_permissions: Optional[:class:`Permissions`] + The new permissions of the default guild installation context. Can be ``None`` to remove the permissions. + + .. versionadded: 2.5 + user_install_scopes: Optional[List[:class:`str`]] + The new list of :ddocs:`OAuth2 scopes ` of + the default user installation context. Can be ``None`` to remove the scopes. + + .. versionadded: 2.5 + user_install_permissions: Optional[:class:`Permissions`] + The new permissions of the default user installation context. Can be ``None`` to remove the permissions. + + .. versionadded: 2.5 + reason: Optional[:class:`str`] + The reason for editing the application. Shows up on the audit log. + + Raises + ------- + HTTPException + Editing the application failed + ValueError + The image format passed in to ``icon`` or ``cover_image`` is invalid. This is also raised + when ``install_params_scopes`` and ``install_params_permissions`` are incompatible with each other, + or when ``guild_install_scopes`` and ``guild_install_permissions`` are incompatible with each other. + + Returns + ------- + :class:`AppInfo` + The newly updated application info. + """ + payload: Dict[str, Any] = {} + + if custom_install_url is not MISSING: + payload['custom_install_url'] = custom_install_url + + if description is not MISSING: + payload['description'] = description + + if role_connections_verification_url is not MISSING: + payload['role_connections_verification_url'] = role_connections_verification_url + + if install_params_scopes is not MISSING: + install_params: Optional[Dict[str, Any]] = {} + if install_params_scopes is None: + install_params = None + else: + if "bot" not in install_params_scopes and install_params_permissions is not MISSING: + raise ValueError("'bot' must be in install_params_scopes if install_params_permissions is set") + + install_params['scopes'] = install_params_scopes + + if install_params_permissions is MISSING: + install_params['permissions'] = 0 + else: + if install_params_permissions is None: + install_params['permissions'] = 0 + else: + install_params['permissions'] = install_params_permissions.value + + payload['install_params'] = install_params + + else: + if install_params_permissions is not MISSING: + raise ValueError('install_params_scopes must be set if install_params_permissions is set') + + if flags is not MISSING: + if flags is None: + payload['flags'] = flags + else: + payload['flags'] = flags.value + + if icon is not MISSING: + if icon is None: + payload['icon'] = icon + else: + payload['icon'] = utils._bytes_to_base64_data(icon) + + if cover_image is not MISSING: + if cover_image is None: + payload['cover_image'] = cover_image + else: + payload['cover_image'] = utils._bytes_to_base64_data(cover_image) + + if interactions_endpoint_url is not MISSING: + payload['interactions_endpoint_url'] = interactions_endpoint_url + + if tags is not MISSING: + payload['tags'] = tags + + integration_types_config: Dict[str, Any] = {} + if guild_install_scopes is not MISSING or guild_install_permissions is not MISSING: + guild_install_params: Optional[Dict[str, Any]] = {} + if guild_install_scopes in (None, MISSING): + guild_install_scopes = [] + + if 'bot' not in guild_install_scopes and guild_install_permissions is not MISSING: + raise ValueError("'bot' must be in guild_install_scopes if guild_install_permissions is set") + + if guild_install_permissions in (None, MISSING): + guild_install_params['permissions'] = 0 + else: + guild_install_params['permissions'] = guild_install_permissions.value + + guild_install_params['scopes'] = guild_install_scopes + + integration_types_config['0'] = {'oauth2_install_params': guild_install_params or None} + else: + if guild_install_permissions is not MISSING: + raise ValueError('guild_install_scopes must be set if guild_install_permissions is set') + + if user_install_scopes is not MISSING or user_install_permissions is not MISSING: + user_install_params: Optional[Dict[str, Any]] = {} + if user_install_scopes in (None, MISSING): + user_install_scopes = [] + + if 'bot' not in user_install_scopes and user_install_permissions is not MISSING: + raise ValueError("'bot' must be in user_install_scopes if user_install_permissions is set") + + if user_install_permissions in (None, MISSING): + user_install_params['permissions'] = 0 + else: + user_install_params['permissions'] = user_install_permissions.value + + user_install_params['scopes'] = user_install_scopes + + integration_types_config['1'] = {'oauth2_install_params': user_install_params or None} + else: + if user_install_permissions is not MISSING: + raise ValueError('user_install_scopes must be set if user_install_permissions is set') + + if integration_types_config: + payload['integration_types_config'] = integration_types_config + + data = await self._state.http.edit_application_info(reason=reason, payload=payload) + return AppInfo(data=data, state=self._state) + + +class PartialAppInfo: + """Represents a partial AppInfo given by :func:`~discord.abc.GuildChannel.create_invite` + + .. versionadded:: 2.0 + + Attributes + ------------- + id: :class:`int` + The application ID. + name: :class:`str` + The application name. + description: :class:`str` + The application description. + rpc_origins: Optional[List[:class:`str`]] + A list of RPC origin URLs, if RPC is enabled. + verify_key: :class:`str` + The hex encoded key for verification in interactions and the + GameSDK's :ddocs:`GetTicket `. + terms_of_service_url: Optional[:class:`str`] + The application's terms of service URL, if set. + privacy_policy_url: Optional[:class:`str`] + The application's privacy policy URL, if set. + approximate_guild_count: :class:`int` + The approximate count of the guilds the bot was added to. + + .. versionadded:: 2.3 + redirect_uris: List[:class:`str`] + A list of authentication redirect URIs. + + .. versionadded:: 2.3 + interactions_endpoint_url: Optional[:class:`str`] + The interactions endpoint url of the application to receive interactions over this endpoint rather than + over the gateway, if configured. + + .. versionadded:: 2.3 + role_connections_verification_url: Optional[:class:`str`] + The application's connection verification URL which will render the application as + a verification method in the guild's role verification configuration. + + .. versionadded:: 2.3 + """ + + __slots__ = ( + '_state', + 'id', + 'name', + 'description', + 'rpc_origins', + 'verify_key', + 'terms_of_service_url', + 'privacy_policy_url', + '_icon', + '_flags', + '_cover_image', + 'approximate_guild_count', + 'redirect_uris', + 'interactions_endpoint_url', + 'role_connections_verification_url', + ) + + def __init__(self, *, state: ConnectionState, data: PartialAppInfoPayload): + self._state: ConnectionState = state + self.id: int = int(data['id']) + self.name: str = data['name'] + self._icon: Optional[str] = data.get('icon') + self._flags: int = data.get('flags', 0) + self._cover_image: Optional[str] = data.get('cover_image') + self.description: str = data['description'] + self.rpc_origins: Optional[List[str]] = data.get('rpc_origins') + self.verify_key: str = data['verify_key'] + self.terms_of_service_url: Optional[str] = data.get('terms_of_service_url') + self.privacy_policy_url: Optional[str] = data.get('privacy_policy_url') + self.approximate_guild_count: int = data.get('approximate_guild_count', 0) + self.redirect_uris: List[str] = data.get('redirect_uris', []) + self.interactions_endpoint_url: Optional[str] = data.get('interactions_endpoint_url') + self.role_connections_verification_url: Optional[str] = data.get('role_connections_verification_url') + + def __repr__(self) -> str: + return f'<{self.__class__.__name__} id={self.id} name={self.name!r} description={self.description!r}>' + + @property + def icon(self) -> Optional[Asset]: + """Optional[:class:`.Asset`]: Retrieves the application's icon asset, if any.""" + if self._icon is None: + return None + return Asset._from_icon(self._state, self.id, self._icon, path='app') + + @property + def cover_image(self) -> Optional[Asset]: + """Optional[:class:`.Asset`]: Retrieves the cover image of the application's default rich presence. + + This is only available if the application is a game sold on Discord. + + .. versionadded:: 2.3 + """ + if self._cover_image is None: + return None + return Asset._from_cover_image(self._state, self.id, self._cover_image) + + @property + def flags(self) -> ApplicationFlags: + """:class:`ApplicationFlags`: The application's flags. + + .. versionadded:: 2.0 + """ + return ApplicationFlags._from_value(self._flags) + + +class AppInstallParams: + """Represents the settings for custom authorization URL of an application. + + .. versionadded:: 2.0 + + Attributes + ---------- + scopes: List[:class:`str`] + The list of :ddocs:`OAuth2 scopes ` + to add the application to a guild with. + permissions: :class:`Permissions` + The permissions to give to application in the guild. + """ + + __slots__ = ('scopes', 'permissions') + + def __init__(self, data: InstallParamsPayload) -> None: + self.scopes: List[str] = data.get('scopes', []) + self.permissions: Permissions = Permissions(int(data['permissions'])) + + +class IntegrationTypeConfig: + """Represents the default settings for the application's installation context. + + .. versionadded:: 2.5 + + Attributes + ---------- + oauth2_install_params: Optional[:class:`AppInstallParams`] + The install params for this installation context's default in-app authorization link. + """ + + def __init__(self, data: AppIntegrationTypeConfigPayload) -> None: + self.oauth2_install_params: Optional[AppInstallParams] = None + try: + self.oauth2_install_params = AppInstallParams(data['oauth2_install_params']) # type: ignore # EAFP + except KeyError: + pass diff --git a/venv/lib/python3.12/site-packages/discord/asset.py b/venv/lib/python3.12/site-packages/discord/asset.py new file mode 100644 index 00000000..e3422f31 --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/asset.py @@ -0,0 +1,536 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from __future__ import annotations + +import io +import os +from typing import Any, Literal, Optional, TYPE_CHECKING, Tuple, Union +from .errors import DiscordException +from . import utils +from .file import File + +import yarl + +# fmt: off +__all__ = ( + 'Asset', +) +# fmt: on + +if TYPE_CHECKING: + from typing_extensions import Self + + from .state import ConnectionState + from .webhook.async_ import _WebhookState + + _State = Union[ConnectionState, _WebhookState] + + ValidStaticFormatTypes = Literal['webp', 'jpeg', 'jpg', 'png'] + ValidAssetFormatTypes = Literal['webp', 'jpeg', 'jpg', 'png', 'gif'] + +VALID_STATIC_FORMATS = frozenset({"jpeg", "jpg", "webp", "png"}) +VALID_ASSET_FORMATS = VALID_STATIC_FORMATS | {"gif"} + + +MISSING = utils.MISSING + + +class AssetMixin: + __slots__ = () + url: str + _state: Optional[Any] + + async def read(self) -> bytes: + """|coro| + + Retrieves the content of this asset as a :class:`bytes` object. + + Raises + ------ + DiscordException + There was no internal connection state. + HTTPException + Downloading the asset failed. + NotFound + The asset was deleted. + + Returns + ------- + :class:`bytes` + The content of the asset. + """ + if self._state is None: + raise DiscordException('Invalid state (no ConnectionState provided)') + + return await self._state.http.get_from_cdn(self.url) + + async def save(self, fp: Union[str, bytes, os.PathLike[Any], io.BufferedIOBase], *, seek_begin: bool = True) -> int: + """|coro| + + Saves this asset into a file-like object. + + Parameters + ---------- + fp: Union[:class:`io.BufferedIOBase`, :class:`os.PathLike`] + The file-like object to save this asset to or the filename + to use. If a filename is passed then a file is created with that + filename and used instead. + seek_begin: :class:`bool` + Whether to seek to the beginning of the file after saving is + successfully done. + + Raises + ------ + DiscordException + There was no internal connection state. + HTTPException + Downloading the asset failed. + NotFound + The asset was deleted. + + Returns + -------- + :class:`int` + The number of bytes written. + """ + + data = await self.read() + if isinstance(fp, io.BufferedIOBase): + written = fp.write(data) + if seek_begin: + fp.seek(0) + return written + else: + with open(fp, 'wb') as f: + return f.write(data) + + async def to_file( + self, + *, + filename: Optional[str] = MISSING, + description: Optional[str] = None, + spoiler: bool = False, + ) -> File: + """|coro| + + Converts the asset into a :class:`File` suitable for sending via + :meth:`abc.Messageable.send`. + + .. versionadded:: 2.0 + + Parameters + ----------- + filename: Optional[:class:`str`] + The filename of the file. If not provided, then the filename from + the asset's URL is used. + description: Optional[:class:`str`] + The description for the file. + spoiler: :class:`bool` + Whether the file is a spoiler. + + Raises + ------ + DiscordException + The asset does not have an associated state. + ValueError + The asset is a unicode emoji. + TypeError + The asset is a sticker with lottie type. + HTTPException + Downloading the asset failed. + NotFound + The asset was deleted. + + Returns + ------- + :class:`File` + The asset as a file suitable for sending. + """ + + data = await self.read() + file_filename = filename if filename is not MISSING else yarl.URL(self.url).name + return File(io.BytesIO(data), filename=file_filename, description=description, spoiler=spoiler) + + +class Asset(AssetMixin): + """Represents a CDN asset on Discord. + + .. container:: operations + + .. describe:: str(x) + + Returns the URL of the CDN asset. + + .. describe:: len(x) + + Returns the length of the CDN asset's URL. + + .. describe:: x == y + + Checks if the asset is equal to another asset. + + .. describe:: x != y + + Checks if the asset is not equal to another asset. + + .. describe:: hash(x) + + Returns the hash of the asset. + """ + + __slots__: Tuple[str, ...] = ( + '_state', + '_url', + '_animated', + '_key', + ) + + BASE = 'https://cdn.discordapp.com' + + def __init__(self, state: _State, *, url: str, key: str, animated: bool = False) -> None: + self._state: _State = state + self._url: str = url + self._animated: bool = animated + self._key: str = key + + @classmethod + def _from_default_avatar(cls, state: _State, index: int) -> Self: + return cls( + state, + url=f'{cls.BASE}/embed/avatars/{index}.png', + key=str(index), + animated=False, + ) + + @classmethod + def _from_avatar(cls, state: _State, user_id: int, avatar: str) -> Self: + animated = avatar.startswith('a_') + format = 'gif' if animated else 'png' + return cls( + state, + url=f'{cls.BASE}/avatars/{user_id}/{avatar}.{format}?size=1024', + key=avatar, + animated=animated, + ) + + @classmethod + def _from_guild_avatar(cls, state: _State, guild_id: int, member_id: int, avatar: str) -> Self: + animated = avatar.startswith('a_') + format = 'gif' if animated else 'png' + return cls( + state, + url=f"{cls.BASE}/guilds/{guild_id}/users/{member_id}/avatars/{avatar}.{format}?size=1024", + key=avatar, + animated=animated, + ) + + @classmethod + def _from_guild_banner(cls, state: _State, guild_id: int, member_id: int, banner: str) -> Self: + animated = banner.startswith('a_') + format = 'gif' if animated else 'png' + return cls( + state, + url=f"{cls.BASE}/guilds/{guild_id}/users/{member_id}/banners/{banner}.{format}?size=1024", + key=banner, + animated=animated, + ) + + @classmethod + def _from_avatar_decoration(cls, state: _State, avatar_decoration: str) -> Self: + return cls( + state, + url=f'{cls.BASE}/avatar-decoration-presets/{avatar_decoration}.png?size=96', + key=avatar_decoration, + animated=True, + ) + + @classmethod + def _from_icon(cls, state: _State, object_id: int, icon_hash: str, path: str) -> Self: + return cls( + state, + url=f'{cls.BASE}/{path}-icons/{object_id}/{icon_hash}.png?size=1024', + key=icon_hash, + animated=False, + ) + + @classmethod + def _from_app_icon( + cls, state: _State, object_id: int, icon_hash: str, asset_type: Literal['icon', 'cover_image'] + ) -> Self: + return cls( + state, + url=f'{cls.BASE}/app-icons/{object_id}/{asset_type}.png?size=1024', + key=icon_hash, + animated=False, + ) + + @classmethod + def _from_cover_image(cls, state: _State, object_id: int, cover_image_hash: str) -> Self: + return cls( + state, + url=f'{cls.BASE}/app-assets/{object_id}/store/{cover_image_hash}.png?size=1024', + key=cover_image_hash, + animated=False, + ) + + @classmethod + def _from_scheduled_event_cover_image(cls, state: _State, scheduled_event_id: int, cover_image_hash: str) -> Self: + return cls( + state, + url=f'{cls.BASE}/guild-events/{scheduled_event_id}/{cover_image_hash}.png?size=1024', + key=cover_image_hash, + animated=False, + ) + + @classmethod + def _from_guild_image(cls, state: _State, guild_id: int, image: str, path: str) -> Self: + animated = image.startswith('a_') + format = 'gif' if animated else 'png' + return cls( + state, + url=f'{cls.BASE}/{path}/{guild_id}/{image}.{format}?size=1024', + key=image, + animated=animated, + ) + + @classmethod + def _from_guild_icon(cls, state: _State, guild_id: int, icon_hash: str) -> Self: + animated = icon_hash.startswith('a_') + format = 'gif' if animated else 'png' + return cls( + state, + url=f'{cls.BASE}/icons/{guild_id}/{icon_hash}.{format}?size=1024', + key=icon_hash, + animated=animated, + ) + + @classmethod + def _from_sticker_banner(cls, state: _State, banner: int) -> Self: + return cls( + state, + url=f'{cls.BASE}/app-assets/710982414301790216/store/{banner}.png', + key=str(banner), + animated=False, + ) + + @classmethod + def _from_user_banner(cls, state: _State, user_id: int, banner_hash: str) -> Self: + animated = banner_hash.startswith('a_') + format = 'gif' if animated else 'png' + return cls( + state, + url=f'{cls.BASE}/banners/{user_id}/{banner_hash}.{format}?size=512', + key=banner_hash, + animated=animated, + ) + + def __str__(self) -> str: + return self._url + + def __len__(self) -> int: + return len(self._url) + + def __repr__(self) -> str: + shorten = self._url.replace(self.BASE, '') + return f'' + + def __eq__(self, other: object) -> bool: + return isinstance(other, Asset) and self._url == other._url + + def __hash__(self) -> int: + return hash(self._url) + + @property + def url(self) -> str: + """:class:`str`: Returns the underlying URL of the asset.""" + return self._url + + @property + def key(self) -> str: + """:class:`str`: Returns the identifying key of the asset.""" + return self._key + + def is_animated(self) -> bool: + """:class:`bool`: Returns whether the asset is animated.""" + return self._animated + + def replace( + self, + *, + size: int = MISSING, + format: ValidAssetFormatTypes = MISSING, + static_format: ValidStaticFormatTypes = MISSING, + ) -> Self: + """Returns a new asset with the passed components replaced. + + + .. versionchanged:: 2.0 + ``static_format`` is now preferred over ``format`` + if both are present and the asset is not animated. + + .. versionchanged:: 2.0 + This function will now raise :exc:`ValueError` instead of + ``InvalidArgument``. + + Parameters + ----------- + size: :class:`int` + The new size of the asset. + format: :class:`str` + The new format to change it to. Must be either + 'webp', 'jpeg', 'jpg', 'png', or 'gif' if it's animated. + static_format: :class:`str` + The new format to change it to if the asset isn't animated. + Must be either 'webp', 'jpeg', 'jpg', or 'png'. + + Raises + ------- + ValueError + An invalid size or format was passed. + + Returns + -------- + :class:`Asset` + The newly updated asset. + """ + url = yarl.URL(self._url) + path, _ = os.path.splitext(url.path) + + if format is not MISSING: + if self._animated: + if format not in VALID_ASSET_FORMATS: + raise ValueError(f'format must be one of {VALID_ASSET_FORMATS}') + else: + if static_format is MISSING and format not in VALID_STATIC_FORMATS: + raise ValueError(f'format must be one of {VALID_STATIC_FORMATS}') + url = url.with_path(f'{path}.{format}') + + if static_format is not MISSING and not self._animated: + if static_format not in VALID_STATIC_FORMATS: + raise ValueError(f'static_format must be one of {VALID_STATIC_FORMATS}') + url = url.with_path(f'{path}.{static_format}') + + if size is not MISSING: + if not utils.valid_icon_size(size): + raise ValueError('size must be a power of 2 between 16 and 4096') + url = url.with_query(size=size) + else: + url = url.with_query(url.raw_query_string) + + url = str(url) + return self.__class__(state=self._state, url=url, key=self._key, animated=self._animated) + + def with_size(self, size: int, /) -> Self: + """Returns a new asset with the specified size. + + .. versionchanged:: 2.0 + This function will now raise :exc:`ValueError` instead of + ``InvalidArgument``. + + Parameters + ------------ + size: :class:`int` + The new size of the asset. + + Raises + ------- + ValueError + The asset had an invalid size. + + Returns + -------- + :class:`Asset` + The new updated asset. + """ + if not utils.valid_icon_size(size): + raise ValueError('size must be a power of 2 between 16 and 4096') + + url = str(yarl.URL(self._url).with_query(size=size)) + return self.__class__(state=self._state, url=url, key=self._key, animated=self._animated) + + def with_format(self, format: ValidAssetFormatTypes, /) -> Self: + """Returns a new asset with the specified format. + + .. versionchanged:: 2.0 + This function will now raise :exc:`ValueError` instead of + ``InvalidArgument``. + + Parameters + ------------ + format: :class:`str` + The new format of the asset. + + Raises + ------- + ValueError + The asset had an invalid format. + + Returns + -------- + :class:`Asset` + The new updated asset. + """ + + if self._animated: + if format not in VALID_ASSET_FORMATS: + raise ValueError(f'format must be one of {VALID_ASSET_FORMATS}') + else: + if format not in VALID_STATIC_FORMATS: + raise ValueError(f'format must be one of {VALID_STATIC_FORMATS}') + + url = yarl.URL(self._url) + path, _ = os.path.splitext(url.path) + url = str(url.with_path(f'{path}.{format}').with_query(url.raw_query_string)) + return self.__class__(state=self._state, url=url, key=self._key, animated=self._animated) + + def with_static_format(self, format: ValidStaticFormatTypes, /) -> Self: + """Returns a new asset with the specified static format. + + This only changes the format if the underlying asset is + not animated. Otherwise, the asset is not changed. + + .. versionchanged:: 2.0 + This function will now raise :exc:`ValueError` instead of + ``InvalidArgument``. + + Parameters + ------------ + format: :class:`str` + The new static format of the asset. + + Raises + ------- + ValueError + The asset had an invalid format. + + Returns + -------- + :class:`Asset` + The new updated asset. + """ + + if self._animated: + return self + return self.with_format(format) diff --git a/venv/lib/python3.12/site-packages/discord/audit_logs.py b/venv/lib/python3.12/site-packages/discord/audit_logs.py new file mode 100644 index 00000000..af67855d --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/audit_logs.py @@ -0,0 +1,938 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, Any, Callable, ClassVar, Mapping, Generator, List, Optional, Tuple, Type, TypeVar, Union + +from . import enums, flags, utils +from .asset import Asset +from .colour import Colour +from .invite import Invite +from .mixins import Hashable +from .object import Object +from .permissions import PermissionOverwrite, Permissions +from .automod import AutoModTrigger, AutoModRuleAction, AutoModRule +from .role import Role +from .emoji import Emoji +from .partial_emoji import PartialEmoji +from .member import Member +from .scheduled_event import ScheduledEvent +from .stage_instance import StageInstance +from .sticker import GuildSticker +from .threads import Thread +from .integrations import PartialIntegration +from .channel import ForumChannel, StageChannel, ForumTag + +__all__ = ( + 'AuditLogDiff', + 'AuditLogChanges', + 'AuditLogEntry', +) + + +if TYPE_CHECKING: + import datetime + + from . import abc + from .guild import Guild + from .state import ConnectionState + from .types.audit_log import ( + AuditLogChange as AuditLogChangePayload, + AuditLogEntry as AuditLogEntryPayload, + _AuditLogChange_TriggerMetadata as AuditLogChangeTriggerMetadataPayload, + ) + from .types.channel import ( + PermissionOverwrite as PermissionOverwritePayload, + ForumTag as ForumTagPayload, + DefaultReaction as DefaultReactionPayload, + ) + from .types.invite import Invite as InvitePayload + from .types.role import Role as RolePayload + from .types.snowflake import Snowflake + from .types.command import ApplicationCommandPermissions + from .types.automod import AutoModerationAction + from .user import User + from .app_commands import AppCommand + from .webhook import Webhook + + TargetType = Union[ + Guild, + abc.GuildChannel, + Member, + User, + Role, + Invite, + Emoji, + StageInstance, + GuildSticker, + Thread, + Object, + PartialIntegration, + AutoModRule, + ScheduledEvent, + Webhook, + AppCommand, + None, + ] + + +def _transform_timestamp(entry: AuditLogEntry, data: Optional[str]) -> Optional[datetime.datetime]: + return utils.parse_time(data) + + +def _transform_color(entry: AuditLogEntry, data: int) -> Colour: + return Colour(data) + + +def _transform_snowflake(entry: AuditLogEntry, data: Snowflake) -> int: + return int(data) + + +def _transform_channel(entry: AuditLogEntry, data: Optional[Snowflake]) -> Optional[Union[abc.GuildChannel, Object]]: + if data is None: + return None + return entry.guild.get_channel(int(data)) or Object(id=data) + + +def _transform_channels_or_threads( + entry: AuditLogEntry, data: List[Snowflake] +) -> List[Union[abc.GuildChannel, Thread, Object]]: + return [entry.guild.get_channel_or_thread(int(data)) or Object(id=data) for data in data] + + +def _transform_member_id(entry: AuditLogEntry, data: Optional[Snowflake]) -> Union[Member, User, None]: + if data is None: + return None + return entry._get_member(int(data)) + + +def _transform_guild_id(entry: AuditLogEntry, data: Optional[Snowflake]) -> Optional[Guild]: + if data is None: + return None + return entry._state._get_guild(int(data)) + + +def _transform_roles(entry: AuditLogEntry, data: List[Snowflake]) -> List[Union[Role, Object]]: + return [entry.guild.get_role(int(role_id)) or Object(role_id, type=Role) for role_id in data] + + +def _transform_applied_forum_tags(entry: AuditLogEntry, data: List[Snowflake]) -> List[Union[ForumTag, Object]]: + thread = entry.target + if isinstance(thread, Thread) and isinstance(thread.parent, ForumChannel): + return [thread.parent.get_tag(tag_id) or Object(id=tag_id, type=ForumTag) for tag_id in map(int, data)] + return [Object(id=tag_id, type=ForumTag) for tag_id in data] + + +def _transform_overloaded_flags(entry: AuditLogEntry, data: int) -> Union[int, flags.ChannelFlags]: + # The `flags` key is definitely overloaded. Right now it's for channels and threads but + # I am aware of `member.flags` and `user.flags` existing. However, this does not impact audit logs + # at the moment but better safe than sorry. + channel_audit_log_types = ( + enums.AuditLogAction.channel_create, + enums.AuditLogAction.channel_update, + enums.AuditLogAction.channel_delete, + enums.AuditLogAction.thread_create, + enums.AuditLogAction.thread_update, + enums.AuditLogAction.thread_delete, + ) + + if entry.action in channel_audit_log_types: + return flags.ChannelFlags._from_value(data) + return data + + +def _transform_forum_tags(entry: AuditLogEntry, data: List[ForumTagPayload]) -> List[ForumTag]: + return [ForumTag.from_data(state=entry._state, data=d) for d in data] + + +def _transform_default_reaction(entry: AuditLogEntry, data: DefaultReactionPayload) -> Optional[PartialEmoji]: + if data is None: + return None + + emoji_name = data.get('emoji_name') or '' + emoji_id = utils._get_as_snowflake(data, 'emoji_id') or None # Coerce 0 -> None + return PartialEmoji.with_state(state=entry._state, name=emoji_name, id=emoji_id) + + +def _transform_overwrites( + entry: AuditLogEntry, data: List[PermissionOverwritePayload] +) -> List[Tuple[Object, PermissionOverwrite]]: + overwrites = [] + for elem in data: + allow = Permissions(int(elem['allow'])) + deny = Permissions(int(elem['deny'])) + ow = PermissionOverwrite.from_pair(allow, deny) + + ow_type = elem['type'] + ow_id = int(elem['id']) + target = None + if ow_type == '0': + target = entry.guild.get_role(ow_id) + elif ow_type == '1': + target = entry._get_member(ow_id) + + if target is None: + target = Object(id=ow_id, type=Role if ow_type == '0' else Member) + + overwrites.append((target, ow)) + + return overwrites + + +def _transform_icon(entry: AuditLogEntry, data: Optional[str]) -> Optional[Asset]: + if data is None: + return None + if entry.action is enums.AuditLogAction.guild_update: + return Asset._from_guild_icon(entry._state, entry.guild.id, data) + else: + return Asset._from_icon(entry._state, entry._target_id, data, path='role') # type: ignore # target_id won't be None in this case + + +def _transform_avatar(entry: AuditLogEntry, data: Optional[str]) -> Optional[Asset]: + if data is None: + return None + return Asset._from_avatar(entry._state, entry._target_id, data) # type: ignore # target_id won't be None in this case + + +def _transform_cover_image(entry: AuditLogEntry, data: Optional[str]) -> Optional[Asset]: + if data is None: + return None + return Asset._from_scheduled_event_cover_image(entry._state, entry._target_id, data) # type: ignore # target_id won't be None in this case + + +def _guild_hash_transformer(path: str) -> Callable[[AuditLogEntry, Optional[str]], Optional[Asset]]: + def _transform(entry: AuditLogEntry, data: Optional[str]) -> Optional[Asset]: + if data is None: + return None + return Asset._from_guild_image(entry._state, entry.guild.id, data, path=path) + + return _transform + + +def _transform_automod_actions(entry: AuditLogEntry, data: List[AutoModerationAction]) -> List[AutoModRuleAction]: + return [AutoModRuleAction.from_data(action) for action in data] + + +def _transform_default_emoji(entry: AuditLogEntry, data: str) -> PartialEmoji: + return PartialEmoji(name=data) + + +E = TypeVar('E', bound=enums.Enum) + + +def _enum_transformer(enum: Type[E]) -> Callable[[AuditLogEntry, int], E]: + def _transform(entry: AuditLogEntry, data: int) -> E: + return enums.try_enum(enum, data) + + return _transform + + +F = TypeVar('F', bound=flags.BaseFlags) + + +def _flag_transformer(cls: Type[F]) -> Callable[[AuditLogEntry, Union[int, str]], F]: + def _transform(entry: AuditLogEntry, data: Union[int, str]) -> F: + return cls._from_value(int(data)) + + return _transform + + +def _transform_type( + entry: AuditLogEntry, data: Union[int, str] +) -> Union[enums.ChannelType, enums.StickerType, enums.WebhookType, str]: + if entry.action.name.startswith('sticker_'): + return enums.try_enum(enums.StickerType, data) + elif entry.action.name.startswith('integration_'): + return data # type: ignore # integration type is str + elif entry.action.name.startswith('webhook_'): + return enums.try_enum(enums.WebhookType, data) + else: + return enums.try_enum(enums.ChannelType, data) + + +class AuditLogDiff: + def __len__(self) -> int: + return len(self.__dict__) + + def __iter__(self) -> Generator[Tuple[str, Any], None, None]: + yield from self.__dict__.items() + + def __repr__(self) -> str: + values = ' '.join('%s=%r' % item for item in self.__dict__.items()) + return f'' + + if TYPE_CHECKING: + + def __getattr__(self, item: str) -> Any: + ... + + def __setattr__(self, key: str, value: Any) -> Any: + ... + + +Transformer = Callable[["AuditLogEntry", Any], Any] + + +class AuditLogChanges: + # fmt: off + TRANSFORMERS: ClassVar[Mapping[str, Tuple[Optional[str], Optional[Transformer]]]] = { + 'verification_level': (None, _enum_transformer(enums.VerificationLevel)), + 'explicit_content_filter': (None, _enum_transformer(enums.ContentFilter)), + 'allow': (None, _flag_transformer(Permissions)), + 'deny': (None, _flag_transformer(Permissions)), + 'permissions': (None, _flag_transformer(Permissions)), + 'id': (None, _transform_snowflake), + 'color': ('colour', _transform_color), + 'owner_id': ('owner', _transform_member_id), + 'inviter_id': ('inviter', _transform_member_id), + 'channel_id': ('channel', _transform_channel), + 'afk_channel_id': ('afk_channel', _transform_channel), + 'system_channel_id': ('system_channel', _transform_channel), + 'system_channel_flags': (None, _flag_transformer(flags.SystemChannelFlags)), + 'widget_channel_id': ('widget_channel', _transform_channel), + 'rules_channel_id': ('rules_channel', _transform_channel), + 'public_updates_channel_id': ('public_updates_channel', _transform_channel), + 'permission_overwrites': ('overwrites', _transform_overwrites), + 'splash_hash': ('splash', _guild_hash_transformer('splashes')), + 'banner_hash': ('banner', _guild_hash_transformer('banners')), + 'discovery_splash_hash': ('discovery_splash', _guild_hash_transformer('discovery-splashes')), + 'icon_hash': ('icon', _transform_icon), + 'avatar_hash': ('avatar', _transform_avatar), + 'rate_limit_per_user': ('slowmode_delay', None), + 'default_thread_rate_limit_per_user': ('default_thread_slowmode_delay', None), + 'guild_id': ('guild', _transform_guild_id), + 'tags': ('emoji', None), + 'default_message_notifications': ('default_notifications', _enum_transformer(enums.NotificationLevel)), + 'video_quality_mode': (None, _enum_transformer(enums.VideoQualityMode)), + 'privacy_level': (None, _enum_transformer(enums.PrivacyLevel)), + 'format_type': (None, _enum_transformer(enums.StickerFormatType)), + 'type': (None, _transform_type), + 'communication_disabled_until': ('timed_out_until', _transform_timestamp), + 'expire_behavior': (None, _enum_transformer(enums.ExpireBehaviour)), + 'mfa_level': (None, _enum_transformer(enums.MFALevel)), + 'status': (None, _enum_transformer(enums.EventStatus)), + 'entity_type': (None, _enum_transformer(enums.EntityType)), + 'preferred_locale': (None, _enum_transformer(enums.Locale)), + 'image_hash': ('cover_image', _transform_cover_image), + 'trigger_type': (None, _enum_transformer(enums.AutoModRuleTriggerType)), + 'event_type': (None, _enum_transformer(enums.AutoModRuleEventType)), + 'actions': (None, _transform_automod_actions), + 'exempt_channels': (None, _transform_channels_or_threads), + 'exempt_roles': (None, _transform_roles), + 'applied_tags': (None, _transform_applied_forum_tags), + 'available_tags': (None, _transform_forum_tags), + 'flags': (None, _transform_overloaded_flags), + 'default_reaction_emoji': (None, _transform_default_reaction), + 'emoji_name': ('emoji', _transform_default_emoji), + 'user_id': ('user', _transform_member_id) + } + # fmt: on + + def __init__(self, entry: AuditLogEntry, data: List[AuditLogChangePayload]): + self.before: AuditLogDiff = AuditLogDiff() + self.after: AuditLogDiff = AuditLogDiff() + # special case entire process since each + # element in data is a different target + # key is the target id + if entry.action is enums.AuditLogAction.app_command_permission_update: + self.before.app_command_permissions = [] + self.after.app_command_permissions = [] + + for elem in data: + self._handle_app_command_permissions( + self.before, + entry, + elem.get('old_value'), # type: ignore # value will be an ApplicationCommandPermissions if present + ) + + self._handle_app_command_permissions( + self.after, + entry, + elem.get('new_value'), # type: ignore # value will be an ApplicationCommandPermissions if present + ) + return + + for elem in data: + attr = elem['key'] + + # special cases for role add/remove + if attr == '$add': + self._handle_role(self.before, self.after, entry, elem['new_value']) # type: ignore # new_value is a list of roles in this case + continue + elif attr == '$remove': + self._handle_role(self.after, self.before, entry, elem['new_value']) # type: ignore # new_value is a list of roles in this case + continue + + # special case for automod trigger + if attr == 'trigger_metadata': + # given full metadata dict + self._handle_trigger_metadata(entry, elem, data) # type: ignore # should be trigger metadata + continue + elif entry.action is enums.AuditLogAction.automod_rule_update and attr.startswith('$'): + # on update, some trigger attributes are keys and formatted as $(add/remove)_{attribute} + action, _, trigger_attr = attr.partition('_') + # new_value should be a list of added/removed strings for keyword_filter, regex_patterns, or allow_list + if action == '$add': + self._handle_trigger_attr_update(self.before, self.after, entry, trigger_attr, elem['new_value']) # type: ignore + elif action == '$remove': + self._handle_trigger_attr_update(self.after, self.before, entry, trigger_attr, elem['new_value']) # type: ignore + continue + + try: + key, transformer = self.TRANSFORMERS[attr] + except (ValueError, KeyError): + transformer = None + else: + if key: + attr = key + + transformer: Optional[Transformer] + + try: + before = elem['old_value'] + except KeyError: + before = None + else: + if transformer: + before = transformer(entry, before) + + setattr(self.before, attr, before) + + try: + after = elem['new_value'] + except KeyError: + after = None + else: + if transformer: + after = transformer(entry, after) + + setattr(self.after, attr, after) + + # add an alias + if hasattr(self.after, 'colour'): + self.after.color = self.after.colour + self.before.color = self.before.colour + if hasattr(self.after, 'expire_behavior'): + self.after.expire_behaviour = self.after.expire_behavior + self.before.expire_behaviour = self.before.expire_behavior + + def __repr__(self) -> str: + return f'' + + def _handle_role(self, first: AuditLogDiff, second: AuditLogDiff, entry: AuditLogEntry, elem: List[RolePayload]) -> None: + if not hasattr(first, 'roles'): + setattr(first, 'roles', []) + + data = [] + g: Guild = entry.guild + + for e in elem: + role_id = int(e['id']) + role = g.get_role(role_id) + + if role is None: + role = Object(id=role_id, type=Role) + role.name = e['name'] # type: ignore # Object doesn't usually have name + + data.append(role) + + setattr(second, 'roles', data) + + def _handle_app_command_permissions( + self, + diff: AuditLogDiff, + entry: AuditLogEntry, + data: Optional[ApplicationCommandPermissions], + ): + if data is None: + return + + # avoid circular import + from discord.app_commands import AppCommandPermissions + + state = entry._state + guild = entry.guild + diff.app_command_permissions.append(AppCommandPermissions(data=data, guild=guild, state=state)) + + def _handle_trigger_metadata( + self, + entry: AuditLogEntry, + data: AuditLogChangeTriggerMetadataPayload, + full_data: List[AuditLogChangePayload], + ): + trigger_value: Optional[int] = None + trigger_type: Optional[enums.AutoModRuleTriggerType] = None + + # try to get trigger type from before or after + trigger_type = getattr(self.before, 'trigger_type', getattr(self.after, 'trigger_type', None)) + + if trigger_type is None: + if isinstance(entry.target, AutoModRule): + # Trigger type cannot be changed, so it should be the same before and after updates. + # Avoids checking which keys are in data to guess trigger type + trigger_value = entry.target.trigger.type.value + else: + # found a trigger type from before or after + trigger_value = trigger_type.value + + if trigger_value is None: + # try to find trigger type in the full list of changes + _elem = utils.find(lambda elem: elem['key'] == 'trigger_type', full_data) + if _elem is not None: + trigger_value = _elem.get('old_value', _elem.get('new_value')) # type: ignore # trigger type values should be int + + if trigger_value is None: + # try to infer trigger_type from the keys in old or new value + combined = (data.get('old_value') or {}).keys() | (data.get('new_value') or {}).keys() + if not combined: + trigger_value = enums.AutoModRuleTriggerType.spam.value + elif 'presets' in combined: + trigger_value = enums.AutoModRuleTriggerType.keyword_preset.value + elif 'keyword_filter' in combined or 'regex_patterns' in combined: + trigger_value = enums.AutoModRuleTriggerType.keyword.value + elif 'mention_total_limit' in combined or 'mention_raid_protection_enabled' in combined: + trigger_value = enums.AutoModRuleTriggerType.mention_spam.value + else: + # some unknown type + trigger_value = -1 + + self.before.trigger = AutoModTrigger.from_data(trigger_value, data.get('old_value')) + self.after.trigger = AutoModTrigger.from_data(trigger_value, data.get('new_value')) + + def _handle_trigger_attr_update( + self, first: AuditLogDiff, second: AuditLogDiff, entry: AuditLogEntry, attr: str, data: List[str] + ): + self._create_trigger(first, entry) + trigger = self._create_trigger(second, entry) + try: + # guard unexpecte non list attributes or non iterable data + getattr(trigger, attr).extend(data) + except (AttributeError, TypeError): + pass + + def _create_trigger(self, diff: AuditLogDiff, entry: AuditLogEntry) -> AutoModTrigger: + # check if trigger has already been created + if not hasattr(diff, 'trigger'): + # create a trigger + if isinstance(entry.target, AutoModRule): + # get trigger type from the automod rule + trigger_type = entry.target.trigger.type + else: + # unknown trigger type + trigger_type = enums.try_enum(enums.AutoModRuleTriggerType, -1) + + diff.trigger = AutoModTrigger(type=trigger_type) + return diff.trigger + + +class _AuditLogProxy: + def __init__(self, **kwargs: Any) -> None: + for k, v in kwargs.items(): + setattr(self, k, v) + + +class _AuditLogProxyMemberPrune(_AuditLogProxy): + delete_member_days: int + members_removed: int + + +class _AuditLogProxyMemberMoveOrMessageDelete(_AuditLogProxy): + channel: Union[abc.GuildChannel, Thread] + count: int + + +class _AuditLogProxyMemberDisconnect(_AuditLogProxy): + count: int + + +class _AuditLogProxyPinAction(_AuditLogProxy): + channel: Union[abc.GuildChannel, Thread] + message_id: int + + +class _AuditLogProxyStageInstanceAction(_AuditLogProxy): + channel: abc.GuildChannel + + +class _AuditLogProxyMessageBulkDelete(_AuditLogProxy): + count: int + + +class _AuditLogProxyAutoModAction(_AuditLogProxy): + automod_rule_name: str + automod_rule_trigger_type: str + channel: Optional[Union[abc.GuildChannel, Thread]] + + +class _AuditLogProxyMemberKickOrMemberRoleUpdate(_AuditLogProxy): + integration_type: Optional[str] + + +class AuditLogEntry(Hashable): + r"""Represents an Audit Log entry. + + You retrieve these via :meth:`Guild.audit_logs`. + + .. container:: operations + + .. describe:: x == y + + Checks if two entries are equal. + + .. describe:: x != y + + Checks if two entries are not equal. + + .. describe:: hash(x) + + Returns the entry's hash. + + .. versionchanged:: 1.7 + Audit log entries are now comparable and hashable. + + Attributes + ----------- + action: :class:`AuditLogAction` + The action that was done. + user: Optional[:class:`abc.User`] + The user who initiated this action. Usually a :class:`Member`\, unless gone + then it's a :class:`User`. + user_id: Optional[:class:`int`] + The user ID who initiated this action. + + .. versionadded:: 2.2 + id: :class:`int` + The entry ID. + guild: :class:`Guild` + The guild that this entry belongs to. + target: Any + The target that got changed. The exact type of this depends on + the action being done. + reason: Optional[:class:`str`] + The reason this action was done. + extra: Any + Extra information that this entry has that might be useful. + For most actions, this is ``None``. However in some cases it + contains extra information. See :class:`AuditLogAction` for + which actions have this field filled out. + """ + + def __init__( + self, + *, + users: Mapping[int, User], + integrations: Mapping[int, PartialIntegration], + app_commands: Mapping[int, AppCommand], + automod_rules: Mapping[int, AutoModRule], + webhooks: Mapping[int, Webhook], + data: AuditLogEntryPayload, + guild: Guild, + ): + self._state: ConnectionState = guild._state + self.guild: Guild = guild + self._users: Mapping[int, User] = users + self._integrations: Mapping[int, PartialIntegration] = integrations + self._app_commands: Mapping[int, AppCommand] = app_commands + self._automod_rules: Mapping[int, AutoModRule] = automod_rules + self._webhooks: Mapping[int, Webhook] = webhooks + self._from_data(data) + + def _from_data(self, data: AuditLogEntryPayload) -> None: + self.action: enums.AuditLogAction = enums.try_enum(enums.AuditLogAction, data['action_type']) + self.id: int = int(data['id']) + + # this key is technically not usually present + self.reason: Optional[str] = data.get('reason') + extra = data.get('options') + + # fmt: off + self.extra: Union[ + _AuditLogProxyMemberPrune, + _AuditLogProxyMemberMoveOrMessageDelete, + _AuditLogProxyMemberDisconnect, + _AuditLogProxyPinAction, + _AuditLogProxyStageInstanceAction, + _AuditLogProxyMessageBulkDelete, + _AuditLogProxyAutoModAction, + _AuditLogProxyMemberKickOrMemberRoleUpdate, + Member, User, None, PartialIntegration, + Role, Object + ] = None + # fmt: on + + if isinstance(self.action, enums.AuditLogAction) and extra: + if self.action is enums.AuditLogAction.member_prune: + # member prune has two keys with useful information + self.extra = _AuditLogProxyMemberPrune( + delete_member_days=int(extra['delete_member_days']), + members_removed=int(extra['members_removed']), + ) + elif self.action is enums.AuditLogAction.member_move or self.action is enums.AuditLogAction.message_delete: + channel_id = int(extra['channel_id']) + self.extra = _AuditLogProxyMemberMoveOrMessageDelete( + count=int(extra['count']), + channel=self.guild.get_channel_or_thread(channel_id) or Object(id=channel_id), + ) + elif self.action is enums.AuditLogAction.member_disconnect: + # The member disconnect action has a dict with some information + self.extra = _AuditLogProxyMemberDisconnect(count=int(extra['count'])) + elif self.action is enums.AuditLogAction.message_bulk_delete: + # The bulk message delete action has the number of messages deleted + self.extra = _AuditLogProxyMessageBulkDelete(count=int(extra['count'])) + elif self.action in (enums.AuditLogAction.kick, enums.AuditLogAction.member_role_update): + # The member kick action has a dict with some information + integration_type = extra.get('integration_type') + self.extra = _AuditLogProxyMemberKickOrMemberRoleUpdate(integration_type=integration_type) + elif self.action.name.endswith('pin'): + # the pin actions have a dict with some information + channel_id = int(extra['channel_id']) + self.extra = _AuditLogProxyPinAction( + channel=self.guild.get_channel_or_thread(channel_id) or Object(id=channel_id), + message_id=int(extra['message_id']), + ) + elif ( + self.action is enums.AuditLogAction.automod_block_message + or self.action is enums.AuditLogAction.automod_flag_message + or self.action is enums.AuditLogAction.automod_timeout_member + ): + channel_id = utils._get_as_snowflake(extra, 'channel_id') + channel = None + + # May be an empty string instead of None due to a Discord issue + if channel_id: + channel = self.guild.get_channel_or_thread(channel_id) or Object(id=channel_id) + + self.extra = _AuditLogProxyAutoModAction( + automod_rule_name=extra['auto_moderation_rule_name'], + automod_rule_trigger_type=enums.try_enum( + enums.AutoModRuleTriggerType, extra['auto_moderation_rule_trigger_type'] + ), + channel=channel, + ) + + elif self.action.name.startswith('overwrite_'): + # the overwrite_ actions have a dict with some information + instance_id = int(extra['id']) + the_type = extra.get('type') + if the_type == '1': + self.extra = self._get_member(instance_id) + elif the_type == '0': + role = self.guild.get_role(instance_id) + if role is None: + role = Object(id=instance_id, type=Role) + role.name = extra.get('role_name') # type: ignore # Object doesn't usually have name + self.extra = role + elif self.action.name.startswith('stage_instance'): + channel_id = int(extra['channel_id']) + self.extra = _AuditLogProxyStageInstanceAction( + channel=self.guild.get_channel(channel_id) or Object(id=channel_id, type=StageChannel) + ) + elif self.action.name.startswith('app_command'): + app_id = int(extra['application_id']) + self.extra = self._get_integration_by_app_id(app_id) or Object(app_id, type=PartialIntegration) + + # this key is not present when the above is present, typically. + # It's a list of { new_value: a, old_value: b, key: c } + # where new_value and old_value are not guaranteed to be there depending + # on the action type, so let's just fetch it for now and only turn it + # into meaningful data when requested + self._changes = data.get('changes', []) + + self.user_id: Optional[int] = utils._get_as_snowflake(data, 'user_id') + self.user: Optional[Union[User, Member]] = self._get_member(self.user_id) + self._target_id = utils._get_as_snowflake(data, 'target_id') + + def _get_member(self, user_id: Optional[int]) -> Union[Member, User, None]: + if user_id is None: + return None + + return self.guild.get_member(user_id) or self._users.get(user_id) + + def _get_integration(self, integration_id: Optional[int]) -> Optional[PartialIntegration]: + if integration_id is None: + return None + + return self._integrations.get(integration_id) + + def _get_integration_by_app_id(self, application_id: Optional[int]) -> Optional[PartialIntegration]: + if application_id is None: + return None + + # get PartialIntegration by application id + return utils.get(self._integrations.values(), application_id=application_id) + + def _get_app_command(self, app_command_id: Optional[int]) -> Optional[AppCommand]: + if app_command_id is None: + return None + + return self._app_commands.get(app_command_id) + + def __repr__(self) -> str: + return f'' + + @utils.cached_property + def created_at(self) -> datetime.datetime: + """:class:`datetime.datetime`: Returns the entry's creation time in UTC.""" + return utils.snowflake_time(self.id) + + @utils.cached_property + def target(self) -> TargetType: + if self.action.target_type is None: + return None + + try: + converter = getattr(self, '_convert_target_' + self.action.target_type) + except AttributeError: + if self._target_id is None: + return None + return Object(id=self._target_id) + else: + return converter(self._target_id) + + @utils.cached_property + def category(self) -> Optional[enums.AuditLogActionCategory]: + """Optional[:class:`AuditLogActionCategory`]: The category of the action, if applicable.""" + return self.action.category + + @utils.cached_property + def changes(self) -> AuditLogChanges: + """:class:`AuditLogChanges`: The list of changes this entry has.""" + obj = AuditLogChanges(self, self._changes) + del self._changes + return obj + + @utils.cached_property + def before(self) -> AuditLogDiff: + """:class:`AuditLogDiff`: The target's prior state.""" + return self.changes.before + + @utils.cached_property + def after(self) -> AuditLogDiff: + """:class:`AuditLogDiff`: The target's subsequent state.""" + return self.changes.after + + def _convert_target_guild(self, target_id: int) -> Guild: + return self.guild + + def _convert_target_channel(self, target_id: int) -> Union[abc.GuildChannel, Object]: + return self.guild.get_channel(target_id) or Object(id=target_id) + + def _convert_target_user(self, target_id: Optional[int]) -> Optional[Union[Member, User, Object]]: + # For some reason the member_disconnect and member_move action types + # do not have a non-null target_id so safeguard against that + if target_id is None: + return None + + return self._get_member(target_id) or Object(id=target_id, type=Member) + + def _convert_target_role(self, target_id: int) -> Union[Role, Object]: + return self.guild.get_role(target_id) or Object(id=target_id, type=Role) + + def _convert_target_invite(self, target_id: None) -> Invite: + # invites have target_id set to null + # so figure out which change has the full invite data + changeset = self.before if self.action is enums.AuditLogAction.invite_delete else self.after + + fake_payload: InvitePayload = { + 'max_age': changeset.max_age, + 'max_uses': changeset.max_uses, + 'code': changeset.code, + 'temporary': changeset.temporary, + 'uses': changeset.uses, + 'channel': None, # type: ignore # the channel is passed to the Invite constructor directly + } + + obj = Invite(state=self._state, data=fake_payload, guild=self.guild, channel=changeset.channel) + try: + obj.inviter = changeset.inviter + except AttributeError: + pass + return obj + + def _convert_target_emoji(self, target_id: int) -> Union[Emoji, Object]: + return self._state.get_emoji(target_id) or Object(id=target_id, type=Emoji) + + def _convert_target_message(self, target_id: Optional[int]) -> Optional[Union[Member, User, Object]]: + # The message_pin and message_unpin action types do not have a + # non-null target_id so safeguard against that + + if target_id is None: + return None + + return self._get_member(target_id) or Object(id=target_id, type=Member) + + def _convert_target_stage_instance(self, target_id: int) -> Union[StageInstance, Object]: + return self.guild.get_stage_instance(target_id) or Object(id=target_id, type=StageInstance) + + def _convert_target_sticker(self, target_id: int) -> Union[GuildSticker, Object]: + return self._state.get_sticker(target_id) or Object(id=target_id, type=GuildSticker) + + def _convert_target_thread(self, target_id: int) -> Union[Thread, Object]: + return self.guild.get_thread(target_id) or Object(id=target_id, type=Thread) + + def _convert_target_guild_scheduled_event(self, target_id: int) -> Union[ScheduledEvent, Object]: + return self.guild.get_scheduled_event(target_id) or Object(id=target_id, type=ScheduledEvent) + + def _convert_target_integration(self, target_id: int) -> Union[PartialIntegration, Object]: + return self._get_integration(target_id) or Object(target_id, type=PartialIntegration) + + def _convert_target_app_command(self, target_id: int) -> Union[AppCommand, Object]: + target = self._get_app_command(target_id) + if not target: + # circular import + from .app_commands import AppCommand + + target = Object(target_id, type=AppCommand) + + return target + + def _convert_target_integration_or_app_command(self, target_id: int) -> Union[PartialIntegration, AppCommand, Object]: + target = self._get_integration_by_app_id(target_id) or self._get_app_command(target_id) + if not target: + try: + # circular import + from .app_commands import AppCommand + + # get application id from extras + # if it matches target id, type should be integration + target_app = self.extra + # extra should be an Object or PartialIntegration + app_id = target_app.application_id if isinstance(target_app, PartialIntegration) else target_app.id # type: ignore + type = PartialIntegration if target_id == app_id else AppCommand + except AttributeError: + return Object(target_id) + else: + return Object(target_id, type=type) + + return target + + def _convert_target_auto_moderation(self, target_id: int) -> Union[AutoModRule, Object]: + return self._automod_rules.get(target_id) or Object(target_id, type=AutoModRule) + + def _convert_target_webhook(self, target_id: int) -> Union[Webhook, Object]: + # circular import + from .webhook import Webhook + + return self._webhooks.get(target_id) or Object(target_id, type=Webhook) diff --git a/venv/lib/python3.12/site-packages/discord/automod.py b/venv/lib/python3.12/site-packages/discord/automod.py new file mode 100644 index 00000000..61683c26 --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/automod.py @@ -0,0 +1,672 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from __future__ import annotations +import datetime + +from typing import TYPE_CHECKING, Any, Dict, Optional, List, Set, Union, Sequence, overload, Literal + +from .enums import AutoModRuleTriggerType, AutoModRuleActionType, AutoModRuleEventType, try_enum +from .flags import AutoModPresets +from . import utils +from .utils import MISSING, cached_slot_property + +if TYPE_CHECKING: + from typing_extensions import Self + from .abc import Snowflake, GuildChannel + from .threads import Thread + from .guild import Guild + from .member import Member + from .state import ConnectionState + from .types.automod import ( + AutoModerationRule as AutoModerationRulePayload, + AutoModerationTriggerMetadata as AutoModerationTriggerMetadataPayload, + AutoModerationAction as AutoModerationActionPayload, + AutoModerationActionExecution as AutoModerationActionExecutionPayload, + ) + from .role import Role + +__all__ = ( + 'AutoModRuleAction', + 'AutoModTrigger', + 'AutoModRule', + 'AutoModAction', +) + + +class AutoModRuleAction: + """Represents an auto moderation's rule action. + + .. note:: + Only one of ``channel_id``, ``duration``, or ``custom_message`` can be used. + + .. versionadded:: 2.0 + + Attributes + ----------- + type: :class:`AutoModRuleActionType` + The type of action to take. + Defaults to :attr:`~AutoModRuleActionType.block_message`. + channel_id: Optional[:class:`int`] + The ID of the channel or thread to send the alert message to, if any. + Passing this sets :attr:`type` to :attr:`~AutoModRuleActionType.send_alert_message`. + duration: Optional[:class:`datetime.timedelta`] + The duration of the timeout to apply, if any. + Has a maximum of 28 days. + Passing this sets :attr:`type` to :attr:`~AutoModRuleActionType.timeout`. + custom_message: Optional[:class:`str`] + A custom message which will be shown to a user when their message is blocked. + Passing this sets :attr:`type` to :attr:`~AutoModRuleActionType.block_message`. + + .. versionadded:: 2.2 + """ + + __slots__ = ('type', 'channel_id', 'duration', 'custom_message') + + @overload + def __init__(self, *, channel_id: int = ...) -> None: + ... + + @overload + def __init__(self, *, type: Literal[AutoModRuleActionType.send_alert_message], channel_id: int = ...) -> None: + ... + + @overload + def __init__(self, *, duration: datetime.timedelta = ...) -> None: + ... + + @overload + def __init__(self, *, type: Literal[AutoModRuleActionType.timeout], duration: datetime.timedelta = ...) -> None: + ... + + @overload + def __init__(self, *, custom_message: str = ...) -> None: + ... + + @overload + def __init__(self, *, type: Literal[AutoModRuleActionType.block_message]) -> None: + ... + + @overload + def __init__(self, *, type: Literal[AutoModRuleActionType.block_message], custom_message: Optional[str] = ...) -> None: + ... + + @overload + def __init__( + self, + *, + type: Optional[AutoModRuleActionType] = ..., + channel_id: Optional[int] = ..., + duration: Optional[datetime.timedelta] = ..., + custom_message: Optional[str] = ..., + ) -> None: + ... + + def __init__( + self, + *, + type: Optional[AutoModRuleActionType] = None, + channel_id: Optional[int] = None, + duration: Optional[datetime.timedelta] = None, + custom_message: Optional[str] = None, + ) -> None: + if sum(v is None for v in (channel_id, duration, custom_message)) < 2: + raise ValueError('Only one of channel_id, duration, or custom_message can be passed.') + + self.type: AutoModRuleActionType + self.channel_id: Optional[int] = None + self.duration: Optional[datetime.timedelta] = None + self.custom_message: Optional[str] = None + + if type is not None: + self.type = type + elif channel_id is not None: + self.type = AutoModRuleActionType.send_alert_message + elif duration is not None: + self.type = AutoModRuleActionType.timeout + else: + self.type = AutoModRuleActionType.block_message + + if self.type is AutoModRuleActionType.send_alert_message: + if channel_id is None: + raise ValueError('channel_id cannot be None if type is send_alert_message') + self.channel_id = channel_id + + if self.type is AutoModRuleActionType.timeout: + if duration is None: + raise ValueError('duration cannot be None set if type is timeout') + self.duration = duration + + if self.type is AutoModRuleActionType.block_message: + self.custom_message = custom_message + + def __repr__(self) -> str: + return f'' + + @classmethod + def from_data(cls, data: AutoModerationActionPayload) -> Self: + if data['type'] == AutoModRuleActionType.timeout.value: + duration_seconds = data['metadata']['duration_seconds'] + return cls(duration=datetime.timedelta(seconds=duration_seconds)) + elif data['type'] == AutoModRuleActionType.send_alert_message.value: + channel_id = int(data['metadata']['channel_id']) + return cls(channel_id=channel_id) + elif data['type'] == AutoModRuleActionType.block_message.value: + custom_message = data.get('metadata', {}).get('custom_message') + return cls(type=AutoModRuleActionType.block_message, custom_message=custom_message) + + return cls(type=AutoModRuleActionType.block_member_interactions) + + def to_dict(self) -> Dict[str, Any]: + ret = {'type': self.type.value, 'metadata': {}} + if self.type is AutoModRuleActionType.block_message and self.custom_message is not None: + ret['metadata'] = {'custom_message': self.custom_message} + elif self.type is AutoModRuleActionType.timeout: + ret['metadata'] = {'duration_seconds': int(self.duration.total_seconds())} # type: ignore # duration cannot be None here + elif self.type is AutoModRuleActionType.send_alert_message: + ret['metadata'] = {'channel_id': str(self.channel_id)} + return ret + + +class AutoModTrigger: + r"""Represents a trigger for an auto moderation rule. + + The following table illustrates relevant attributes for each :class:`AutoModRuleTriggerType`: + + +-----------------------------------------------+------------------------------------------------+ + | Type | Attributes | + +===============================================+================================================+ + | :attr:`AutoModRuleTriggerType.keyword` | :attr:`keyword_filter`, :attr:`regex_patterns`,| + | | :attr:`allow_list` | + +-----------------------------------------------+------------------------------------------------+ + | :attr:`AutoModRuleTriggerType.spam` | | + +-----------------------------------------------+------------------------------------------------+ + | :attr:`AutoModRuleTriggerType.keyword_preset` | :attr:`presets`\, :attr:`allow_list` | + +-----------------------------------------------+------------------------------------------------+ + | :attr:`AutoModRuleTriggerType.mention_spam` | :attr:`mention_limit`, | + | | :attr:`mention_raid_protection` | + +-----------------------------------------------+------------------------------------------------+ + | :attr:`AutoModRuleTriggerType.member_profile` | :attr:`keyword_filter`, :attr:`regex_patterns`,| + | | :attr:`allow_list` | + +-----------------------------------------------+------------------------------------------------+ + + .. versionadded:: 2.0 + + Attributes + ----------- + type: :class:`AutoModRuleTriggerType` + The type of trigger. + keyword_filter: List[:class:`str`] + The list of strings that will trigger the filter. + Maximum of 1000. Keywords can only be up to 60 characters in length. + + This could be combined with :attr:`regex_patterns`. + regex_patterns: List[:class:`str`] + The regex pattern that will trigger the filter. The syntax is based off of + `Rust's regex syntax `_. + Maximum of 10. Regex strings can only be up to 260 characters in length. + + This could be combined with :attr:`keyword_filter` and/or :attr:`allow_list` + + .. versionadded:: 2.1 + presets: :class:`AutoModPresets` + The presets used with the preset keyword filter. + allow_list: List[:class:`str`] + The list of words that are exempt from the commonly flagged words. Maximum of 100. + Keywords can only be up to 60 characters in length. + mention_limit: :class:`int` + The total number of user and role mentions a message can contain. + Has a maximum of 50. + mention_raid_protection: :class:`bool` + Whether mention raid protection is enabled or not. + + .. versionadded:: 2.4 + """ + + __slots__ = ( + 'type', + 'keyword_filter', + 'presets', + 'allow_list', + 'mention_limit', + 'regex_patterns', + 'mention_raid_protection', + ) + + def __init__( + self, + *, + type: Optional[AutoModRuleTriggerType] = None, + keyword_filter: Optional[List[str]] = None, + presets: Optional[AutoModPresets] = None, + allow_list: Optional[List[str]] = None, + mention_limit: Optional[int] = None, + regex_patterns: Optional[List[str]] = None, + mention_raid_protection: Optional[bool] = None, + ) -> None: + unique_args = (keyword_filter or regex_patterns, presets, mention_limit or mention_raid_protection) + if type is None and sum(arg is not None for arg in unique_args) > 1: + raise ValueError( + 'Please pass only one of keyword_filter/regex_patterns, presets, or mention_limit/mention_raid_protection.' + ) + + if type is not None: + self.type = type + elif keyword_filter is not None or regex_patterns is not None: + self.type = AutoModRuleTriggerType.keyword + elif presets is not None: + self.type = AutoModRuleTriggerType.keyword_preset + elif mention_limit is not None or mention_raid_protection is not None: + self.type = AutoModRuleTriggerType.mention_spam + else: + raise ValueError( + 'Please pass the trigger type explicitly if not using keyword_filter, regex_patterns, presets, mention_limit, or mention_raid_protection.' + ) + + self.keyword_filter: List[str] = keyword_filter if keyword_filter is not None else [] + self.presets: AutoModPresets = presets if presets is not None else AutoModPresets() + self.allow_list: List[str] = allow_list if allow_list is not None else [] + self.mention_limit: int = mention_limit if mention_limit is not None else 0 + self.mention_raid_protection: bool = mention_raid_protection if mention_raid_protection is not None else False + self.regex_patterns: List[str] = regex_patterns if regex_patterns is not None else [] + + def __repr__(self) -> str: + data = self.to_metadata_dict() + if data: + joined = ' '.join(f'{k}={v!r}' for k, v in data.items()) + return f'' + + return f'' + + @classmethod + def from_data(cls, type: int, data: Optional[AutoModerationTriggerMetadataPayload]) -> Self: + type_ = try_enum(AutoModRuleTriggerType, type) + if data is None: + return cls(type=type_) + elif type_ in (AutoModRuleTriggerType.keyword, AutoModRuleTriggerType.member_profile): + return cls( + type=type_, + keyword_filter=data.get('keyword_filter'), + regex_patterns=data.get('regex_patterns'), + allow_list=data.get('allow_list'), + ) + elif type_ is AutoModRuleTriggerType.keyword_preset: + return cls( + type=type_, presets=AutoModPresets._from_value(data.get('presets', [])), allow_list=data.get('allow_list') + ) + elif type_ is AutoModRuleTriggerType.mention_spam: + return cls( + type=type_, + mention_limit=data.get('mention_total_limit'), + mention_raid_protection=data.get('mention_raid_protection_enabled'), + ) + else: + return cls(type=type_) + + def to_metadata_dict(self) -> Optional[Dict[str, Any]]: + if self.type in (AutoModRuleTriggerType.keyword, AutoModRuleTriggerType.member_profile): + return { + 'keyword_filter': self.keyword_filter, + 'regex_patterns': self.regex_patterns, + 'allow_list': self.allow_list, + } + elif self.type is AutoModRuleTriggerType.keyword_preset: + return {'presets': self.presets.to_array(), 'allow_list': self.allow_list} + elif self.type is AutoModRuleTriggerType.mention_spam: + return { + 'mention_total_limit': self.mention_limit, + 'mention_raid_protection_enabled': self.mention_raid_protection, + } + + +class AutoModRule: + """Represents an auto moderation rule. + + .. versionadded:: 2.0 + + Attributes + ----------- + id: :class:`int` + The ID of the rule. + guild: :class:`Guild` + The guild the rule is for. + name: :class:`str` + The name of the rule. + creator_id: :class:`int` + The ID of the user that created the rule. + trigger: :class:`AutoModTrigger` + The rule's trigger. + enabled: :class:`bool` + Whether the rule is enabled. + exempt_role_ids: Set[:class:`int`] + The IDs of the roles that are exempt from the rule. + exempt_channel_ids: Set[:class:`int`] + The IDs of the channels that are exempt from the rule. + event_type: :class:`AutoModRuleEventType` + The type of event that will trigger the the rule. + """ + + __slots__ = ( + '_state', + '_cs_exempt_roles', + '_cs_exempt_channels', + '_cs_actions', + 'id', + 'guild', + 'name', + 'creator_id', + 'event_type', + 'trigger', + 'enabled', + 'exempt_role_ids', + 'exempt_channel_ids', + '_actions', + ) + + def __init__(self, *, data: AutoModerationRulePayload, guild: Guild, state: ConnectionState) -> None: + self._state: ConnectionState = state + self.guild: Guild = guild + self.id: int = int(data['id']) + self.name: str = data['name'] + self.creator_id = int(data['creator_id']) + self.event_type: AutoModRuleEventType = try_enum(AutoModRuleEventType, data['event_type']) + self.trigger: AutoModTrigger = AutoModTrigger.from_data(data['trigger_type'], data=data.get('trigger_metadata')) + self.enabled: bool = data['enabled'] + self.exempt_role_ids: Set[int] = {int(role_id) for role_id in data['exempt_roles']} + self.exempt_channel_ids: Set[int] = {int(channel_id) for channel_id in data['exempt_channels']} + self._actions: List[AutoModerationActionPayload] = data['actions'] + + def __repr__(self) -> str: + return f'' + + def to_dict(self) -> AutoModerationRulePayload: + ret: AutoModerationRulePayload = { + 'id': str(self.id), + 'guild_id': str(self.guild.id), + 'name': self.name, + 'creator_id': str(self.creator_id), + 'event_type': self.event_type.value, + 'trigger_type': self.trigger.type.value, + 'trigger_metadata': self.trigger.to_metadata_dict(), + 'actions': [action.to_dict() for action in self.actions], + 'enabled': self.enabled, + 'exempt_roles': [str(role_id) for role_id in self.exempt_role_ids], + 'exempt_channels': [str(channel_id) for channel_id in self.exempt_channel_ids], + } # type: ignore # trigger types break the flow here. + + return ret + + @property + def creator(self) -> Optional[Member]: + """Optional[:class:`Member`]: The member that created this rule.""" + return self.guild.get_member(self.creator_id) + + @cached_slot_property('_cs_exempt_roles') + def exempt_roles(self) -> List[Role]: + """List[:class:`Role`]: The roles that are exempt from this rule.""" + result = [] + get_role = self.guild.get_role + for role_id in self.exempt_role_ids: + role = get_role(role_id) + if role is not None: + result.append(role) + + return utils._unique(result) + + @cached_slot_property('_cs_exempt_channels') + def exempt_channels(self) -> List[Union[GuildChannel, Thread]]: + """List[Union[:class:`abc.GuildChannel`, :class:`Thread`]]: The channels that are exempt from this rule.""" + it = filter(None, map(self.guild._resolve_channel, self.exempt_channel_ids)) + return utils._unique(it) + + @cached_slot_property('_cs_actions') + def actions(self) -> List[AutoModRuleAction]: + """List[:class:`AutoModRuleAction`]: The actions that are taken when this rule is triggered.""" + return [AutoModRuleAction.from_data(action) for action in self._actions] + + def is_exempt(self, obj: Snowflake, /) -> bool: + """Check if an object is exempt from the automod rule. + + Parameters + ----------- + obj: :class:`abc.Snowflake` + The role, channel, or thread to check. + + Returns + -------- + :class:`bool` + Whether the object is exempt from the automod rule. + """ + return obj.id in self.exempt_channel_ids or obj.id in self.exempt_role_ids + + async def edit( + self, + *, + name: str = MISSING, + event_type: AutoModRuleEventType = MISSING, + actions: List[AutoModRuleAction] = MISSING, + trigger: AutoModTrigger = MISSING, + enabled: bool = MISSING, + exempt_roles: Sequence[Snowflake] = MISSING, + exempt_channels: Sequence[Snowflake] = MISSING, + reason: str = MISSING, + ) -> Self: + """|coro| + + Edits this auto moderation rule. + + You must have :attr:`Permissions.manage_guild` to edit rules. + + Parameters + ----------- + name: :class:`str` + The new name to change to. + event_type: :class:`AutoModRuleEventType` + The new event type to change to. + actions: List[:class:`AutoModRuleAction`] + The new rule actions to update. + trigger: :class:`AutoModTrigger` + The new trigger to update. + You can only change the trigger metadata, not the type. + enabled: :class:`bool` + Whether the rule should be enabled or not. + exempt_roles: Sequence[:class:`abc.Snowflake`] + The new roles to exempt from the rule. + exempt_channels: Sequence[:class:`abc.Snowflake`] + The new channels to exempt from the rule. + reason: :class:`str` + The reason for updating this rule. Shows up on the audit log. + + Raises + ------- + Forbidden + You do not have permission to edit this rule. + HTTPException + Editing the rule failed. + + Returns + -------- + :class:`AutoModRule` + The updated auto moderation rule. + """ + payload = {} + if actions is not MISSING: + payload['actions'] = [action.to_dict() for action in actions] + + if name is not MISSING: + payload['name'] = name + + if event_type is not MISSING: + payload['event_type'] = event_type.value + + if trigger is not MISSING: + trigger_metadata = trigger.to_metadata_dict() + if trigger_metadata is not None: + payload['trigger_metadata'] = trigger_metadata + + if enabled is not MISSING: + payload['enabled'] = enabled + + if exempt_roles is not MISSING: + payload['exempt_roles'] = [x.id for x in exempt_roles] + + if exempt_channels is not MISSING: + payload['exempt_channels'] = [x.id for x in exempt_channels] + + data = await self._state.http.edit_auto_moderation_rule( + self.guild.id, + self.id, + reason=reason, + **payload, + ) + + return self.__class__(data=data, guild=self.guild, state=self._state) + + async def delete(self, *, reason: str = MISSING) -> None: + """|coro| + + Deletes the auto moderation rule. + + You must have :attr:`Permissions.manage_guild` to delete rules. + + Parameters + ----------- + reason: :class:`str` + The reason for deleting this rule. Shows up on the audit log. + + Raises + ------- + Forbidden + You do not have permissions to delete the rule. + HTTPException + Deleting the rule failed. + """ + await self._state.http.delete_auto_moderation_rule(self.guild.id, self.id, reason=reason) + + +class AutoModAction: + """Represents an action that was taken as the result of a moderation rule. + + .. versionadded:: 2.0 + + Attributes + ----------- + action: :class:`AutoModRuleAction` + The action that was taken. + message_id: Optional[:class:`int`] + The message ID that triggered the action. This is only available if the + action is done on an edited message. + rule_id: :class:`int` + The ID of the rule that was triggered. + rule_trigger_type: :class:`AutoModRuleTriggerType` + The trigger type of the rule that was triggered. + guild_id: :class:`int` + The ID of the guild where the rule was triggered. + user_id: :class:`int` + The ID of the user that triggered the rule. + channel_id: :class:`int` + The ID of the channel where the rule was triggered. + alert_system_message_id: Optional[:class:`int`] + The ID of the system message that was sent to the predefined alert channel. + content: :class:`str` + The content of the message that triggered the rule. + Requires the :attr:`Intents.message_content` or it will always return an empty string. + matched_keyword: Optional[:class:`str`] + The matched keyword from the triggering message. + matched_content: Optional[:class:`str`] + The matched content from the triggering message. + Requires the :attr:`Intents.message_content` or it will always return ``None``. + """ + + __slots__ = ( + '_state', + 'action', + 'rule_id', + 'rule_trigger_type', + 'guild_id', + 'user_id', + 'channel_id', + 'message_id', + 'alert_system_message_id', + 'content', + 'matched_keyword', + 'matched_content', + ) + + def __init__(self, *, data: AutoModerationActionExecutionPayload, state: ConnectionState) -> None: + self._state: ConnectionState = state + self.message_id: Optional[int] = utils._get_as_snowflake(data, 'message_id') + self.action: AutoModRuleAction = AutoModRuleAction.from_data(data['action']) + self.rule_id: int = int(data['rule_id']) + self.rule_trigger_type: AutoModRuleTriggerType = try_enum(AutoModRuleTriggerType, data['rule_trigger_type']) + self.guild_id: int = int(data['guild_id']) + self.channel_id: Optional[int] = utils._get_as_snowflake(data, 'channel_id') + self.user_id: int = int(data['user_id']) + self.alert_system_message_id: Optional[int] = utils._get_as_snowflake(data, 'alert_system_message_id') + self.content: str = data.get('content', '') + self.matched_keyword: Optional[str] = data['matched_keyword'] + self.matched_content: Optional[str] = data.get('matched_content') + + def __repr__(self) -> str: + return f'' + + @property + def guild(self) -> Guild: + """:class:`Guild`: The guild this action was taken in.""" + return self._state._get_or_create_unavailable_guild(self.guild_id) + + @property + def channel(self) -> Optional[Union[GuildChannel, Thread]]: + """Optional[Union[:class:`abc.GuildChannel`, :class:`Thread`]]: The channel this action was taken in.""" + if self.channel_id: + return self.guild.get_channel_or_thread(self.channel_id) + return None + + @property + def member(self) -> Optional[Member]: + """Optional[:class:`Member`]: The member this action was taken against /who triggered this rule.""" + return self.guild.get_member(self.user_id) + + async def fetch_rule(self) -> AutoModRule: + """|coro| + + Fetch the rule whose action was taken. + + You must have :attr:`Permissions.manage_guild` to do this. + + Raises + ------- + Forbidden + You do not have permissions to view the rule. + HTTPException + Fetching the rule failed. + + Returns + -------- + :class:`AutoModRule` + The rule that was executed. + """ + + data = await self._state.http.get_auto_moderation_rule(self.guild.id, self.rule_id) + return AutoModRule(data=data, guild=self.guild, state=self._state) diff --git a/venv/lib/python3.12/site-packages/discord/backoff.py b/venv/lib/python3.12/site-packages/discord/backoff.py new file mode 100644 index 00000000..cfb93ad2 --- /dev/null +++ b/venv/lib/python3.12/site-packages/discord/backoff.py @@ -0,0 +1,108 @@ +""" +The MIT License (MIT) + +Copyright (c) 2015-present Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + +from __future__ import annotations + + +import time +import random +from typing import Callable, Generic, Literal, TypeVar, overload, Union + +T = TypeVar('T', bool, Literal[True], Literal[False]) + +# fmt: off +__all__ = ( + 'ExponentialBackoff', +) +# fmt: on + + +class ExponentialBackoff(Generic[T]): + """An implementation of the exponential backoff algorithm + + Provides a convenient interface to implement an exponential backoff + for reconnecting or retrying transmissions in a distributed network. + + Once instantiated, the delay method will return the next interval to + wait for when retrying a connection or transmission. The maximum + delay increases exponentially with each retry up to a maximum of + 2^10 * base, and is reset if no more attempts are needed in a period + of 2^11 * base seconds. + + Parameters + ---------- + base: :class:`int` + The base delay in seconds. The first retry-delay will be up to + this many seconds. + integral: :class:`bool` + Set to ``True`` if whole periods of base is desirable, otherwise any + number in between may be returned. + """ + + def __init__(self, base: int = 1, *, integral: T = False): + self._base: int = base + + self._exp: int = 0 + self._max: int = 10 + self._reset_time: int = base * 2**11 + self._last_invocation: float = time.monotonic() + + # Use our own random instance to avoid messing with global one + rand = random.Random() + rand.seed() + + self._randfunc: Callable[..., Union[int, float]] = rand.randrange if integral else rand.uniform + + @overload + def delay(self: ExponentialBackoff[Literal[False]]) -> float: + ... + + @overload + def delay(self: ExponentialBackoff[Literal[True]]) -> int: + ... + + @overload + def delay(self: ExponentialBackoff[bool]) -> Union[int, float]: + ... + + def delay(self) -> Union[int, float]: + """Compute the next delay + + Returns the next delay to wait according to the exponential + backoff algorithm. This is a value between 0 and base * 2^exp + where exponent starts off at 1 and is incremented at every + invocation of this method up to a maximum of 10. + + If a period of more than base * 2^11 has passed since the last + retry, the exponent is reset to 1. + """ + invocation = time.monotonic() + interval = invocation - self._last_invocation + self._last_invocation = invocation + + if interval > self._reset_time: + self._exp = 0 + + self._exp = min(self._exp + 1, self._max) + return self._randfunc(0, self._base * 2**self._exp) diff --git a/venv/lib/python3.12/site-packages/discord/bin/libopus-0.x64.dll b/venv/lib/python3.12/site-packages/discord/bin/libopus-0.x64.dll new file mode 100644 index 0000000000000000000000000000000000000000..74a8e3554ff00d07d979d7763f03555d8e392f21 GIT binary patch literal 441856 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%0DfdGRmjsdzH`o8kKLF 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