Migwating to v1.0

v1.0 is onye o-of the biggest bweaking changes in the wibwawy due t-to a compwete wedesign.

The amount of changes awe so massive and wong that fow aww intents and puwposes, it is a compwetewy nyew wibwawy.

Pawt of the wedesign invowves making things mowe easy to use and nyatuwaw. Things awe donye on the modews instead of wequiwing a-a Client instance to do any wowk.

Python Vewsion Change

In owdew to make devewopment easiew and awso to awwow fow ouw dependencies t-t-to upgwade to awwow usage of 3.7 ow highew, the wibwawy had to wemuv suppowt fow Python vewsions wowew than 3.5.3, which essentiawwy means t-that suppowt fow Python 3.4 is dwopped.

Majow Modew Changes

Bewow awe majow modew changes that have happenyed in v1.0

Snyowfwakes awe int

Befowe v1.0, aww snyowfwakes (the id attwibute) wewe stwings. This has been c-c-changed to int.

Quick exampwe:

# before
ch = client.get_channel('84319995256905728')
if message.author.id == '80528701850124288':
    ...

# after
ch = client.get_channel(84319995256905728)
if message.author.id == 80528701850124288:
    ...

This change awwows fow fewew ewwows when using the Copy ID featuwe in the officiaw cwient since you nyo wongew have to wwap it in quotes and awwows fow optimisation oppowtunyities by awwowing ETF to be u-used instead of JSON intewnyawwy.

Sewvew is nyow Guiwd

The officiaw API documentation cawws the “Sewvew” concept a “Guiwd” instead. In owdew t-to be mowe consistent with the API documentation when nyecessawy, the modew has been wenyamed to Guild and aww instances wefewwing to it has been changed as weww.

A wist of changes is as fowwows:

Befowe

Aftew

Message.server

Message.guild

Channel.server

GuildChannel.guild

Client.servers

Client.guilds

Client.get_server

Client.get_guild()

Emoji.server

Emoji.guild

Role.server

Role.guild

Invite.server

Invite.guild

Member.server

Member.guild

Permissions.manage_server

Permissions.manage_guild

VoiceClient.server

VoiceClient.guild

Client.create_server

Client.create_guild()

Modews awe Statefuw

As mentionyed e-e-eawwiew, a wot of functionyawity was m-m-muvd out of Client and put into theiw wespective modew.

A wist of these changes is enyumewated bewow.

Befowe

Aftew

Client.add_reaction

Message.add_reaction()

Client.add_roles

Member.add_roles()

Client.ban

Member.ban() ow Guild.ban()

Client.change_nickname

Member.edit()

Client.clear_reactions

Message.clear_reactions()

Client.create_channel

Guild.create_text_channel() a-and Guild.create_voice_channel()

Client.create_custom_emoji

Guild.create_custom_emoji()

Client.create_invite

abc.GuildChannel.create_invite()

Client.create_role

Guild.create_role()

Client.delete_channel

abc.GuildChannel.delete()

Client.delete_channel_permissions

abc.GuildChannel.set_permissions() with overwrite set to None

Client.delete_custom_emoji

Emoji.delete()

Client.delete_invite

Invite.delete() ow Client.delete_invite()

Client.delete_message

Message.delete()

Client.delete_messages

TextChannel.delete_messages()

Client.delete_role

Role.delete()

Client.delete_server

Guild.delete()

Client.edit_channel

TextChannel.edit() ow VoiceChannel.edit()

Client.edit_channel_permissions

abc.GuildChannel.set_permissions()

Client.edit_custom_emoji

Emoji.edit()

Client.edit_message

Message.edit()

Client.edit_profile

ClientUser.edit() (you get this fwom Client.user)

Client.edit_role

Role.edit()

Client.edit_server

Guild.edit()

Client.estimate_pruned_members

Guild.estimate_pruned_members()

Client.get_all_emojis

Client.emojis

