or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

app-commands.mdcommands-framework.mdcore-objects.mdevent-handling.mdindex.mduser-interface.mdutilities.mdvoice-audio.mdwebhooks.md

utilities.mddocs/

0

# Utilities & Helpers

1

2

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.

3

4

## Capabilities

5

6

### Authentication & URLs

7

8

Utilities for generating OAuth URLs and handling Discord authentication.

9

10

```python { .api }

11

def oauth_url(

12

client_id: int,

13

*,

14

permissions: Optional[Permissions] = None,

15

guild: Optional[Guild] = None,

16

redirect_uri: Optional[str] = None,

17

scopes: Optional[List[str]] = None,

18

disable_guild_select: bool = False

19

) -> str:

20

"""

21

Generate OAuth2 authorization URL for bot invitation.

22

23

Parameters:

24

- client_id: Bot's application ID

25

- permissions: Permissions to request

26

- guild: Specific guild to add bot to

27

- redirect_uri: URL to redirect to after authorization

28

- scopes: OAuth2 scopes to request (defaults to ['bot'])

29

- disable_guild_select: Whether to disable guild selection

30

31

Returns:

32

str: OAuth2 authorization URL

33

"""

34

35

def oauth_url_from_client(

36

client: Client,

37

*,

38

permissions: Optional[Permissions] = None,

39

guild: Optional[Guild] = None,

40

redirect_uri: Optional[str] = None,

41

scopes: Optional[List[str]] = None,

42

disable_guild_select: bool = False

43

) -> str:

44

"""

45

Generate OAuth2 URL from client instance.

46

47

Parameters:

48

- client: Discord client instance

49

- permissions: Permissions to request

50

- guild: Specific guild to add bot to

51

- redirect_uri: URL to redirect to after authorization

52

- scopes: OAuth2 scopes to request

53

- disable_guild_select: Whether to disable guild selection

54

55

Returns:

56

str: OAuth2 authorization URL

57

"""

58

```

59

60

### Snowflake Utilities

61

62

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

63

64

```python { .api }

65

def snowflake_time(id: int) -> datetime:

66

"""

67

Extract creation timestamp from Discord snowflake ID.

68

69

Parameters:

70

- id: Discord snowflake ID

71

72

Returns:

73

datetime: UTC timestamp when the snowflake was created

74

"""

75

76

def time_snowflake(dt: datetime, high: bool = False) -> int:

77

"""

78

Generate a snowflake ID from a timestamp.

79

80

Parameters:

81

- dt: Datetime to convert to snowflake

82

- high: Whether to generate highest or lowest possible snowflake for the timestamp

83

84

Returns:

85

int: Snowflake ID

86

"""

87

88

DISCORD_EPOCH: int = 1420070400000

89

"""Discord epoch timestamp (January 1, 2015)."""

90

```

91

92

### Time & Date Utilities

93

94

Helper functions for time formatting and Discord timestamp formatting.

95

96

```python { .api }

97

def utcnow() -> datetime:

98

"""

99

Get current UTC datetime.

100

101

Returns:

102

datetime: Current UTC timestamp

103

"""

104

105

def compute_timedelta(dt: datetime) -> float:

106

"""

107

Compute time delta between datetime and now.

108

109

Parameters:

110

- dt: Target datetime

111

112

Returns:

113

float: Seconds until target datetime

114

"""

115

116

async def sleep_until(when: datetime, *, result: Any = None) -> Any:

117

"""

118

Sleep until a specific datetime.

119

120

Parameters:

121

- when: Datetime to sleep until

122

- result: Value to return after sleeping

123

124

Returns:

125

Any: The result parameter value

126

"""

127

128

def format_dt(dt: datetime, style: Optional[str] = None) -> str:

129

"""

130

Format datetime for Discord timestamp display.

131

132

Parameters:

133

- dt: Datetime to format

134

- style: Format style ('t', 'T', 'd', 'D', 'f', 'F', 'R')

135

- 't': Short time (16:20)

136

- 'T': Long time (16:20:30)

137

- 'd': Short date (20/04/2021)

138

- 'D': Long date (20 April 2021)

139

- 'f': Short date/time (default)

140

- 'F': Long date/time

141

- 'R': Relative time (2 months ago)

142

143

Returns:

144

str: Discord timestamp string (<t:timestamp:style>)

145

"""

146

```

