mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-06 03:08:55 -05:00
[Core] Support already loaded packages in [p]load (#2116)
This commit is contained in:
parent
ee7e8aa782
commit
76bbcf2f8c
@ -11,10 +11,10 @@ import discord
|
||||
import sys
|
||||
from discord.ext.commands import when_mentioned_or
|
||||
|
||||
from . import Config, i18n, commands, errors
|
||||
from .cog_manager import CogManager
|
||||
from . import Config, i18n, commands
|
||||
from .rpc import RPCMixin
|
||||
from .help_formatter import Help, help as help_
|
||||
from .rpc import RPCMixin
|
||||
from .sentry import SentryManager
|
||||
from .utils import common_filters
|
||||
|
||||
@ -217,7 +217,7 @@ class RedBase(commands.GroupMixin, commands.bot.BotBase, RPCMixin):
|
||||
async def load_extension(self, spec: ModuleSpec):
|
||||
name = spec.name.split(".")[-1]
|
||||
if name in self.extensions:
|
||||
raise discord.ClientException(f"there is already a package named {name} loaded")
|
||||
raise errors.PackageAlreadyLoaded(spec)
|
||||
|
||||
lib = spec.loader.load_module()
|
||||
if not hasattr(lib, "setup"):
|
||||
|
||||
@ -13,7 +13,7 @@ from collections import namedtuple
|
||||
from pathlib import Path
|
||||
from random import SystemRandom
|
||||
from string import ascii_letters, digits
|
||||
from typing import TYPE_CHECKING, Union
|
||||
from typing import TYPE_CHECKING, Union, Tuple, List, Optional, Iterable, Sequence, Dict
|
||||
|
||||
import aiohttp
|
||||
import discord
|
||||
@ -25,6 +25,7 @@ from redbot.core import (
|
||||
VersionInfo,
|
||||
checks,
|
||||
commands,
|
||||
errors,
|
||||
i18n,
|
||||
)
|
||||
from .utils.predicates import MessagePredicate
|
||||
@ -59,7 +60,9 @@ class CoreLogic:
|
||||
self.bot.register_rpc_handler(self._version_info)
|
||||
self.bot.register_rpc_handler(self._invite_url)
|
||||
|
||||
async def _load(self, cog_names: list):
|
||||
async def _load(
|
||||
self, cog_names: Iterable[str]
|
||||
) -> Tuple[List[str], List[str], List[str], List[str]]:
|
||||
"""
|
||||
Loads cogs by name.
|
||||
Parameters
|
||||
@ -69,11 +72,12 @@ class CoreLogic:
|
||||
Returns
|
||||
-------
|
||||
tuple
|
||||
3 element tuple of loaded, failed, and not found cogs.
|
||||
4-tuple of loaded, failed, not found and already loaded cogs.
|
||||
"""
|
||||
failed_packages = []
|
||||
loaded_packages = []
|
||||
notfound_packages = []
|
||||
alreadyloaded_packages = []
|
||||
|
||||
bot = self.bot
|
||||
|
||||
@ -98,6 +102,8 @@ class CoreLogic:
|
||||
try:
|
||||
self._cleanup_and_refresh_modules(spec.name)
|
||||
await bot.load_extension(spec)
|
||||
except errors.PackageAlreadyLoaded:
|
||||
alreadyloaded_packages.append(name)
|
||||
except Exception as e:
|
||||
log.exception("Package loading failed", exc_info=e)
|
||||
|
||||
@ -109,9 +115,10 @@ class CoreLogic:
|
||||
await bot.add_loaded_package(name)
|
||||
loaded_packages.append(name)
|
||||
|
||||
return loaded_packages, failed_packages, notfound_packages
|
||||
return loaded_packages, failed_packages, notfound_packages, alreadyloaded_packages
|
||||
|
||||
def _cleanup_and_refresh_modules(self, module_name: str):
|
||||
@staticmethod
|
||||
def _cleanup_and_refresh_modules(module_name: str) -> None:
|
||||
"""Interally reloads modules so that changes are detected"""
|
||||
splitted = module_name.split(".")
|
||||
|
||||
@ -123,6 +130,7 @@ class CoreLogic:
|
||||
else:
|
||||
importlib._bootstrap._exec(lib.__spec__, lib)
|
||||
|
||||
# noinspection PyTypeChecker
|
||||
modules = itertools.accumulate(splitted, "{}.{}".format)
|
||||
for m in modules:
|
||||
maybe_reload(m)
|
||||
@ -131,7 +139,10 @@ class CoreLogic:
|
||||
for child_name, lib in children.items():
|
||||
importlib._bootstrap._exec(lib.__spec__, lib)
|
||||
|
||||
def _get_package_strings(self, packages: list, fmt: str, other: tuple = None):
|
||||
@staticmethod
|
||||
def _get_package_strings(
|
||||
packages: List[str], fmt: str, other: Optional[Tuple[str, ...]] = None
|
||||
) -> str:
|
||||
"""
|
||||
Gets the strings needed for the load, unload and reload commands
|
||||
"""
|
||||
@ -147,7 +158,7 @@ class CoreLogic:
|
||||
final_string = fmt.format(**form)
|
||||
return final_string
|
||||
|
||||
async def _unload(self, cog_names: list):
|
||||
async def _unload(self, cog_names: Iterable[str]) -> Tuple[List[str], List[str]]:
|
||||
"""
|
||||
Unloads cogs with the given names.
|
||||
|
||||
@ -175,14 +186,16 @@ class CoreLogic:
|
||||
|
||||
return unloaded_packages, failed_packages
|
||||
|
||||
async def _reload(self, cog_names):
|
||||
async def _reload(
|
||||
self, cog_names: Sequence[str]
|
||||
) -> Tuple[List[str], List[str], List[str], List[str]]:
|
||||
await self._unload(cog_names)
|
||||
|
||||
loaded, load_failed, not_found = await self._load(cog_names)
|
||||
loaded, load_failed, not_found, already_loaded = await self._load(cog_names)
|
||||
|
||||
return loaded, load_failed, not_found
|
||||
return loaded, load_failed, not_found, already_loaded
|
||||
|
||||
async def _name(self, name: str = None):
|
||||
async def _name(self, name: Optional[str] = None) -> str:
|
||||
"""
|
||||
Gets or sets the bot's username.
|
||||
|
||||
@ -201,7 +214,7 @@ class CoreLogic:
|
||||
|
||||
return self.bot.user.name
|
||||
|
||||
async def _prefixes(self, prefixes: list = None):
|
||||
async def _prefixes(self, prefixes: Optional[Sequence[str]] = None) -> List[str]:
|
||||
"""
|
||||
Gets or sets the bot's global prefixes.
|
||||
|
||||
@ -220,7 +233,8 @@ class CoreLogic:
|
||||
await self.bot.db.prefix.set(prefixes)
|
||||
return await self.bot.db.prefix()
|
||||
|
||||
async def _version_info(self):
|
||||
@classmethod
|
||||
async def _version_info(cls) -> Dict[str, str]:
|
||||
"""
|
||||
Version information for Red and discord.py
|
||||
|
||||
@ -231,7 +245,7 @@ class CoreLogic:
|
||||
"""
|
||||
return {"redbot": __version__, "discordpy": discord.__version__}
|
||||
|
||||
async def _invite_url(self):
|
||||
async def _invite_url(self) -> str:
|
||||
"""
|
||||
Generates the invite URL for the bot.
|
||||
|
||||
@ -248,11 +262,8 @@ class CoreLogic:
|
||||
class Core(commands.Cog, CoreLogic):
|
||||
"""Commands related to core functions"""
|
||||
|
||||
def __init__(self, bot):
|
||||
super().__init__(bot)
|
||||
|
||||
@commands.command(hidden=True)
|
||||
async def ping(self, ctx):
|
||||
async def ping(self, ctx: commands.Context):
|
||||
"""Pong."""
|
||||
await ctx.send("Pong.")
|
||||
|
||||
@ -313,7 +324,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
passed = self.get_bot_uptime()
|
||||
await ctx.send("Been up for: **{}** (since {} UTC)".format(passed, since))
|
||||
|
||||
def get_bot_uptime(self, *, brief=False):
|
||||
def get_bot_uptime(self, *, brief: bool = False):
|
||||
# Courtesy of Danny
|
||||
now = datetime.datetime.utcnow()
|
||||
delta = now - self.bot.uptime
|
||||
@ -416,7 +427,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
|
||||
@commands.command()
|
||||
@checks.is_owner()
|
||||
async def traceback(self, ctx, public: bool = False):
|
||||
async def traceback(self, ctx: commands.Context, public: bool = False):
|
||||
"""Sends to the owner the last command exception that has occurred
|
||||
|
||||
If public (yes is specified), it will be sent to the chat instead"""
|
||||
@ -433,14 +444,14 @@ class Core(commands.Cog, CoreLogic):
|
||||
|
||||
@commands.command()
|
||||
@checks.is_owner()
|
||||
async def invite(self, ctx):
|
||||
async def invite(self, ctx: commands.Context):
|
||||
"""Show's Red's invite url"""
|
||||
await ctx.author.send(await self._invite_url())
|
||||
|
||||
@commands.command()
|
||||
@commands.guild_only()
|
||||
@checks.is_owner()
|
||||
async def leave(self, ctx):
|
||||
async def leave(self, ctx: commands.Context):
|
||||
"""Leaves server"""
|
||||
await ctx.send("Are you sure you want me to leave this server? (y/n)")
|
||||
|
||||
@ -460,7 +471,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
|
||||
@commands.command()
|
||||
@checks.is_owner()
|
||||
async def servers(self, ctx):
|
||||
async def servers(self, ctx: commands.Context):
|
||||
"""Lists and allows to leave servers"""
|
||||
guilds = sorted(list(self.bot.guilds), key=lambda s: s.name.lower())
|
||||
msg = ""
|
||||
@ -502,18 +513,21 @@ class Core(commands.Cog, CoreLogic):
|
||||
|
||||
@commands.command()
|
||||
@checks.is_owner()
|
||||
async def load(self, ctx, *, cog_name: str):
|
||||
async def load(self, ctx: commands.Context, *cogs: str):
|
||||
"""Loads packages"""
|
||||
|
||||
cog_names = [c.strip() for c in cog_name.split(" ")]
|
||||
async with ctx.typing():
|
||||
loaded, failed, not_found = await self._load(cog_names)
|
||||
loaded, failed, not_found, already_loaded = await self._load(cogs)
|
||||
|
||||
if loaded:
|
||||
fmt = "Loaded {packs}."
|
||||
formed = self._get_package_strings(loaded, fmt)
|
||||
await ctx.send(formed)
|
||||
|
||||
if already_loaded:
|
||||
fmt = "The package{plural} {packs} {other} already loaded."
|
||||
formed = self._get_package_strings(already_loaded, fmt, ("is", "are"))
|
||||
await ctx.send(formed)
|
||||
|
||||
if failed:
|
||||
fmt = (
|
||||
"Failed to load package{plural} {packs}. Check your console or "
|
||||
@ -529,12 +543,9 @@ class Core(commands.Cog, CoreLogic):
|
||||
|
||||
@commands.command()
|
||||
@checks.is_owner()
|
||||
async def unload(self, ctx, *, cog_name: str):
|
||||
async def unload(self, ctx: commands.Context, *cogs: str):
|
||||
"""Unloads packages"""
|
||||
|
||||
cog_names = [c.strip() for c in cog_name.split(" ")]
|
||||
|
||||
unloaded, failed = await self._unload(cog_names)
|
||||
unloaded, failed = await self._unload(cogs)
|
||||
|
||||
if unloaded:
|
||||
fmt = "Package{plural} {packs} {other} unloaded."
|
||||
@ -548,10 +559,10 @@ class Core(commands.Cog, CoreLogic):
|
||||
|
||||
@commands.command(name="reload")
|
||||
@checks.is_owner()
|
||||
async def reload(self, ctx, *cogs: str):
|
||||
async def reload(self, ctx: commands.Context, *cogs: str):
|
||||
"""Reloads packages"""
|
||||
async with ctx.typing():
|
||||
loaded, failed, not_found = await self._reload(cogs)
|
||||
loaded, failed, not_found, already_loaded = await self._reload(cogs)
|
||||
|
||||
if loaded:
|
||||
fmt = "Package{plural} {packs} {other} reloaded."
|
||||
@ -570,34 +581,30 @@ class Core(commands.Cog, CoreLogic):
|
||||
|
||||
@commands.command(name="shutdown")
|
||||
@checks.is_owner()
|
||||
async def _shutdown(self, ctx, silently: bool = False):
|
||||
async def _shutdown(self, ctx: commands.Context, silently: bool = False):
|
||||
"""Shuts down the bot"""
|
||||
wave = "\N{WAVING HAND SIGN}"
|
||||
skin = "\N{EMOJI MODIFIER FITZPATRICK TYPE-3}"
|
||||
try: # We don't want missing perms to stop our shutdown
|
||||
with contextlib.suppress(discord.HTTPException):
|
||||
if not silently:
|
||||
await ctx.send(_("Shutting down... ") + wave + skin)
|
||||
except:
|
||||
pass
|
||||
await ctx.bot.shutdown()
|
||||
|
||||
@commands.command(name="restart")
|
||||
@checks.is_owner()
|
||||
async def _restart(self, ctx, silently: bool = False):
|
||||
async def _restart(self, ctx: commands.Context, silently: bool = False):
|
||||
"""Attempts to restart Red
|
||||
|
||||
Makes Red quit with exit code 26
|
||||
The restart is not guaranteed: it must be dealt
|
||||
with by the process manager in use"""
|
||||
try:
|
||||
with contextlib.suppress(discord.HTTPException):
|
||||
if not silently:
|
||||
await ctx.send(_("Restarting..."))
|
||||
except:
|
||||
pass
|
||||
await ctx.bot.shutdown(restart=True)
|
||||
|
||||
@commands.group(name="set")
|
||||
async def _set(self, ctx):
|
||||
async def _set(self, ctx: commands.Context):
|
||||
"""Changes Red's settings"""
|
||||
if ctx.invoked_subcommand is None:
|
||||
if ctx.guild:
|
||||
@ -629,7 +636,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
@_set.command()
|
||||
@checks.guildowner()
|
||||
@commands.guild_only()
|
||||
async def adminrole(self, ctx, *, role: discord.Role):
|
||||
async def adminrole(self, ctx: commands.Context, *, role: discord.Role):
|
||||
"""Sets the admin role for this server"""
|
||||
await ctx.bot.db.guild(ctx.guild).admin_role.set(role.id)
|
||||
await ctx.send(_("The admin role for this guild has been set."))
|
||||
@ -637,7 +644,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
@_set.command()
|
||||
@checks.guildowner()
|
||||
@commands.guild_only()
|
||||
async def modrole(self, ctx, *, role: discord.Role):
|
||||
async def modrole(self, ctx: commands.Context, *, role: discord.Role):
|
||||
"""Sets the mod role for this server"""
|
||||
await ctx.bot.db.guild(ctx.guild).mod_role.set(role.id)
|
||||
await ctx.send(_("The mod role for this guild has been set."))
|
||||
@ -645,7 +652,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
@_set.command(aliases=["usebotcolor"])
|
||||
@checks.guildowner()
|
||||
@commands.guild_only()
|
||||
async def usebotcolour(self, ctx):
|
||||
async def usebotcolour(self, ctx: commands.Context):
|
||||
"""
|
||||
Toggle whether to use the bot owner-configured colour for embeds.
|
||||
|
||||
@ -663,7 +670,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
@_set.command()
|
||||
@checks.guildowner()
|
||||
@commands.guild_only()
|
||||
async def serverfuzzy(self, ctx):
|
||||
async def serverfuzzy(self, ctx: commands.Context):
|
||||
"""
|
||||
Toggle whether to enable fuzzy command search for the server.
|
||||
|
||||
@ -679,7 +686,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
|
||||
@_set.command()
|
||||
@checks.is_owner()
|
||||
async def fuzzy(self, ctx):
|
||||
async def fuzzy(self, ctx: commands.Context):
|
||||
"""
|
||||
Toggle whether to enable fuzzy command search in DMs.
|
||||
|
||||
@ -695,7 +702,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
|
||||
@_set.command(aliases=["color"])
|
||||
@checks.is_owner()
|
||||
async def colour(self, ctx, *, colour: discord.Colour = None):
|
||||
async def colour(self, ctx: commands.Context, *, colour: discord.Colour = None):
|
||||
"""
|
||||
Sets a default colour to be used for the bot's embeds.
|
||||
|
||||
@ -713,7 +720,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
|
||||
@_set.command()
|
||||
@checks.is_owner()
|
||||
async def avatar(self, ctx, url: str):
|
||||
async def avatar(self, ctx: commands.Context, url: str):
|
||||
"""Sets Red's avatar"""
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(url) as r:
|
||||
@ -737,7 +744,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
@_set.command(name="game")
|
||||
@checks.bot_in_a_guild()
|
||||
@checks.is_owner()
|
||||
async def _game(self, ctx, *, game: str = None):
|
||||
async def _game(self, ctx: commands.Context, *, game: str = None):
|
||||
"""Sets Red's playing status"""
|
||||
|
||||
if game:
|
||||
@ -751,7 +758,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
@_set.command(name="listening")
|
||||
@checks.bot_in_a_guild()
|
||||
@checks.is_owner()
|
||||
async def _listening(self, ctx, *, listening: str = None):
|
||||
async def _listening(self, ctx: commands.Context, *, listening: str = None):
|
||||
"""Sets Red's listening status"""
|
||||
|
||||
status = ctx.bot.guilds[0].me.status if len(ctx.bot.guilds) > 0 else discord.Status.online
|
||||
@ -765,7 +772,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
@_set.command(name="watching")
|
||||
@checks.bot_in_a_guild()
|
||||
@checks.is_owner()
|
||||
async def _watching(self, ctx, *, watching: str = None):
|
||||
async def _watching(self, ctx: commands.Context, *, watching: str = None):
|
||||
"""Sets Red's watching status"""
|
||||
|
||||
status = ctx.bot.guilds[0].me.status if len(ctx.bot.guilds) > 0 else discord.Status.online
|
||||
@ -779,7 +786,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
@_set.command()
|
||||
@checks.bot_in_a_guild()
|
||||
@checks.is_owner()
|
||||
async def status(self, ctx, *, status: str):
|
||||
async def status(self, ctx: commands.Context, *, status: str):
|
||||
"""Sets Red's status
|
||||
|
||||
Available statuses:
|
||||
@ -808,7 +815,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
@_set.command()
|
||||
@checks.bot_in_a_guild()
|
||||
@checks.is_owner()
|
||||
async def stream(self, ctx, streamer=None, *, stream_title=None):
|
||||
async def stream(self, ctx: commands.Context, streamer=None, *, stream_title=None):
|
||||
"""Sets Red's streaming status
|
||||
Leaving both streamer and stream_title empty will clear it."""
|
||||
|
||||
@ -829,7 +836,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
|
||||
@_set.command(name="username", aliases=["name"])
|
||||
@checks.is_owner()
|
||||
async def _username(self, ctx, *, username: str):
|
||||
async def _username(self, ctx: commands.Context, *, username: str):
|
||||
"""Sets Red's username"""
|
||||
try:
|
||||
await self._name(name=username)
|
||||
@ -848,7 +855,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
@_set.command(name="nickname")
|
||||
@checks.admin()
|
||||
@commands.guild_only()
|
||||
async def _nickname(self, ctx, *, nickname: str = None):
|
||||
async def _nickname(self, ctx: commands.Context, *, nickname: str = None):
|
||||
"""Sets Red's nickname"""
|
||||
try:
|
||||
await ctx.guild.me.edit(nick=nickname)
|
||||
@ -859,7 +866,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
|
||||
@_set.command(aliases=["prefixes"])
|
||||
@checks.is_owner()
|
||||
async def prefix(self, ctx, *prefixes):
|
||||
async def prefix(self, ctx: commands.Context, *prefixes: str):
|
||||
"""Sets Red's global prefix(es)"""
|
||||
if not prefixes:
|
||||
await ctx.send_help()
|
||||
@ -870,7 +877,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
@_set.command(aliases=["serverprefixes"])
|
||||
@checks.admin()
|
||||
@commands.guild_only()
|
||||
async def serverprefix(self, ctx, *prefixes):
|
||||
async def serverprefix(self, ctx: commands.Context, *prefixes: str):
|
||||
"""Sets Red's server prefix(es)"""
|
||||
if not prefixes:
|
||||
await ctx.bot.db.guild(ctx.guild).prefix.set([])
|
||||
@ -882,7 +889,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
|
||||
@_set.command()
|
||||
@commands.cooldown(1, 60 * 10, commands.BucketType.default)
|
||||
async def owner(self, ctx):
|
||||
async def owner(self, ctx: commands.Context):
|
||||
"""Sets Red's main owner"""
|
||||
# According to the Python docs this is suitable for cryptographic use
|
||||
random = SystemRandom()
|
||||
@ -926,7 +933,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
|
||||
@_set.command()
|
||||
@checks.is_owner()
|
||||
async def token(self, ctx, token: str):
|
||||
async def token(self, ctx: commands.Context, token: str):
|
||||
"""Change bot token."""
|
||||
|
||||
if not isinstance(ctx.channel, discord.DMChannel):
|
||||
@ -1071,7 +1078,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
|
||||
@commands.command()
|
||||
@checks.is_owner()
|
||||
async def backup(self, ctx, backup_path: str = None):
|
||||
async def backup(self, ctx: commands.Context, backup_path: str = None):
|
||||
"""Creates a backup of all data for the instance."""
|
||||
from redbot.core.data_manager import basic_config, instance_name
|
||||
from redbot.core.drivers.red_json import JSON
|
||||
@ -1134,7 +1141,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
tar.add(str(f), recursive=False)
|
||||
print(str(backup_file))
|
||||
await ctx.send(
|
||||
_("A backup has been made of this instance. It is at {}.").format((backup_file))
|
||||
_("A backup has been made of this instance. It is at {}.").format(backup_file)
|
||||
)
|
||||
await ctx.send(_("Would you like to receive a copy via DM? (y/n)"))
|
||||
|
||||
@ -1157,7 +1164,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
|
||||
@commands.command()
|
||||
@commands.cooldown(1, 60, commands.BucketType.user)
|
||||
async def contact(self, ctx, *, message: str):
|
||||
async def contact(self, ctx: commands.Context, *, message: str):
|
||||
"""Sends a message to the owner"""
|
||||
guild = ctx.message.guild
|
||||
owner = discord.utils.get(ctx.bot.get_all_members(), id=ctx.bot.owner_id)
|
||||
@ -1200,7 +1207,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
await ctx.send(
|
||||
_("I cannot send your message, I'm unable to find my owner... *sigh*")
|
||||
)
|
||||
except:
|
||||
except discord.HTTPException:
|
||||
await ctx.send(_("I'm unable to deliver your message. Sorry."))
|
||||
else:
|
||||
await ctx.send(_("Your message has been sent."))
|
||||
@ -1212,14 +1219,14 @@ class Core(commands.Cog, CoreLogic):
|
||||
await ctx.send(
|
||||
_("I cannot send your message, I'm unable to find my owner... *sigh*")
|
||||
)
|
||||
except:
|
||||
except discord.HTTPException:
|
||||
await ctx.send(_("I'm unable to deliver your message. Sorry."))
|
||||
else:
|
||||
await ctx.send(_("Your message has been sent."))
|
||||
|
||||
@commands.command()
|
||||
@checks.is_owner()
|
||||
async def dm(self, ctx, user_id: int, *, message: str):
|
||||
async def dm(self, ctx: commands.Context, user_id: int, *, message: str):
|
||||
"""Sends a DM to a user
|
||||
|
||||
This command needs a user id to work.
|
||||
@ -1253,7 +1260,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
|
||||
try:
|
||||
await destination.send(embed=e)
|
||||
except:
|
||||
except discord.HTTPException:
|
||||
await ctx.send(
|
||||
_("Sorry, I couldn't deliver your message to {}").format(destination)
|
||||
)
|
||||
@ -1263,7 +1270,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
response = "{}\nMessage:\n\n{}".format(description, message)
|
||||
try:
|
||||
await destination.send("{}\n{}".format(box(response), content))
|
||||
except:
|
||||
except discord.HTTPException:
|
||||
await ctx.send(
|
||||
_("Sorry, I couldn't deliver your message to {}").format(destination)
|
||||
)
|
||||
@ -1272,7 +1279,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
|
||||
@commands.group()
|
||||
@checks.is_owner()
|
||||
async def whitelist(self, ctx):
|
||||
async def whitelist(self, ctx: commands.Context):
|
||||
"""
|
||||
Whitelist management commands.
|
||||
"""
|
||||
@ -1290,7 +1297,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
await ctx.send(_("User added to whitelist."))
|
||||
|
||||
@whitelist.command(name="list")
|
||||
async def whitelist_list(self, ctx):
|
||||
async def whitelist_list(self, ctx: commands.Context):
|
||||
"""
|
||||
Lists whitelisted users.
|
||||
"""
|
||||
@ -1304,7 +1311,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
await ctx.send(box(page))
|
||||
|
||||
@whitelist.command(name="remove")
|
||||
async def whitelist_remove(self, ctx, user: discord.User):
|
||||
async def whitelist_remove(self, ctx: commands.Context, user: discord.User):
|
||||
"""
|
||||
Removes user from whitelist.
|
||||
"""
|
||||
@ -1321,7 +1328,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
await ctx.send(_("User was not in the whitelist."))
|
||||
|
||||
@whitelist.command(name="clear")
|
||||
async def whitelist_clear(self, ctx):
|
||||
async def whitelist_clear(self, ctx: commands.Context):
|
||||
"""
|
||||
Clears the whitelist.
|
||||
"""
|
||||
@ -1330,19 +1337,19 @@ class Core(commands.Cog, CoreLogic):
|
||||
|
||||
@commands.group()
|
||||
@checks.is_owner()
|
||||
async def blacklist(self, ctx):
|
||||
async def blacklist(self, ctx: commands.Context):
|
||||
"""
|
||||
blacklist management commands.
|
||||
"""
|
||||
pass
|
||||
|
||||
@blacklist.command(name="add")
|
||||
async def blacklist_add(self, ctx, user: discord.User):
|
||||
async def blacklist_add(self, ctx: commands.Context, user: discord.User):
|
||||
"""
|
||||
Adds a user to the blacklist.
|
||||
"""
|
||||
if await ctx.bot.is_owner(user):
|
||||
ctx.send(_("You cannot blacklist an owner!"))
|
||||
await ctx.send(_("You cannot blacklist an owner!"))
|
||||
return
|
||||
|
||||
async with ctx.bot.db.blacklist() as curr_list:
|
||||
@ -1352,7 +1359,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
await ctx.send(_("User added to blacklist."))
|
||||
|
||||
@blacklist.command(name="list")
|
||||
async def blacklist_list(self, ctx):
|
||||
async def blacklist_list(self, ctx: commands.Context):
|
||||
"""
|
||||
Lists blacklisted users.
|
||||
"""
|
||||
@ -1366,7 +1373,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
await ctx.send(box(page))
|
||||
|
||||
@blacklist.command(name="remove")
|
||||
async def blacklist_remove(self, ctx, user: discord.User):
|
||||
async def blacklist_remove(self, ctx: commands.Context, user: discord.User):
|
||||
"""
|
||||
Removes user from blacklist.
|
||||
"""
|
||||
@ -1383,7 +1390,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
await ctx.send(_("User was not in the blacklist."))
|
||||
|
||||
@blacklist.command(name="clear")
|
||||
async def blacklist_clear(self, ctx):
|
||||
async def blacklist_clear(self, ctx: commands.Context):
|
||||
"""
|
||||
Clears the blacklist.
|
||||
"""
|
||||
@ -1393,14 +1400,14 @@ class Core(commands.Cog, CoreLogic):
|
||||
@commands.group()
|
||||
@commands.guild_only()
|
||||
@checks.admin_or_permissions(administrator=True)
|
||||
async def localwhitelist(self, ctx):
|
||||
async def localwhitelist(self, ctx: commands.Context):
|
||||
"""
|
||||
Whitelist management commands.
|
||||
"""
|
||||
pass
|
||||
|
||||
@localwhitelist.command(name="add")
|
||||
async def localwhitelist_add(self, ctx, *, user_or_role: str):
|
||||
async def localwhitelist_add(self, ctx: commands.Context, *, user_or_role: str):
|
||||
"""
|
||||
Adds a user or role to the whitelist.
|
||||
"""
|
||||
@ -1421,7 +1428,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
await ctx.send(_("Role added to whitelist."))
|
||||
|
||||
@localwhitelist.command(name="list")
|
||||
async def localwhitelist_list(self, ctx):
|
||||
async def localwhitelist_list(self, ctx: commands.Context):
|
||||
"""
|
||||
Lists whitelisted users and roles.
|
||||
"""
|
||||
@ -1435,7 +1442,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
await ctx.send(box(page))
|
||||
|
||||
@localwhitelist.command(name="remove")
|
||||
async def localwhitelist_remove(self, ctx, *, user_or_role: str):
|
||||
async def localwhitelist_remove(self, ctx: commands.Context, *, user_or_role: str):
|
||||
"""
|
||||
Removes user or role from whitelist.
|
||||
"""
|
||||
@ -1465,7 +1472,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
await ctx.send(_("Role was not in the whitelist."))
|
||||
|
||||
@localwhitelist.command(name="clear")
|
||||
async def localwhitelist_clear(self, ctx):
|
||||
async def localwhitelist_clear(self, ctx: commands.Context):
|
||||
"""
|
||||
Clears the whitelist.
|
||||
"""
|
||||
@ -1475,14 +1482,14 @@ class Core(commands.Cog, CoreLogic):
|
||||
@commands.group()
|
||||
@commands.guild_only()
|
||||
@checks.admin_or_permissions(administrator=True)
|
||||
async def localblacklist(self, ctx):
|
||||
async def localblacklist(self, ctx: commands.Context):
|
||||
"""
|
||||
blacklist management commands.
|
||||
"""
|
||||
pass
|
||||
|
||||
@localblacklist.command(name="add")
|
||||
async def localblacklist_add(self, ctx, *, user_or_role: str):
|
||||
async def localblacklist_add(self, ctx: commands.Context, *, user_or_role: str):
|
||||
"""
|
||||
Adds a user or role to the blacklist.
|
||||
"""
|
||||
@ -1495,7 +1502,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
user = True
|
||||
|
||||
if user and await ctx.bot.is_owner(obj):
|
||||
ctx.send(_("You cannot blacklist an owner!"))
|
||||
await ctx.send(_("You cannot blacklist an owner!"))
|
||||
return
|
||||
|
||||
async with ctx.bot.db.guild(ctx.guild).blacklist() as curr_list:
|
||||
@ -1508,7 +1515,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
await ctx.send(_("Role added to blacklist."))
|
||||
|
||||
@localblacklist.command(name="list")
|
||||
async def localblacklist_list(self, ctx):
|
||||
async def localblacklist_list(self, ctx: commands.Context):
|
||||
"""
|
||||
Lists blacklisted users and roles.
|
||||
"""
|
||||
@ -1522,7 +1529,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
await ctx.send(box(page))
|
||||
|
||||
@localblacklist.command(name="remove")
|
||||
async def localblacklist_remove(self, ctx, *, user_or_role: str):
|
||||
async def localblacklist_remove(self, ctx: commands.Context, *, user_or_role: str):
|
||||
"""
|
||||
Removes user or role from blacklist.
|
||||
"""
|
||||
@ -1552,7 +1559,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
await ctx.send(_("Role was not in the blacklist."))
|
||||
|
||||
@localblacklist.command(name="clear")
|
||||
async def localblacklist_clear(self, ctx):
|
||||
async def localblacklist_clear(self, ctx: commands.Context):
|
||||
"""
|
||||
Clears the blacklist.
|
||||
"""
|
||||
@ -1703,8 +1710,8 @@ class Core(commands.Cog, CoreLogic):
|
||||
@autoimmune_group.command(name="list")
|
||||
async def autoimmune_list(self, ctx: commands.Context):
|
||||
"""
|
||||
Get's the current members and roles
|
||||
|
||||
Get's the current members and roles
|
||||
|
||||
configured for automatic moderation action immunity
|
||||
"""
|
||||
ai_ids = await ctx.bot.db.guild(ctx.guild).autoimmune_ids()
|
||||
|
||||
16
redbot/core/errors.py
Normal file
16
redbot/core/errors.py
Normal file
@ -0,0 +1,16 @@
|
||||
import importlib.machinery
|
||||
|
||||
|
||||
class RedError(Exception):
|
||||
"""Base error class for Red-related errors."""
|
||||
|
||||
|
||||
class PackageAlreadyLoaded(RedError):
|
||||
"""Raised when trying to load an already-loaded package."""
|
||||
|
||||
def __init__(self, spec: importlib.machinery.ModuleSpec, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.spec: importlib.machinery.ModuleSpec = spec
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"There is already a package named {self.spec.name.split('.')[-1]} loaded"
|
||||
@ -3,8 +3,6 @@ import re
|
||||
from pathlib import Path
|
||||
from typing import Callable, Union
|
||||
|
||||
from . import commands
|
||||
|
||||
__all__ = ["get_locale", "set_locale", "reload_locales", "cog_i18n", "Translator"]
|
||||
|
||||
_current_locale = "en_us"
|
||||
@ -219,6 +217,12 @@ class Translator(Callable[[str], str]):
|
||||
self.translations.update({untranslated: translated})
|
||||
|
||||
|
||||
# This import to be down here to avoid circular import issues.
|
||||
# This will be cleaned up at a later date
|
||||
# noinspection PyPep8
|
||||
from . import commands
|
||||
|
||||
|
||||
def cog_i18n(translator: Translator):
|
||||
"""Get a class decorator to link the translator to this cog."""
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user