Merge V3/release/3.0.0 into V3/develop (#2209)

This commit is contained in:
Toby Harradine 2018-10-09 09:10:05 +11:00 committed by GitHub
commit 00bc3c86b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 150 additions and 121 deletions

View File

@ -288,7 +288,10 @@ class Alias(commands.Cog):
"""Try to execute help for the base command of the alias."""
is_alias, alias = await self.is_alias(ctx.guild, alias_name=alias_name)
if is_alias:
base_cmd = alias.command[0]
if self.is_command(alias.command):
base_cmd = alias.command
else:
base_cmd = alias.command.rsplit(" ", 1)[0]
new_msg = copy(ctx.message)
new_msg.content = _("{prefix}help {command}").format(

View File

@ -48,7 +48,7 @@ class Audio(commands.Cog):
"ws_port": "2332",
"password": "youshallnotpass",
"status": False,
"current_build": [3, 0, 0, "alpha", 0],
"current_build": redbot.core.VersionInfo.from_str("3.0.0a0").to_json(),
"use_external_lavalink": False,
}

View File

@ -43,11 +43,8 @@ class CommandObj:
@staticmethod
async def get_commands(config) -> dict:
commands = await config.commands()
customcommands = {k: v for k, v in commands.items() if commands[k]}
if len(customcommands) == 0:
return None
return customcommands
_commands = await config.commands()
return {k: v for k, v in _commands.items() if _commands[k]}
async def get_responses(self, ctx):
intro = _(
@ -79,7 +76,8 @@ class CommandObj:
responses.append(msg.content)
return responses
def get_now(self) -> str:
@staticmethod
def get_now() -> str:
# Get current time as a string, for 'created_at' and 'edited_at' fields
# in the ccinfo dict
return "{:%d/%m/%Y %H:%M:%S}".format(datetime.utcnow())
@ -312,8 +310,6 @@ class CustomCommands(commands.Cog):
Example:
- `[p]customcom edit yourcommand Text you want`
"""
command = command.lower()
try:
await self.commandobj.edit(ctx=ctx, command=command, response=text)
await ctx.send(_("Custom command successfully edited."))
@ -353,12 +349,12 @@ class CustomCommands(commands.Cog):
continue
results.append("{command:<15} : {result}".format(command=command, result=result))
commands = "\n".join(results)
_commands = "\n".join(results)
if len(commands) < 1500:
await ctx.send(box(commands))
if len(_commands) < 1500:
await ctx.send(box(_commands))
else:
for page in pagify(commands, delims=[" ", "\n"]):
for page in pagify(_commands, delims=[" ", "\n"]):
await ctx.author.send(box(page))
async def on_message(self, message):
@ -411,11 +407,11 @@ class CustomCommands(commands.Cog):
async def cc_command(self, ctx, *cc_args, raw_response, **cc_kwargs) -> None:
cc_args = (*cc_args, *cc_kwargs.values())
results = re.findall(r"\{([^}]+)\}", raw_response)
results = re.findall(r"{([^}]+)\}", raw_response)
for result in results:
param = self.transform_parameter(result, ctx.message)
raw_response = raw_response.replace("{" + result + "}", param)
results = re.findall(r"\{((\d+)[^\.}]*(\.[^:}]+)?[^}]*)\}", raw_response)
results = re.findall(r"{((\d+)[^.}]*(\.[^:}]+)?[^}]*)\}", raw_response)
if results:
low = min(int(result[1]) for result in results)
for result in results:
@ -424,9 +420,10 @@ class CustomCommands(commands.Cog):
raw_response = raw_response.replace("{" + result[0] + "}", arg)
await ctx.send(raw_response)
def prepare_args(self, raw_response) -> Mapping[str, Parameter]:
args = re.findall(r"\{(\d+)[^:}]*(:[^\.}]*)?[^}]*\}", raw_response)
default = [["ctx", Parameter("ctx", Parameter.POSITIONAL_OR_KEYWORD)]]
@staticmethod
def prepare_args(raw_response) -> Mapping[str, Parameter]:
args = re.findall(r"{(\d+)[^:}]*(:[^.}]*)?[^}]*\}", raw_response)
default = [("ctx", Parameter("ctx", Parameter.POSITIONAL_OR_KEYWORD))]
if not args:
return OrderedDict(default)
allowed_builtins = {
@ -466,7 +463,7 @@ class CustomCommands(commands.Cog):
try:
anno = getattr(discord, anno)
# force an AttributeError if there's no discord.py converter
getattr(commands.converter, anno.__name__ + "Converter")
getattr(commands, anno.__name__ + "Converter")
except AttributeError:
anno = allowed_builtins.get(anno.lower(), Parameter.empty)
if (
@ -520,7 +517,8 @@ class CustomCommands(commands.Cog):
# only update cooldowns if the command isn't on cooldown
self.cooldowns.update(new_cooldowns)
def transform_arg(self, result, attr, obj) -> str:
@staticmethod
def transform_arg(result, attr, obj) -> str:
attr = attr[1:] # strip initial dot
if not attr:
return str(obj)
@ -530,7 +528,8 @@ class CustomCommands(commands.Cog):
return raw_result
return str(getattr(obj, attr, raw_result))
def transform_parameter(self, result, message) -> str:
@staticmethod
def transform_parameter(result, message) -> str:
"""
For security reasons only specific objects are allowed
Internals are ignored

View File

@ -268,7 +268,7 @@ class Economy(commands.Cog):
await ctx.send(
_(
"{author.mention} Here, take some {currency}. "
"Enjoy! (+{amount} {new_balance}!)\n\n"
"Enjoy! (+{amount} {currency}!)\n\n"
"You currently have {new_balance} {currency}.\n\n"
"You are currently #{pos} on the global leaderboard!"
).format(

View File

@ -193,7 +193,7 @@ class Mod(commands.Cog):
yes_or_no=_("Yes") if respect_hierarchy else _("No")
)
msg += _("Delete delay: {num_seconds}\n").format(
num_seconds=_("{num} seconds").format(delete_delay)
num_seconds=_("{num} seconds").format(num=delete_delay)
if delete_delay != -1
else _("None")
)

View File

@ -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"):

View File

@ -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
View 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"

View File

@ -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."""