A modern, feature-rich, and async-ready API wrapper for Discord written in Python
—
Essential Discord entities that form the foundation of all bot interactions. These objects represent users, servers, channels, messages, and other core Discord concepts with comprehensive attribute access and methods for common operations.
The main client class manages the bot's connection to Discord, handles events, and provides access to the HTTP API and gateway connection.
class Client:
"""
Main Discord client for bot connections and API access.
Parameters:
- intents: Intents object specifying which events to receive
- heartbeat_timeout: Seconds to wait for heartbeat response (default: 60.0)
- guild_ready_timeout: Seconds to wait for guild data (default: 2.0)
- max_messages: Maximum messages to cache (default: 1000)
"""
def __init__(
self,
*,
intents: Intents,
heartbeat_timeout: float = 60.0,
guild_ready_timeout: float = 2.0,
max_messages: Optional[int] = 1000
): ...
async def start(self, token: str) -> None:
"""Start the client connection with the provided bot token."""
async def close(self) -> None:
"""Close the connection and cleanup resources."""
async def connect(self, *, reconnect: bool = True) -> None:
"""Connect to Discord's gateway."""
async def login(self, token: str) -> None:
"""Login with the provided token without connecting."""
def run(
self,
token: str,
*,
reconnect: bool = True,
log_handler: Optional[logging.Handler] = None,
log_formatter: logging.Formatter = None,
log_level: int = logging.INFO,
root_logger: bool = False
) -> None:
"""Convenience method to login and connect with logging setup."""
async def wait_until_ready(self) -> None:
"""Wait until the client is ready to process events."""
# Properties
user: Optional[ClientUser] # The bot user
guilds: List[Guild] # List of guilds the bot is in
users: List[User] # Cached users
cached_messages: List[Message] # Cached messages
latency: float # WebSocket latency in seconds
is_ready: bool # Whether the client is ready
is_closed: bool # Whether the connection is closedUser objects represent Discord accounts, including both regular users and the bot itself.
class User:
"""
Represents a Discord user account.
"""
id: int # User's unique snowflake ID
name: str # Username (without discriminator for new usernames)
discriminator: str # User discriminator (0000 for new usernames)
global_name: Optional[str] # Display name
avatar: Optional[Asset] # User's avatar asset
bot: bool # Whether the user is a bot
system: bool # Whether the user is a system user
created_at: datetime # Account creation timestamp
default_avatar: Asset # Default avatar asset
display_avatar: Asset # Avatar or default if none
mention: str # Mention string (<@user_id>)
async def create_dm(self) -> DMChannel:
"""Create a DM channel with this user."""
def mentioned_in(self, message: Message) -> bool:
"""Check if user is mentioned in a message."""
class ClientUser(User):
"""
Represents the bot user account with additional properties.
"""
email: Optional[str] # Bot's email (if available)
verified: bool # Whether email is verified
mfa_enabled: bool # Whether 2FA is enabled
async def edit(self, *, username: str = None, avatar: bytes = None) -> ClientUser:
"""Edit the bot's profile."""Member objects represent users within the context of a specific guild, including guild-specific data like roles and permissions.
class Member(User):
"""
Represents a guild member (user + guild-specific data).
"""
nick: Optional[str] # Member's nickname in the guild
roles: List[Role] # Member's roles (includes @everyone)
joined_at: Optional[datetime] # When member joined the guild
premium_since: Optional[datetime] # When member started boosting
guild: Guild # The guild this member belongs to
voice: Optional[VoiceState] # Member's voice state
activities: List[Activity] # Member's activities/presence
status: Status # Member's status (online, idle, dnd, offline)
raw_status: str # Raw status string
mobile_status: Status # Mobile client status
desktop_status: Status # Desktop client status
web_status: Status # Web client status
guild_permissions: Permissions # Member's guild-wide permissions
display_name: str # Nick or global_name or name
display_avatar: Asset # Guild avatar or user avatar
async def edit(
self,
*,
nick: str = None,
roles: List[Role] = None,
mute: bool = None,
deafen: bool = None,
voice_channel: Optional[VoiceChannel] = None,
timeout_until: Optional[datetime] = None
) -> None:
"""Edit member properties (requires permissions)."""
async def add_roles(self, *roles: Role, reason: str = None) -> None:
"""Add roles to the member."""
async def remove_roles(self, *roles: Role, reason: str = None) -> None:
"""Remove roles from the member."""
async def ban(self, *, reason: str = None, delete_message_days: int = 1) -> None:
"""Ban the member from the guild."""
async def kick(self, *, reason: str = None) -> None:
"""Kick the member from the guild."""
async def timeout(self, until: datetime, *, reason: str = None) -> None:
"""Timeout the member until the specified time."""
def permissions_in(self, channel: GuildChannel) -> Permissions:
"""Calculate member's permissions in a specific channel."""Guild objects represent Discord servers with comprehensive access to channels, members, roles, and server settings.
class Guild:
"""
Represents a Discord guild (server).
"""
id: int # Guild's unique snowflake ID
name: str # Guild name
icon: Optional[Asset] # Guild icon asset
splash: Optional[Asset] # Guild splash asset
discovery_splash: Optional[Asset] # Guild discovery splash
banner: Optional[Asset] # Guild banner asset
description: Optional[str] # Guild description
owner_id: int # Guild owner's user ID
owner: Optional[Member] # Guild owner member object
region: str # Voice region
verification_level: VerificationLevel # Verification level required
default_notifications: NotificationLevel # Default notification setting
explicit_content_filter: ContentFilter # Content filter level
features: List[str] # Guild feature flags
premium_tier: int # Server boost level (0-3)
premium_subscription_count: int # Number of boosts
member_count: int # Total member count
large: bool # Whether guild is considered large (>250 members)
max_members: int # Maximum member limit
max_presences: Optional[int] # Maximum presence limit
vanity_url_code: Optional[str] # Vanity URL code
premium_progress_bar_enabled: bool # Whether boost progress bar is enabled
created_at: datetime # Guild creation timestamp
# Collections
members: List[Member] # Guild members
channels: List[GuildChannel] # Guild channels
roles: List[Role] # Guild roles
emojis: List[Emoji] # Custom emojis
stickers: List[GuildSticker] # Custom stickers
voice_channels: List[VoiceChannel] # Voice channels only
text_channels: List[TextChannel] # Text channels only
categories: List[CategoryChannel] # Category channels only
# Useful properties
system_channel: Optional[TextChannel] # System messages channel
rules_channel: Optional[TextChannel] # Rules channel
public_updates_channel: Optional[TextChannel] # Community updates channel
me: Member # Bot's member object in this guild
async def leave(self) -> None:
"""Leave the guild."""
async def delete(self) -> None:
"""Delete the guild (bot must be owner)."""
async def edit(self, *, name: str = None, description: str = None, icon: bytes = None) -> Guild:
"""Edit guild properties."""
async def create_text_channel(self, name: str, **options) -> TextChannel:
"""Create a new text channel."""
async def create_voice_channel(self, name: str, **options) -> VoiceChannel:
"""Create a new voice channel."""
async def create_category(self, name: str, **options) -> CategoryChannel:
"""Create a new category channel."""
async def create_role(self, *, name: str = None, permissions: Permissions = None, **options) -> Role:
"""Create a new role."""
async def ban(self, user: User, *, reason: str = None, delete_message_days: int = 1) -> None:
"""Ban a user from the guild."""
async def unban(self, user: User, *, reason: str = None) -> None:
"""Unban a user from the guild."""
async def kick(self, user: Member, *, reason: str = None) -> None:
"""Kick a member from the guild."""
async def fetch_member(self, user_id: int) -> Member:
"""Fetch a member by ID."""
async def fetch_ban(self, user: User) -> BanEntry:
"""Fetch ban information for a user."""
def get_member(self, user_id: int) -> Optional[Member]:
"""Get a cached member by ID."""
def get_channel(self, channel_id: int) -> Optional[GuildChannel]:
"""Get a cached channel by ID."""
def get_role(self, role_id: int) -> Optional[Role]:
"""Get a cached role by ID."""Channel objects represent different types of Discord channels with specialized functionality for text, voice, and organizational purposes.
class TextChannel:
"""
Represents a guild text channel.
"""
id: int # Channel's unique snowflake ID
name: str # Channel name
guild: Guild # Guild this channel belongs to
position: int # Channel position in the list
category: Optional[CategoryChannel] # Parent category
topic: Optional[str] # Channel topic
slowmode_delay: int # Slowmode delay in seconds
nsfw: bool # Whether channel is age-restricted
permissions_synced: bool # Whether permissions sync with category
created_at: datetime # Channel creation timestamp
mention: str # Channel mention string (<#channel_id>)
async def send(
self,
content: str = None,
*,
embed: Embed = None,
embeds: List[Embed] = None,
file: File = None,
files: List[File] = None,
view: View = None,
tts: bool = False,
ephemeral: bool = False,
allowed_mentions: AllowedMentions = None,
reference: MessageReference = None
) -> Message:
"""Send a message to the channel."""
async def edit(self, *, name: str = None, topic: str = None, position: int = None) -> TextChannel:
"""Edit channel properties."""
async def delete(self, *, reason: str = None) -> None:
"""Delete the channel."""
async def purge(self, *, limit: int = 100, check: Callable = None) -> List[Message]:
"""Bulk delete messages."""
async def create_webhook(self, *, name: str, avatar: bytes = None) -> Webhook:
"""Create a webhook in this channel."""
def history(self, *, limit: int = 100, before: datetime = None) -> AsyncIterator[Message]:
"""Iterate through channel message history."""
def permissions_for(self, obj: Union[Member, Role]) -> Permissions:
"""Calculate permissions for a member or role."""
class VoiceChannel:
"""
Represents a guild voice channel.
"""
id: int # Channel's unique snowflake ID
name: str # Channel name
guild: Guild # Guild this channel belongs to
position: int # Channel position
category: Optional[CategoryChannel] # Parent category
bitrate: int # Voice bitrate
user_limit: int # User limit (0 = unlimited)
rtc_region: Optional[str] # Voice server region
video_quality_mode: int # Video quality mode
members: List[Member] # Connected members
async def connect(self, *, timeout: float = 60.0, reconnect: bool = True) -> VoiceClient:
"""Connect to the voice channel."""
async def edit(self, *, name: str = None, bitrate: int = None, user_limit: int = None) -> VoiceChannel:
"""Edit voice channel properties."""
class DMChannel:
"""
Represents a direct message channel.
"""
id: int # Channel ID
recipient: User # The other user in the DM
me: ClientUser # The bot user
async def send(self, content: str = None, **kwargs) -> Message:
"""Send a DM message."""
class CategoryChannel:
"""
Represents a channel category for organization.
"""
id: int # Category ID
name: str # Category name
guild: Guild # Guild this category belongs to
position: int # Category position
channels: List[GuildChannel] # Channels in this category
async def create_text_channel(self, name: str, **options) -> TextChannel:
"""Create a text channel in this category."""
async def create_voice_channel(self, name: str, **options) -> VoiceChannel:
"""Create a voice channel in this category."""Message objects represent Discord messages with comprehensive metadata, content access, and interaction methods.
class Message:
"""
Represents a Discord message.
"""
id: int # Message's unique snowflake ID
channel: Union[TextChannel, DMChannel, GroupChannel] # Channel message was sent in
guild: Optional[Guild] # Guild if sent in a guild channel
author: Union[User, Member] # Message author
content: str # Message text content
clean_content: str # Content with mentions resolved
created_at: datetime # Message creation timestamp
edited_at: Optional[datetime] # Last edit timestamp
tts: bool # Whether message is text-to-speech
mention_everyone: bool # Whether message mentions @everyone
mentions: List[Union[User, Member]] # Mentioned users
channel_mentions: List[GuildChannel] # Mentioned channels
role_mentions: List[Role] # Mentioned roles
attachments: List[Attachment] # File attachments
embeds: List[Embed] # Rich embeds
reactions: List[Reaction] # Message reactions
pinned: bool # Whether message is pinned
type: MessageType # Message type (default, reply, etc.)
system_content: Optional[str] # System message content
flags: MessageFlags # Message flags
reference: Optional[MessageReference] # Reference to replied message
components: List[Component] # UI components attached
async def edit(
self,
*,
content: str = None,
embed: Embed = None,
embeds: List[Embed] = None,
attachments: List[Attachment] = None,
view: View = None
) -> Message:
"""Edit the message (bot must be author)."""
async def delete(self, *, delay: float = None) -> None:
"""Delete the message."""
async def pin(self, *, reason: str = None) -> None:
"""Pin the message."""
async def unpin(self, *, reason: str = None) -> None:
"""Unpin the message."""
async def add_reaction(self, emoji: Union[Emoji, str]) -> None:
"""Add a reaction to the message."""
async def remove_reaction(self, emoji: Union[Emoji, str], member: Member) -> None:
"""Remove a reaction from the message."""
async def clear_reactions(self) -> None:
"""Clear all reactions from the message."""
async def reply(self, content: str = None, **kwargs) -> Message:
"""Reply to the message."""
def to_reference(self) -> MessageReference:
"""Create a message reference for replies."""
class Attachment:
"""
Represents a message file attachment.
"""
id: int # Attachment ID
filename: str # Original filename
description: Optional[str] # Alt text description
content_type: Optional[str] # MIME type
size: int # File size in bytes
url: str # Attachment URL
proxy_url: str # Proxied URL
height: Optional[int] # Image/video height
width: Optional[int] # Image/video width
ephemeral: bool # Whether attachment is ephemeral
async def save(self, fp: Union[str, bytes, os.PathLike], *, seek_begin: bool = True) -> int:
"""Save attachment to file."""
async def read(self) -> bytes:
"""Read attachment data."""
def to_file(self) -> File:
"""Convert to a File object for re-uploading."""Role and permission objects manage access control and user organization within guilds.
class Role:
"""
Represents a guild role.
"""
id: int # Role's unique snowflake ID
name: str # Role name
guild: Guild # Guild this role belongs to
colour: Colour # Role color
color: Colour # Alias for colour
hoist: bool # Whether role is displayed separately
position: int # Role position in hierarchy
managed: bool # Whether role is managed by integration
mentionable: bool # Whether role can be mentioned
permissions: Permissions # Role permissions
tags: Optional[RoleTags] # Role tags (bot, premium subscriber, etc.)
created_at: datetime # Role creation timestamp
mention: str # Role mention string (<@&role_id>)
members: List[Member] # Members with this role
async def edit(
self,
*,
name: str = None,
permissions: Permissions = None,
colour: Colour = None,
hoist: bool = None,
mentionable: bool = None,
position: int = None
) -> Role:
"""Edit role properties."""
async def delete(self, *, reason: str = None) -> None:
"""Delete the role."""
def is_default(self) -> bool:
"""Check if this is the @everyone role."""
def is_bot_managed(self) -> bool:
"""Check if role is managed by a bot."""
def is_premium_subscriber(self) -> bool:
"""Check if role is the premium subscriber role."""
class Permissions:
"""
Represents Discord permissions as a bitfield.
"""
value: int # Permission bitfield value
def __init__(self, permissions: int = 0): ...
@classmethod
def none(cls) -> Permissions:
"""Create permissions with no flags set."""
@classmethod
def all(cls) -> Permissions:
"""Create permissions with all flags set."""
@classmethod
def all_channel(cls) -> Permissions:
"""Create permissions with all channel-specific flags."""
@classmethod
def general(cls) -> Permissions:
"""Create permissions with general flags."""
@classmethod
def text(cls) -> Permissions:
"""Create permissions with text channel flags."""
@classmethod
def voice(cls) -> Permissions:
"""Create permissions with voice channel flags."""
@classmethod
def stage(cls) -> Permissions:
"""Create permissions with stage channel flags."""
# Permission properties (read/write)
create_instant_invite: bool
kick_members: bool
ban_members: bool
administrator: bool
manage_channels: bool
manage_guild: bool
add_reactions: bool
view_audit_log: bool
priority_speaker: bool
stream: bool
read_messages: bool
view_channel: bool # Alias for read_messages
send_messages: bool
send_tts_messages: bool
manage_messages: bool
embed_links: bool
attach_files: bool
read_message_history: bool
mention_everyone: bool
external_emojis: bool
use_external_emojis: bool # Alias for external_emojis
view_guild_insights: bool
connect: bool
speak: bool
mute_members: bool
deafen_members: bool
move_members: bool
use_voice_activation: bool
change_nickname: bool
manage_nicknames: bool
manage_roles: bool
manage_permissions: bool # Alias for manage_roles
manage_webhooks: bool
manage_emojis: bool
manage_emojis_and_stickers: bool
use_application_commands: bool
use_slash_commands: bool # Alias for use_application_commands
request_to_speak: bool
manage_events: bool
manage_threads: bool
create_public_threads: bool
create_private_threads: bool
external_stickers: bool
use_external_stickers: bool # Alias for external_stickers
send_messages_in_threads: bool
start_embedded_activities: bool
moderate_members: bool
def update(self, **kwargs) -> None:
"""Update multiple permission flags."""
def is_subset(self, other: Permissions) -> bool:
"""Check if permissions are a subset of another."""
def is_superset(self, other: Permissions) -> bool:
"""Check if permissions are a superset of another."""
def is_strict_subset(self, other: Permissions) -> bool:
"""Check if permissions are a strict subset."""
def is_strict_superset(self, other: Permissions) -> bool:
"""Check if permissions are a strict superset."""Emoji and asset objects provide access to Discord's custom emojis and media assets like avatars and icons.
class Emoji:
"""
Represents a custom guild emoji.
"""
id: int # Emoji's unique snowflake ID
name: str # Emoji name
guild: Guild # Guild this emoji belongs to
animated: bool # Whether emoji is animated
managed: bool # Whether emoji is managed by integration
require_colons: bool # Whether emoji requires colons
roles: List[Role] # Roles that can use this emoji
user: Optional[User] # User who created the emoji
available: bool # Whether emoji is available for use
created_at: datetime # Emoji creation timestamp
url: str # Emoji image URL
async def edit(self, *, name: str = None, roles: List[Role] = None) -> Emoji:
"""Edit emoji properties."""
async def delete(self, *, reason: str = None) -> None:
"""Delete the emoji."""
def __str__(self) -> str:
"""Return emoji string for sending in messages."""
class PartialEmoji:
"""
Represents a partial emoji (from reactions, etc.).
"""
id: Optional[int] # Emoji ID (None for unicode)
name: str # Emoji name or unicode character
animated: bool # Whether emoji is animated
def __str__(self) -> str:
"""Return emoji string."""
@property
def url(self) -> Optional[str]:
"""Emoji URL if custom emoji."""
class Asset:
"""
Represents a Discord CDN asset (avatar, icon, etc.).
"""
url: str # Asset URL
key: str # Asset key/hash
def replace(self, *, size: int = None, format: str = None, static_format: str = None) -> Asset:
"""Create a new asset with different parameters."""
def with_size(self, size: int) -> Asset:
"""Create asset with specific size."""
def with_format(self, format: str) -> Asset:
"""Create asset with specific format."""
def with_static_format(self, format: str) -> Asset:
"""Create asset with static format."""
async def save(self, fp: Union[str, bytes, os.PathLike], *, seek_begin: bool = True) -> int:
"""Save asset to file."""
async def read(self) -> bytes:
"""Read asset data."""# Base Exceptions
class DiscordException(Exception):
"""Base exception for discord.py."""
pass
class ClientException(DiscordException):
"""Exception for client-side errors."""
pass
# Connection Exceptions
class GatewayNotFound(DiscordException):
"""Gateway URL could not be found."""
pass
class ConnectionClosed(ClientException):
"""WebSocket connection was closed."""
def __init__(self, socket, *, shard_id: int, code: int = None): ...
shard_id: int
code: Optional[int]
# HTTP Exceptions
class HTTPException(DiscordException):
"""Exception for HTTP request errors."""
def __init__(self, response, message: str): ...
response: aiohttp.ClientResponse
status: int
code: int
text: str
class Forbidden(HTTPException):
"""403 Forbidden HTTP error."""
pass
class NotFound(HTTPException):
"""404 Not Found HTTP error."""
pass
class DiscordServerError(HTTPException):
"""5xx server error."""
pass
class RateLimited(HTTPException):
"""429 Rate Limited error."""
retry_after: float
# Authentication Exceptions
class LoginFailure(ClientException):
"""Invalid authentication credentials."""
pass
class PrivilegedIntentsRequired(ClientException):
"""Bot requires privileged intents."""
pass
# Data Exceptions
class InvalidData(ClientException):
"""Invalid or unexpected data received."""
pass
class InvalidArgument(ClientException):
"""Invalid argument passed to function."""
passInstall with Tessl CLI
npx tessl i tessl/pypi-discord-py