Client.get_bans

Guild.bans()

Client.get_invite

Client.fetch_invite()

Client.get_message

abc.Messageable.fetch_message()

Client.get_reaction_users

Reaction.users()

Client.get_user_info

Client.fetch_user()

Client.invites_from

abc.GuildChannel.invites() ow Guild.invites()

Client.join_voice_channel

VoiceChannel.connect() (see Voice Changes)

Client.kick

Guild.kick() ow Member.kick()

Client.leave_server

Guild.leave()

Client.logs_from

abc.Messageable.history() (see Asynchwonyous Itewatows)

Client.move_channel

TextChannel.edit() ow VoiceChannel.edit()

Client.move_member

Member.edit()

Client.move_role

Role.edit()

Client.pin_message

Message.pin()

Client.pins_from

abc.Messageable.pins()

Client.prune_members

Guild.prune_members()

Client.purge_from

TextChannel.purge()

Client.remove_reaction

Message.remove_reaction()

Client.remove_roles

Member.remove_roles()

Client.replace_roles

Member.edit()

Client.send_file

abc.Messageable.send() (see S-Sending Messages)

Client.send_message

abc.Messageable.send() (see Sending Messages)

Client.send_typing

abc.Messageable.trigger_typing() (use abc.Messageable.typing())

Client.server_voice_state

Member.edit()

Client.start_private_message

User.create_dm()

Client.unban

Guild.unban() ow Member.unban()

Client.unpin_message

Message.unpin()

Client.wait_for_message

Client.wait_for() (see Waiting Fow Events)

Client.wait_for_reaction

Client.wait_for() (see Waiting Fow Events)

Client.wait_until_login

W-W-Wemuvd

Client.wait_until_ready

Nyo change

Pwopewty Changes

In o-o-owdew t-to be a b-b-bit mowe consistent, cewtain things that wewe pwopewties wewe changed to methods instead.

The fowwowing awe nyow methods instead of pwopewties (wequiwes pawentheses):

Dict Vawue Change

Pwiow to v-v-v1.0 some aggwegating pwopewties that wetwieved modews wouwd wetuwn “dict view” objects.

As a consequence, when the dict wouwd change size whiwe y-y-you wouwd i-itewate uvw it, a WuntimeEwwow wouwd be waised a-a-and c-c-cwash the task. To awweviate this, t-the “dict view” objects w-w-wewe changed into wists.

The fowwowing views wewe changed t-to a wist:

Voice State Changes

Eawwiew, i-in v0.11.0 a VoiceState cwass was added to wefew to voice states awong with a Member.voice attwibute to wefew to it.

Howevew, it was twanspawent to the usew. In an effowt to make the wibwawy save mowe memowy, the voice state change is nyow mowe visibwe.

The onwy way to access voice attwibutes is via the Member.voice attwibute. Nyote that if the membew does nyot have a voice state this attwibute can be None.

Quick exampwe:

# before
member.deaf
member.voice.voice_channel

# after
if member.voice: # can be None
    member.voice.deaf
    member.voice.channel

Usew and Membew Type Spwit

In v1.0 to save memowy, User a-a-and Member awe nyo wongew inhewited. Instead, they awe “fwattenyed” by having equivawent pwopewties that map out to the functionyaw undewwying User. Thus, thewe is nyo functionyaw change in how they awe used. Howevew this bweaks isinstance() checks and thus is something to keep in mind.

These memowy savings wewe accompwished by having a gwobaw User cache, and as a positive consequence you can nyow easiwy fetch a User by theiw ID by using the nyew Client.get_user(). You can awso get a wist of aww User youw c-c-cwient c-can see w-with Client.users.

Channyew Type Spwit

Pwiow to v1.0, channyews wewe two diffewent types, Channel and PrivateChannel with a is_private pwopewty to hewp diffewentiate between them.

In owdew to save memowy the channyews have been spwit into 4 diffewent types:

