CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-discord-py

A modern, feature-rich, and async-ready API wrapper for Discord written in Python

Pending
Overview
Eval results
Files

utilities.mddocs/

Utilities & Helpers

Helper functions and utilities for common Discord operations including OAuth URLs, snowflake handling, time formatting, markdown processing, and various convenience functions for Discord bot development.

Capabilities

Authentication & URLs

Utilities for generating OAuth URLs and handling Discord authentication.

def oauth_url(
    client_id: int, 
    *, 
    permissions: Optional[Permissions] = None,
    guild: Optional[Guild] = None,
    redirect_uri: Optional[str] = None,
    scopes: Optional[List[str]] = None,
    disable_guild_select: bool = False
) -> str:
    """
    Generate OAuth2 authorization URL for bot invitation.
    
    Parameters:
    - client_id: Bot's application ID
    - permissions: Permissions to request
    - guild: Specific guild to add bot to
    - redirect_uri: URL to redirect to after authorization
    - scopes: OAuth2 scopes to request (defaults to ['bot'])
    - disable_guild_select: Whether to disable guild selection
    
    Returns:
    str: OAuth2 authorization URL
    """

def oauth_url_from_client(
    client: Client,
    *,
    permissions: Optional[Permissions] = None,
    guild: Optional[Guild] = None,
    redirect_uri: Optional[str] = None,
    scopes: Optional[List[str]] = None,
    disable_guild_select: bool = False
) -> str:
    """
    Generate OAuth2 URL from client instance.
    
    Parameters:
    - client: Discord client instance
    - permissions: Permissions to request
    - guild: Specific guild to add bot to
    - redirect_uri: URL to redirect to after authorization
    - scopes: OAuth2 scopes to request
    - disable_guild_select: Whether to disable guild selection
    
    Returns:
    str: OAuth2 authorization URL
    """

Snowflake Utilities

Functions for working with Discord snowflake IDs and extracting timestamp information.

def snowflake_time(id: int) -> datetime:
    """
    Extract creation timestamp from Discord snowflake ID.
    
    Parameters:
    - id: Discord snowflake ID
    
    Returns:
    datetime: UTC timestamp when the snowflake was created
    """

def time_snowflake(dt: datetime, high: bool = False) -> int:
    """
    Generate a snowflake ID from a timestamp.
    
    Parameters:
    - dt: Datetime to convert to snowflake
    - high: Whether to generate highest or lowest possible snowflake for the timestamp
    
    Returns:
    int: Snowflake ID
    """

DISCORD_EPOCH: int = 1420070400000
"""Discord epoch timestamp (January 1, 2015)."""

Time & Date Utilities

Helper functions for time formatting and Discord timestamp formatting.

def utcnow() -> datetime:
    """
    Get current UTC datetime.
    
    Returns:
    datetime: Current UTC timestamp
    """

def compute_timedelta(dt: datetime) -> float:
    """
    Compute time delta between datetime and now.
    
    Parameters:
    - dt: Target datetime
    
    Returns:
    float: Seconds until target datetime
    """

async def sleep_until(when: datetime, *, result: Any = None) -> Any:
    """
    Sleep until a specific datetime.
    
    Parameters:
    - when: Datetime to sleep until
    - result: Value to return after sleeping
    
    Returns:
    Any: The result parameter value
    """

def format_dt(dt: datetime, style: Optional[str] = None) -> str:
    """
    Format datetime for Discord timestamp display.
    
    Parameters:
    - dt: Datetime to format
    - style: Format style ('t', 'T', 'd', 'D', 'f', 'F', 'R')
        - 't': Short time (16:20)
        - 'T': Long time (16:20:30)
        - 'd': Short date (20/04/2021)
        - 'D': Long date (20 April 2021)
        - 'f': Short date/time (default)
        - 'F': Long date/time
        - 'R': Relative time (2 months ago)
    
    Returns:
    str: Discord timestamp string (<t:timestamp:style>)
    """

Text Processing

Functions for handling markdown, mentions, and text formatting.

def escape_markdown(text: str, *, as_needed: bool = False, ignore_links: bool = True) -> str:
    """
    Escape Discord markdown characters in text.
    
    Parameters:
    - text: Text to escape
    - as_needed: Only escape characters that would affect formatting
    - ignore_links: Don't escape characters in URLs
    
    Returns:
    str: Text with markdown characters escaped
    """

