From f0f2f2ec1be8e53a2d4e8db5182729aad190983d Mon Sep 17 00:00:00 2001 From: Devon R Date: Sat, 23 Apr 2022 00:14:51 +0900 Subject: [PATCH 01/10] Sync diagnostics --- jishaku/features/management.py | 113 +++++++++++++++++++++++++++++---- 1 file changed, 99 insertions(+), 14 deletions(-) diff --git a/jishaku/features/management.py b/jishaku/features/management.py index 9e0e7474..aacd83f5 100644 --- a/jishaku/features/management.py +++ b/jishaku/features/management.py @@ -13,8 +13,10 @@ import itertools import math +import re import time import traceback +import typing from urllib.parse import urlencode import discord @@ -23,7 +25,7 @@ from jishaku.features.baseclass import Feature from jishaku.flags import Flags from jishaku.modules import ExtensionConverter -from jishaku.paginators import WrappedPaginator +from jishaku.repl import inspections class ManagementFeature(Feature): @@ -39,7 +41,7 @@ async def jsk_load(self, ctx: commands.Context, *extensions: ExtensionConverter) Reports any extensions that failed to load. """ - paginator = WrappedPaginator(prefix='', suffix='') + paginator = commands.Paginator(prefix='', suffix='') # 'jsk reload' on its own just reloads jishaku if ctx.invoked_with == 'reload' and not extensions: @@ -75,7 +77,7 @@ async def jsk_unload(self, ctx: commands.Context, *extensions: ExtensionConverte Reports any extensions that failed to unload. """ - paginator = WrappedPaginator(prefix='', suffix='') + paginator = commands.Paginator(prefix='', suffix='') icon = "\N{OUTBOX TRAY}" for extension in itertools.chain(*extensions): @@ -191,25 +193,108 @@ async def jsk_rtt(self, ctx: commands.Context): if self.bot.latency > 0.0: websocket_readings.append(self.bot.latency) + SLASH_COMMAND_ERROR = re.compile(r"In ((?:\d+\.[a-z]+\.?)+)") + @Feature.Command(parent="jsk", name="sync") - async def jsk_sync(self, ctx: commands.Context, *guild_ids: int): + async def jsk_sync(self, ctx: commands.Context, *targets: str): """ Sync global or guild application commands to Discord. """ - paginator = WrappedPaginator(prefix='', suffix='') + paginator = commands.Paginator(prefix='', suffix='') - if not guild_ids: - synced = await self.bot.tree.sync() - paginator.add_line(f"\N{SATELLITE ANTENNA} Synced {len(synced)} global commands") - else: - for guild_id in guild_ids: + guilds = set() + for target in targets: + if target == '$': + guilds.add(None) + elif target == '.': + guilds.add(ctx.guild.id) + else: try: - synced = await self.bot.tree.sync(guild=discord.Object(guild_id)) - except discord.HTTPException as exc: - paginator.add_line(f"\N{WARNING SIGN} `{guild_id}`: {exc.text}") + guilds.add(int(target)) + except ValueError as error: + raise commands.BadArgument(f"{target} is not a valid guild ID") from error + + if not guilds: + guilds.add(None) + + guilds: typing.List[typing.Optional[int]] = list(guilds) + guilds.sort() + + for guild in guilds: + slash_commands = self.bot.tree._get_all_commands( # pylint: disable=protected-access + guild=discord.Object(guild) if guild else None + ) + payload = [command.to_dict() for command in slash_commands] + + try: + if guild is None: + data = await self.bot.http.bulk_upsert_global_commands(self.bot.application_id, payload=payload) + else: + data = await self.bot.http.bulk_upsert_guild_commands(self.bot.application_id, guild, payload=payload) + + synced = [discord.app_commands.AppCommand(data=d, state=ctx._state) for d in data] # pylint: disable=protected-access + + except discord.HTTPException as error: + # It's diagnosis time + error_text = [] + for line in str(error).split("\n"): + error_text.append(line) + + try: + match = self.SLASH_COMMAND_ERROR.match(line) + if not match: + continue + + pool = slash_commands + selected_command = None + name = "" + parts = match.group(1).split('.') + assert len(parts) % 2 == 0 + + for part_index in range(0, len(parts), 2): + index = int(parts[part_index]) + # prop = parts[part_index + 1] + + if pool: + # If the pool exists, this should be a subcommand + selected_command = pool[index] + name += selected_command.name + " " + + if hasattr(selected_command, '_children'): + pool = list(selected_command._children.values()) # pylint: disable=protected-access + else: + pool = None + else: + # Otherwise, the pool has been exhausted, and this likely is referring to a parameter + param = list(selected_command._params.keys())[index] # pylint: disable=protected-access + name += f"(parameter: {param}) " + + if selected_command: + error_text.append(''.join( + "\N{MAGNET} This is likely caused by: `", + name, + "` at ", + str(inspections.file_loc_inspection(selected_command.callback)), + ":", + str(inspections.line_span_inspection(selected_command.callback)) + )) + + except Exception: # pylint: disable=broad-except + # If something strange happens, it means our diagnosis failed and we should just show the error as-is. + pass + + error_text = '\n'.join(error_text) + + if guild: + paginator.add_line(f"\N{WARNING SIGN} `{guild}`: {error_text}") + else: + paginator.add_line(f"\N{WARNING SIGN} Global: {error_text}") + else: + if guild: + paginator.add_line(f"\N{SATELLITE ANTENNA} `{guild}` Synced {len(synced)} guild commands") else: - paginator.add_line(f"\N{SATELLITE ANTENNA} `{guild_id}` Synced {len(synced)} guild commands") + paginator.add_line(f"\N{SATELLITE ANTENNA} Synced {len(synced)} global commands") for page in paginator.pages: await ctx.send(page) From 5cb189a4e1cd5a0d15046ef2ea2363857f909ab9 Mon Sep 17 00:00:00 2001 From: Devon R Date: Sat, 23 Apr 2022 00:17:23 +0900 Subject: [PATCH 02/10] Report diagnostic errors --- jishaku/features/management.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/jishaku/features/management.py b/jishaku/features/management.py index aacd83f5..eca6f1f7 100644 --- a/jishaku/features/management.py +++ b/jishaku/features/management.py @@ -280,9 +280,8 @@ async def jsk_sync(self, ctx: commands.Context, *targets: str): str(inspections.line_span_inspection(selected_command.callback)) )) - except Exception: # pylint: disable=broad-except - # If something strange happens, it means our diagnosis failed and we should just show the error as-is. - pass + except Exception as error: # pylint: disable=broad-except + error_text.append(f"\N{MAGNET} Couldn't determine cause: {type(error).__name__}: {error}") error_text = '\n'.join(error_text) From f49dce99eb93d6bff591be0892795e831af1e96c Mon Sep 17 00:00:00 2001 From: Devon R Date: Sat, 23 Apr 2022 00:18:26 +0900 Subject: [PATCH 03/10] Whoops --- jishaku/features/management.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jishaku/features/management.py b/jishaku/features/management.py index eca6f1f7..5b85280d 100644 --- a/jishaku/features/management.py +++ b/jishaku/features/management.py @@ -271,14 +271,14 @@ async def jsk_sync(self, ctx: commands.Context, *targets: str): name += f"(parameter: {param}) " if selected_command: - error_text.append(''.join( + error_text.append(''.join([ "\N{MAGNET} This is likely caused by: `", name, "` at ", str(inspections.file_loc_inspection(selected_command.callback)), ":", str(inspections.line_span_inspection(selected_command.callback)) - )) + ])) except Exception as error: # pylint: disable=broad-except error_text.append(f"\N{MAGNET} Couldn't determine cause: {type(error).__name__}: {error}") From 23409470fed0d1c50698587f4f4156a0152839db Mon Sep 17 00:00:00 2001 From: Devon R Date: Sat, 23 Apr 2022 00:22:58 +0900 Subject: [PATCH 04/10] Support syncing all guilds using * --- jishaku/features/management.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jishaku/features/management.py b/jishaku/features/management.py index 5b85280d..10ccfca4 100644 --- a/jishaku/features/management.py +++ b/jishaku/features/management.py @@ -207,6 +207,8 @@ async def jsk_sync(self, ctx: commands.Context, *targets: str): for target in targets: if target == '$': guilds.add(None) + elif target == '*': + guilds |= set(self.bot.tree._guild_commands.keys()) # pylint: disable=protected-access elif target == '.': guilds.add(ctx.guild.id) else: From 75c2c3ed5de844ff2da540a2d61e7115646ee291 Mon Sep 17 00:00:00 2001 From: Devon R Date: Sat, 23 Apr 2022 00:24:34 +0900 Subject: [PATCH 05/10] Ensure global sorts first --- jishaku/features/management.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jishaku/features/management.py b/jishaku/features/management.py index 10ccfca4..ee7a032b 100644 --- a/jishaku/features/management.py +++ b/jishaku/features/management.py @@ -221,7 +221,7 @@ async def jsk_sync(self, ctx: commands.Context, *targets: str): guilds.add(None) guilds: typing.List[typing.Optional[int]] = list(guilds) - guilds.sort() + guilds.sort(key=lambda g: (g is not None, g)) for guild in guilds: slash_commands = self.bot.tree._get_all_commands( # pylint: disable=protected-access From 3bdde18ed04452d44d1f8c878f270ebea767b0ba Mon Sep 17 00:00:00 2001 From: Devon R Date: Sat, 23 Apr 2022 00:25:33 +0900 Subject: [PATCH 06/10] Space guilds with empty lines --- jishaku/features/management.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jishaku/features/management.py b/jishaku/features/management.py index ee7a032b..a8a9567e 100644 --- a/jishaku/features/management.py +++ b/jishaku/features/management.py @@ -297,5 +297,7 @@ async def jsk_sync(self, ctx: commands.Context, *targets: str): else: paginator.add_line(f"\N{SATELLITE ANTENNA} Synced {len(synced)} global commands") + paginator.add_line(empty=True) + for page in paginator.pages: await ctx.send(page) From 6e6ee768cc5a3b487dca073defd7f56259cccd29 Mon Sep 17 00:00:00 2001 From: Devon R Date: Sat, 23 Apr 2022 00:26:39 +0900 Subject: [PATCH 07/10] I forgot how empty worked for a moment --- jishaku/features/management.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/jishaku/features/management.py b/jishaku/features/management.py index a8a9567e..adbc6df5 100644 --- a/jishaku/features/management.py +++ b/jishaku/features/management.py @@ -288,16 +288,14 @@ async def jsk_sync(self, ctx: commands.Context, *targets: str): error_text = '\n'.join(error_text) if guild: - paginator.add_line(f"\N{WARNING SIGN} `{guild}`: {error_text}") + paginator.add_line(f"\N{WARNING SIGN} `{guild}`: {error_text}", empty=True) else: - paginator.add_line(f"\N{WARNING SIGN} Global: {error_text}") + paginator.add_line(f"\N{WARNING SIGN} Global: {error_text}", empty=True) else: if guild: - paginator.add_line(f"\N{SATELLITE ANTENNA} `{guild}` Synced {len(synced)} guild commands") + paginator.add_line(f"\N{SATELLITE ANTENNA} `{guild}` Synced {len(synced)} guild commands", empty=True) else: - paginator.add_line(f"\N{SATELLITE ANTENNA} Synced {len(synced)} global commands") - - paginator.add_line(empty=True) + paginator.add_line(f"\N{SATELLITE ANTENNA} Synced {len(synced)} global commands", empty=True) for page in paginator.pages: await ctx.send(page) From 0e9412b31365f3e8c187dce87ddac397336e855a Mon Sep 17 00:00:00 2001 From: Devon R Date: Sat, 23 Apr 2022 00:38:27 +0900 Subject: [PATCH 08/10] Handle errors that tie to cogs or uninspectables --- jishaku/features/management.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/jishaku/features/management.py b/jishaku/features/management.py index adbc6df5..33791a43 100644 --- a/jishaku/features/management.py +++ b/jishaku/features/management.py @@ -273,14 +273,24 @@ async def jsk_sync(self, ctx: commands.Context, *targets: str): name += f"(parameter: {param}) " if selected_command: - error_text.append(''.join([ - "\N{MAGNET} This is likely caused by: `", - name, - "` at ", - str(inspections.file_loc_inspection(selected_command.callback)), - ":", - str(inspections.line_span_inspection(selected_command.callback)) - ])) + to_inspect = None + + if hasattr(selected_command, 'callback'): + to_inspect = selected_command.callback + elif isinstance(selected_command, commands.Cog): + to_inspect = type(selected_command) + + if to_inspect: + error_text.append(''.join([ + "\N{MAGNET} This is likely caused by: `", + name, + "` at ", + str(inspections.file_loc_inspection(to_inspect)), + ":", + str(inspections.line_span_inspection(to_inspect)) + ])) + else: + error_text.append(f"\N{MAGNET} This is likely caused by: `{name}`") except Exception as error: # pylint: disable=broad-except error_text.append(f"\N{MAGNET} Couldn't determine cause: {type(error).__name__}: {error}") From 92ed782718a1296db160bcc34c9bf4b9cae50b09 Mon Sep 17 00:00:00 2001 From: Devon R Date: Sat, 23 Apr 2022 00:41:42 +0900 Subject: [PATCH 09/10] Try to handle uninspectables --- jishaku/features/management.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jishaku/features/management.py b/jishaku/features/management.py index 33791a43..cecae309 100644 --- a/jishaku/features/management.py +++ b/jishaku/features/management.py @@ -280,7 +280,7 @@ async def jsk_sync(self, ctx: commands.Context, *targets: str): elif isinstance(selected_command, commands.Cog): to_inspect = type(selected_command) - if to_inspect: + try: error_text.append(''.join([ "\N{MAGNET} This is likely caused by: `", name, @@ -289,7 +289,7 @@ async def jsk_sync(self, ctx: commands.Context, *targets: str): ":", str(inspections.line_span_inspection(to_inspect)) ])) - else: + except Exception: # pylint: disable=broad-except error_text.append(f"\N{MAGNET} This is likely caused by: `{name}`") except Exception as error: # pylint: disable=broad-except From ec94dc78148ec579e9144c7606b5581e296f752a Mon Sep 17 00:00:00 2001 From: Devon R Date: Sat, 23 Apr 2022 00:46:59 +0900 Subject: [PATCH 10/10] Fix pylint complaints --- jishaku/features/management.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/jishaku/features/management.py b/jishaku/features/management.py index cecae309..915fc9a3 100644 --- a/jishaku/features/management.py +++ b/jishaku/features/management.py @@ -235,7 +235,10 @@ async def jsk_sync(self, ctx: commands.Context, *targets: str): else: data = await self.bot.http.bulk_upsert_guild_commands(self.bot.application_id, guild, payload=payload) - synced = [discord.app_commands.AppCommand(data=d, state=ctx._state) for d in data] # pylint: disable=protected-access + synced = [ + discord.app_commands.AppCommand(data=d, state=ctx._state) # pylint: disable=protected-access,no-member + for d in data + ] except discord.HTTPException as error: # It's diagnosis time @@ -292,8 +295,8 @@ async def jsk_sync(self, ctx: commands.Context, *targets: str): except Exception: # pylint: disable=broad-except error_text.append(f"\N{MAGNET} This is likely caused by: `{name}`") - except Exception as error: # pylint: disable=broad-except - error_text.append(f"\N{MAGNET} Couldn't determine cause: {type(error).__name__}: {error}") + except Exception as diag_error: # pylint: disable=broad-except + error_text.append(f"\N{MAGNET} Couldn't determine cause: {type(diag_error).__name__}: {diag_error}") error_text = '\n'.join(error_text)