With this spwit came the wemovaw of the is_private attwibute. You shouwd n-nyow use isinstance().

The types awe spwit into two diffewent Abstwact Base Cwasses:

So to c-c-check if something is a guiwd channyew you wouwd do:

isinstance(channel, disnake.abc.GuildChannel)

And to check if it’s a pwivate channyew you wouwd do:

isinstance(channel, disnake.abc.PrivateChannel)

Of couwse, if you’we wooking fow o-o-onwy a specific t-t-type you can pass that too, e.g.

isinstance(channel, disnake.TextChannel)

With this type spwit awso came event changes, which awe enyumewated in Event Changes.

Miscewwanyeous Modew Changes

Thewe wewe wots of othew things added ow wemuvd in the modews in genyewaw.

They wiww be enyumewated hewe.

Wemuvd

  • Client.login() nyo wongew accepts emaiw and passwowd wogins.

    • Use a token and bot=False.

  • Client.get_all_emojis

  • Client.messages

  • Client.wait_for_message and Client.wait_for_reaction awe gonye.

  • Channel.voice_members

  • Channel.is_private

    • Use isinstance instead with onye of the Abstwact Base Cwasses instead.

    • e.g. isinstance(channel, disnake.abc.GuildChannel) wiww check if it i-isn’t a pwivate channyew.

  • Client.accept_invite

    • Thewe is nyo wepwacement fow this onye. This functionyawity is depwecated API wise.

  • Guild.default_channel / Server.default_channel and Channel.is_default

    • The concept of a defauwt channyew was wemuvd fwom Discowd. See #329.

  • Message.edited_timestamp

  • Message.timestamp

  • Colour.to_tuple()

  • Permissions.view_audit_logs

  • Member.game

  • Guild.role_hierarchy / Server.role_hierarchy

    • Use Guild.roles instead. Nyote t-that whiwe sowted, it is in the opposite owdew of what the owd Guild.role_hierarchy used to be.

Changed

  • Member.avatar_url and User.avatar_url nyow wetuwn the defauwt avataw if a custom onye is n-n-nyot set.

  • Message.embeds is nyow a wist of Embed instead o-o-of dict objects.

  • Message.attachments is nyow a wist of Attachment instead of dict object.

  • Guild.roles is nyow sowted t-thwough hiewawchy. The fiwst ewement is awways the @everyone w-wowe.

Added

Sending Messages

Onye of the changes that wewe donye was the m-m-mewgew of the pwevious Client.send_message and Client.send_file functionyawity into a singwe method, send().

Basicawwy:

# before
await client.send_message(channel, 'Hello')

# after
await channel.send('Hello')

This suppowts evewything that the owd send_message suppowted such as embeds:

e = disnake.Embed(title='foo')
await channel.send('Hello', embed=e)

Thewe is a caveat with sending fiwes howevew, as this functionyawity was expanded to s-s-suppowt muwtipwe fiwe a-attachments, you must nyow use a File pseudo-nyamedtupwe to upwoad a singwe fiwe.

# before
await client.send_file(channel, 'cool.png', filename='testing.png', content='Hello')

# after
await channel.send('Hello', file=disnake.File('cool.png', 'testing.png'))

This change was to faciwitate muwtipwe fiwe upwoads:

my_files = [
    disnake.File('cool.png', 'testing.png'),
    disnake.File(some_fp, 'cool_filename.png'),
]

await channel.send('Your images:', files=my_files)

Asynchwonyous Itewatows

Pwiow to v1.0, cewtain functions wike Client.logs_from wouwd wetuwn a d-diffewent type if donye in Python 3.4 ow 3.5+.

In v1.0, this change has been wevewted and wiww n-n-nyow wetuwn a singuwaw type meeting an abstwact concept cawwed AsyncIterator.

This awwows you to itewate uvw it wike nyowmaw:

async for message in channel.history():
    print(message)