147

148

### Text Processing

149

150

Functions for handling markdown, mentions, and text formatting.

151

152

```python { .api }

153

def escape_markdown(text: str, *, as_needed: bool = False, ignore_links: bool = True) -> str:

154

"""

155

Escape Discord markdown characters in text.

156

157

Parameters:

158

- text: Text to escape

159

- as_needed: Only escape characters that would affect formatting

160

- ignore_links: Don't escape characters in URLs

161

162

Returns:

163

str: Text with markdown characters escaped

164

"""

165

166

def escape_mentions(text: str) -> str:

167

"""

168

Escape user, channel, and role mentions in text.

169

170

Parameters:

171

- text: Text to escape mentions in

172

173

Returns:

174

str: Text with mentions escaped

175

"""

176

177

def remove_markdown(text: str, *, ignore_links: bool = True) -> str:

178

"""

179

Remove Discord markdown formatting from text.

180

181

Parameters:

182

- text: Text to remove markdown from

183

- ignore_links: Don't remove markdown from URLs

184

185

Returns:

186

str: Text with markdown formatting removed

187

"""

188

189

def clean_content(content: str, *, fix_channel_mentions: bool = False) -> str:

190

"""

191

Clean message content by resolving mentions to readable text.

192

193

Parameters:

194

- content: Message content to clean

195

- fix_channel_mentions: Whether to convert channel mentions to #channel-name

196

197

Returns:

198

str: Cleaned content with mentions resolved

199

"""

200

```

201

202

### Collection Utilities

203

204

Helper functions for working with sequences and collections.

205

206

```python { .api }

207

def find(predicate: Callable[[Any], bool], seq: Sequence[Any]) -> Optional[Any]:

208

"""

209

Find first element in sequence matching predicate.

210

211

Parameters:

212

- predicate: Function returning True for matching element

213

- seq: Sequence to search

214

215

Returns:

216

Any: First matching element, or None if not found

217

"""

218

219

def get(iterable: Iterable[Any], **attrs: Any) -> Optional[Any]:

220

"""

221

Find first element with matching attributes.

222

223

Parameters:

224

- iterable: Iterable to search

225

- attrs: Attributes to match (name=value pairs)

226

227

Returns:

228

Any: First matching element, or None if not found

229

"""

230

231

def as_chunks(iterator: Iterator[Any], max_size: int) -> Iterator[List[Any]]:

232

"""

233

Split iterator into chunks of maximum size.

234

235

Parameters:

236

- iterator: Iterator to split

237

- max_size: Maximum chunk size

238

239

Yields:

240

List[Any]: Chunks of iterator items

241

"""

242

243

T = TypeVar('T')

244

245

class SequenceProxy(Generic[T]):

246

"""

247

Proxy for sequences with filtering and transformation.

248

"""

249

def __init__(self, proxied: Sequence[T], *, predicate: Optional[Callable[[T], bool]] = None): ...

250

251

def __len__(self) -> int: ...

252

def __iter__(self) -> Iterator[T]: ...

253

def __getitem__(self, idx: Union[int, slice]) -> Union[T, Sequence[T]]: ...

254

255

def filter(self, predicate: Callable[[T], bool]) -> SequenceProxy[T]:

256

"""Filter sequence by predicate."""

257

258

def map(self, func: Callable[[T], Any]) -> SequenceProxy[Any]:

259

"""Transform sequence elements."""

260

```

261

262

### Async Utilities

263

264

Helper functions and classes for async programming patterns.

265

266

