aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRapptz <[email protected]>2020-01-06 22:03:27 -0500
committerRapptz <[email protected]>2020-01-06 22:03:56 -0500
commitae3dac0d5971e156f04fecafe5cc1773b019f93f (patch)
tree61a5605ecea92eed34012a84c4220a0d3110f9ae
parent[commands] Document the changed Command.can_run behaviour (diff)
downloaddiscord.py-ae3dac0d5971e156f04fecafe5cc1773b019f93f.tar.xz
discord.py-ae3dac0d5971e156f04fecafe5cc1773b019f93f.zip
[commands] Add check_any check to OR together various checks
-rw-r--r--discord/ext/commands/core.py70
-rw-r--r--discord/ext/commands/errors.py21
-rw-r--r--docs/ext/commands/api.rst2
3 files changed, 93 insertions, 0 deletions
diff --git a/discord/ext/commands/core.py b/discord/ext/commands/core.py
index f29ada94..5a7093d8 100644
--- a/discord/ext/commands/core.py
+++ b/discord/ext/commands/core.py
@@ -48,6 +48,7 @@ __all__ = (
'has_permissions',
'has_any_role',
'check',
+ 'check_any',
'bot_has_role',
'bot_has_permissions',
'bot_has_any_role',
@@ -1379,6 +1380,75 @@ def check(predicate):
decorator.predicate = predicate
return decorator
+def check_any(*checks):
+ """A :func:`check` that is added that checks if any of the checks passed
+ will pass, i.e. using logical OR.
+
+ If all checks fail then :exc:`.CheckAnyFailure` is raised to signal the failure.
+ It inherits from :exc:`.CheckFailure`.
+
+ .. note::
+
+ The ``predicate`` attribute for this function **is** a coroutine.
+
+ .. versionadded:: 1.3.0
+
+ Parameters
+ ------------
+ \*checks: Callable[[:class:`Context`], :class:`bool`]
+ An argument list of checks that have been decorated with
+ the :func:`check` decorator.
+
+ Raises
+ -------
+ TypeError
+ A check passed has not been decorated with the :func:`check`
+ decorator.
+
+ Examples
+ ---------
+
+ Creating a basic check to see if it's the bot owner or
+ the server owner:
+
+ .. code-block:: python3
+
+ def is_guild_owner():
+ def predicate(ctx):
+ return ctx.guild is not None and ctx.guild.owner_id == ctx.author.id
+ return commands.check(predicate)
+
+ @bot.command()
+ @commands.check_any(commands.is_owner(), is_guild_owner())
+ async def only_for_owners(ctx):
+ await ctx.send('Hello mister owner!')
+ """
+
+ unwrapped = []
+ for wrapped in checks:
+ try:
+ pred = wrapped.predicate
+ except AttributeError:
+ raise TypeError('%r must be wrapped by commands.check decorator' % wrapped) from None
+ else:
+ unwrapped.append(pred)
+
+ async def predicate(ctx):
+ errors = []
+ maybe = discord.utils.maybe_coroutine
+ for func in unwrapped:
+ try:
+ value = await maybe(func, ctx)
+ except CheckFailure as e:
+ errors.append(e)
+ else:
+ if value:
+ return True
+ # if we're here, all checks failed
+ raise CheckAnyFailure(unwrapped, errors)
+
+ return check(predicate)
+
def has_role(item):
"""A :func:`.check` that is added that checks if the member invoking the
command has the role specified via the name or ID specified.
diff --git a/discord/ext/commands/errors.py b/discord/ext/commands/errors.py
index fa92c049..71a0098a 100644
--- a/discord/ext/commands/errors.py
+++ b/discord/ext/commands/errors.py
@@ -34,6 +34,7 @@ __all__ = (
'PrivateMessageOnly',
'NoPrivateMessage',
'CheckFailure',
+ 'CheckAnyFailure',
'CommandNotFound',
'DisabledCommand',
'CommandInvokeError',
@@ -153,6 +154,26 @@ class CheckFailure(CommandError):
"""
pass
+class CheckAnyFailure(CheckFailure):
+ """Exception raised when all predicates in :func:`check_any` fail.
+
+ This inherits from :exc:`CheckFailure`.
+
+ .. versionadded:: 1.3
+
+ Attributes
+ ------------
+ errors: List[:class:`CheckFailure`]
+ A list of errors that were caught during execution.
+ checks: List[Callable[[:class:`Context`], :class:`bool`]]
+ A list of check predicates that failed.
+ """
+
+ def __init__(self, checks, errors):
+ self.checks = checks
+ self.errors = errors
+ super().__init__('You do not have permission to run this command.')
+
class PrivateMessageOnly(CheckFailure):
"""Exception raised when an operation does not work outside of private
message contexts.
diff --git a/docs/ext/commands/api.rst b/docs/ext/commands/api.rst
index 71efb2b5..3672823a 100644
--- a/docs/ext/commands/api.rst
+++ b/docs/ext/commands/api.rst
@@ -118,6 +118,8 @@ Checks
.. autofunction:: discord.ext.commands.check
+.. autofunction:: discord.ext.commands.check_any
+
.. autofunction:: discord.ext.commands.has_role
.. autofunction:: discord.ext.commands.has_permissions