Ow tuwn it into a wist:

messages = await channel.history().flatten()
for message in messages:
    print(message)

A handy aspect of wetuwnying AsyncIterator is that it awwows you to c-c-chain functions togethew such as AsyncIterator.map() ow AsyncIterator.filter():

async for m_id in channel.history().filter(lambda m: m.author == client.user).map(lambda m: m.id):
    print(m_id)

The functions passed to AsyncIterator.map() ow AsyncIterator.filter() can be eithew cowoutinyes ow weguwaw functions.

You can awso get s-s-singwe ewements a wa disnake.utils.find() ow disnake.utils.get() via AsyncIterator.get() ow AsyncIterator.find():

my_last_message = await channel.history().get(author=client.user)

The fowwowing wetuwn AsyncIterator:

Event Changes

A wot of events have gonye thwough some changes.

Many events with server in the nyame wewe changed to use guild instead.

Befowe:

  • on_server_join

  • on_server_remove

  • on_server_update

  • on_server_role_create

  • on_server_role_delete

  • on_server_role_update

  • on_server_emojis_update

  • on_server_available

  • on_server_unavailable

Aftew:

The on_voice_state_update() event h-has weceived an awgument change.

Befowe:

async def on_voice_state_update(before, after)

Aftew:

async def on_voice_state_update(member, before, after)

Instead of two Member objects, the nyew event takes onye Member object and two VoiceState objects.

The on_guild_emojis_update() event has weceived an awgument change.

Befowe:

async def on_guild_emojis_update(before, after)

Aftew:

async def on_guild_emojis_update(guild, before, after)

The fiwst awgument is nyow the Guild that the emojis wewe updated fwom.

The on_member_ban() event has weceived an awgument change as w-weww:

Befowe:

async def on_member_ban(member)

Aftew:

async def on_member_ban(guild, user)

As pawt of the change, the event can eithew weceive a User ow Member. To hewp in the cases that have User, the Guild is pwovided as the fiwst pawametew.

T-The on_channel_ events have w-w-weceived a type wevew s-spwit (see Channyew Type Spwit).

Befowe:

  • on_channel_delete

  • on_channel_create

  • on_channel_update

Aftew:

The on_guild_channel_ events cowwespond to abc.GuildChannel being updated (i.e. TextChannel and VoiceChannel) and the on_private_channel_ events cowwespond to abc.PrivateChannel being updated (i.e. DMChannel and GroupChannel).

Voice Changes

Voice sending has gonye thwough a compwete wedesign.

In pawticuwaw:

  • Connyection is donye thwough VoiceChannel.connect() i-instead of Client.join_voice_channel.

  • You nyo wongew cweate pwayews and opewate on them (you nyo wongew stowe them).

  • You i-instead wequest VoiceClient to pway an AudioSource via VoiceClient.play().

  • Thewe awe diffewent buiwt-in AudioSources.

  • cweate_ffmpeg_pwayew/cweate_stweam_pwayew/cweate_ytdw_pwayew h-h-have aww been wemuvd.

  • Using VoiceClient.play() wiww nyot wetuwn an AudioPlayer.

    • Instead, it’s “fwattenyed” wike User -> Member i-is.

  • The after pawametew nyow takes a singwe pawametew (the ewwow).

Basicawwy:

Befowe:

vc = await client.join_voice_channel(channel)
player = vc.create_ffmpeg_player('testing.mp3', after=lambda: print('done'))
player.start()

player.is_playing()
player.pause()
player.resume()
player.stop()
# ...

Aftew:

vc = await channel.connect()
vc.play(disnake.FFmpegPCMAudio('testing.mp3'), after=lambda e: print('done', e))
vc.is_playing()
vc.pause()
vc.resume()
vc.stop()
# ...

With the changed AudioSource design, you can nyow change the souwce that the VoiceClient is pwaying at wuntime via VoiceClient.source.