```python { .api }

267

async def maybe_coroutine(f: Union[Callable[..., Any], Callable[..., Awaitable[Any]]], *args: Any, **kwargs: Any) -> Any:

268

"""

269

Call function whether it's a coroutine or regular function.

270

271

Parameters:

272

- f: Function to call (sync or async)

273

- args: Positional arguments

274

- kwargs: Keyword arguments

275

276

Returns:

277

Any: Function result

278

"""

279

280

def setup_logging(

281

*,

282

handler: Optional[logging.Handler] = None,

283

formatter: Optional[logging.Formatter] = None,

284

level: int = logging.INFO,

285

root: bool = True

286

) -> None:

287

"""

288

Set up logging for discord.py library.

289

290

Parameters:

291

- handler: Log handler to use (defaults to StreamHandler)

292

- formatter: Log formatter to use

293

- level: Logging level

294

- root: Whether to set up root logger

295

"""

296

297

class _MissingSentinel:

298

"""Sentinel class for missing values."""

299

def __bool__(self) -> bool:

300

return False

301

302

def __repr__(self) -> str:

303

return '...'

304

305

MISSING: Any = _MissingSentinel()

306

"""Sentinel value for missing/unset parameters."""

307

```

308

309

### File & Data Utilities

310

311

Functions for handling files and data conversion.

312

313

```python { .api }

314

def parse_time(timestamp: str) -> Optional[datetime]:

315

"""

316

Parse ISO 8601 timestamp string.

317

318

Parameters:

319

- timestamp: ISO timestamp string

320

321

Returns:

322

datetime: Parsed datetime, or None if invalid

323

"""

324

325

def copy_doc(original: Callable) -> Callable:

326

"""

327

Decorator to copy docstring from another function.

328

329

Parameters:

330

- original: Function to copy docstring from

331

332

Returns:

333

Callable: Decorator function

334

"""

335

336

def cached_slot_property(name: str) -> property:

337

"""

338

Create a cached property that stores value in __slots__.

339

340

Parameters:

341

- name: Slot name to store cached value

342

343

Returns:

344

property: Cached property descriptor

345

"""

346

347

def generate_snowflake() -> int:

348

"""

349

Generate a unique snowflake ID.

350

351

Returns:

352

int: Generated snowflake ID

353

"""

354

```

355

356

### Permission Utilities

357

358

Helper functions for working with Discord permissions.

359

360

```python { .api }

361

def permissions_in_channel(

362

member: Member,

363

channel: GuildChannel,

364

*,

365

ignore_timeout: bool = False

366

) -> Permissions:

367

"""

368

Calculate member's permissions in a channel.

369

370

Parameters:

371

- member: Guild member

372

- channel: Guild channel

373

- ignore_timeout: Whether to ignore member timeout

374

375

Returns:

376

Permissions: Member's effective permissions in the channel

377

"""

378

379

def permissions_for_roles(

380

roles: List[Role],

381

channel: Optional[GuildChannel] = None

382

) -> Permissions:

383

"""

384

Calculate combined permissions for a list of roles.

385

386

Parameters:

387

- roles: List of roles

388

- channel: Channel for permission overwrites (optional)

389

390

Returns:

391

Permissions: Combined permissions

392

"""

393

```

394

395

### Message Utilities

396

397

Helper functions for working with messages and message references.

398

399

```python { .api }

400

def message_reference_from_url(url: str) -> Optional[MessageReference]:

401

"""

402

Create MessageReference from Discord message URL.

403

404

Parameters:

405

- url: Discord message URL

406

407

Returns:

408

MessageReference: Reference object, or None if invalid URL

409

"""

410

411

def jump_url_from_ids(guild_id: Optional[int], channel_id: int, message_id: int) -> str:

412

"""

413

Create Discord message jump URL from IDs.

414

415

Parameters:

416

- guild_id: Guild ID (None for DM)

417

- channel_id: Channel ID

418

- message_id: Message ID

419

420

Returns:

421

str: Discord message jump URL

422

"""

423

424

def resolve_invite(invite: Union[str, Invite]) -> str:

425

"""

426

Resolve invite to invite code.

427

428

Parameters:

429

- invite: Invite object or invite URL/code

430

431

Returns:

432

str: Invite code

433

"""

434

435

def resolve_template(template: Union[str, Template]) -> str:

436

"""

437

Resolve template to template code.

438

439

Parameters:

440

- template: Template object or template URL/code

441

442

Returns:

443

str: Template code

444

"""

445

```

446

447

### Context Managers

448

