A modern, easy-to-use, feature-rich async-ready API wrapper for Discord written in Python
—
Core client and bot classes for establishing Discord connections and managing bot functionality. The Client class provides basic Discord API connectivity, while Bot classes extend this with command handling capabilities.
The foundational client class for Discord API connections with essential connection management and event handling.
class Client:
def __init__(
self,
*,
asyncio_debug: bool = False,
loop: Optional[AbstractEventLoop] = None,
shard_id: Optional[int] = None,
shard_count: Optional[int] = None,
enable_debug_events: bool = False,
enable_gateway_error_handler: bool = True,
localization_provider: Optional[LocalizationProtocol] = None,
strict_localization: bool = False,
gateway_params: Optional[GatewayParams] = None,
connector: Optional[BaseConnector] = None,
proxy: Optional[str] = None,
proxy_auth: Optional[BasicAuth] = None,
assume_unsync_clock: bool = True,
max_messages: Optional[int] = 1000,
application_id: Optional[int] = None,
heartbeat_timeout: float = 60.0,
guild_ready_timeout: float = 2.0,
allowed_mentions: Optional[AllowedMentions] = None,
activity: Optional[BaseActivity] = None,
status: Optional[Union[Status, str]] = None,
intents: Optional[Intents] = None,
chunk_guilds_at_startup: Optional[bool] = None,
member_cache_flags: Optional[MemberCacheFlags] = None
):
"""
Initialize a Discord client.
Parameters:
- asyncio_debug: Whether to enable asyncio debugging
- loop: Event loop to use (optional)
- shard_id: Shard ID for sharded bots (optional)
- shard_count: Total number of shards (optional)
- enable_debug_events: Whether to enable debug events for gateway data
- enable_gateway_error_handler: Whether to enable gateway error handling
- localization_provider: Custom localization provider for commands
- strict_localization: Whether to raise errors for missing localizations
- gateway_params: Gateway connection parameters
- connector: HTTP connector for requests (optional)
- proxy: Proxy URL for connections (optional)
- proxy_auth: Basic auth for proxy connections
- assume_unsync_clock: Whether to assume system clock is unsynced
- max_messages: Maximum messages to store in cache
- application_id: Application ID for the bot (optional)
- heartbeat_timeout: Gateway heartbeat timeout in seconds
- guild_ready_timeout: Guild ready timeout in seconds
- allowed_mentions: Default allowed mentions configuration
- activity: Default activity/presence
- status: Default status (online, idle, dnd, invisible)
- intents: Gateway intents to request (optional)
- chunk_guilds_at_startup: Whether to chunk guild members at startup
- member_cache_flags: Member cache configuration flags
"""
async def login(self, token: str) -> None:
"""
Login to Discord with a bot token.
Parameters:
- token: Bot token from Discord Developer Portal
"""
async def connect(self, *, reconnect: bool = True) -> None:
"""
Connect to Discord gateway.
Parameters:
- reconnect: Whether to reconnect on connection loss
"""
def run(self, token: str, **kwargs) -> None:
"""
Run the client with automatic connection management.
Parameters:
- token: Bot token
- log_handler: Custom log handler (optional)
- log_formatter: Custom log formatter (optional)
- log_level: Logging level (optional)
- root_logger: Whether to configure root logger (optional)
"""
async def close(self) -> None:
"""Close the client connection and cleanup resources."""
async def wait_until_ready(self) -> None:
"""Wait until the client is fully ready."""
def wait_for(
self,
event: str,
*,
check: Optional[Callable[..., bool]] = None,
timeout: Optional[float] = None
) -> Any:
"""
Wait for a specific event.
Parameters:
- event: Event name to wait for
- check: Optional check function
- timeout: Maximum time to wait
Returns:
Event data when the event occurs
"""
def dispatch(self, event: str, *args, **kwargs) -> None:
"""
Dispatch an event to registered listeners.
Parameters:
- event: Event name
- args: Event arguments
- kwargs: Event keyword arguments
"""
async def fetch_user(self, user_id: int) -> User:
"""
Fetch a user by ID from Discord API.
Parameters:
- user_id: Discord user ID
Returns:
User object
"""
def get_user(self, user_id: int) -> Optional[User]:
"""
Get a user from cache by ID.
Parameters:
- user_id: Discord user ID
Returns:
User object if cached, None otherwise
"""
async def fetch_channel(self, channel_id: int) -> Union[GuildChannel, PrivateChannel]:
"""
Fetch a channel by ID from Discord API.
Parameters:
- channel_id: Discord channel ID
Returns:
Channel object
"""
def get_channel(self, channel_id: int) -> Optional[Union[GuildChannel, PrivateChannel]]:
"""
Get a channel from cache by ID.
Parameters:
- channel_id: Discord channel ID
Returns:
Channel object if cached, None otherwise
"""
async def sync_commands(
self,
*,
commands: Optional[Sequence[APIApplicationCommand]] = None,
guild_id: Optional[int] = None,
delete_existing: bool = True,
sync_on_cog_actions: Optional[bool] = None
) -> None:
"""
Sync application commands with Discord.
Parameters:
- commands: Commands to sync (optional)
- guild_id: Guild ID for guild-specific sync (optional)
- delete_existing: Whether to delete commands not in the list
- sync_on_cog_actions: Override sync_on_cog_actions setting
"""
@property
def user(self) -> Optional[ClientUser]:
"""The bot's user object."""
@property
def guilds(self) -> List[Guild]:
"""All guilds the bot is in."""
@property
def users(self) -> List[User]:
"""All users in the bot's cache."""
@property
def emojis(self) -> List[Emoji]:
"""All emojis the client has access to."""
@property
def stickers(self) -> List[GuildSticker]:
"""All guild stickers the client has access to."""
@property
def latency(self) -> float:
"""WebSocket latency in seconds."""
@property
def is_ready(self) -> bool:
"""Whether the client is ready."""
def is_ws_ratelimited(self) -> bool:
"""Whether the websocket is currently rate limited."""
async def get_or_fetch_user(self, user_id: int, *, strict: bool = False) -> Optional[User]:
"""
Get a user from cache or fetch from API.
Parameters:
- user_id: Discord user ID
- strict: Whether to raise error if user not found
Returns:
User object if found, None otherwise (unless strict=True)
"""Bot class with traditional text-based command support extending the basic client functionality.
class Bot(commands.BotBase, Client):
def __init__(
self,
command_prefix: Union[str, Iterable[str], Callable[[Bot, Message], Union[str, Iterable[str]]]],
*,
help_command: Optional[commands.HelpCommand] = ...,
description: Optional[str] = None,
**options
):
"""
Initialize a bot with message command support.
Parameters:
- command_prefix: Command prefix(es) or callable returning prefix(es)
- help_command: Custom help command implementation
- description: Bot description for help command
- options: Additional client options
"""
@property
def commands(self) -> Set[commands.Command]:
"""All registered commands."""
def add_command(self, command: commands.Command) -> None:
"""
Add a command to the bot.
Parameters:
- command: Command to add
"""
def remove_command(self, name: str) -> Optional[commands.Command]:
"""
Remove a command by name.
Parameters:
- name: Command name
Returns:
Removed command if found
"""
def get_command(self, name: str) -> Optional[commands.Command]:
"""
Get a command by name.
Parameters:
- name: Command name
Returns:
Command if found
"""
async def process_commands(self, message: Message) -> None:
"""
Process a message for commands.
Parameters:
- message: Message to process
"""
async def invoke(self, ctx: commands.Context) -> None:
"""
Invoke a command from context.
Parameters:
- ctx: Command context
"""
def command(self, name: str = None, **kwargs):
"""
Decorator for registering commands.
Parameters:
- name: Command name (optional)
- kwargs: Command options
"""
def group(self, name: str = None, **kwargs):
"""
Decorator for registering command groups.
Parameters:
- name: Group name (optional)
- kwargs: Group options
"""Bot with automatic sharding for large bot deployments across multiple processes.
class AutoShardedBot(commands.AutoShardedBotBase, Bot):
def __init__(self, command_prefix, **options):
"""
Initialize an auto-sharded bot.
Parameters:
- command_prefix: Command prefix(es)
- options: Bot options including shard configuration
"""Specialized bot focused on application commands (slash commands, context menus) with streamlined interaction handling.
class InteractionBot(commands.InteractionBotBase, Client):
def __init__(self, **options):
"""
Initialize an interaction-focused bot.
Parameters:
- options: Client options
"""
@property
def slash_commands(self) -> Set[SlashCommand]:
"""All registered slash commands."""
@property
def user_commands(self) -> Set[UserCommand]:
"""All registered user commands."""
@property
def message_commands(self) -> Set[MessageCommand]:
"""All registered message commands."""
def add_slash_command(self, command: SlashCommand) -> None:
"""
Add a slash command.
Parameters:
- command: Slash command to add
"""
def slash_command(self, name: str = None, **kwargs):
"""
Decorator for slash commands.
Parameters:
- name: Command name (optional)
- kwargs: Command options
"""
def user_command(self, name: str = None, **kwargs):
"""
Decorator for user context menu commands.
Parameters:
- name: Command name (optional)
- kwargs: Command options
"""
def message_command(self, name: str = None, **kwargs):
"""
Decorator for message context menu commands.
Parameters:
- name: Command name (optional)
- kwargs: Command options
"""Interaction bot with automatic sharding capabilities for large-scale deployments.
class AutoShardedInteractionBot(commands.AutoShardedBotBase, InteractionBot):
def __init__(self, **options):
"""
Initialize an auto-sharded interaction bot.
Parameters:
- options: Bot options including shard configuration
"""import disnake
intents = disnake.Intents.default()
intents.message_content = True
client = disnake.Client(intents=intents)
@client.event
async def on_ready():
print(f'Logged in as {client.user}')
@client.event
async def on_message(message):
if message.author == client.user:
return
if message.content.startswith('!hello'):
await message.channel.send('Hello!')
client.run('YOUR_BOT_TOKEN')from disnake.ext import commands
bot = commands.Bot(command_prefix='!', intents=disnake.Intents.all())
@bot.event
async def on_ready():
print(f'Bot ready: {bot.user}')
@bot.command()
async def ping(ctx):
latency = round(bot.latency * 1000)
await ctx.send(f'Pong! Latency: {latency}ms')
@bot.group()
async def admin(ctx):
if ctx.invoked_subcommand is None:
await ctx.send('Invalid admin command.')
@admin.command()
async def kick(ctx, member: disnake.Member, *, reason="No reason provided"):
await member.kick(reason=reason)
await ctx.send(f'Kicked {member}')
bot.run('YOUR_BOT_TOKEN')import disnake
bot = disnake.InteractionBot(intents=disnake.Intents.default())
@bot.slash_command(description="Get bot latency")
async def ping(inter: disnake.ApplicationCommandInteraction):
latency = round(bot.latency * 1000)
await inter.response.send_message(f'Pong! Latency: {latency}ms')
@bot.slash_command(description="Say something")
async def say(
inter: disnake.ApplicationCommandInteraction,
message: str = disnake.Param(description="Message to say")
):
await inter.response.send_message(message)
bot.run('YOUR_BOT_TOKEN')Install with Tessl CLI
npx tessl i tessl/pypi-disnake