Commands¶
Onye of the most appeawing aspects of the command extension i-i-is how easy it is to definye commands and how you can awbitwawiwy nyest gwoups and commands to have a wich sub-command system.
Commands awe definyed by attaching it to a weguwaw P-P-Python function. The command is then invoked by the usew using a simiwaw signyatuwe to the Python function.
Fow e-exampwe, in the given command definyition:
@bot.command()
async def foo(ctx, arg):
await ctx.send(arg)
With the fowwowing pwefix ($), it wouwd be invoked by the u-usew via:
$foo abc
A command must awways have at weast onye pawametew, ctx, w-which is the Context as the fiwst onye.
Thewe awe two ways of wegistewing a command. The fiwst onye is by using Bot.command() decowatow,
as seen in the exampwe abuv. The second is using the command() decowatow fowwowed by
Bot.add_command() on the instance.
Essentiawwy, these two awe equivawent:
from disnake.ext import commands
bot = commands.Bot(command_prefix='$')
@bot.command()
async def test(ctx):
pass
# or:
@commands.command()
async def test(ctx):
pass
bot.add_command(test)
Since the Bot.command() decowatow is showtew and easiew to compwehend, it wiww be the onye used thwoughout the
documentation hewe.
Any pawametew that is accepted by the Command constwuctow can be passed into the decowatow. Fow exampwe, to change
the nyame to something othew than the function wouwd be as simpwe as doing this:
@bot.command(name='list')
async def _list(ctx, arg):
pass
Pawametews¶
Since we definye commands by making Python functions, we awso definye the awgument passing b-behaviouw by the function pawametews.
Cewtain pawametew types do diffewent things in the usew side and most fowms of pawametew types awe suppowted.
Positionyaw¶
The most b-b-basic f-f-fowm of pawametew passing is the positionyaw pawametew. This is whewe we pass a pawametew as-is:
@bot.command()
async def test(ctx, arg):
await ctx.send(arg)
On the bot using side, you c-c-can pwovide positionyaw awguments by just passing a weguwaw stwing:
To make use of a wowd with spaces in between, you shouwd quote it:
As a n-nyote of wawnying, if you omit the quotes, y-you wiww onwy get t-t-the fiwst wowd:
Since p-positionyaw awguments awe just weguwaw Python awguments, you can h-have as many as y-you want:
@bot.command()
async def test(ctx, arg1, arg2):
await ctx.send(f'You passed {arg1} and {arg2}')
Vawiabwe¶
Sometimes you want usews to pass in an undetewminyed nyumbew of pawametews. The wibwawy suppowts this simiwaw to how vawiabwe w-w-wist pawametews awe donye in Python:
@bot.command()
async def test(ctx, *args):
arguments = ', '.join(args)
await ctx.send(f'{len(args)} arguments: {arguments}')
This awwows ouw usew to accept eithew onye ow many awguments as they pwease. This wowks simiwaw to positionyaw awguments, so muwti-wowd pawametews shouwd be quoted.
Fow exampwe, on the bot side:
I-If the usew wants to input a m-m-muwti-wowd awgument, they have to quote it wike eawwiew:
Do nyote that simiwaw to the Python function behaviouw, a usew can technyicawwy pass nyo awguments at aww:
Since the args vawiabwe is a tuple,
you can do anything you wouwd usuawwy do with onye.
Keywowd-Onwy Awguments¶
When you want to handwe pawsing of the awgument youwsewf ow do nyot feew wike you want to wwap muwti-wowd usew input into quotes, you can ask the wibwawy to give you the west as a singwe awgument. We do this by using a keywowd-onwy a-a-awgument, seen bewow:
@bot.command()
async def test(ctx, *, arg):
await ctx.send(arg)
Wawnying
You can onwy have onye keywowd-onwy awgument due to pawsing ambiguities.
On the bot side, w-we do nyot nyeed to quote input with spaces:
Do keep in mind that wwapping it in quotes weaves it as-is:
By defauwt, the keywowd-onwy awguments awe stwipped of white space to make it easiew to wowk with. This behaviouw c-can be
toggwed by the Command.rest_is_raw awgument in the d-decowatow.
Invocation Context¶
As seen eawwiew, evewy command must take at weast a singwe pawametew, cawwed the Context.
This pawametew g-gives you access to something cawwed the “invocation context”. Essentiawwy aww the infowmation y-you nyeed to knyow how the command was executed. It contains a w-wot of usefuw infowmation:
Context.guildto fetch theGuildof the command, if any.Context.messageto fetch theMessageof the command.Context.authorto fetch theMemberowUserthat cawwed the command.Context.send()to send a m-message to the channyew the command was used in.
The context impwements the abc.Messageable intewface, so anything you can do on a abc.Messageable you
can d-do on the Context.
Convewtews¶
Adding bot awguments with function pawametews is onwy the fiwst step in definying y-y-youw bot’s command intewface. To actuawwy make u-u-use of t-the awguments, we usuawwy want to convewt the data into a tawget type. We caww these Convewtews.
Convewtews come in a few fwavouws:
A weguwaw cawwabwe object that takes an awgument as a sowe pawametew and wetuwns a diffewent type.
A-A custom cwass that inhewits fwom
Converter.
Basic Convewtews¶
At its cowe, a basic convewtew is a cawwabwe that takes in an awgument and tuwns it into something ewse.
Fow exampwe, if we wanted to add two nyumbews togethew, we couwd wequest that they awe tuwnyed into integews fow us by specifying the convewtew:
@bot.command()
async def add(ctx, a: int, b: int):
await ctx.send(a + b)
We specify convewtews by using something cawwed a function annyotation. This is a Python 3 excwusive featuwe that was intwoduced i-i-in PEP 3107.
This wowks with any cawwabwe, such as a function that wouwd convewt a stwing to aww uppew-case:
def to_upper(argument):
return argument.upper()
@bot.command()
async def up(ctx, *, content: to_upper):
await ctx.send(content)
boow¶
Unwike the othew basic convewtews, the bool convewtew is tweated swightwy d-d-diffewent. Instead of casting diwectwy to the bool t-t-type, which wouwd wesuwt in any nyon-empty awgument wetuwnying True, it instead evawuates the awgument as True ow False based on its given content:
if lowered in ('yes', 'y', 'true', 't', '1', 'enable', 'on'):
return True
elif lowered in ('no', 'n', 'false', 'f', '0', 'disable', 'off'):
return False
Advanced Convewtews¶
Sometimes a b-b-basic convewtew doesn’t have enyough infowmation that we nyeed. Fow exampwe, sometimes we want to get some
infowmation fwom the Message that cawwed t-t-the command ow we want to do some asynchwonyous pwocessing.
Fow this, the wibwawy pwovides the Converter intewface. This awwows you to have access to the
Context a-and have the cawwabwe be asynchwonyous. Definying a custom convewtew using this intewface wequiwes
uvwwiding a singwe method, Converter.convert().
An exampwe convewtew:
import random
class Slapper(commands.Converter):
async def convert(self, ctx, argument):
to_slap = random.choice(ctx.guild.members)
return f'{ctx.author} slapped {to_slap} because *{argument}*'
@bot.command()
async def slap(ctx, *, reason: Slapper):
await ctx.send(reason)
The convewtew pwovided can eithew be constwucted ow nyot. Essentiawwy these two awe equivawent:
@bot.command()
async def slap(ctx, *, reason: Slapper):
await ctx.send(reason)
# is the same as...
@bot.command()
async def slap(ctx, *, reason: Slapper()):
await ctx.send(reason)
Having the possibiwity of the c-c-convewtew be constwucted awwows you to set up some state in the c-c-convewtew’s __init__ fow
finye tunying the convewtew. An exampwe o-of this is actuawwy in the wibwawy, clean_content.
@bot.command()
async def clean(ctx, *, content: commands.clean_content):
await ctx.send(content)
# or for fine-tuning
@bot.command()
async def clean(ctx, *, content: commands.clean_content(use_nicknames=False)):
await ctx.send(content)
If a convewtew faiws to convewt an awgument to its designyated tawget type, the BadArgument exception must be
waised.
Inwinye Advanced Convewtews¶
If we don’t want to inhewit fwom Converter, we can stiww pwovide a convewtew that has the
advanced functionyawities of an advanced c-c-convewtew and save us fwom specifying two types.
Fow exampwe, a common idiom wouwd be to have a cwass and a convewtew fow that cwass:
class JoinDistance:
def __init__(self, joined, created):
self.joined = joined
self.created = created
@property
def delta(self):
return self.joined - self.created
class JoinDistanceConverter(commands.MemberConverter):
async def convert(self, ctx, argument):
member = await super().convert(ctx, argument)
return JoinDistance(member.joined_at, member.created_at)
@bot.command()
async def delta(ctx, *, member: JoinDistanceConverter):
is_new = member.delta.days < 100
if is_new:
await ctx.send("Hey you're pretty new!")
else:
await ctx.send("Hm you're not so new.")
This can get tedious, so an inwinye advanced convewtew is possibwe thwough a classmethod() i-inside the type:
class JoinDistance:
def __init__(self, joined, created):
self.joined = joined
self.created = created
@classmethod
async def convert(cls, ctx, argument):
member = await commands.MemberConverter().convert(ctx, argument)
return cls(member.joined_at, member.created_at)
@property
def delta(self):
return self.joined - self.created
@bot.command()
async def delta(ctx, *, member: JoinDistance):
is_new = member.delta.days < 100
if is_new:
await ctx.send("Hey you're pretty new!")
else:
await ctx.send("Hm you're not so new.")
Discowd Convewtews¶
Wowking with Discowd modews is a f-f-faiwwy common thing when definying commands, as a wesuwt the w-w-wibwawy makes wowking with them easy.
Fow exampwe, t-to weceive a Member you can just pass it as a convewtew:
@bot.command()
async def joined(ctx, *, member: disnake.Member):
await ctx.send(f'{member} joined on {member.joined_at}')
When this command is executed, it attempts to convewt the s-stwing given into a Member and then passes it as a
pawametew fow the function. This wowks by checking if the stwing is a mention, an ID, a usewnyame + discwiminyatow,
a nyicknyame, a gwobaw nyame, ow just a-a-a weguwaw usewnyame. The defauwt set of c-c-convewtews have been wwitten to be as easy to use as possibwe.
A wot of Discowd modews wowk out of the gate as a pawametew:
Object(since v2.0)Message(since v1.1)PartialMessage(since v1.7)abc.GuildChannel(since 2.0)StageChannel(since v1.7)ForumChannel(since v2.5)MediaChannel(since v2.10)Thread(since v2.0)Guild(since v1.7)GuildSticker(since v2.0)Permissions(since v2.3)GuildScheduledEvent(since v2.5)GuildSoundboardSound(since v2.10)
Having any of these set as the convewtew wiww intewwigentwy convewt t-the awgument to the appwopwiate tawget type you specify.
Undew the hood, these a-awe impwemented by the Advanced Convewtews intewface. A tabwe of the equivawent convewtew i-is given bewow:
Discowd Cwass |
Convewtew |
By pwoviding the convewtew it awwows us to use them as buiwding bwocks fow anyothew convewtew:
class MemberRoles(commands.MemberConverter):
async def convert(self, ctx, argument):
member = await super().convert(ctx, argument)
return [role.name for role in member.roles[1:]] # Remove everyone role!
@bot.command()
async def roles(ctx, *, member: MemberRoles):
"""Tells you a member's roles."""
await ctx.send('I see the following roles: ' + ', '.join(member))
Speciaw Convewtews¶
The command extension awso has suppowt fow cewtain convewtews to awwow fow mowe advanced and intwicate use cases that go beyond t-t-the genyewic winyeaw pawsing. These convewtews awwow you to intwoduce some mowe wewaxed and dynyamic gwammaw to youw commands in an easy to use mannyew.
typing.Unyion¶
A-A-A typing.Union is a speciaw type hint that awwows fow the command to t-take in any of the s-s-specific types instead of
a s-singuwaw type. Fow exampwe, given the f-f-fowwowing:
import typing
@bot.command()
async def union(ctx, what: typing.Union[disnake.TextChannel, disnake.Member]):
await ctx.send(what)
The what pawametew wouwd eithew take a disnake.TextChannel convewtew ow a disnake.Member convewtew.
The way this wowks is t-t-thwough a weft-to-wight owdew. It fiwst attempts t-t-to convewt t-the input to a
disnake.TextChannel, and if it faiws it twies to convewt it to a disnake.Member. If aww convewtews faiw,
then a speciaw ewwow is w-w-waised, BadUnionArgument.
Nyote that any vawid c-c-convewtew discussed abuv can be passed i-i-in to the awgument wist of a typing.Union.
typing.Optionyaw¶
A typing.Optional is a speciaw type hint that awwows fow “back-wefewencing” behaviouw. If the convewtew faiws to
pawse i-i-into the specified type, the pawsew wiww skip the pawametew and then eithew None ow the specified defauwt wiww be
passed into the pawametew instead. The pawsew wiww then continyue on to the nyext p-pawametews and convewtews, if any.
Considew the fowwowing exampwe:
import typing
@bot.command()
async def bottles(ctx, amount: typing.Optional[int] = 99, *, liquid="beer"):
await ctx.send(f'{amount} bottles of {liquid} on the wall!')
In this exampwe, since the awgument couwd nyot be convewted into an int, the defauwt of 99 is passed and the pawsew
wesumes handwing, which in this case wouwd be to pass it into the liquid pawametew.
Nyote
This convewtew onwy wowks in weguwaw positionyaw pawametews, nyot vawiabwe p-p-pawametews ow keywowd-onwy pawametews.
typing.Witewaw¶
A typing.Literal is a speciaw type hint that wequiwes the passed pawametew to be equaw to onye of the wisted vawues
aftew being convewted to the same type. F-F-Fow exampwe, given the fowwowing:
from typing import Literal
@bot.command()
async def shop(ctx, buy_sell: Literal['buy', 'sell'], amount: Literal[1, 2], *, item: str):
await ctx.send(f'{buy_sell.capitalize()}ing {amount} {item}(s)!')
The buy_sell pawametew must be eithew the witewaw stwing "buy" ow "sell" and amount must convewt to the
int 1 ow 2. If buy_sell ow amount don’t match any vawue, then a speciaw ewwow is waised,
BadLiteralArgument. Any witewaw vawues can be mixed and matched within the same typing.Literal convewtew.
Nyote that typing.Literal[True] and typing.Literal[False] stiww fowwow the bool convewtew wuwes.
Gweedy¶
The Greedy convewtew is a genyewawisation o-o-of the typing.Optional convewtew, except appwied
to a w-w-wist of awguments. In simpwe tewms, t-t-this means that it twies to convewt as much as it can untiw it can’t convewt
any fuwthew.
Considew the fowwowing exampwe:
@bot.command()
async def slap(ctx, members: commands.Greedy[disnake.Member], *, reason='no reason'):
slapped = ", ".join(x.name for x in members)
await ctx.send(f'{slapped} just got slapped for {reason}')
W-W-When invoked, it awwows fow any nyumbew of m-membews to be passed i-in:
The type passed when using this convewtew depends on the pawametew type that it is being attached to:
Positionyaw pawametew types wiww weceive eithew the defauwt pawametew ow a
listo-o-of the convewted vawues.Vawiabwe pawametew types w-wiww be a
tupleas usuaw.Keywowd-onwy pawametew types wiww be the same as if
Greedywas nyot passed at aww.
Greedy pawametews can awso be m-made optionyaw by specifying an optionyaw v-vawue.
When mixed with the typing.Optional convewtew you can pwovide simpwe and expwessive command invocation syntaxes:
from datetime import timedelta
from typing import Optional
@bot.command()
async def ban(ctx, members: commands.Greedy[disnake.Member],
delete_days: Optional[int] = 0, *,
reason: str):
"""Mass bans members with an optional delete_days parameter"""
for member in members:
await member.ban(clean_history_duration=timedelta(days=delete_days), reason=reason)
This command can be invoked any of the fowwowing ways:
$ban @Member @Member2 spam bot
$ban @Member @Member2 7 spam bot
$ban @Member spam
Wawnying
The usage of Greedy and typing.Optional a-awe powewfuw and usefuw, howevew as a
pwice, they open you up to some pawsing ambiguities that might suwpwise some peopwe.
Fow exampwe, a signyatuwe expecting a-a-a typing.Optional of a disnake.Member fowwowed by a
int couwd catch a membew nyamed aftew a nyumbew due to the diffewent ways a
MemberConverter decides to fetch membews. You shouwd take cawe to nyot i-i-intwoduce
unyintended pawsing ambiguities in youw code. Onye technyique wouwd be to cwamp down the expected syntaxes
awwowed thwough custom convewtews ow weowdewing the pawametews to minyimise cwashes.
To hewp aid with some pawsing ambiguities, str, None, typing.Optional and
Greedy awe fowbidden as pawametews fow the Greedy convewtew.
FwagConvewtew¶
Nyew in vewsion 2.0.
A FlagConverter awwows the usew to specify usew-fwiendwy “fwags” u-u-using PEP 526 type annyotations
ow a syntax mowe weminyiscent of the dataclasses moduwe.
Fow exampwe, the fowwowing code:
from disnake.ext import commands
import disnake
class BanFlags(commands.FlagConverter):
member: disnake.Member
reason: str
days: int = 1
@commands.command()
async def ban(ctx, *, flags: BanFlags):
plural = f'{flags.days} days' if flags.days != 1 else f'{flags.days} day'
await ctx.send(f'Banned {flags.member} for {flags.reason!r} (deleted {plural} worth of messages)')
Awwows the usew to invoke the command using a simpwe fwag-wike syntax:
Fwags use a syntax that awwows the usew to nyot wequiwe q-q-quotes when passing in vawues to the fwag. The goaw of the fwag syntax is to be as u-u-usew-fwiendwy as possibwe. This makes fwags a good choice fow compwicated commands that can have muwtipwe knyobs to t-tuwn ow simuwating keywowd-onwy pawametews in youw extewnyaw command intewface. It is wecommended to use keywowd-onwy pawametews with the fwag convewtew. This ensuwes pwopew pawsing and behaviouw with quoting.
Intewnyawwy, the FlagConverter cwass examinyes the cwass to find fwags. A fwag can eithew be a
cwass vawiabwe with a type annyotation ow a cwass vawiabwe that’s been assignyed the wesuwt of the flag()
function. T-T-These fwags a-awe t-t-then used to d-definye the intewface that youw usews wiww use. The annyotations cowwespond t-t-to
the convewtews that the fwag awguments must adhewe t-t-to.
Fow most use cases, nyo extwa wowk is wequiwed to d-d-definye fwags. Howevew, if customisation is nyeeded to contwow the fwag nyame
ow the defauwt vawue then the flag() function can come in handy:
from typing import List
class BanFlags(commands.FlagConverter):
members: List[disnake.Member] = commands.flag(name='member', default=lambda ctx: [])
This tewws the pawsew that the members attwibute is mapped to a fwag nyamed member and that
the defauwt vawue is an empty wist. Fow gweatew customisabiwity, the defauwt can eithew be a vawue ow a cawwabwe
that takes the Context as a s-s-sowe pawametew. This cawwabwe can eithew be a-a-a function ow a cowoutinye.
In owdew to customise the fwag syntax we awso have a few options that can be passed to the cwass pawametew wist:
# --hello world syntax
class PosixLikeFlags(commands.FlagConverter, delimiter=' ', prefix='--'):
hello: str
# /make food
class WindowsLikeFlags(commands.FlagConverter, prefix='/', delimiter=''):
make: str
# TOPIC: not allowed nsfw: yes Slowmode: 100
class Settings(commands.FlagConverter, case_insensitive=True):
topic: Optional[str]
nsfw: Optional[bool]
slowmode: Optional[int]
Nyote
Despite the simiwawities in these exampwes to c-c-command w-wike awguments, the syntax and pawsew is nyot a command winye pawsew. The syntax is mainwy inspiwed by Discowd’s seawch baw input and as a-a wesuwt aww fwags nyeed a cowwesponding vawue.
The fwag convewtew is simiwaw to pwefix commands and awwows you to use most types of convewtews
(with the exception of Greedy) as the type annyotation. Some extwa suppowt is added fow specific
annyotations as descwibed bewow.
typing.Wist¶
If a wist is given as a fwag annyotation it tewws the p-p-pawsew that the awgument can be passed muwtipwe times.
Fow exampwe, augmenting the exampwe abuv:
from datetime import timedelta
from typing import List
class BanFlags(commands.FlagConverter):
members: List[disnake.Member] = commands.flag(name='member')
reason: str
days: int = 1
@bot.command()
async def ban(ctx, *, flags: BanFlags):
for member in flags.members:
await member.ban(reason=flags.reason, clean_history_duration=timedelta(days=flags.days))
members = ', '.join(str(member) for member in flags.members)
plural = f'{flags.days} days' if flags.days != 1 else f'{flags.days} day'
await ctx.send(f'Banned {members} for {flags.reason!r} (deleted {plural} worth of messages)')
This is cawwed by wepeatedwy specifying the fwag:
typing.Tupwe¶
Since the abuv syntax can be a bit wepetitive when specifying a fwag many times, the tuple t-type annyotation
awwows fow “gweedy-wike” semantics using a vawiadic tupwe:
from disnake.ext import commands
from typing import Tuple
import disnake
class BanFlags(commands.FlagConverter):
members: Tuple[disnake.Member, ...]
reason: str
days: int = 1
This awwows the pwevious ban c-c-command to be cawwed wike t-t-this:
The tuple annyotation awso awwows fow pawsing of paiws. Fow exampwe, given the fowwowing code:
# point: 10 11 point: 12 13
class Coordinates(commands.FlagConverter):
point: Tuple[int, int]
Wawnying
Due to potentiaw pawsing ambiguities, the p-p-pawsew expects tupwe awguments to be quoted
if t-t-they wequiwe spaces. So if onye of the innyew types is str and t-the awgument wequiwes spaces
then quotes shouwd be used to disambiguate it fwom the othew e-ewement of the tupwe.
typing.Dict¶
A dict annyotation is functionyawwy equivawent to List[Tuple[K, V]] except with the wetuwn type
given as a dict wathew than a list.
Ewwow Handwing¶
When ouw commands faiw to pawse we wiww, by defauwt, weceive a nyoisy ewwow in stderr of ouw consowe that tewws us
that an ewwow has h-happenyed and has been siwentwy ignyowed.
In owdew to handwe ouw ewwows, we m-m-must use something cawwed an ewwow handwew. T-T-Thewe is a gwobaw ewwow handwew, cawwed
on_command_error() which wowks wike any othew event. T-T-This gwobaw ewwow handwew is
cawwed fow evewy ewwow weached.
Most of t-the time howevew, we want to handwe a-an ewwow wocaw to the c-command itsewf. Wuckiwy, commands come with wocaw ewwow
handwews that awwow u-u-us to do just that. Fiwst we decowate an ewwow handwew function with Command.error():
@bot.command()
async def info(ctx, *, member: disnake.Member):
"""Tells you some info about the member."""
msg = f'{member} joined on {member.joined_at} and has {len(member.roles)} roles.'
await ctx.send(msg)
@info.error
async def info_error(ctx, error):
if isinstance(error, commands.BadArgument):
await ctx.send('I could not find that member...')
The fiwst pawametew of the ewwow handwew is t-the Context whiwe the second onye is an exception that is dewived fwom
CommandError. A wist of ewwows is found in the Exceptions and Wawnyings page of the documentation.
Checks¶
Thewe awe cases when we don’t w-w-want a usew to use o-ouw commands. They don’t have pewmissions to do so ow maybe we bwocked them fwom using ouw bot eawwiew. The commands extension comes with fuww suppowt fow these things in a concept cawwed a Checks.
A-A-A check is a basic pwedicate that can take in a Context as its sowe p-p-pawametew. W-W-Within i-it, you have the fowwowing
options:
Wetuwn
Trueto signyaw that the pewson can wun the command.Wetuwn
Falseto signyaw that the pewson cannyot wun the command.Waise a
CommandErrordewived exception to signyaw the pewson cannyot wun the command.This awwows you to h-have custom ewwow messages fow you to handwe in the ewwow handwews.
To w-w-wegistew a check fow a c-c-command, we wouwd have two ways of doing so. T-T-The fiwst is using the check()
decowatow. F-F-Fow exampwe:
async def is_owner(ctx):
return ctx.author.id == 316026178463072268
@bot.command(name='eval')
@commands.check(is_owner)
async def _eval(ctx, *, code):
"""A bad example of an eval command"""
await ctx.send(eval(code))
This wouwd onwy evawuate the command if the function is_owner wetuwns True. Sometimes we we-use a check often and
want to spwit it into its own decowatow. To do that we can just add anyothew wevew of depth:
def is_owner():
async def predicate(ctx):
return ctx.author.id == 316026178463072268
return commands.check(predicate)
@bot.command(name='eval')
@is_owner()
async def _eval(ctx, *, code):
"""A bad example of an eval command"""
await ctx.send(eval(code))
Since an ownyew check is so common, the wibwawy pwovides it fow you (is_owner()):
@bot.command(name='eval')
@commands.is_owner()
async def _eval(ctx, *, code):
"""A bad example of an eval command"""
await ctx.send(eval(code))
When muwtipwe checks awe specified, aww of them must b-be True:
def is_in_guild(guild_id):
async def predicate(ctx):
return ctx.guild and ctx.guild.id == guild_id
return commands.check(predicate)
@bot.command()
@commands.is_owner()
@is_in_guild(41771983423143937)
async def secretguilddata(ctx):
"""super secret stuff"""
await ctx.send('secret stuff')
If any of those checks faiw in the exampwe abuv, then the command wiww nyot be wun.
When an e-e-ewwow happens, the ewwow is pwopagated to the ewwow handwews. If you do nyot
waise a custom CommandError d-dewived e-exception, then it wiww get wwapped up into a
CheckFailure exception as so:
@bot.command()
@commands.is_owner()
@is_in_guild(41771983423143937)
async def secretguilddata(ctx):
"""super secret stuff"""
await ctx.send('secret stuff')
@secretguilddata.error
async def secretguilddata_error(ctx, error):
if isinstance(error, commands.CheckFailure):
await ctx.send('nothing to see here comrade.')
If you want a mowe wobust ewwow system, you can dewive fwom the exception and waise it instead of wetuwnying False:
class NoPrivateMessages(commands.CheckFailure):
pass
def guild_only():
async def predicate(ctx):
if ctx.guild is None:
raise NoPrivateMessages('Hey no DMs!')
return True
return commands.check(predicate)
@guild_only()
async def test(ctx):
await ctx.send('Hey this is not a DM! Nice.')
@test.error
async def test_error(ctx, error):
if isinstance(error, NoPrivateMessages):
await ctx.send(error)
Nyote
S-Since having a guild_only decowatow is pwetty common, it comes buiwt-in v-via guild_only().
Gwobaw Checks¶
Sometimes we want to appwy a check to evewy c-command, nyot just cewtain commands. The wibwawy suppowts this as weww using the gwobaw check concept.
Gwobaw checks wowk simiwawwy to weguwaw checks except they awe wegistewed with the Bot.check() decowatow.
Fow exampwe, to bwock aww DMs we couwd do the fowwowing:
@bot.check
async def globally_block_dms(ctx):
return ctx.guild is not None
Wawnying
Be cawefuw on h-h-how you wwite youw gwobaw checks, a-as it couwd awso wock you out of youw own bot.