Skip to content

Commit

Permalink
Implement check examptions
Browse files Browse the repository at this point in the history
  • Loading branch information
tandemdude committed Jun 5, 2021
1 parent b267726 commit 43d4c77
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 7 deletions.
29 changes: 29 additions & 0 deletions lightbulb/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"bot_has_permissions",
"has_attachment",
"check",
"check_exempt",
]

import functools
Expand Down Expand Up @@ -564,3 +565,31 @@ def decorate(command: T_inv) -> T_inv:
return command

return decorate


def check_exempt(predicate):
"""
A decorator which allows checks to be bypassed if the ``predicate`` conditions are met. Predicate can
be a coroutine or a normal function but must take a single argument - ``context`` - and must return a
boolean - ``True`` if checks should be bypassed or ``False`` if not.
Args:
predicate: The callable which determines if command checks should be bypassed or not.
Example:
.. code-block:: python
@checks.check_exempt(lambda ctx: ctx.author.id == 1234)
@checks.guild_only()
@bot.command()
async def foo(ctx):
await ctx.respond("foo")
"""

def decorate(command: T_inv) -> T_inv:
_check_check_decorator_above_commands_decorator(command)
command._check_exempt_predicate = predicate
return command

return decorate
5 changes: 4 additions & 1 deletion lightbulb/command_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -864,7 +864,10 @@ async def process_commands_for_event(self, event: hikari.MessageCreateEvent) ->

try:
positional_args, keyword_arg = self.resolve_args_for_command(command, final_args)
await self._evaluate_checks(command, context)
if not await maybe_await(command._check_exempt_predicate, context):
await self._evaluate_checks(command, context)
else:
_LOGGER.debug("Checks bypassed for command: %s", context.message.content)
except (
errors.NotEnoughArguments,
errors.TooManyArguments,
Expand Down
13 changes: 7 additions & 6 deletions lightbulb/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ def __init__(
self._aliases = aliases
self.hidden = hidden
self._checks = []
self._check_exempt_predicate = lambda ctx: False
self._raw_error_listener = None
self._raw_before_invoke = None
self._raw_after_invoke = None
Expand Down Expand Up @@ -351,7 +352,7 @@ def callback(self) -> typing.Callable:
return self._callback

@property
def checks(self) -> typing.Iterable[typing.Callable[[context.Context], bool]]:
def checks(self) -> typing.Iterable[typing.Callable[[context_.Context], bool]]:
"""
The command's checks.
Expand Down Expand Up @@ -403,8 +404,8 @@ def before_invoke(self):
"""

def decorate(
func: typing.Callable[[context.Context], typing.Coroutine[None, None, typing.Any]]
) -> typing.Callable[[context.Context], typing.Coroutine[None, None, typing.Any]]:
func: typing.Callable[[context_.Context], typing.Coroutine[None, None, typing.Any]]
) -> typing.Callable[[context_.Context], typing.Coroutine[None, None, typing.Any]]:
self._raw_before_invoke = func
return func

Expand All @@ -419,8 +420,8 @@ def after_invoke(self):
"""

def decorate(
func: typing.Callable[[context.Context], typing.Coroutine[None, None, typing.Any]]
) -> typing.Callable[[context.Context], typing.Coroutine[None, None, typing.Any]]:
func: typing.Callable[[context_.Context], typing.Coroutine[None, None, typing.Any]]
) -> typing.Callable[[context_.Context], typing.Coroutine[None, None, typing.Any]]:
self._raw_after_invoke = func
return func

Expand Down Expand Up @@ -514,7 +515,7 @@ async def invoke(self, context: context_.Context, *args: str, **kwargs: str) ->

return await self._callback(context, *new_args, **kwargs)

def add_check(self, check_func: typing.Callable[[context.Context], typing.Coroutine[None, None, bool]]) -> None:
def add_check(self, check_func: typing.Callable[[context_.Context], typing.Coroutine[None, None, bool]]) -> None:
"""
Add a check to an instance of :obj:`~.commands.Command` or a subclass. The check passed must
be an awaitable function taking a single argument which will be an instance of :obj:`~.context.Context`.
Expand Down

0 comments on commit 43d4c77

Please sign in to comment.