def escape_mentions(text: str) -> str:
    """
    Escape user, channel, and role mentions in text.
    
    Parameters:
    - text: Text to escape mentions in
    
    Returns:
    str: Text with mentions escaped
    """

def remove_markdown(text: str, *, ignore_links: bool = True) -> str:
    """
    Remove Discord markdown formatting from text.
    
    Parameters:
    - text: Text to remove markdown from
    - ignore_links: Don't remove markdown from URLs
    
    Returns:
    str: Text with markdown formatting removed
    """

def clean_content(content: str, *, fix_channel_mentions: bool = False) -> str:
    """
    Clean message content by resolving mentions to readable text.
    
    Parameters:
    - content: Message content to clean
    - fix_channel_mentions: Whether to convert channel mentions to #channel-name
    
    Returns:
    str: Cleaned content with mentions resolved
    """

Collection Utilities

Helper functions for working with sequences and collections.

def find(predicate: Callable[[Any], bool], seq: Sequence[Any]) -> Optional[Any]:
    """
    Find first element in sequence matching predicate.
    
    Parameters:
    - predicate: Function returning True for matching element
    - seq: Sequence to search
    
    Returns:
    Any: First matching element, or None if not found
    """

def get(iterable: Iterable[Any], **attrs: Any) -> Optional[Any]:
    """
    Find first element with matching attributes.
    
    Parameters:
    - iterable: Iterable to search
    - attrs: Attributes to match (name=value pairs)
    
    Returns:
    Any: First matching element, or None if not found
    """

def as_chunks(iterator: Iterator[Any], max_size: int) -> Iterator[List[Any]]:
    """
    Split iterator into chunks of maximum size.
    
    Parameters:
    - iterator: Iterator to split
    - max_size: Maximum chunk size
    
    Yields:
    List[Any]: Chunks of iterator items
    """

T = TypeVar('T')

class SequenceProxy(Generic[T]):
    """
    Proxy for sequences with filtering and transformation.
    """
    def __init__(self, proxied: Sequence[T], *, predicate: Optional[Callable[[T], bool]] = None): ...
    
    def __len__(self) -> int: ...
    def __iter__(self) -> Iterator[T]: ...
    def __getitem__(self, idx: Union[int, slice]) -> Union[T, Sequence[T]]: ...
    
    def filter(self, predicate: Callable[[T], bool]) -> SequenceProxy[T]:
        """Filter sequence by predicate."""
    
    def map(self, func: Callable[[T], Any]) -> SequenceProxy[Any]:
        """Transform sequence elements."""

Async Utilities

Helper functions and classes for async programming patterns.

async def maybe_coroutine(f: Union[Callable[..., Any], Callable[..., Awaitable[Any]]], *args: Any, **kwargs: Any) -> Any:
    """
    Call function whether it's a coroutine or regular function.
    
    Parameters:
    - f: Function to call (sync or async)
    - args: Positional arguments
    - kwargs: Keyword arguments
    
    Returns:
    Any: Function result
    """

def setup_logging(
    *,
    handler: Optional[logging.Handler] = None,
    formatter: Optional[logging.Formatter] = None,
    level: int = logging.INFO,
    root: bool = True
) -> None:
    """
    Set up logging for discord.py library.
    
    Parameters:
    - handler: Log handler to use (defaults to StreamHandler)
    - formatter: Log formatter to use
    - level: Logging level
    - root: Whether to set up root logger
    """

class _MissingSentinel:
    """Sentinel class for missing values."""
    def __bool__(self) -> bool:
        return False
    
    def __repr__(self) -> str:
        return '...'

MISSING: Any = _MissingSentinel()
"""Sentinel value for missing/unset parameters."""

File & Data Utilities

Functions for handling files and data conversion.

def parse_time(timestamp: str) -> Optional[datetime]:
    """
    Parse ISO 8601 timestamp string.
    
    Parameters:
    - timestamp: ISO timestamp string
    
    Returns:
    datetime: Parsed datetime, or None if invalid
    """

def copy_doc(original: Callable) -> Callable:
    """
    Decorator to copy docstring from another function.
    
    Parameters:
    - original: Function to copy docstring from
    
    Returns:
    Callable: Decorator function
    """

def cached_slot_property(name: str) -> property:
    """
    Create a cached property that stores value in __slots__.
    
    Parameters:
    - name: Slot name to store cached value
    
    Returns:
    property: Cached property descriptor
    """

def generate_snowflake() -> int:
    """
    Generate a unique snowflake ID.
    
    Returns:
    int: Generated snowflake ID
    """