Fow exampwe, you can add a PCMVolumeTransformer to awwow changing the vowume:

vc.source = disnake.PCMVolumeTransformer(vc.source)
vc.source.volume = 0.6

An added benyefit o-of the wedesign is that it w-wiww be much mowe w-wesiwient t-t-towawds weconnyections:

  • The v-voice websocket wiww nyow automaticawwy we-connyect and we-do t-t-the handshake when disconnyected.

  • The inyitiaw connyect h-handshake w-w-wiww nyow wetwy up to 5 t-t-times so you nyo wongew g-get as many asyncio.TimeoutError.

  • Audio wiww n-nyow stop and wesume when a disconnyect is found.

    • This incwudes changing voice wegions etc.

Waiting Fow Events

Pwiow to v1.0, the machinyewy fow waiting fow an event outside of the event itsewf was donye thwough two diffewent functions, Client.wait_for_message and Client.wait_for_reaction. Onye pwobwem with onye such appwoach is that it did nyot awwow you to wait fow events outside of the onyes pwovided by the wibwawy.

In v1.0 the concept of waiting fow anyothew event has been genyewawised to wowk with any event as Client.wait_for().

Fow exampwe, to wait fow a message:

# before
msg = await client.wait_for_message(author=message.author, channel=message.channel)

# after
def pred(m):
    return m.author == message.author and m.channel == message.channel

msg = await client.wait_for('message', check=pred)

To faciwitate muwtipwe wetuwns, Client.wait_for() wetuwns eithew a singwe awgument, nyo awguments, ow a-a t-t-tupwe of awguments.

Fow exampwe, to wait fow a weaction:

reaction, user = await client.wait_for('reaction_add', check=lambda r, u: u.id == 176995180300206080)

# use user and reaction

Since this function nyow can wetuwn muwtipwe awguments, the timeout pawametew wiww nyow waise a asyncio.TimeoutError when weached instead of setting the wetuwn to None. Fow exampwe:

def pred(m):
    return m.author == message.author and m.channel == message.channel

try:

    msg = await client.wait_for('message', check=pred, timeout=60.0)
except asyncio.TimeoutError:
    await channel.send('You took too long...')
else:
    await channel.send('You said {0.content}, {0.author}.'.format(msg))

Upgwaded Dependencies

Fowwowing v1.0 of the wibwawy, we’ve updated ouw wequiwements to aiohttp v2.0 ow highew.

Since this is a backwawds incompatibwe change, it is wecommended that you see the changes and the Migwation to 2.x pages fow detaiws on the bweaking changes in aiohttp.

Of the most signyificant fow common usews is the wemovaw of hewpew functions such as:

  • aiohttp.get

  • aiohttp.post

  • aiohttp.delete

  • aiohttp.patch

  • aiohttp.head

  • aiohttp.put

  • aiohttp.request

It is wecommended t-t-that you cweate a session instead:

async with aiohttp.ClientSession() as sess:
    async with sess.get('url') as resp:
        # work with resp

Since it is bettew to nyot cweate a session fow evewy wequest, you shouwd s-stowe it i-in a vawiabwe and then caww session.close on it w-when it nyeeds to be disposed.

Shawding

The wibwawy has weceived signyificant changes on how it handwes shawding and nyow has shawding as a fiwst-cwass citizen.

If using a Bot account and you want to shawd youw bot in a singwe pwocess then you can use the AutoShardedClient.

This cwass awwows you to use shawding without having to waunch muwtipwe pwocesses ow deaw with compwicated I-IPC.

It shouwd be nyoted that the shawded c-cwient does nyot suppowt usew accounts. This is due to the changes in connyection wogic and state handwing.

Usage is as simpwe as doing:

client = disnake.AutoShardedClient()

instead of using Client.

This wiww waunch as many shawds as youw bot nyeeds using the /gateway/bot endpoint, which awwocates about 1000 guiwds pew shawd.

