Pycord v2.0 introduced new Discord features and made several breaking changes to support modern Discord functionality. This guide will help you migrate your bot from v1.x to v2.x.
Python Version Requirements
Breaking Change: Python 3.7 and below are no longer supported.
Pycord v2.0 requires Python 3.8 or higher. Make sure to upgrade your Python version before migrating.
Major Changes
Dropped User Account Support
User account support has been removed as it violates Discord’s Terms of Service. The following features have been removed:
All user account-related features have been completely removed:
bot argument of Client.start() and Client.run()
afk argument of Client.change_presence()
Classes: Profile, Relationship, CallMessage, GroupCall
Client.self_bot, Client.fetch_user_profile()
ClientUser.email, premium, premium_type, relationships, friends, blocked
Events: on_relationship_add, on_relationship_update
Timezone-Aware Datetime Objects
All datetime objects are now timezone-aware and use UTC.
from datetime import datetime
embed = discord.Embed(
title = "Pi Day 2021" ,
timestamp = datetime( 2021 , 3 , 14 , 15 , 9 , 2 )
)
Asset Changes
Asset-related attributes now return Asset objects instead of hash strings.
# Getting avatar URL
avatar_url = str (user.avatar_url)
# Custom size
avatar_url = str (user.avatar_url_as( size = 128 ))
# Static format
avatar_url = str (user.avatar_url_as( size = 128 , static_format = "png" ))
# Reading avatar data
data = await user.avatar_url.read()
Important: User.avatar now returns None if the user has no custom avatar. Use User.display_avatar to get the avatar or default avatar.
Emoji URL Changes
emoji_url = str (emoji.url)
resized_url = str (emoji.url_as( size = 32 ))
Webhook Changes
Webhooks are now split into async and sync variants.
# Async webhook
webhook = discord.Webhook.from_url(
webhook_url,
adapter = discord.AsyncWebhookAdapter(session)
)
await webhook.send( "Hello!" )
WebhookAdapter, AsyncWebhookAdapter, and RequestsWebhookAdapter have been removed.
Intents Changes
Message Content Intent
Breaking Change: Intents.message_content is now a privileged intent .
Without this intent enabled:
Message.content will be an empty string
Message.embeds will be an empty list
Message.attachments will be an empty list
Message.components will be an empty list
Text commands will not work
intents = discord.Intents.default()
bot = commands.Bot( command_prefix = "!" , intents = intents)
# Message content was available by default
You must also enable this intent in the Discord Developer Portal .
Threads Support
Threads are now supported as first-class citizens. The following methods can now return Thread objects:
Message.channel
Client.fetch_channel()
Guild.fetch_channel()
Client.get_channel()
# Check if channel is a thread
if isinstance (channel, discord.Thread):
print ( f "Thread: { channel.name } " )
print ( f "Parent channel: { channel.parent } " )
Permission Changes
# Check permissions
perms = user.permissions_in(channel)
if perms.administrator:
print ( "User is admin" )
Edit Method Behavior
Breaking Change: edit() methods no longer update objects in-place.
await message.edit( content = "Updated content" )
# message object is automatically updated
print (message.content) # "Updated content"
Positional and Keyword Arguments
Now Positional-Only
The following methods now require positional arguments:
# These must be called with positional args
channel.permissions_for(member) # Not permissions_for(member=member)
guild.get_channel(channel_id) # Not get_channel(id=channel_id)
guild.get_role(role_id)
guild.fetch_member(member_id)
messageable.fetch_message(message_id)
Now Keyword-Only
The following methods now require keyword arguments:
# These must be called with keyword args
url = discord.utils.oauth_url(client_id, permissions = permissions)
users = reaction.users( limit = 100 )
Event Changes
Presence Updates
@bot.event
async def on_member_update ( before , after ):
# Handled both attribute and presence updates
if before.status != after.status:
print ( f " { after.name } is now { after.status } " )
Removed Events
The following events have been removed:
on_private_channel_create
on_private_channel_delete
on_relationship_add
on_relationship_update
Message Type for Replies
if message.type == discord.MessageType.default:
# This matched both regular messages and replies
print ( "Regular message" )
Sticker Changes
Sticker.preview_image was removed
StickerType was renamed to StickerFormatType
Message.stickers now returns List[StickerItem] instead of List[Sticker]
Use StickerItem.fetch() to get the full Sticker object
# Fetch full sticker information
for sticker_item in message.stickers:
sticker = await sticker_item.fetch()
print ( f "Sticker: { sticker.name } " )
Type Changes
Optional Attributes
Many attributes can now be None:
DMChannel.recipient can be None
User.avatar can be None (use User.display_avatar instead)
Guild.vanity_invite can be None
Context attributes: prefix, command, invoked_with, invoked_subcommand can be None
# Always check for None
if user.avatar is not None :
print (user.avatar.url)
else :
print (user.default_avatar.url)
# Or use display_avatar
print (user.display_avatar.url) # Always works
Miscellaneous Changes
Removed Features
The following have been removed:
Client.request_offline_members()
Client.logout() (use Client.close() instead)
ExtensionNotFound.original
MemberCacheFlags.online
guild_subscriptions argument
fetch_offline_members argument
VerificationLevel.table_flip and related aliases
Renamed Features
# Blurple color
color = discord.Colour.blurple()
# Missing permissions
try :
await command()
except discord.ext.commands.MissingPermissions as e:
print (e.missing_perms)
Behavior Changes
Embed objects with any content are now always truthy
Bot.add_cog() now raises an error if a cog with the same name exists (use override=True to bypass)
StageChannel.edit() can no longer edit topic (use StageInstance.edit() instead)
Reaction.custom_emoji is now Reaction.is_custom_emoji()
# Adding cogs safely
try :
bot.add_cog(MyCog())
except discord.ClientException:
# Cog already exists
bot.add_cog(MyCog(), override = True )
New Features in v2.0
While migrating, take advantage of these new v2.0 features:
Slash Commands : Modern interaction-based commands
UI Components : Buttons, select menus, modals
Application Commands : Slash commands, user commands, message commands
Threads : Full thread support
Stage Channels : Complete stage channel functionality
For more information on these features, check out the Pycord Guide .
Migration Checklist
Click to expand migration checklist
Getting Help
If you need help migrating, join the Pycord Discord Server where the community can assist you.