Permission Utilities

Helper functions for working with Discord permissions.

def permissions_in_channel(
    member: Member,
    channel: GuildChannel,
    *,
    ignore_timeout: bool = False
) -> Permissions:
    """
    Calculate member's permissions in a channel.
    
    Parameters:
    - member: Guild member
    - channel: Guild channel
    - ignore_timeout: Whether to ignore member timeout
    
    Returns:
    Permissions: Member's effective permissions in the channel
    """

def permissions_for_roles(
    roles: List[Role],
    channel: Optional[GuildChannel] = None
) -> Permissions:
    """
    Calculate combined permissions for a list of roles.
    
    Parameters:
    - roles: List of roles
    - channel: Channel for permission overwrites (optional)
    
    Returns:
    Permissions: Combined permissions
    """

Message Utilities

Helper functions for working with messages and message references.

def message_reference_from_url(url: str) -> Optional[MessageReference]:
    """
    Create MessageReference from Discord message URL.
    
    Parameters:
    - url: Discord message URL
    
    Returns:
    MessageReference: Reference object, or None if invalid URL
    """

def jump_url_from_ids(guild_id: Optional[int], channel_id: int, message_id: int) -> str:
    """
    Create Discord message jump URL from IDs.
    
    Parameters:
    - guild_id: Guild ID (None for DM)
    - channel_id: Channel ID
    - message_id: Message ID
    
    Returns:
    str: Discord message jump URL
    """

def resolve_invite(invite: Union[str, Invite]) -> str:
    """
    Resolve invite to invite code.
    
    Parameters:
    - invite: Invite object or invite URL/code
    
    Returns:
    str: Invite code
    """

def resolve_template(template: Union[str, Template]) -> str:
    """
    Resolve template to template code.
    
    Parameters:
    - template: Template object or template URL/code
    
    Returns:
    str: Template code
    """

Context Managers

Utility context managers for common Discord operations.

class Typing:
    """
    Context manager for typing indicator.
    """
    def __init__(self, messageable: Messageable): ...
    
    async def __aenter__(self) -> Typing:
        """Start typing indicator."""
    
    async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
        """Stop typing indicator."""

def typing(messageable: Messageable) -> Typing:
    """
    Create typing context manager.
    
    Parameters:
    - messageable: Channel or messageable to type in
    
    Returns:
    Typing: Typing context manager
    """

Usage Examples

Basic Utility Usage

import discord
from discord.utils import *

# Generate OAuth URL
bot_id = 123456789012345678
permissions = discord.Permissions(send_messages=True, read_messages=True)
invite_url = oauth_url(bot_id, permissions=permissions)
print(f"Invite URL: {invite_url}")

# Work with snowflakes
user_id = 98765432109876543
creation_time = snowflake_time(user_id)
print(f"User created at: {creation_time}")

# Generate snowflake for specific time
import datetime
specific_time = datetime.datetime(2023, 1, 1, tzinfo=datetime.timezone.utc)
snowflake_id = time_snowflake(specific_time)
print(f"Snowflake for {specific_time}: {snowflake_id}")

Text Processing Examples

import discord
from discord.utils import *

# Escape markdown
text_with_markdown = "This has **bold** and *italic* text!"
escaped_text = escape_markdown(text_with_markdown)
print(f"Escaped: {escaped_text}")

# Remove markdown
clean_text = remove_markdown(text_with_markdown)
print(f"Clean: {clean_text}")

# Escape mentions
text_with_mentions = "Hello <@123456789> and <#987654321>!"
escaped_mentions = escape_mentions(text_with_mentions)
print(f"Escaped mentions: {escaped_mentions}")

# Format Discord timestamps
now = discord.utils.utcnow()
timestamp_formats = {
    't': format_dt(now, 't'),  # Short time
    'T': format_dt(now, 'T'),  # Long time
    'd': format_dt(now, 'd'),  # Short date
    'D': format_dt(now, 'D'),  # Long date
    'f': format_dt(now, 'f'),  # Short date/time
    'F': format_dt(now, 'F'),  # Long date/time
    'R': format_dt(now, 'R'),  # Relative time
}

for style, formatted in timestamp_formats.items():
    print(f"Style '{style}': {formatted}")

Collection Utilities Examples

import discord
from discord.utils import *