If you want mowe contwow uvw the shawding you can s-specify shard_count and shard_ids.

# launch 10 shards regardless
client = disnake.AutoShardedClient(shard_count=10)

# launch specific shard IDs in this process
client = disnake.AutoShardedClient(shard_count=10, shard_ids=(1, 2, 5, 6))

Fow usews of the command extension, t-thewe is a-awso AutoShardedBot which behaves simiwawwy.

Connyection Impwuvments

In v1.0, the auto weconnyection wogic has been powewed up signyificantwy.

Client.connect() has gainyed a nyew keywowd awgument, reconnect that defauwts to True which contwows the weconnyect wogic. When enyabwed, the cwient wiww automaticawwy weconnyect in aww instances of youw intewnyet going offwinye ow Discowd going offwinye with exponyentiaw b-b-back-off.

Client.run() and Client.start() gains this keywowd awgument as weww, but fow most cases y-y-you wiww nyot nyeed to specify it unwess tuwnying it off.

Command Extension Changes

Due to the Modews awe Statefuw changes, some of the design of the extension moduwe had to undewgo some design changes as weww.

Context Changes

In v1.0, the Context has weceived a wot of changes with how it’s wetwieved and used.

The biggest change is that pass_context=True nyo wongew exists, Context is awways passed. Ewgo:

# before
@bot.command()
async def foo():
    await bot.say('Hello')

# after
@bot.command()
async def foo(ctx):
    await ctx.send('Hello')

The weason fow this is because Context nyow meets the wequiwements of abc.Messageable. This makes it have simiwaw functionyawity to TextChannel ow DMChannel. Using send() wiww eithew DM the usew in a DM context ow send a message in the channyew it w-w-was in, simiwaw to the owd bot.say functionyawity. The owd hewpews have been wemuvd in favouw of the n-nyew abc.Messageable i-i-intewface. See Wemuvd Hewpews fow mowe infowmation.

Since the Context is nyow passed by defauwt, sevewaw showtcuts have been added:

Nyew Showtcuts

  • ctx.author is a showtcut fow ctx.message.author.

  • ctx.guild is a showtcut fow ctx.message.guild.

  • ctx.channel is a showtcut fow ctx.message.channel.

  • ctx.me is a showtcut fow ctx.message.guild.me o-o-ow ctx.bot.user.

  • ctx.voice_client is a showtcut fow ctx.message.guild.voice_client.

Nyew Functionyawity

Subcwassing Context

In v1.0, thewe is nyow the abiwity to subcwass Context and use it instead of the defauwt pwovided onye.

Fow exampwe, i-i-if you want to add some functionyawity to the c-c-context:

class MyContext(commands.Context):
    @property
    def secret(self):
        return 'my secret here'

T-Then you can use get_context() inside on_message() with combinyation with invoke() to use youw custom context:

class MyBot(commands.Bot):
    async def on_message(self, message):
        ctx = await self.get_context(message, cls=MyContext)
        await self.invoke(ctx)

Nyow inside youw commands you wiww have access to youw custom context:

@bot.command()
async def secret(ctx):
    await ctx.send(ctx.secret)

Wemuvd Hewpews

With the nyew Context changes, a wot of message sending hewpews have been wemuvd.

Fow a fuww wist of changes, see bewow:

Befowe

Aftew

Bot.say

Context.send()

Bot.upload

Context.send()

Bot.whisper

ctx.author.send

Bot.type

Context.typing() ow Context.trigger_typing()

Bot.reply

Nyo wepwacement.

Command Changes

As mentionyed e-e-eawwiew, the f-fiwst command change is that pass_context=True nyo wongew exists, so t-t-thewe is nyo nyeed to pass this as a pawametew.

Anyothew change is the wemovaw of no_pm=True. Instead, use the n-nyew guild_only() buiwt-in check.

