v1.0への移行¶
v1.0 は完全な書き直しによる、ライブラリの中で最大の破壊的な変更の1つです。
変更量が膨大かつ長く、どこからどう見ても完全に新しいライブラリです。
再設計の一部は、物事をより使いやすく、自然にすることです。 models では、 Client
インスタンスを動作させる代わりに行われます。
Pythonのバージョンの変更¶
discord.py の開発をより簡単にし、またその依存関係にあるライブラリをアップグレードして Python 3.7 以上を使えるようにするために、 discord. py は Python 3.5.3 より古いバージョンに対するサポートを諦めざるを得ませんでした。これはつまり Python 3.4 に対するサポートは打ち切られた ということです。
主要なモデルの変更¶
以下は、v1.0における主なモデルの変更点です。
Snowflakeのint型への変更¶
v1.0以前は、全てのsnowflakes ( id
属性) が文字列でしたが、 int
に変更されました。
簡単な例:
# before
ch = client.get_channel('84319995256905728')
if message.author.id == '80528701850124288':
...
# after
ch = client.get_channel(84319995256905728)
if message.author.id == 80528701850124288:
...
この変更により,公式クライアントの「 ID をコピー」機能を使用した際に間違いがより起こりにくくなりました。もはや取得した ID をクォーテーションマークで囲う必要はありませんし,内部で JSON の代わりに ETF を用いることで最適化の機会を得ることにもなります。
Server から Guild に変更。¶
公式APIドキュメントでは「Server」は「Guild」と呼ばれています。APIドキュメントとの一貫性を保つために、モデルの名称が Guild
に変更され、それを参照するすべてのインスタンスも変更されました。
変更の一覧は以下の通りです。
変更前 |
変更後 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
モデルのステートフル化¶
前述したように、多くの機能が Client
からそれぞれの model へと移されました。
これらの変更点の一覧は以下の通りです。
変更前 |
変更後 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
削除済 |
|
変更なし |
プロパティの変更¶
一貫性を持たせるために、いくつかのプロパティがメソッドに変更されました。
プロパティの代わりに追加されたメソッドは以下のとおりです。(使用の際にはカッコが必要です)
辞書の値の変更¶
v1.0以前では、複数のモデルを集約して取得するプロパティは「辞書ビュー」オブジェクトで結果を返していました。
これは、オブジェクトを用いて繰り返し処理を行っている間に、辞書サイズが変更されたとき、RuntimeErrorを発生させてタスクをクラッシュさせていました。これを軽減させるため「辞書ビュー」オブジェクトはリストに変更されました。
以下のビューがリストへ変更されています。
Client.users
(v1.0で新規追加)Client.emojis
(v1.0にて追加)Guild.text_channels
(v1.0にて追加)Guild.voice_channels
(v1.0にて追加)
ボイスステートの変更¶
v0.11.0では、ボイスステートを参照するために VoiceState
が追加され、このクラスを参照するために Member.voice
が使われていました。
これはユーザーにとって透過的なものでしたが、ライブラリがメモリを節約できるようボイスステートの変化が可視的になりました。
ボイスの属性にアクセスするには Member.voice
を用いる方法しか存在しません。メンバーがボイスステートを持たない場合は None
が返ることに注意してください。
簡単な例:
# before
member.deaf
member.voice.voice_channel
# after
if member.voice: # can be None
member.voice.deaf
member.voice.channel
ユーザーとメンバーの分離¶
v1.0では、メモリの節約のため、 Member
は User
のサブクラスではなくなりました。代わりに、 User
に記述されたものと同等のプロパティを実装することで、この二つのクラスはフラット化されています。そのため、使用方法に機能的変更はありません。ただし、 isinstance()
が使えなくなってしまったことは留意しておくべきです。
メモリの節約は、グローバルな User
のキャッシュを持つことで実現しました。これによって Client.get_user()
を使ってIDから簡単に User
を取得できます。また、あなたのクライアントが見ることができる User
を Client.users
ですべて取得できるようにもなりました。
チャンネルタイプの分割¶
v1.0以前のバージョンでは、チャンネルは is_private
で判別する Channel
と PrivateChannel
の二通りしかありませんでした。
メモリ使用量を削減するため、チャンネルを4つのタイプへ分割しました。
ギルドのテキストチャンネル用である
TextChannel
。ギルドのボイスチャンネル用である
VoiceChannel
。メンバーのDMチャンネル用である
DMChannel
。メンバーが参加するグループDMチャンネル用である
GroupChannel
。
これらに分割されたことにより、 is_private
は削除されました。v1.0では isinstance()
を使うべきでしょう。
型は二通りの 抽象基底クラス に分けられます。
ギルドのチャンネルを表す
abc.GuildChannel
。プライベートチャンネル(DMやグループDM)を表す
abc.PrivateChannel
。
チャンネルがギルドチャンネルであるかをチェックしたい場合:
isinstance(channel, discord.abc.GuildChannel)
チャンネルがプライベートチャンネルであるかをチェックしたい場合:
isinstance(channel, discord.abc.PrivateChannel)
もちろん、特定のチャンネルタイプを探したい場合、そのチャンネルタイプを渡すことも可能です。
isinstance(channel, discord.TextChannel)
この型の分割により、イベントにも変更がありました。これについては、 イベントの変更点 で列挙されています。
その他のモデルの変更点¶
その他にも、モデルに追加または削除されたものが多くあります。
以下がその一覧です。
削除済
Client.login()
はメールとパスワードによるログインを受け付けなくなりました。トークンと
bot=False
を使用してください。
Client.get_all_emojis
代わりに
Client.emojis
を使用してください。
Client.messages
読み取り専用の
Client.cached_messages
を代わりに使用してください。
Client.wait_for_message
とClient.wait_for_reaction
は削除されました。代わりに
Client.wait_for()
を使用してください。
Channel.voice_members
代わりに
VoiceChannel.members
を使用してください。
Channel.is_private
代わりに 抽象基底クラス のいずれかを使って、
isinstance
を使用してください。例:
isinstance(channel, discord.abc.GuildChannel)
はプライベートチャンネルでないことを確認します。
Client.accept_invite
これに代わるものはありません。この機能はAPI的に非推奨です。
Guild.default_channel
/Server.default_channel
とChannel.is_default
デフォルトチャンネルの概念はDiscordから削除されました。 #329 を参照してください。
Message.edited_timestamp
代わりに
Message.edited_at
を使用してください。
Message.timestamp
代わりに
Message.created_at
を使用してください。
Colour.to_tuple()
代わりに
Colour.to_rgb()
を使用してください。
Permissions.view_audit_logs
代わりに
Permissions.view_audit_log
使用してください。
Member.game
代わりに
Member.activities
使用してください。
Guild.role_hierarchy
/Server.role_hierarchy
代わりに
Guild.roles
を使用してください。ソート順が以前のGuild.role_hierarchy
とは逆になっていることに注意してください。
変更
Member.avatar_url
とUser.avatar_url
はアバターが設定されていなければ、デフォルトアバターが返るようになりました。Message.embeds
はdict
オブジェクトからEmbed
のリストに変更されました。Message.attachments
はdict
オブジェクトからAttachment
のリストに変更されました。Guild.roles
はヒエラルキー順にソートされるようになりました。先頭には必ず@everyone
が格納されます。
追加
Discordのアタッチメントを表す
Attachment
。チャンネルのカテゴリを表す
CategoryChannel
。ボイスチャンネルに接続しているメンバーを取得する
VoiceChannel.members
。テキストチャンネルを閲覧可能なメンバーを取得する
TextChannel.members
。役割を持っているメンバーを取得する
Role.members
。テキストチャンネルのみを取得する
Guild.text_channels
。ボイスチャンネルのみを取得する
Guild.voice_channels
。チャンネルのカテゴリのみを取得する
Guild.categories
。チャンネルが属するカテゴリを取得する
TextChannel.category
とVoiceChannel.category
。カテゴリによってグループ化されたチャンネルを取得する
Guild.by_category()
。メンバーのチャンク状態を確認する
Guild.chunked
。不適切な表現のフィルターを取得する
Guild.explicit_content_filter
。シャードを使用している場合にて、ギルドのシャード IDを取得する
Guild.shard_id
。Botによって取得できる
User
インスタンスをすべて返すClient.users
。Client.get_user()
はIDからUser
を取得します。特定のサイズ、あるいはフォーマットのアバターを取得する
User.avatar_url_as()
。ギルドのカスタム招待URLを取得する
Guild.vanity_invite()
。ギルドのサーバーログを取得する
Guild.audit_logs()
。メッセージのWebhook IDを取得する
Message.webhook_id
。リッチプレゼンスに関する情報を取得する
Message.activity
およびMessage.application
。テキストチャンネルがNSFWであるかを確認する
TextChannel.is_nsfw()
。RGBのタプルから
Colour
を作成するColour.from_rgb()
。IDからロールを取得する
Guild.get_role()
。
メッセージの送信¶
変更点の一つは、以前の Client.send_message
と Client.send_file
の機能を単一のメソッド send()
に統合したことです。
基本的には以下のとおりです:
# before
await client.send_message(channel, 'Hello')
# after
await channel.send('Hello')
これは埋め込みメッセージなどといった、従来の send_message
が持っていた機能を全てサポートしています。
e = discord.Embed(title='foo')
await channel.send('Hello', embed=e)
これはファイルの送信に対応できるように拡張されましたが、複数のファイルを送信する際には、 File
の擬似的な名前付きタプルでファイルを渡す必要があります。
# before
await client.send_file(channel, 'cool.png', filename='testing.png', content='Hello')
# after
await channel.send('Hello', file=discord.File('cool.png', 'testing.png'))
この変更は、複数の添付ファイルの送信を容易にするために行われました。
my_files = [
discord.File('cool.png', 'testing.png'),
discord.File(some_fp, 'cool_filename.png'),
]
await channel.send('Your images:', files=my_files)
非同期のイテレータ¶
v1.0以前のバージョンは、Python 3.4 または 3.5以上の環境において Client.logs_from
のような特定の関数で、処理終了時に異なった型を返していました。
これはv1.0で元に戻り、 AsyncIterator
という抽象概念を満たす特異な型を返します。
これは通常のイテレータと同様の処理が行なえます。
async for message in channel.history():
print(message)
またはリストにできます。
messages = await channel.history().flatten()
for message in messages:
print(message)
AsyncIterator
を返すことで便利な点は AsyncIterator.map()
や AsyncIterator.filter()
といった関数をチェーンできることです:
async for m_id in channel.history().filter(lambda m: m.author == client.user).map(lambda m: m.id):
print(m_id)
AsyncIterator.map()
または AsyncIterator.filter()
に渡される関数はコルーチンか通常の関数です。
AsyncIterator.get()
または AsyncIterator.find()
を介して discord.utils.get()
または discord.utils.find()
で単一の要素を取得することもできます。
my_last_message = await channel.history().get(author=client.user)
AsyncIterator
を返すのは以下のとおりです:
イベントの変更点¶
多くのイベントに変更がありました。
名前に server
が含まれていたイベントのほとんどが、 guild
を使った名前に変更されました。
変更前:
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
変更後:
on_voice_state_update()
イベントの引数が変更されました。
変更前:
async def on_voice_state_update(before, after)
変更後:
async def on_voice_state_update(member, before, after)
新しくなったイベントは、二つの Member
の代わりに、 一つの Member
と二つの VoiceState
を受け取るようになりました。
on_guild_emojis_update()
イベントの引数が変更されました。
変更前:
async def on_guild_emojis_update(before, after)
変更後:
async def on_guild_emojis_update(guild, before, after)
最初の引数は絵文字の更新が行われた Guild
です。
on_member_ban()
も引数が変更されました。
変更前:
async def on_member_ban(member)
変更後:
async def on_member_ban(guild, user)
変更の一つは、イベントが Member
または User
のどちらかを受け取れるようになったことです。 User
で受け取る場合には第一引数として Guild
が渡されます。
on_channel_
のようなイベントは、チャンネルタイプにより分割されました ( チャンネルタイプの分割 を参照)。
変更前:
on_channel_delete
on_channel_create
on_channel_update
変更後:
on_private_channel_delete()
on_private_channel_create()
on_guild_channel_
イベントは更新される abc.GuildChannel
(TextChannel
および VoiceChannel
)に対応しており、 on_private_channel_
イベントは更新される abc.PrivateChannel
(DMChannel
および GroupChannel
)に対応しています。
ボイスの変更¶
ボイスの送信が完全に再構成されました。
主な変更点は以下のとおりです。
ボイスチャンネルへの接続は
Client.join_voice_channel
に代わってVoiceChannel.connect()
になりました。プレイヤーを作成せずに操作が可能になりました。(プレイヤーの保存の必要もありません)
代わりに
VoiceClient
のVoiceClient.play()
を介してAudioSource
の再生を要求します。様々な組み込み
AudioSource
があります。FFmpegPCMAudio
はcreate_ffmpeg_player
と同等です。
create_ffmpeg_player/create_stream_player/create_ytdl_player はすべて削除されました。
代わりに
AudioSource
を作成してください。
VoiceClient.play()
を呼び出してもAudioPlayer
は返ってきません。after
パラメータの関数は、ひとつの引数 (エラー) を取ります。
基本的には以下のとおりです。
変更前:
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()
# ...
変更後:
vc = await channel.connect()
vc.play(discord.FFmpegPCMAudio('testing.mp3'), after=lambda e: print('done', e))
vc.is_playing()
vc.pause()
vc.resume()
vc.stop()
# ...
AudioSource
の再設計により、 VoiceClient.source
を介して実行中の VoiceClient
のソースを変更できるようになりました。
例えば、 PCMVolumeTransformer
を追加すると、ボリュームの変更ができるようになります。
vc.source = discord.PCMVolumeTransformer(vc.source)
vc.source.volume = 0.6
再設計によるさらなる利点は、再接続において遥かに柔軟性を持ったことです。
音声ウェブソケットは、切断された際に自動的に再接続し、ハンドシェイクを再実行します。
初期接続のハンドシェイクは、最大5回までの再試行となったので、大量の
asyncio.TimeoutError
に悩まされることはなくなりました。VCの切断を検知すると、オーディオは停止し、再開しようとします。
これはサーバーリージョンの変更も含まれます。
イベントの待機¶
v1.0以前のバージョンでは、イベントの発生を待つ方法として Client.wait_for_message
と Client.wait_for_reaction
の二つの関数が用意されていました。このアプローチの欠点はライブラリが提供するイベント以外の発生を待つことが出来ない点です。
v1.0では別のイベントを待つ概念が Client.wait_for()
として一般化され、どのイベントでも動くようになりました。
例えば、メッセージを待つ処理は以下のようになります。
# 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)
複数の返り値に対応するため、 Client.wait_for()
は単一の引数、引数なし、あるいは引数のタプルを返すようになっています。
例えば、リアクションを待つ処理は以下のようになります。
reaction, user = await client.wait_for('reaction_add', check=lambda r, u: u.id == 176995180300206080)
# use user and reaction
この関数は複数の引数を返すため、 timeout
に設定した時間経過すると、 None
を返すのではなく、 asyncio.TimeoutError
を発生させるようになりました。以下はその例になります。
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))
依存関係のアップグレード¶
ライブラリのv1.0への更新に伴い、要件が aiohttp v2.0以上へと変更されました。
これは後方互換性のない変更となるため、 aiohttp の変更点の詳細について changes と Migration to 2.x ページを参照すべきです。
ユーザーにとって最も重要な変更点は、以下のヘルパー関数の削除です。
aiohttp.get
aiohttp.post
aiohttp.delete
aiohttp.patch
aiohttp.head
aiohttp.put
aiohttp.request
代わりにセッションを作成することをお勧めします。
async with aiohttp.ClientSession() as sess:
async with sess.get('url') as resp:
# work with resp
リクエストごとにセッションを作成するのは良いとは言えないため、変数に格納しておき、破棄しなければならない時に session.close
を呼び出すのが良いでしょう。
接続の改善¶
v1.0では、自動再接続機能が大幅に強化されました。
Client.connect()
には新しいキーワード引数が追加されました。再接続機能の設定を行う reconnect
はデフォルトで True
に設定されています。有効にすると、クライアントは全インターネットのインスタンスがオフラインになった際や、Discordが指数関数的後退によってオフラインになった際に自動で再接続を試みます。
Client.run()
や Client.start()
にも同様のキーワード引数が追加されていますが、このさい接続機能をオフにする場合以外は指定する必要はありません。
コマンド拡張の変更¶
モデルのステートフル化 により、拡張モジュールの設計にもいくつかの変更があります。
コンテキストの変更¶
v1.0において、 Context
は取得と利用の面において、多くの変更があります。
最も大きな変更点は pass_context=True
が廃止され、常に Context
が渡されるようになったことです。そのため以下のようになります。
# before
@bot.command()
async def foo():
await bot.say('Hello')
# after
@bot.command()
async def foo(ctx):
await ctx.send('Hello')
その理由として、 Context
が abc.Messageable
の要件を満たしていることが挙げられます。 これは TextChannel
や DMChannel
と同等の機能を持っており、 send()
を用いることで、従来の bot.say
のようにDMまたはテキストチャンネルにメッセージを送信することが出来ます。古いヘルパー関数は新しい abc.Messageable
インタフェースの実装に伴い削除されました。詳細は ヘルパー関数の削除 を参照してください。
Context
がデフォルトで渡されるので、ショートカットが追加されました:
新しいショートカット
ctx.author
はctx.message.author
のショートカットです。ctx.guild
はctx.message.guild
のショートカットです。ctx.channel
はctx.message.channel
のショートカットです。ctx.me
はctx.message.guild.me
のショートカットです。ctx.voice_client
はctx.message.guild.voice_client
のショートカットです。
新しい機能
Context.reinvoke()
はコマンドを再度呼び出します。クールダウンの回避に利用できます。
Context.valid
で、Bot.invoke()
で呼びだせるか確認します。Context.send_help()
を使うと、新しいHelpCommand
システムである項目のヘルプを出力できます。コマンドの使用法を誤ったときにヘルプを表示させたい場合に便利です。
コンテキストのサブクラス¶
v1.0では、 Context
を継承したサブクラスを作成し、デフォルトで実装されているものの代わりに使うことが出来ます。
例えば、コンテキストに機能の追加を行いたい場合は以下のように実装が出来ます。
class MyContext(commands.Context):
@property
def secret(self):
return 'my secret here'
また、 on_message()
内で get_context()
と invoke()
を組み合わせることであなたのカスタムコンテキストを使用できます。
class MyBot(commands.Bot):
async def on_message(self, message):
ctx = await self.get_context(message, cls=MyContext)
await self.invoke(ctx)
これにより、コマンドからあなたのカスタムコンテキストにアクセスすることが可能です。
@bot.command()
async def secret(ctx):
await ctx.send(ctx.secret)
ヘルパー関数の削除¶
新しい Context
の変更によって、たくさんのメッセージ送信用のヘルパー関数が削除されました。
以下が削除された関数のリストです。
変更前 |
変更後 |
|
|
|
|
|
|
|
|
|
代替となるものはありません。 |
コマンドの変更¶
前述の通り、 pass_context=True
は削除されたため、これをパラメータとして渡す必要はありません。
他に no_pm=True
も削除されました。代わりに新しい組み込みチェックである guild_only()
を使用してください。
Bot
と Group
の commands
属性は辞書からエイリアスを持たないsetに変更されました。以前のような辞書を取得するには all_commands
を使用してください。
コマンドインスタンスには新たな属性とプロパティが追加されました。
コマンドのシグネチャを取得する
signature
。usage
はデフォルトのシグネチャをオーバーライドする属性ですroot_parent
はサブコマンドのルートである、親グループを取得します
commands
は エイリアスなしのset
に変更されました。すべてのコマンドを従来の
dict
で取得するにはall_commands
を使用してください。
チェックの変更¶
v1.0以前のバージョンでは check()
は同期関数でしたが、 v1.0のチェックはコルーチンにもなれます。
この変更に加え、新たなチェックが二つ追加されました。
guild_only()
が以前のno_pm=True
機能を置き換えました。is_owner()
はClient.application_info()
のエンドポイントを使用してオーナーIDを取得します。実際には
is_owner()
という別の関数を使用して実行されます。Bot.owner_id
に値を指定することで自分でオーナーIDの設定ができます。
is_nsfw()
はコマンドが実行されたチャンネルがNSFWチャンネルかどうかをチェックします。これは新しく追加された
TextChannel.is_nsfw()
メソッドにより実行されています。
イベントの変更点¶
すべてのコマンド拡張のイベントが変更されました。
変更前:
on_command(command, ctx)
on_command_completion(command, ctx)
on_command_error(error, ctx)
変更後:
on_command(ctx)
on_command_completion(ctx)
on_command_error(ctx, error)
on_command()
と on_command_completion()
の command
パラメータが削除されました。 Command
インスタンスは更新されておらず、正しいものではありませんでした。最新の Command
インスタンスを取得するには Context.command
属性を使用してください。
error()
や on_command_error()
のようなエラーハンドラは他のイベント及びコマンドとの一貫性を保つため、最初のパラメータとして Context
を使用するよう変更されました。
HelpFormatter および Help Command の変更¶
HelpFormatter
クラスは削除され、 HelpCommand
に置き換えられました。このクラスはヘルプコマンドのコマンドハンドリングや処理などといったすべてが格納されています。
ヘルプコマンドは属性である Bot.help_command
に格納されています。追加の機能として、この属性に None
を代入するか、 help_command=None
のようにして __init__
にわたすことでヘルプコマンドを完全に無効化できます。
新しいインタフェースでは特殊なメソッドをオーバーライドすることでヘルプコマンドをカスタマイズすることができます。
HelpCommand.send_bot_help()
ユーザーが ボット全体のヘルプを要求した時に呼び出されます。
HelpCommand.send_cog_help()
ユーザーが特定のコグについてのヘルプを要求した時に呼び出されます。
HelpCommand.send_group_help()
ユーザーが
Group
についてのヘルプを要求した時に呼び出されます。
HelpCommand.send_command_help()
ユーザーが
Command
のヘルプを要求した時に呼び出されます。
HelpCommand.get_destination()
ヘルプメッセージの送信先を知るために呼び出されます。DMとして送るかどうかを決める際に役立ちます。
HelpCommand.command_not_found()
コマンドが見つからなかったときに文字列を返す関数(またはコルーチン)。
HelpCommand.subcommand_not_found()
サブコマンドが見つからなかったときに文字列を返す関数(またはコルーチン)。
HelpCommand.send_error_message()
HelpCommand.command_not_found()
とHelpCommand.subcommand_not_found()
の結果が渡されるコルーチン。デフォルトではメッセージの送信のみを行いますが、たとえば、そのメッセージを埋め込み化したい場合などにオーバーライドして使うことができます。
HelpCommand.on_help_command_error()
ヘルプコマンドの エラーハンドラ 。追加したい場合のみ使用してください。
HelpCommand.prepare_help_command()
ヘルプコマンドの処理が行われる前に呼び出されるコルーチン。
特定のサブクラスはさらにカスタマイズ可能なメソッドを実装できます。
以前の HelpFormatter
はその機能を全て実装した DefaultHelpCommand
に置き換えられました。カスタマイズメソッドは添付のドキュメントで確認することができます。
このライブラリは多くのスペースをとらない、より小規模化した HelpCommand
の実装である MinimalHelpCommand
を提供します。カスタマイズ可能なメソッドは付随のドキュメントから確認することが可能です。
ヘルプコマンドをコグに関連付けることはできないのかという要望が多くありました。この新しい設計では HelpCommand.cog
にバインドすることでコグを動的に変更することが可能です。この割当をおこなった後、ヘルプコマンドはコグの一部として、期待通りの動きをするでしょう。コグがアンロードされると、ヘルプコマンドはコグから「バインド解除」されます。
例えば、 HelpCommand
をコグに実装するには、次のコードが役立つでしょう。
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
詳しくは、こちらの説明 をご覧ください。
コグの変更¶
コグは完全に刷新されました。これは コグ としてドキュメント化されています。
コグは将来的な校正のためのクラスである Cog
を基底クラスとして持つ必要があります。このクラスには動作のカスタマイズのために、特別なメソッドが用意されています。
Cog.cog_unload()
これはタスクのキャンセルのような、コグに何らかのクリーンアップが必要なときに呼び出されます。
Cog.bot_check_once()
これは
Bot.check_once()
チェックを登録します。
Cog.bot_check()
これは普通の
Bot.check()
チェックを登録します。
Cog.cog_check()
これはコグのすべてのコマンドに適用されるチェックを登録します。
Cog.cog_command_error()
これは特別なエラーハンドラで、コグ内でエラーが発生するたびに呼び出されます。
Cog.cog_before_invoke()
とCog.cog_after_invoke()
コグの前後に呼び出されるフックを登録する特別なメソッドです。詳細は 前後処理のフック に記載されています。
コグ内で on_message
のようなリスナーを使用していた人は、 commands.Cog.listener()
デコレータを用いて、リスナーを明示する必要があります。
それによって、コグはクラス定義の行で指定することによって、独自の名前を持てるようになりました。オプションはこれらを容易にするメタクラス、commands.CogMeta
で見つかります。
すべての特別なメソッドを使用し、そして名前を指定したコグの例が以下のようになります:
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
前後処理のフック¶
コマンドに、コマンドの実行前および実行後に処理が行えるようにするフックが新たに追加されました。
これは単一のパラメータとして Context
を受け取り、かつコルーチンである必要があります。
また、このフックは全体、コグごと、あるいはコマンドごとに設定することが可能です。
基本的には以下のとおりです:
# 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
後処理のフックは コマンドのエラー発生に関わらず 必ず呼び出されます。そのため、データベース接続のようなリソースのクリーンアップやエラー処理に最適です。
コマンドごとに設定する方法は以下のとおりです。
@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
これらのコグ用の特別なメソッドは Cog.cog_before_invoke()
と Cog.cog_after_invoke()
です。例:
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)
Context.command_failed
を使うことで、後処理でコマンドがエラーになったかを確認する事ができます。
呼び出される順序は以下のとおりです。
コマンドごとの前処理。
コグごとの前処理。
全体での前処理。
実行されたコマンド。
コマンドごとの後処理。
コグごとの後処理。
全体での後処理。
コンバーターの変更¶
v1.0以前では、コンバーターはユーザーにより渡された引数を、文字列の単独引数として呼び出す型ヒントでした。
このシステムは最終的に Context
が組み込み可能な Converter
システムをサポートするために拡張され、ビルトインの「discord」コンバータのようにより複雑な変換が行なえるようになりました。
v1.0ではこのコンバーターシステムは Converter
派生のクラスを使用できるよう変更されました。一貫性を保つため、 convert()
は常にコルーチンとなるよう変更され、二つのパラメータを受け取ります。
更新前:
class MyConverter(commands.Converter):
def convert(self):
return self.ctx.message.server.me
変更後:
class MyConverter(commands.Converter):
async def convert(self, ctx, argument):
return ctx.me
コマンドフレームワークにも二つのコンバーターが追加されました。
clean_content
はメンションなどを取り除くMessage.clean_content
と同じものです。UserConverter
はUser
だけを適切に変換します。ChannelConverter
は、2 つの異なるコンバーターに分割されました。