449

Utility context managers for common Discord operations.

450

451

```python { .api }

452

class Typing:

453

"""

454

Context manager for typing indicator.

455

"""

456

def __init__(self, messageable: Messageable): ...

457

458

async def __aenter__(self) -> Typing:

459

"""Start typing indicator."""

460

461

async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:

462

"""Stop typing indicator."""

463

464

def typing(messageable: Messageable) -> Typing:

465

"""

466

Create typing context manager.

467

468

Parameters:

469

- messageable: Channel or messageable to type in

470

471

Returns:

472

Typing: Typing context manager

473

"""

474

```

475

476

## Usage Examples

477

478

### Basic Utility Usage

479

480

```python

481

import discord

482

from discord.utils import *

483

484

# Generate OAuth URL

485

bot_id = 123456789012345678

486

permissions = discord.Permissions(send_messages=True, read_messages=True)

487

invite_url = oauth_url(bot_id, permissions=permissions)

488

print(f"Invite URL: {invite_url}")

489

490

# Work with snowflakes

491

user_id = 98765432109876543

492

creation_time = snowflake_time(user_id)

493

print(f"User created at: {creation_time}")

494

495

# Generate snowflake for specific time

496

import datetime

497

specific_time = datetime.datetime(2023, 1, 1, tzinfo=datetime.timezone.utc)

498

snowflake_id = time_snowflake(specific_time)

499

print(f"Snowflake for {specific_time}: {snowflake_id}")

500

```

501

502

### Text Processing Examples

503

504

```python

505

import discord

506

from discord.utils import *

507

508

# Escape markdown

509

text_with_markdown = "This has **bold** and *italic* text!"

510

escaped_text = escape_markdown(text_with_markdown)

511

print(f"Escaped: {escaped_text}")

512

513

# Remove markdown

514

clean_text = remove_markdown(text_with_markdown)

515

print(f"Clean: {clean_text}")

516

517

# Escape mentions

518

text_with_mentions = "Hello <@123456789> and <#987654321>!"

519

escaped_mentions = escape_mentions(text_with_mentions)

520

print(f"Escaped mentions: {escaped_mentions}")

521

522

# Format Discord timestamps

523

now = discord.utils.utcnow()

524

timestamp_formats = {

525

't': format_dt(now, 't'), # Short time

526

'T': format_dt(now, 'T'), # Long time

527

'd': format_dt(now, 'd'), # Short date

528

'D': format_dt(now, 'D'), # Long date

529

'f': format_dt(now, 'f'), # Short date/time

530

'F': format_dt(now, 'F'), # Long date/time

531

'R': format_dt(now, 'R'), # Relative time

532

}

533

534

for style, formatted in timestamp_formats.items():

535

print(f"Style '{style}': {formatted}")

536

```

537

538

### Collection Utilities Examples

539

540

```python

541

import discord

542

from discord.utils import *

543

544

# Example with guild members

545

async def find_member_examples(guild: discord.Guild):

546

# Find member by name

547

member = find(lambda m: m.name == "example_user", guild.members)

548

if member:

549

print(f"Found member: {member}")

550

551

# Get member by attribute

552

member = get(guild.members, name="example_user", discriminator="1234")

553

if member:

554

print(f"Found member: {member}")

555

556

# Find member with specific role

557

admin_role = get(guild.roles, name="Admin")

558

if admin_role:

559

admin = find(lambda m: admin_role in m.roles, guild.members)

560

if admin:

561

print(f"Found admin: {admin}")

562

563

# Split members into chunks

564

member_chunks = list(as_chunks(iter(guild.members), 10))

565

print(f"Split {len(guild.members)} members into {len(member_chunks)} chunks")

566

567

# Use SequenceProxy for filtering

568

online_members = SequenceProxy(guild.members).filter(

569

lambda m: m.status != discord.Status.offline

570

)

571

print(f"Online members: {len(online_members)}")

572

```

573

574

### Advanced Utility Bot

575

576