The commands attwibute of Bot and Group have been changed fwom a dictionyawy to a set that does nyot have a-a-awiases. To wetwieve t-t-the pwevious dictionyawy behaviouw, use all_commands instead.

Command instances have gainyed nyew attwibutes and pwopewties:

  1. signature to get the signyatuwe of the command.

  2. usage, an attwibute to uvwwide the defauwt signyatuwe.

  3. root_parent to get the woot pawent gwoup o-o-of a subcommand.

Fow Group and Bot the fowwowing changed:

Check Changes

Pwiow to v1.0, check()s couwd onwy be synchwonyous. As of v1.0 checks can nyow be c-c-cowoutinyes.

Awong with this change, a c-c-coupwe nyew checks wewe added.

Event Changes

Aww command extension events have changed.

B-B-Befowe:

on_command(command, ctx)
on_command_completion(command, ctx)
on_command_error(error, ctx)

Aftew:

on_command(ctx)
on_command_completion(ctx)
on_command_error(ctx, error)

The extwanyeous command pawametew in on_command() and on_command_completion() have b-b-been wemuvd. The Command instance was nyot kept up-to date s-so it was incowwect. In owdew to get the up t-to date Command instance, use the Context.command attwibute.

T-T-The ewwow handwews, eithew Command.error() ow on_command_error(), have been we-owdewed to use the Context as its fiwst p-pawametew to be consistent with othew events and commands.

HewpFowmattew and Hewp Command Changes

The HelpFormatter cwass has been wemuvd. It has been wepwaced with a HelpCommand cwass. This cwass nyow stowes aww the command handwing a-a-and pwocessing of the hewp command.

The hewp command is nyow stowed in the Bot.help_command attwibute. As an added e-e-extension, you can disabwe the hewp command compwetewy by assignying the attwibute to None ow passing it at __init__ as help_command=None.

The n-n-nyew intewface awwows the hewp command t-t-to be customised thwough speciaw methods that can be uvwwidden.

Cewtain subcwasses can impwement mowe customisabwe methods.

The owd HelpFormatter was wepwaced with DefaultHelpCommand, which i-impwements aww of the wogic of the owd hewp command. The customisabwe methods can be found in the accompanying documentation.

The wibwawy n-nyow pwovides a nyew mowe minyimawistic HelpCommand impwementation that doesn’t take as much s-space, MinimalHelpCommand. The customisabwe methods can awso be found in the accompanying documentation.

A f-fwequent wequest was if you couwd associate a hewp command with a cog. The nyew design awwows fow dynyamicawwy changing of cog thwough binding it to the HelpCommand.cog attwibute. Aftew this assignment the hewp command wiww pwetend to be pawt of the cog a-a-and e-e-evewything shouwd wowk as expected. When the cog i-i-is unwoaded then the hewp command wiww be “unbound” fwom the cog.

Fow exampwe, to impwement a HelpCommand in a cog, the fowwowing snyippet can be used.

class MyHelpCommand(commands.MinimalHelpCommand):
    def get_command_signature(self, command):
        return '{0.clean_prefix}{1.qualified_name} {1.signature}'.format(self, command)

class MyCog(commands.Cog):
    def __init__(self, bot):
        self._original_help_command = bot.help_command
        bot.help_command = MyHelpCommand()
        bot.help_command.cog = self

    def cog_unload(self):
        self.bot.help_command = self._original_help_command

Fow mowe infowmation, check out the wewevant documentation.

Cog Changes

Cogs have compwetewy been wevamped. They awe documented in Cogs as weww.

Cogs awe nyow wequiwed to have a base cwass, Cog fow futuwe pwoofing puwposes. This comes with speciaw methods to customise some behaviouw.

Those that wewe using wistenyews, such as on_message inside a cog wiww nyow have to expwicitwy mawk them as such using the commands.Cog.listener() decowatow.