# Example with guild members
async def find_member_examples(guild: discord.Guild):
    # Find member by name
    member = find(lambda m: m.name == "example_user", guild.members)
    if member:
        print(f"Found member: {member}")
    
    # Get member by attribute
    member = get(guild.members, name="example_user", discriminator="1234")
    if member:
        print(f"Found member: {member}")
    
    # Find member with specific role
    admin_role = get(guild.roles, name="Admin")
    if admin_role:
        admin = find(lambda m: admin_role in m.roles, guild.members)
        if admin:
            print(f"Found admin: {admin}")
    
    # Split members into chunks
    member_chunks = list(as_chunks(iter(guild.members), 10))
    print(f"Split {len(guild.members)} members into {len(member_chunks)} chunks")
    
    # Use SequenceProxy for filtering
    online_members = SequenceProxy(guild.members).filter(
        lambda m: m.status != discord.Status.offline
    )
    print(f"Online members: {len(online_members)}")

Advanced Utility Bot

import discord
from discord.ext import commands
from discord.utils import *
import asyncio

class UtilityBot(commands.Bot):
    def __init__(self):
        intents = discord.Intents.default()
        intents.message_content = True
        super().__init__(command_prefix='!', intents=intents)
    
    async def setup_hook(self):
        print(f"Bot is ready! Invite URL: {oauth_url_from_client(self)}")

bot = UtilityBot()

@bot.command()
async def userinfo(ctx, *, user: discord.User = None):
    """Get information about a user."""
    user = user or ctx.author
    
    # Use snowflake utility
    created_at = snowflake_time(user.id)
    
    embed = discord.Embed(title=f"User Info: {user}", color=0x0099ff)
    embed.set_thumbnail(url=user.display_avatar.url)
    embed.add_field(name="ID", value=user.id, inline=True)
    embed.add_field(name="Created", value=format_dt(created_at, 'F'), inline=True)
    embed.add_field(name="Account Age", value=format_dt(created_at, 'R'), inline=True)
    
    # If in guild, show member info
    if ctx.guild and isinstance(user, discord.Member):
        embed.add_field(name="Joined", value=format_dt(user.joined_at, 'F'), inline=True)
        embed.add_field(name="Member Since", value=format_dt(user.joined_at, 'R'), inline=True)
        embed.add_field(name="Roles", value=len(user.roles) - 1, inline=True)
        
        # Show top role
        top_role = get(user.roles[1:], position=max(r.position for r in user.roles[1:]))
        if top_role:
            embed.add_field(name="Top Role", value=top_role.mention, inline=True)
    
    await ctx.send(embed=embed)

@bot.command()
async def serverstat(ctx):
    """Show server statistics."""
    guild = ctx.guild
    if not guild:
        await ctx.send("This command can only be used in a server!")
        return
    
    # Use collection utilities
    online_members = len([m for m in guild.members if m.status != discord.Status.offline])
    bot_count = len([m for m in guild.members if m.bot])
    human_count = len(guild.members) - bot_count
    
    # Channel statistics
    text_channels = len(guild.text_channels)
    voice_channels = len(guild.voice_channels)
    categories = len(guild.categories)
    
    embed = discord.Embed(title=f"{guild.name} Statistics", color=0x00ff00)
    embed.set_thumbnail(url=guild.icon.url if guild.icon else None)
    
    # Member stats
    embed.add_field(name="👥 Members", value=f"""
    Total: {guild.member_count}
    Online: {online_members}
    Humans: {human_count}
    Bots: {bot_count}
    """, inline=True)
    
    # Channel stats
    embed.add_field(name="📁 Channels", value=f"""
    Text: {text_channels}
    Voice: {voice_channels}
    Categories: {categories}
    Total: {text_channels + voice_channels}
    """, inline=True)
    
    # Server info
    embed.add_field(name="ℹ️ Server Info", value=f"""
    Created: {format_dt(guild.created_at, 'R')}
    Owner: {guild.owner.mention if guild.owner else 'Unknown'}
    Roles: {len(guild.roles)}
    Emojis: {len(guild.emojis)}
    """, inline=True)
    
    await ctx.send(embed=embed)