```python

577

import discord

578

from discord.ext import commands

579

from discord.utils import *

580

import asyncio

581

582

class UtilityBot(commands.Bot):

583

def __init__(self):

584

intents = discord.Intents.default()

585

intents.message_content = True

586

super().__init__(command_prefix='!', intents=intents)

587

588

async def setup_hook(self):

589

print(f"Bot is ready! Invite URL: {oauth_url_from_client(self)}")

590

591

bot = UtilityBot()

592

593

@bot.command()

594

async def userinfo(ctx, *, user: discord.User = None):

595

"""Get information about a user."""

596

user = user or ctx.author

597

598

# Use snowflake utility

599

created_at = snowflake_time(user.id)

600

601

embed = discord.Embed(title=f"User Info: {user}", color=0x0099ff)

602

embed.set_thumbnail(url=user.display_avatar.url)

603

embed.add_field(name="ID", value=user.id, inline=True)

604

embed.add_field(name="Created", value=format_dt(created_at, 'F'), inline=True)

605

embed.add_field(name="Account Age", value=format_dt(created_at, 'R'), inline=True)

606

607

# If in guild, show member info

608

if ctx.guild and isinstance(user, discord.Member):

609

embed.add_field(name="Joined", value=format_dt(user.joined_at, 'F'), inline=True)

610

embed.add_field(name="Member Since", value=format_dt(user.joined_at, 'R'), inline=True)

611

embed.add_field(name="Roles", value=len(user.roles) - 1, inline=True)

612

613

# Show top role

614

top_role = get(user.roles[1:], position=max(r.position for r in user.roles[1:]))

615

if top_role:

616

embed.add_field(name="Top Role", value=top_role.mention, inline=True)

617

618

await ctx.send(embed=embed)

619

620

@bot.command()

621

async def serverstat(ctx):

622

"""Show server statistics."""

623

guild = ctx.guild

624

if not guild:

625

await ctx.send("This command can only be used in a server!")

626

return

627

628

# Use collection utilities

629

online_members = len([m for m in guild.members if m.status != discord.Status.offline])

630

bot_count = len([m for m in guild.members if m.bot])

631

human_count = len(guild.members) - bot_count

632

633

# Channel statistics

634

text_channels = len(guild.text_channels)

635

voice_channels = len(guild.voice_channels)

636

categories = len(guild.categories)

637

638

embed = discord.Embed(title=f"{guild.name} Statistics", color=0x00ff00)

639

embed.set_thumbnail(url=guild.icon.url if guild.icon else None)

640

641

# Member stats

642

embed.add_field(name="👥 Members", value=f"""

643

Total: {guild.member_count}

644

Online: {online_members}

645

Humans: {human_count}

646

Bots: {bot_count}

647

""", inline=True)

648

649

# Channel stats

650

embed.add_field(name="📁 Channels", value=f"""

651

Text: {text_channels}

652

Voice: {voice_channels}

653

Categories: {categories}

654

Total: {text_channels + voice_channels}

655

""", inline=True)

656

657

# Server info

658

embed.add_field(name="ℹ️ Server Info", value=f"""

659

Created: {format_dt(guild.created_at, 'R')}

660

Owner: {guild.owner.mention if guild.owner else 'Unknown'}

661

Roles: {len(guild.roles)}

662

Emojis: {len(guild.emojis)}

663

""", inline=True)

664

665

await ctx.send(embed=embed)

666

667

@bot.command()

668

async def clean_text(ctx, *, text: str):

669

"""Demonstrate text cleaning utilities."""

670

embed = discord.Embed(title="Text Cleaning Example", color=0x9932cc)

671

672

# Original text

673

embed.add_field(name="Original", value=f"```{text}```", inline=False)

674

675

# Escaped markdown

676

escaped_md = escape_markdown(text)

677

embed.add_field(name="Escaped Markdown", value=f"```{escaped_md}```", inline=False)

678

679

# Removed markdown

680

no_markdown = remove_markdown(text)

681

embed.add_field(name="Removed Markdown", value=f"```{no_markdown}```", inline=False)

682

683

# Escaped mentions

684

escaped_mentions = escape_mentions(text)

685

embed.add_field(name="Escaped Mentions", value=f"```{escaped_mentions}```", inline=False)

686

687

await ctx.send(embed=embed)

688

689

@bot.command()

690

async def type_demo(ctx):

691

"""Demonstrate typing context manager."""

692

async with ctx.typing():

693

await asyncio.sleep(3) # Simulate work

694

await ctx.send("Done with typing indicator!")

695

696

@bot.command()

697

async def find_role(ctx, *, role_name: str):

698

"""Find a role by name (case insensitive)."""

699

# Use find utility

700

role = find(lambda r: r.name.lower() == role_name.lower(), ctx.guild.roles)

701

702

if role:

703

embed = discord.Embed(title=f"Role: {role.name}", color=role.color)

704

embed.add_field(name="ID", value=role.id, inline=True)

705

embed.add_field(name="Created", value=format_dt(role.created_at, 'R'), inline=True)

706

embed.add_field(name="Members", value=len(role.members), inline=True)

707

embed.add_field(name="Mentionable", value=role.mentionable, inline=True)

708

embed.add_field(name="Hoisted", value=role.hoist, inline=True)

709

embed.add_field(name="Position", value=role.position, inline=True)

710

711

await ctx.send(embed=embed)

712

else:

713

await ctx.send(f"Role '{role_name}' not found!")

714

715

@bot.command()

716

async def invite_link(ctx, permissions: str = None):

717

"""Generate bot invite link with optional permissions."""

718

perms = None

719

720

if permissions:

721

# Parse basic permissions

722

perm_dict = {}

723

for perm in permissions.split(','):

724

perm = perm.strip().lower()

725

if perm in ['admin', 'administrator']:

726

perm_dict['administrator'] = True

727

elif perm in ['manage', 'manage_guild']:

728

perm_dict['manage_guild'] = True

729

elif perm in ['kick', 'kick_members']:

730

perm_dict['kick_members'] = True

731

elif perm in ['ban', 'ban_members']:

732

perm_dict['ban_members'] = True

733

elif perm in ['messages', 'send_messages']:

734

perm_dict['send_messages'] = True

735

elif perm in ['embed', 'embed_links']:

736

perm_dict['embed_links'] = True

737

738

if perm_dict:

739

perms = discord.Permissions(**perm_dict)

740

741

# Generate invite URL

742

invite_url = oauth_url_from_client(ctx.bot, permissions=perms)

743

744

embed = discord.Embed(

745

title="Bot Invite Link",

746

description=f"[Click here to invite {ctx.bot.user.name}]({invite_url})",

747

color=0x0099ff

748

)

749

750

if perms:

751

embed.add_field(

752

name="Requested Permissions",

753

value=', '.join([perm.replace('_', ' ').title() for perm, value in perms if value]),

754

inline=False

755

)

756

757

await ctx.send(embed=embed)

758

759

# Error handling with utilities

760

@bot.event

761

async def on_command_error(ctx, error):

762

if isinstance(error, commands.CommandNotFound):

763

return

764

765

# Log error with timestamp

766

print(f"[{utcnow()}] Error in command {ctx.command}: {error}")

767

await ctx.send("An error occurred while processing the command.")

768

769

bot.run('YOUR_BOT_TOKEN')

770

```

771

772

### Sleep and Timing Examples

773

774

```python

775

import discord

776

from discord.utils import *

777

import asyncio

778

779

async def scheduled_tasks_example():

780

"""Example of using sleep_until for scheduled tasks."""

781

782

# Sleep until a specific time

783

target_time = utcnow().replace(hour=12, minute=0, second=0, microsecond=0)

784

if target_time < utcnow():

785

target_time += datetime.timedelta(days=1) # Tomorrow if time has passed

786

787

print(f"Sleeping until {format_dt(target_time, 'F')}")

788

await sleep_until(target_time)

789

print("Woke up at scheduled time!")

790

791

# Sleep for a computed duration

792

future_time = utcnow() + datetime.timedelta(minutes=5)

793

duration = compute_timedelta(future_time)

794

print(f"Sleeping for {duration} seconds")

795

await asyncio.sleep(duration)

796

print("Done sleeping!")

797

798

# Run the example

799

# asyncio.run(scheduled_tasks_example())

800

```