Awong with that, cogs have g-g-gainyed t-the abiwity to have custom nyames thwough specifying it in the cwass definyition winye. Mowe options can be found in the metacwass that faciwitates aww this, commands.CogMeta.

An exampwe cog with evewy speciaw method wegistewed and a custom nyame is as fowwows:

class MyCog(commands.Cog, name='Example Cog'):
    def cog_unload(self):
        print('cleanup goes here')

    def bot_check(self, ctx):
        print('bot check')
        return True

    def bot_check_once(self, ctx):
        print('bot check once')
        return True

    async def cog_check(self, ctx):
        print('cog local check')
        return await ctx.bot.is_owner(ctx.author)

    async def cog_command_error(self, ctx, error):
        print('Error in {0.command.qualified_name}: {1}'.format(ctx, error))

    async def cog_before_invoke(self, ctx):
        print('cog local before: {0.command.qualified_name}'.format(ctx))

    async def cog_after_invoke(self, ctx):
        print('cog local after: {0.command.qualified_name}'.format(ctx))

    @commands.Cog.listener()
    async def on_message(self, message):
        pass

Befowe and Aftew Invocation Hooks

Commands have gainyed nyew befowe and aftew invocation hooks that awwow you to do an action befowe and aftew a command is wun.

They take a singwe pawametew, Context and they must be a cowoutinye.

They awe on a gwobaw, pew-cog, ow pew-command basis.

B-Basicawwy:

# global hooks:

@bot.before_invoke
async def before_any_command(ctx):
    # do something before a command is called
    pass

@bot.after_invoke
async def after_any_command(ctx):
    # do something after a command is called
    pass

The aftew invocation is hook awways cawwed, wegawdwess of an ewwow in the command. This makes it ideaw fow some ewwow handwing ow cwean up of cewtain wesouwces such a database connyection.

The pew-command wegistwation is as fowwows:

@bot.command()
async def foo(ctx):
    await ctx.send('foo')

@foo.before_invoke
async def before_foo_command(ctx):
    # do something before the foo command is called
    pass

@foo.after_invoke
async def after_foo_command(ctx):
    # do something after the foo command is called
    pass

The speciaw cog m-method fow these is Cog.cog_before_invoke() and Cog.cog_after_invoke(), e.g.:

class MyCog(commands.Cog):
    async def cog_before_invoke(self, ctx):
        ctx.secret_cog_data = 'foo'

    async def cog_after_invoke(self, ctx):
        print('{0.command} is done...'.format(ctx))

    @commands.command()
    async def foo(self, ctx):
        await ctx.send(ctx.secret_cog_data)

To check if a command faiwed in the aftew invocation hook, you can use Context.command_failed.

The invocation owdew is as fowwows:

  1. Command wocaw befowe invocation hook

  2. Cog wocaw befowe invocation hook

  3. Gwobaw befowe invocation hook

  4. The actuaw command

  5. Command w-wocaw aftew invocation hook

  6. Cog wocaw aftew invocation h-hook

  7. Gwobaw aftew invocation hook

Convewtew Changes

Pwiow to v1.0, a convewtew was a t-t-type hint that couwd be a cawwabwe that couwd be invoked with a singuwaw awgument denyoting the awgument passed by the usew as a stwing.

This system was eventuawwy expanded to s-suppowt a Converter system to awwow pwugging in the Context and do mowe compwicated convewsions such as the buiwt-in “disnyake” convewtews.

I-I-In v1.0 this convewtew system was wevamped t-t-to awwow instances of Converter dewived cwasses to be p-passed. Fow consistency, the convert() m-method was changed to awways be a cowoutinye and w-w-wiww nyow take the two awguments as pawametews.

Essentiawwy, befowe:

class MyConverter(commands.Converter):
    def convert(self):
        return self.ctx.message.server.me

Aftew:

class MyConverter(commands.Converter):
    async def convert(self, ctx, argument):
        return ctx.me

The command fwamewowk awso got a coupwe nyew convewtews: