Fix file endings (#6002)

This commit is contained in:
Kowlin 2023-03-21 23:34:01 +01:00 committed by GitHub
parent f06b734e15
commit 0a5aa94cde
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 401 additions and 401 deletions

View File

@ -1,48 +1,48 @@
.. _autostart_windows: .. _autostart_windows:
============================================== ==============================================
Setting up auto-restart using batch on Windows Setting up auto-restart using batch on Windows
============================================== ==============================================
.. note:: This guide assumes that you already have a working Red instance. .. note:: This guide assumes that you already have a working Red instance.
----------------------- -----------------------
Creating the batch file Creating the batch file
----------------------- -----------------------
Create a new text document anywhere you want to. This file will be used to launch the bot, so you may want to put it somewhere convenient, like Documents or Desktop. Create a new text document anywhere you want to. This file will be used to launch the bot, so you may want to put it somewhere convenient, like Documents or Desktop.
Open that document in Notepad, and paste the following text in it: Open that document in Notepad, and paste the following text in it:
.. code-block:: batch .. code-block:: batch
@ECHO OFF @ECHO OFF
:RED :RED
CALL "%userprofile%\redenv\Scripts\activate.bat" CALL "%userprofile%\redenv\Scripts\activate.bat"
python -O -m redbot <your instance name> python -O -m redbot <your instance name>
IF %ERRORLEVEL% NEQ 0 ( IF %ERRORLEVEL% NEQ 0 (
ECHO Restarting Red... ECHO Restarting Red...
GOTO RED GOTO RED
) )
Replace ``<your instance name>`` with the instance name of your bot. Replace ``<your instance name>`` with the instance name of your bot.
If you created your VENV at a location other than the recommended one, replace ``%userprofile%\redenv\Scripts\activate.bat`` with the path to your VENV. If you created your VENV at a location other than the recommended one, replace ``%userprofile%\redenv\Scripts\activate.bat`` with the path to your VENV.
Click "File", "Save as". Change the dropdown "Save as type" to "All Files (*.*)". Set the filename to ``start_redbot.bat``, and click save. Click "File", "Save as". Change the dropdown "Save as type" to "All Files (*.*)". Set the filename to ``start_redbot.bat``, and click save.
There should now be a new file in the location you created the text document in. You can delete that text document as it is no longer needed. There should now be a new file in the location you created the text document in. You can delete that text document as it is no longer needed.
You can now use the ``start_redbot.bat`` batch file to launch Red by double clicking it. You can now use the ``start_redbot.bat`` batch file to launch Red by double clicking it.
This script will automatically restart red when the ``[p]restart`` command is used or when the bot shuts down abnormally. This script will automatically restart red when the ``[p]restart`` command is used or when the bot shuts down abnormally.
------------------------- -------------------------
Launch the bot on startup Launch the bot on startup
------------------------- -------------------------
Create a shortcut of your ``start_redbot.bat`` file. Create a shortcut of your ``start_redbot.bat`` file.
Open the "Run" dialogue box using Windows Key + R. Open the "Run" dialogue box using Windows Key + R.
Enter ``shell:startup`` if you want the bot to launch only when the current user logs in, or ``shell:common startup`` if you want the bot to launch when any user logs in. Enter ``shell:startup`` if you want the bot to launch only when the current user logs in, or ``shell:common startup`` if you want the bot to launch when any user logs in.
Drag the shortcut into the folder that is opened. The bot will now launch on startup. Drag the shortcut into the folder that is opened. The bot will now launch on startup.

View File

@ -1,21 +1,21 @@
.. tree module docs .. tree module docs
==== ====
Tree Tree
==== ====
Red uses a subclass of discord.py's ``CommandTree`` object in order to allow Cog Creators to add application commands to their cogs without worrying about the command count limit and to support caching ``AppCommand`` objects. When an app command is added to the bot's tree, it will not show up in ``tree.get_commands`` or other similar methods unless the command is "enabled" with ``[p]slash enable`` (similar to "load"ing a cog) and ``tree.red_check_enabled`` has been run since the command was added to the tree. Red uses a subclass of discord.py's ``CommandTree`` object in order to allow Cog Creators to add application commands to their cogs without worrying about the command count limit and to support caching ``AppCommand`` objects. When an app command is added to the bot's tree, it will not show up in ``tree.get_commands`` or other similar methods unless the command is "enabled" with ``[p]slash enable`` (similar to "load"ing a cog) and ``tree.red_check_enabled`` has been run since the command was added to the tree.
.. note:: .. note::
If you are adding app commands to the tree during load time, the loading process will call ``tree.red_check_enabled`` for your cog and its app commands. If you are adding app commands to the bot **outside of load time**, a call to ``tree.red_check_enabled`` after adding the commands is required to ensure the commands will appear properly. If you are adding app commands to the tree during load time, the loading process will call ``tree.red_check_enabled`` for your cog and its app commands. If you are adding app commands to the bot **outside of load time**, a call to ``tree.red_check_enabled`` after adding the commands is required to ensure the commands will appear properly.
If application commands from your cog show up in ``[p]slash list`` as enabled from an ``(unknown)`` cog and disabled from your cog at the same time, you did not follow the instructions above. You must manually call ``tree.red_check_enabled`` **after** adding the commands to the tree. If application commands from your cog show up in ``[p]slash list`` as enabled from an ``(unknown)`` cog and disabled from your cog at the same time, you did not follow the instructions above. You must manually call ``tree.red_check_enabled`` **after** adding the commands to the tree.
.. automodule:: redbot.core.tree .. automodule:: redbot.core.tree
RedTree RedTree
^^^^^^^ ^^^^^^^
.. autoclass:: RedTree .. autoclass:: RedTree
:members: :members:

View File

@ -1,332 +1,332 @@
import discord import discord
from discord.abc import Snowflake from discord.abc import Snowflake
from discord.utils import MISSING from discord.utils import MISSING
from discord.app_commands import ( from discord.app_commands import (
Command, Command,
Group, Group,
ContextMenu, ContextMenu,
AppCommand, AppCommand,
AppCommandError, AppCommandError,
BotMissingPermissions, BotMissingPermissions,
CheckFailure, CheckFailure,
CommandAlreadyRegistered, CommandAlreadyRegistered,
CommandInvokeError, CommandInvokeError,
CommandNotFound, CommandNotFound,
CommandOnCooldown, CommandOnCooldown,
NoPrivateMessage, NoPrivateMessage,
TransformerError, TransformerError,
) )
from .i18n import Translator from .i18n import Translator
from .utils.chat_formatting import humanize_list, inline from .utils.chat_formatting import humanize_list, inline
import logging import logging
import traceback import traceback
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
from typing import List, Dict, Tuple, Union, Optional, Sequence from typing import List, Dict, Tuple, Union, Optional, Sequence
log = logging.getLogger("red") log = logging.getLogger("red")
_ = Translator(__name__, __file__) _ = Translator(__name__, __file__)
class RedTree(discord.app_commands.CommandTree): class RedTree(discord.app_commands.CommandTree):
"""A container that holds application command information. """A container that holds application command information.
Internally does not actually add commands to the tree unless they are Internally does not actually add commands to the tree unless they are
enabled with ``[p]slash enable``, to support Red's modularity. enabled with ``[p]slash enable``, to support Red's modularity.
See ``discord.app_commands.CommandTree`` for more information. See ``discord.app_commands.CommandTree`` for more information.
""" """
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
# Same structure as superclass # Same structure as superclass
self._disabled_global_commands: Dict[str, Union[Command, Group]] = {} self._disabled_global_commands: Dict[str, Union[Command, Group]] = {}
self._disabled_context_menus: Dict[Tuple[str, Optional[int], int], ContextMenu] = {} self._disabled_context_menus: Dict[Tuple[str, Optional[int], int], ContextMenu] = {}
def add_command( def add_command(
self, self,
command: Union[Command, ContextMenu, Group], command: Union[Command, ContextMenu, Group],
/, /,
*args, *args,
guild: Optional[Snowflake] = MISSING, guild: Optional[Snowflake] = MISSING,
guilds: Sequence[Snowflake] = MISSING, guilds: Sequence[Snowflake] = MISSING,
override: bool = False, override: bool = False,
**kwargs, **kwargs,
) -> None: ) -> None:
"""Adds an application command to the tree. """Adds an application command to the tree.
Commands will be internally stored until enabled by ``[p]slash enable``. Commands will be internally stored until enabled by ``[p]slash enable``.
""" """
# Allow guild specific commands to bypass the internals for development # Allow guild specific commands to bypass the internals for development
if guild is not MISSING or guilds is not MISSING: if guild is not MISSING or guilds is not MISSING:
return super().add_command( return super().add_command(
command, *args, guild=guild, guilds=guilds, override=override, **kwargs command, *args, guild=guild, guilds=guilds, override=override, **kwargs
) )
if isinstance(command, ContextMenu): if isinstance(command, ContextMenu):
name = command.name name = command.name
type = command.type.value type = command.type.value
key = (name, None, type) key = (name, None, type)
# Handle cases where the command already is in the tree # Handle cases where the command already is in the tree
if not override and key in self._disabled_context_menus: if not override and key in self._disabled_context_menus:
raise CommandAlreadyRegistered(name, None) raise CommandAlreadyRegistered(name, None)
if key in self._context_menus: if key in self._context_menus:
if not override: if not override:
raise discord.errors.CommandAlreadyRegistered(name, None) raise discord.errors.CommandAlreadyRegistered(name, None)
del self._context_menus[key] del self._context_menus[key]
self._disabled_context_menus[key] = command self._disabled_context_menus[key] = command
return return
if not isinstance(command, (Command, Group)): if not isinstance(command, (Command, Group)):
raise TypeError( raise TypeError(
f"Expected an application command, received {command.__class__.__name__} instead" f"Expected an application command, received {command.__class__.__name__} instead"
) )
root = command.root_parent or command root = command.root_parent or command
name = root.name name = root.name
# Handle cases where the command already is in the tree # Handle cases where the command already is in the tree
if not override and name in self._disabled_global_commands: if not override and name in self._disabled_global_commands:
raise discord.errors.CommandAlreadyRegistered(name, None) raise discord.errors.CommandAlreadyRegistered(name, None)
if name in self._global_commands: if name in self._global_commands:
if not override: if not override:
raise discord.errors.CommandAlreadyRegistered(name, None) raise discord.errors.CommandAlreadyRegistered(name, None)
del self._global_commands[name] del self._global_commands[name]
self._disabled_global_commands[name] = root self._disabled_global_commands[name] = root
def remove_command( def remove_command(
self, self,
command: str, command: str,
/, /,
*args, *args,
guild: Optional[Snowflake] = None, guild: Optional[Snowflake] = None,
type: discord.AppCommandType = discord.AppCommandType.chat_input, type: discord.AppCommandType = discord.AppCommandType.chat_input,
**kwargs, **kwargs,
) -> Optional[Union[Command, ContextMenu, Group]]: ) -> Optional[Union[Command, ContextMenu, Group]]:
"""Removes an application command from this tree.""" """Removes an application command from this tree."""
if guild is not None: if guild is not None:
return super().remove_command(command, *args, guild=guild, type=type, **kwargs) return super().remove_command(command, *args, guild=guild, type=type, **kwargs)
if type is discord.AppCommandType.chat_input: if type is discord.AppCommandType.chat_input:
return self._disabled_global_commands.pop(command, None) or super().remove_command( return self._disabled_global_commands.pop(command, None) or super().remove_command(
command, *args, guild=guild, type=type, **kwargs command, *args, guild=guild, type=type, **kwargs
) )
elif type in (discord.AppCommandType.user, discord.AppCommandType.message): elif type in (discord.AppCommandType.user, discord.AppCommandType.message):
key = (command, None, type.value) key = (command, None, type.value)
return self._disabled_context_menus.pop(key, None) or super().remove_command( return self._disabled_context_menus.pop(key, None) or super().remove_command(
command, *args, guild=guild, type=type, **kwargs command, *args, guild=guild, type=type, **kwargs
) )
def clear_commands( def clear_commands(
self, self,
*args, *args,
guild: Optional[Snowflake], guild: Optional[Snowflake],
type: Optional[discord.AppCommandType] = None, type: Optional[discord.AppCommandType] = None,
**kwargs, **kwargs,
) -> None: ) -> None:
"""Clears all application commands from the tree.""" """Clears all application commands from the tree."""
if guild is not None: if guild is not None:
return super().clear_commands(*args, guild=guild, type=type, **kwargs) return super().clear_commands(*args, guild=guild, type=type, **kwargs)
if type is None or type is discord.AppCommandType.chat_input: if type is None or type is discord.AppCommandType.chat_input:
self._global_commands.clear() self._global_commands.clear()
self._disabled_global_commands.clear() self._disabled_global_commands.clear()
if type is None: if type is None:
self._disabled_context_menus.clear() self._disabled_context_menus.clear()
else: else:
self._disabled_context_menus = { self._disabled_context_menus = {
(name, _guild_id, value): cmd (name, _guild_id, value): cmd
for (name, _guild_id, value), cmd in self._disabled_context_menus.items() for (name, _guild_id, value), cmd in self._disabled_context_menus.items()
if value != type.value if value != type.value
} }
return super().clear_commands(*args, guild=guild, type=type, **kwargs) return super().clear_commands(*args, guild=guild, type=type, **kwargs)
async def sync(self, *args, guild: Optional[Snowflake] = None, **kwargs) -> List[AppCommand]: async def sync(self, *args, guild: Optional[Snowflake] = None, **kwargs) -> List[AppCommand]:
"""Wrapper to store command IDs when commands are synced.""" """Wrapper to store command IDs when commands are synced."""
commands = await super().sync(*args, guild=guild, **kwargs) commands = await super().sync(*args, guild=guild, **kwargs)
if guild: if guild:
return commands return commands
async with self.client._config.all() as cfg: async with self.client._config.all() as cfg:
for command in commands: for command in commands:
if command.type is discord.AppCommandType.chat_input: if command.type is discord.AppCommandType.chat_input:
cfg["enabled_slash_commands"][command.name] = command.id cfg["enabled_slash_commands"][command.name] = command.id
elif command.type is discord.AppCommandType.message: elif command.type is discord.AppCommandType.message:
cfg["enabled_message_commands"][command.name] = command.id cfg["enabled_message_commands"][command.name] = command.id
elif command.type is discord.AppCommandType.user: elif command.type is discord.AppCommandType.user:
cfg["enabled_user_commands"][command.name] = command.id cfg["enabled_user_commands"][command.name] = command.id
return commands return commands
async def red_check_enabled(self) -> None: async def red_check_enabled(self) -> None:
"""Restructures the commands in this tree, enabling commands that are enabled and disabling commands that are disabled. """Restructures the commands in this tree, enabling commands that are enabled and disabling commands that are disabled.
After running this function, the tree will be populated with enabled commands only. After running this function, the tree will be populated with enabled commands only.
If commands are manually added to the tree outside of the standard cog loading process, this must be run If commands are manually added to the tree outside of the standard cog loading process, this must be run
for them to be usable. for them to be usable.
""" """
enabled_commands = await self.client.list_enabled_app_commands() enabled_commands = await self.client.list_enabled_app_commands()
to_add_commands = [] to_add_commands = []
to_add_context = [] to_add_context = []
to_remove_commands = [] to_remove_commands = []
to_remove_context = [] to_remove_context = []
# Add commands # Add commands
for command in enabled_commands["slash"]: for command in enabled_commands["slash"]:
if command in self._disabled_global_commands: if command in self._disabled_global_commands:
to_add_commands.append(command) to_add_commands.append(command)
# Add context # Add context
for command in enabled_commands["message"]: for command in enabled_commands["message"]:
key = (command, None, discord.AppCommandType.message.value) key = (command, None, discord.AppCommandType.message.value)
if key in self._disabled_context_menus: if key in self._disabled_context_menus:
to_add_context.append(key) to_add_context.append(key)
for command in enabled_commands["user"]: for command in enabled_commands["user"]:
key = (command, None, discord.AppCommandType.user.value) key = (command, None, discord.AppCommandType.user.value)
if key in self._disabled_context_menus: if key in self._disabled_context_menus:
to_add_context.append(key) to_add_context.append(key)
# Remove commands # Remove commands
for command in self._global_commands: for command in self._global_commands:
if command not in enabled_commands["slash"]: if command not in enabled_commands["slash"]:
to_remove_commands.append((command, discord.AppCommandType.chat_input)) to_remove_commands.append((command, discord.AppCommandType.chat_input))
# Remove context # Remove context
for command, guild_id, command_type in self._context_menus: for command, guild_id, command_type in self._context_menus:
if guild_id is not None: if guild_id is not None:
continue continue
if ( if (
discord.AppCommandType(command_type) is discord.AppCommandType.message discord.AppCommandType(command_type) is discord.AppCommandType.message
and command not in enabled_commands["message"] and command not in enabled_commands["message"]
): ):
to_remove_context.append((command, discord.AppCommandType.message)) to_remove_context.append((command, discord.AppCommandType.message))
elif ( elif (
discord.AppCommandType(command_type) is discord.AppCommandType.user discord.AppCommandType(command_type) is discord.AppCommandType.user
and command not in enabled_commands["user"] and command not in enabled_commands["user"]
): ):
to_remove_context.append((command, discord.AppCommandType.user)) to_remove_context.append((command, discord.AppCommandType.user))
# Actually add/remove # Actually add/remove
for command in to_add_commands: for command in to_add_commands:
super().add_command(self._disabled_global_commands[command]) super().add_command(self._disabled_global_commands[command])
del self._disabled_global_commands[command] del self._disabled_global_commands[command]
for key in to_add_context: for key in to_add_context:
super().add_command(self._disabled_context_menus[key]) super().add_command(self._disabled_context_menus[key])
del self._disabled_context_menus[key] del self._disabled_context_menus[key]
for command, type in to_remove_commands: for command, type in to_remove_commands:
com = super().remove_command(command, type=type) com = super().remove_command(command, type=type)
self._disabled_global_commands[command] = com self._disabled_global_commands[command] = com
for command, type in to_remove_context: for command, type in to_remove_context:
com = super().remove_command(command, type=type) com = super().remove_command(command, type=type)
self._disabled_context_menus[(command, None, type.value)] = com self._disabled_context_menus[(command, None, type.value)] = com
@staticmethod @staticmethod
async def _send_from_interaction(interaction, *args, **kwargs): async def _send_from_interaction(interaction, *args, **kwargs):
"""Util for safely sending a message from an interaction.""" """Util for safely sending a message from an interaction."""
if interaction.response.is_done(): if interaction.response.is_done():
if interaction.is_expired(): if interaction.is_expired():
return await interaction.channel.send(*args, **kwargs) return await interaction.channel.send(*args, **kwargs)
return await interaction.followup.send(*args, ephemeral=True, **kwargs) return await interaction.followup.send(*args, ephemeral=True, **kwargs)
return await interaction.response.send_message(*args, ephemeral=True, **kwargs) return await interaction.response.send_message(*args, ephemeral=True, **kwargs)
@staticmethod @staticmethod
def _is_submodule(parent: str, child: str): def _is_submodule(parent: str, child: str):
return parent == child or child.startswith(parent + ".") return parent == child or child.startswith(parent + ".")
async def on_error( async def on_error(
self, interaction: discord.Interaction, error: AppCommandError, /, *args, **kwargs self, interaction: discord.Interaction, error: AppCommandError, /, *args, **kwargs
) -> None: ) -> None:
"""Fallback error handler for app commands.""" """Fallback error handler for app commands."""
if isinstance(error, CommandNotFound): if isinstance(error, CommandNotFound):
await self._send_from_interaction(interaction, _("Command not found.")) await self._send_from_interaction(interaction, _("Command not found."))
log.warning( log.warning(
f"Application command {error.name} could not be resolved. " f"Application command {error.name} could not be resolved. "
"It may be from a cog that was updated or unloaded. " "It may be from a cog that was updated or unloaded. "
"Consider running [p]slash sync to resolve this issue." "Consider running [p]slash sync to resolve this issue."
) )
elif isinstance(error, CommandInvokeError): elif isinstance(error, CommandInvokeError):
log.exception( log.exception(
"Exception in command '{}'".format(error.command.qualified_name), "Exception in command '{}'".format(error.command.qualified_name),
exc_info=error.original, exc_info=error.original,
) )
exception_log = "Exception in command '{}'\n" "".format(error.command.qualified_name) exception_log = "Exception in command '{}'\n" "".format(error.command.qualified_name)
exception_log += "".join( exception_log += "".join(
traceback.format_exception(type(error), error, error.__traceback__) traceback.format_exception(type(error), error, error.__traceback__)
) )
interaction.client._last_exception = exception_log interaction.client._last_exception = exception_log
message = await interaction.client._config.invoke_error_msg() message = await interaction.client._config.invoke_error_msg()
if not message: if not message:
if interaction.user.id in interaction.client.owner_ids: if interaction.user.id in interaction.client.owner_ids:
message = inline( message = inline(
_("Error in command '{command}'. Check your console or logs for details.") _("Error in command '{command}'. Check your console or logs for details.")
) )
else: else:
message = inline(_("Error in command '{command}'.")) message = inline(_("Error in command '{command}'."))
await self._send_from_interaction( await self._send_from_interaction(
interaction, message.replace("{command}", error.command.qualified_name) interaction, message.replace("{command}", error.command.qualified_name)
) )
elif isinstance(error, TransformerError): elif isinstance(error, TransformerError):
if error.__cause__: if error.__cause__:
log.exception("Error in an app command transformer.", exc_info=error.__cause__) log.exception("Error in an app command transformer.", exc_info=error.__cause__)
await self._send_from_interaction(interaction, str(error)) await self._send_from_interaction(interaction, str(error))
elif isinstance(error, BotMissingPermissions): elif isinstance(error, BotMissingPermissions):
formatted = [ formatted = [
'"' + perm.replace("_", " ").title() + '"' for perm in error.missing_permissions '"' + perm.replace("_", " ").title() + '"' for perm in error.missing_permissions
] ]
formatted = humanize_list(formatted).replace("Guild", "Server") formatted = humanize_list(formatted).replace("Guild", "Server")
if len(error.missing_permissions) == 1: if len(error.missing_permissions) == 1:
msg = _("I require the {permission} permission to execute that command.").format( msg = _("I require the {permission} permission to execute that command.").format(
permission=formatted permission=formatted
) )
else: else:
msg = _("I require {permission_list} permissions to execute that command.").format( msg = _("I require {permission_list} permissions to execute that command.").format(
permission_list=formatted permission_list=formatted
) )
await self._send_from_interaction(interaction, msg) await self._send_from_interaction(interaction, msg)
elif isinstance(error, NoPrivateMessage): elif isinstance(error, NoPrivateMessage):
# Seems to be only called normally by the has_role check # Seems to be only called normally by the has_role check
await self._send_from_interaction( await self._send_from_interaction(
interaction, _("That command is not available in DMs.") interaction, _("That command is not available in DMs.")
) )
elif isinstance(error, CommandOnCooldown): elif isinstance(error, CommandOnCooldown):
relative_time = discord.utils.format_dt( relative_time = discord.utils.format_dt(
datetime.now(timezone.utc) + timedelta(seconds=error.retry_after), "R" datetime.now(timezone.utc) + timedelta(seconds=error.retry_after), "R"
) )
msg = _("This command is on cooldown. Try again {relative_time}.").format( msg = _("This command is on cooldown. Try again {relative_time}.").format(
relative_time=relative_time relative_time=relative_time
) )
await self._send_from_interaction(interaction, msg, delete_after=error.retry_after) await self._send_from_interaction(interaction, msg, delete_after=error.retry_after)
elif isinstance(error, CheckFailure): elif isinstance(error, CheckFailure):
await self._send_from_interaction( await self._send_from_interaction(
interaction, _("You are not permitted to use this command.") interaction, _("You are not permitted to use this command.")
) )
else: else:
log.exception(type(error).__name__, exc_info=error) log.exception(type(error).__name__, exc_info=error)
# DEP-WARN # DEP-WARN
def _remove_with_module(self, name: str, *args, **kwargs) -> None: def _remove_with_module(self, name: str, *args, **kwargs) -> None:
"""Handles cases where a module raises an exception in the loading process, but added commands to the tree. """Handles cases where a module raises an exception in the loading process, but added commands to the tree.
Duplication of the logic in the super class, but for the containers used by this subclass. Duplication of the logic in the super class, but for the containers used by this subclass.
""" """
super()._remove_with_module(name, *args, **kwargs) super()._remove_with_module(name, *args, **kwargs)
remove = [] remove = []
for key, cmd in self._disabled_context_menus.items(): for key, cmd in self._disabled_context_menus.items():
if cmd.module is not None and self._is_submodule(name, cmd.module): if cmd.module is not None and self._is_submodule(name, cmd.module):
remove.append(key) remove.append(key)
for key in remove: for key in remove:
del self._disabled_context_menus[key] del self._disabled_context_menus[key]
remove = [] remove = []
for key, cmd in self._disabled_global_commands.items(): for key, cmd in self._disabled_global_commands.items():
if cmd.module is not None and self._is_submodule(name, cmd.module): if cmd.module is not None and self._is_submodule(name, cmd.module):
remove.append(key) remove.append(key)
for key in remove: for key in remove:
del self._disabled_global_commands[key] del self._disabled_global_commands[key]