@bot.command()
async def clean_text(ctx, *, text: str):
    """Demonstrate text cleaning utilities."""
    embed = discord.Embed(title="Text Cleaning Example", color=0x9932cc)
    
    # Original text
    embed.add_field(name="Original", value=f"```{text}```", inline=False)
    
    # Escaped markdown
    escaped_md = escape_markdown(text)
    embed.add_field(name="Escaped Markdown", value=f"```{escaped_md}```", inline=False)
    
    # Removed markdown
    no_markdown = remove_markdown(text)
    embed.add_field(name="Removed Markdown", value=f"```{no_markdown}```", inline=False)
    
    # Escaped mentions
    escaped_mentions = escape_mentions(text)
    embed.add_field(name="Escaped Mentions", value=f"```{escaped_mentions}```", inline=False)
    
    await ctx.send(embed=embed)

@bot.command()
async def type_demo(ctx):
    """Demonstrate typing context manager."""
    async with ctx.typing():
        await asyncio.sleep(3)  # Simulate work
        await ctx.send("Done with typing indicator!")

@bot.command()
async def find_role(ctx, *, role_name: str):
    """Find a role by name (case insensitive)."""
    # Use find utility
    role = find(lambda r: r.name.lower() == role_name.lower(), ctx.guild.roles)
    
    if role:
        embed = discord.Embed(title=f"Role: {role.name}", color=role.color)
        embed.add_field(name="ID", value=role.id, inline=True)
        embed.add_field(name="Created", value=format_dt(role.created_at, 'R'), inline=True)
        embed.add_field(name="Members", value=len(role.members), inline=True)
        embed.add_field(name="Mentionable", value=role.mentionable, inline=True)
        embed.add_field(name="Hoisted", value=role.hoist, inline=True)
        embed.add_field(name="Position", value=role.position, inline=True)
        
        await ctx.send(embed=embed)
    else:
        await ctx.send(f"Role '{role_name}' not found!")

@bot.command()
async def invite_link(ctx, permissions: str = None):
    """Generate bot invite link with optional permissions."""
    perms = None
    
    if permissions:
        # Parse basic permissions
        perm_dict = {}
        for perm in permissions.split(','):
            perm = perm.strip().lower()
            if perm in ['admin', 'administrator']:
                perm_dict['administrator'] = True
            elif perm in ['manage', 'manage_guild']:
                perm_dict['manage_guild'] = True
            elif perm in ['kick', 'kick_members']:
                perm_dict['kick_members'] = True
            elif perm in ['ban', 'ban_members']:
                perm_dict['ban_members'] = True
            elif perm in ['messages', 'send_messages']:
                perm_dict['send_messages'] = True
            elif perm in ['embed', 'embed_links']:
                perm_dict['embed_links'] = True
        
        if perm_dict:
            perms = discord.Permissions(**perm_dict)
    
    # Generate invite URL
    invite_url = oauth_url_from_client(ctx.bot, permissions=perms)
    
    embed = discord.Embed(
        title="Bot Invite Link",
        description=f"[Click here to invite {ctx.bot.user.name}]({invite_url})",
        color=0x0099ff
    )
    
    if perms:
        embed.add_field(
            name="Requested Permissions",
            value=', '.join([perm.replace('_', ' ').title() for perm, value in perms if value]),
            inline=False
        )
    
    await ctx.send(embed=embed)

# Error handling with utilities
@bot.event
async def on_command_error(ctx, error):
    if isinstance(error, commands.CommandNotFound):
        return
    
    # Log error with timestamp
    print(f"[{utcnow()}] Error in command {ctx.command}: {error}")
    await ctx.send("An error occurred while processing the command.")

bot.run('YOUR_BOT_TOKEN')

Sleep and Timing Examples

import discord
from discord.utils import *
import asyncio

async def scheduled_tasks_example():
    """Example of using sleep_until for scheduled tasks."""
    
    # Sleep until a specific time
    target_time = utcnow().replace(hour=12, minute=0, second=0, microsecond=0)
    if target_time < utcnow():
        target_time += datetime.timedelta(days=1)  # Tomorrow if time has passed
    
    print(f"Sleeping until {format_dt(target_time, 'F')}")
    await sleep_until(target_time)
    print("Woke up at scheduled time!")
    
    # Sleep for a computed duration
    future_time = utcnow() + datetime.timedelta(minutes=5)
    duration = compute_timedelta(future_time)
    print(f"Sleeping for {duration} seconds")
    await asyncio.sleep(duration)
    print("Done sleeping!")

# Run the example
# asyncio.run(scheduled_tasks_example())

Install with Tessl CLI

npx tessl i tessl/pypi-discord-py

docs

app-commands.md

commands-framework.md

core-objects.md

event-handling.md

index.md

user-interface.md

utilities.md

voice-audio.md

webhooks.md

tile.json