### Define Extension Setup and Teardown Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/extensions.rst This example demonstrates both the `setup` function for when an extension is loaded and the `teardown` function for when it is unloaded. Exceptions in `teardown` are ignored. ```python3 async def setup(bot): print('I am being loaded!') async def teardown(bot): print('I am being unloaded!') ``` -------------------------------- ### Define a Simple Extension with a Command Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/extensions.rst This example shows how to create a basic extension file (hello.py) that defines a command and an entry point for loading. The setup function must be a coroutine and takes the bot instance as an argument. ```python3 from discord.ext import commands @commands.command() async def hello(ctx): await ctx.send(f'Hello {ctx.author.display_name}.') async def setup(bot): bot.add_command(hello) ``` -------------------------------- ### Asyncio Event Loop Setup with Client Source: https://github.com/dolfies/discord.py-self/blob/master/docs/migrating.rst Use asyncio.run to manage the event loop and start the client within an async context. This replaces the older Client.run method for more complex asynchronous setups. ```python client = discord.Client() async def main(): # do other async things await my_async_function() # start the client async with client: await client.start(TOKEN) asyncio.run(main()) ``` -------------------------------- ### Async Extension Setup Function Source: https://github.com/dolfies/discord.py-self/blob/master/docs/migrating.rst Extensions must now use asynchronous setup and teardown functions. The `setup` function must be a coroutine and await `bot.add_cog`. ```python # before def setup(bot): bot.add_cog(MyCog(bot)) # after async def setup(bot): await bot.add_cog(MyCog(bot)) ``` -------------------------------- ### Install discord.py-self with voice support (Windows) Source: https://github.com/dolfies/discord.py-self/blob/master/README.rst Installs the library with full voice support on Windows. Ensure necessary development packages are installed first. ```sh py -3 -m pip install -U discord.py-self[voice] ``` -------------------------------- ### Command Invocation Example Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst Example of how a user would invoke the 'foo' command with the prefix '$'. ```none $foo abc ``` -------------------------------- ### Install discord.py-self with voice support (Linux/macOS) Source: https://github.com/dolfies/discord.py-self/blob/master/README.rst Installs the library with full voice support on Linux or macOS. Ensure necessary development packages are installed first. ```sh python3 -m pip install -U "discord.py-self[voice]" ``` -------------------------------- ### Install discord.py-self within a virtual environment Source: https://github.com/dolfies/discord.py-self/blob/master/docs/intro.rst After activating the virtual environment, install the library using pip. ```shell $ pip install -U discord.py-self ``` -------------------------------- ### Minimal Discord Bot Example Source: https://github.com/dolfies/discord.py-self/blob/master/docs/quickstart.rst This Python snippet demonstrates how to create a basic Discord bot that responds to a specific message. Ensure you have the discord.py library installed and replace 'your token here' with your actual bot token. ```python import discord client = discord.Client() @client.event async def on_ready(): print(f'We have 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 token here') ``` -------------------------------- ### Advanced Logging Setup with Rotating File Handler Source: https://github.com/dolfies/discord.py-self/blob/master/docs/logging.rst Configure a custom, advanced logging setup using Python's `logging.handlers.RotatingFileHandler`. This example sets the 'discord' logger to DEBUG level and 'discord.http' to INFO, directing output to a rotating file with a specific formatter. ```python import discord import logging import logging.handlers logger = logging.getLogger('discord') logger.setLevel(logging.DEBUG) logging.getLogger('discord.http').setLevel(logging.INFO) handler = logging.handlers.RotatingFileHandler( filename='discord.log', encoding='utf-8', maxBytes=32 * 1024 * 1024, # 32 MiB backupCount=5, # Rotate through 5 files ) dt_fmt = '%Y-%m-%d %H:%M:%S' formatter = logging.Formatter('[{asctime}] [{levelname:<8}] {name}: {message}', dt_fmt, style='{') handler.setFormatter(formatter) logger.addHandler(handler) # Assume client refers to a discord.Client subclass... # Suppress the default configuration since we have our own client.run(token, log_handler=None) ``` -------------------------------- ### Install discord.py-self with voice support Source: https://github.com/dolfies/discord.py-self/blob/master/docs/intro.rst To include voice support, append `[voice]` to the package name during installation. ```shell python3 -m pip install -U discord.py-self[voice] ``` -------------------------------- ### Install discord.py-self (Windows) Source: https://github.com/dolfies/discord.py-self/blob/master/README.rst Installs the library without voice support on Windows. A virtual environment is recommended. ```sh py -3 -m pip install -U discord.py-self ``` -------------------------------- ### Custom Advanced Converter Example Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst Create a custom converter by inheriting from `commands.Converter` to perform asynchronous operations and access context. This example randomly selects a user to slap. ```python import random class Slapper(commands.Converter): async def convert(self, ctx, argument): to_slap = random.choice(ctx.guild.members) return f'{ctx.author} slapped {to_slap} because *{argument}*' @bot.command() async def slap(ctx, *, reason: Slapper): await ctx.send(reason) ``` -------------------------------- ### Install discord.py-self development version Source: https://github.com/dolfies/discord.py-self/blob/master/README.rst Installs the latest development version from the GitHub repository, including voice support. Requires Git. ```sh $ git clone https://github.com/dolfies/discord.py-self $ cd discord.py-self $ python3 -m pip install -U .[voice] ``` -------------------------------- ### Install voice dependencies on Debian-based Linux Source: https://github.com/dolfies/discord.py-self/blob/master/docs/intro.rst On Debian-based systems, install necessary development libraries for voice support using apt. ```shell $ apt install libffi-dev libnacl-dev python3-dev ``` -------------------------------- ### Install discord.py-self (Linux/macOS) Source: https://github.com/dolfies/discord.py-self/blob/master/README.rst Installs the library without voice support on Linux or macOS. A virtual environment is recommended. ```sh python3 -m pip install -U discord.py-self ``` -------------------------------- ### Basic Discord Client Example Source: https://github.com/dolfies/discord.py-self/blob/master/README.rst A simple asynchronous Discord client that logs in, prints a ready message, and responds to 'ping' with 'pong'. Requires a valid token. ```python import discord class MyClient(discord.Client): async def on_ready(self): print('Logged on as', self.user) async def on_message(self, message): # only respond to ourselves if message.author != self.user: return if message.content == 'ping': await message.channel.send('pong') client = MyClient() client.run('token') ``` -------------------------------- ### Basic discord.py-self event handling Source: https://github.com/dolfies/discord.py-self/blob/master/docs/intro.rst A simple Python example demonstrating how to create a client, listen for the 'on_ready' event to confirm login, and the 'on_message' event to print received messages. ```python3 import discord class MyClient(discord.Client): async def on_ready(self): print(f'Logged on as {self.user}!') async def on_message(self, message): print(f'Message from {message.author}: {message.content}') client = MyClient() client.run('token') ``` -------------------------------- ### Setup Logging Manually with discord.utils Source: https://github.com/dolfies/discord.py-self/blob/master/docs/logging.rst Use `discord.utils.setup_logging()` to apply the library's default logging configuration without using `client.run`. You can specify the level and whether to affect the root logger. ```python import discord discord.utils.setup_logging() # or, for example discord.utils.setup_logging(level=logging.INFO, root=False) ``` -------------------------------- ### Discord Bot Example with Commands Source: https://github.com/dolfies/discord.py-self/blob/master/README.rst An example of a Discord bot using the commands extension. It sets a prefix and defines a 'ping' command that replies with 'pong'. Requires a valid token and self_bot=True for user accounts. ```python import discord from discord.ext import commands bot = commands.Bot(command_prefix='>', self_bot=True) @bot.command() async def ping(ctx): await ctx.send('pong') bot.run('token') ``` -------------------------------- ### Wait until bot is ready before starting loop Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/tasks/index.rst This task waits until the bot is ready using `bot.wait_until_ready()` before its first execution. It runs every 5 seconds and prints an index. ```python from discord.ext import tasks, commands class MyCog(commands.Cog): def __init__(self, bot): self.index = 0 self.bot = bot self.printer.start() def cog_unload(self): self.printer.cancel() @tasks.loop(seconds=5.0) async def printer(self): print(self.index) self.index += 1 @printer.before_loop async def before_printer(self): print('waiting...') await self.bot.wait_until_ready() ``` -------------------------------- ### Using `clean_content` Converter Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst Demonstrates using the built-in `clean_content` converter to process message content, with an example of fine-tuning its behavior. ```python @bot.command() async def clean(ctx, *, content: commands.clean_content): await ctx.send(content) ``` ```python @bot.command() async def clean(ctx, *, content: commands.clean_content(use_nicknames=False)): await ctx.send(content) ``` -------------------------------- ### Perform action during task cancellation Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/tasks/index.rst This example demonstrates how to perform a final action, such as inserting remaining data into a database, when a task is cancelled. The task runs every 10 seconds. ```python from discord.ext import tasks, commands import asyncio class MyCog(commands.Cog): def __init__(self, bot): self.bot = bot self._batch = [] self.lock = asyncio.Lock() self.bulker.start() async def cog_unload(self): self.bulker.cancel() async def do_bulk(self): # bulk insert data here ... @tasks.loop(seconds=10.0) async def bulker(self): async with self.lock: await self.do_bulk() @bulker.after_loop async def on_bulker_cancel(self): if self.bulker.is_being_cancelled() and len(self._batch) != 0: # if we're cancelled and we have some data left... # let's insert it to our database await self.do_bulk() ``` -------------------------------- ### Define WindowsLikeFlags Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst Example of a WindowsLikeFlags class inheriting from commands.FlagConverter with a different prefix and delimiter. ```python # /make food class WindowsLikeFlags(commands.FlagConverter, prefix='/', delimiter=''): make: str ``` -------------------------------- ### Define Settings FlagConverter Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst Example of a Settings class inheriting from commands.FlagConverter with case-insensitive parsing and optional arguments. ```python # TOPIC: not allowed nsfw: yes Slowmode: 100 class Settings(commands.FlagConverter, case_insensitive=True): topic: Optional[str] nsfw: Optional[bool] slowmode: Optional[int] ``` -------------------------------- ### Parse Tuple of Integers Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst Example of parsing a tuple of two integers for a flag, demonstrating how pairs can be parsed. ```python # point: 10 11 point: 12 13 class Coordinates(commands.FlagConverter): point: Tuple[int, int] ``` -------------------------------- ### Define a Cog with Commands and Listeners Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/cogs.rst This example shows how to define a cog class that includes both commands and event listeners. Ensure listeners are marked with `@commands.Cog.listener()` and commands with `@commands.command()`. Commands within a cog must accept `self` as the first parameter. ```python class Greetings(commands.Cog): def __init__(self, bot): self.bot = bot self._last_member = None @commands.Cog.listener() async def on_member_join(self, member): channel = member.guild.system_channel if channel is not None: await channel.send(f'Welcome {member.mention}.') @commands.command() async def hello(self, ctx, *, member: discord.Member = None): """Says hello""" member = member or ctx.author if self._last_member is None or self._last_member.id != member.id: await ctx.send(f'Hello {member.name}~') else: await ctx.send(f'Hello {member.name}... This feels familiar.') self._last_member = member ``` -------------------------------- ### Create a Custom Command Check (Simple) Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst Demonstrates how to create a custom check function that returns True or False to determine if a command can be executed. This example checks if the command author's ID matches a specific owner ID. ```python3 import discord from discord.ext import commands bot = commands.Bot(command_prefix='!') async def is_owner(ctx): return ctx.author.id == 316026178463072268 @bot.command(name='eval') @commands.check(is_owner) async def _eval(ctx, *, code): """A bad example of an eval command""" await ctx.send(eval(code)) # bot.run('YOUR_BOT_TOKEN') ``` -------------------------------- ### Combine Multiple Command Checks Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst Demonstrates how to apply multiple checks to a single command. All checks must pass for the command to execute. This example uses both `commands.is_owner()` and a custom `is_in_guild` check. ```python3 import discord from discord.ext import commands bot = commands.Bot(command_prefix='!') def is_in_guild(guild_id): async def predicate(ctx): return ctx.guild and ctx.guild.id == guild_id return commands.check(predicate) @bot.command() @commands.is_owner() @is_in_guild(41771983423143937) async def secretguilddata(ctx): """super secret stuff""" await ctx.send('secret stuff') # bot.run('YOUR_BOT_TOKEN') ``` -------------------------------- ### Define PosixLikeFlags Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst Example of a PosixLikeFlags class inheriting from commands.FlagConverter with a delimiter and prefix. ```python class PosixLikeFlags(commands.FlagConverter, delimiter=' ', prefix='--'): hello: str ``` -------------------------------- ### Simple background task in a Cog Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/tasks/index.rst Use this to run a task every 5 seconds. Ensure the task is started in the Cog's constructor and cancelled when the Cog is unloaded. ```python3 from discord.ext import tasks, commands class MyCog(commands.Cog): def __init__(self): self.index = 0 self.printer.start() def cog_unload(self): self.printer.cancel() @tasks.loop(seconds=5.0) async def printer(self): print(self.index) self.index += 1 ``` -------------------------------- ### Make an HTTP GET Request with aiohttp Source: https://github.com/dolfies/discord.py-self/blob/master/docs/faq.rst Make a non-blocking HTTP request using aiohttp. Ensure the response status is 200 before processing the JSON. ```python3 async with aiohttp.ClientSession() as session: async with session.get('http://aws.random.cat/meow') as r: if r.status == 200: js = await r.json() ``` -------------------------------- ### Run task at multiple specific times each day Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/tasks/index.rst This task can be scheduled to run at multiple specific times throughout the day by providing a list of `datetime.time` objects. The example shows tasks at 8 AM, 12:30 PM, and 4:40:30 PM UTC. ```python import datetime from discord.ext import commands, tasks utc = datetime.timezone.utc # If no tzinfo is given then UTC is assumed. times = [ datetime.time(hour=8, tzinfo=utc), datetime.time(hour=12, minute=30, tzinfo=utc), datetime.time(hour=16, minute=40, second=30, tzinfo=utc) ] class MyCog(commands.Cog): def __init__(self, bot): self.bot = bot self.my_task.start() def cog_unload(self): self.my_task.cancel() @tasks.loop(time=times) async def my_task(self): print("My task is running!") ``` -------------------------------- ### Using Client.setup_hook for Bot Initialization Source: https://github.com/dolfies/discord.py-self/blob/master/docs/migrating.rst Subclass Client and override setup_hook to perform asynchronous operations after login but before connecting to the gateway. This is ideal for initializing bot features. ```python class MyClient(discord.Client): async def setup_hook(self): print('This is asynchronous!') client = MyClient() client.run(TOKEN) ``` -------------------------------- ### Create a virtual environment Source: https://github.com/dolfies/discord.py-self/blob/master/docs/intro.rst Create a virtual environment for your project to manage dependencies separately. ```shell $ python3 -m venv bot-env ``` -------------------------------- ### Async Extension Loading Source: https://github.com/dolfies/discord.py-self/blob/master/docs/migrating.rst Loading extensions is now asynchronous and must be awaited. This can be done within `setup_hook` or using an `async with` block. ```python # before bot.load_extension('my_extension') # after using setup_hook class MyBot(commands.Bot): async def setup_hook(self): await self.load_extension('my_extension') # after using async_with async def main(): async with bot: await self.load_extension('my_extension') await bot.start(TOKEN) asyncio.run(main()) ``` -------------------------------- ### Configure Log Level with Client.run Source: https://github.com/dolfies/discord.py-self/blob/master/docs/logging.rst Set the logging level to `logging.DEBUG` when running the client to capture more detailed information. Requires a file handler to be set up. ```python import logging handler = logging.FileHandler(filename='discord.log', encoding='utf-8', mode='w') # Assume client refers to a discord.Client subclass... client.run(token, log_handler=handler, log_level=logging.DEBUG) ``` -------------------------------- ### Get Next Item from Iterator with anext() in discord.py Source: https://github.com/dolfies/discord.py-self/blob/master/docs/migrating.rst When needing to get a single next item from an asynchronous iterator without a full loop, use the built-in 'anext()' function (Python 3.10+) or '__anext__()' method. ```python # before it = channel.history() first = await it.next() if first.content == 'do not iterate': return async for message in it: ... # after it = channel.history() first = await anext(it) # await it.__anext__() on Python<3.10 if first.content == 'do not iterate': return async for message in it: ... ``` -------------------------------- ### Get Listeners from Cog Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/cogs.rst Retrieves a list of listeners associated with a cog. ```APIDOC ## GET Cog Listeners ### Description Retrieves a list of all listeners defined within a cog. ### Method GET ### Endpoint `/cog/{cog_name}/listeners` ### Parameters #### Path Parameters - **cog_name** (string) - Required - The name of the cog to inspect. ### Request Example ```python cog = bot.get_cog('Greetings') for name, func in cog.get_listeners(): print(name, '->', func) ``` ### Response #### Success Response (200) - **listeners** (list[object]) - A list of listener tuples, where each tuple contains the listener name (string) and the listener function. #### Response Example ```json { "listeners": [ {"name": "on_message", "function": ""}, {"name": "on_member_join", "function": ""} ] } ``` ``` -------------------------------- ### Configure File Logging with Client.run Source: https://github.com/dolfies/discord.py-self/blob/master/docs/logging.rst Set up a file handler for logging by passing it to `client.run`. This redirects logs from the default stderr to a specified file. ```python import logging handler = logging.FileHandler(filename='discord.log', encoding='utf-8', mode='w') # Assume client refers to a discord.Client subclass... client.run(token, log_handler=handler) ``` -------------------------------- ### Get Commands from Cog Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/cogs.rst Retrieves a list of commands associated with a cog. ```APIDOC ## GET Cog Commands ### Description Retrieves a list of all commands directly defined within a cog. ### Method GET ### Endpoint `/cog/{cog_name}/commands` ### Parameters #### Path Parameters - **cog_name** (string) - Required - The name of the cog to inspect. ### Request Example ```python cog = bot.get_cog('Greetings') commands = cog.get_commands() print([c.name for c in commands]) ``` ### Response #### Success Response (200) - **commands** (list[string]) - A list of command names. #### Response Example ```json { "commands": ["hello", "goodbye"] } ``` ``` -------------------------------- ### on_ready() / on_resumed() Source: https://github.com/dolfies/discord.py-self/blob/master/docs/api.rst Gateway connection status events. ```APIDOC ## on_ready() Called when the client is done preparing the data received from Discord. ## on_resumed() Called when the client has resumed a session. ``` -------------------------------- ### Define Greeting FlagConverter Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst Example of a Greeting class inheriting from commands.FlagConverter with a positional argument and a default boolean value. ```python # Hello there --bold True class Greeting(commands.FlagConverter): text: str = commands.flag(positional=True) bold: bool = False ``` -------------------------------- ### Activate virtual environment on Linux/macOS Source: https://github.com/dolfies/discord.py-self/blob/master/docs/intro.rst Activate the created virtual environment using the source command. ```shell $ source bot-env/bin/activate ``` -------------------------------- ### Get Original Message from Command Context Source: https://github.com/dolfies/discord.py-self/blob/master/docs/faq.rst Access the original message object within a command using the 'ctx.message' attribute. ```python3 @bot.command() async def length(ctx): await ctx.send(f'Your message is {len(ctx.message.content)} characters long.') ``` -------------------------------- ### Get Cog Commands Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/cogs.rst Retrieve a list of commands associated with a cog. Ensure the cog is loaded and accessible via bot.get_cog. ```python >>> cog = bot.get_cog('Greetings') >>> commands = cog.get_commands() >>> print([c.name for c in commands]) ``` -------------------------------- ### Create Custom Member Roles Converter Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst Inherit from MemberConverter to create a custom converter that processes member roles. This example removes the 'everyone' role. ```python class MemberRoles(commands.MemberConverter): async def convert(self, ctx, argument): member = await super().convert(ctx, argument) return [role.name for role in member.roles[1:]] # Remove everyone role! @bot.command() async def roles(ctx, *, member: MemberRoles): """Tells you a member's roles.""" await ctx.send('I see the following roles: ' + ', '.join(member)) ``` -------------------------------- ### Registering Commands: Decorator vs. Add Command Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst Demonstrates two equivalent ways to register a command: using the @bot.command() decorator or the @commands.command() decorator followed by bot.add_command(). ```python from discord.ext import commands bot = commands.Bot(command_prefix='$') @bot.command() async def test(ctx): pass # or: @commands.command() async def test(ctx): pass bot.add_command(test) ``` -------------------------------- ### Get Cog Listeners Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/cogs.rst Retrieve a list of listeners registered within a cog. Each item in the list is a tuple containing the listener name and the function object. ```python >>> for name, func in cog.get_listeners(): ... print(name, '->', func) ``` -------------------------------- ### Registering Events via Subclassing Source: https://github.com/dolfies/discord.py-self/blob/master/docs/api.rst Demonstrates how to register event handlers by subclassing the Client class and overriding specific event methods. ```python import discord class MyClient(discord.Client): async def on_message(self, message): if message.author != self.user: return if message.content.startswith('$hello'): await message.channel.send('Hello World!') ``` -------------------------------- ### Load an Extension Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/extensions.rst Use the `load_extension` method on the bot instance to load an extension. The extension name should be a string, following Python's import path rules. ```python3 await bot.load_extension('hello') ``` -------------------------------- ### on_connection_create(connection) Source: https://github.com/dolfies/discord.py-self/blob/master/docs/api.rst Called when a connection is added to your account. ```APIDOC ## on_connection_create(connection) ### Description Called when a connection is added to your account. ### Parameters - **connection** (Connection) - The connection that was added. ``` -------------------------------- ### Define a Simple Command Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst Use the @bot.command() decorator to register a function as a command. The first argument must be ctx (Context). ```python @bot.command() async def foo(ctx, arg): await ctx.send(arg) ``` -------------------------------- ### Define Custom Converter with Parameter Metadata Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst Shows how to use commands.parameter to specify a custom converter for a command argument, helping type checkers understand the runtime conversion. ```python class SomeType: foo: int class MyVeryCoolConverter(commands.Converter[SomeType]): ... # implementation left as an exercise for the reader @bot.command() async def bar(ctx, cool_value: SomeType = commands.parameter(converter=MyVeryCoolConverter)): cool_value.foo # no error (hurray) ``` -------------------------------- ### Create a Custom Command Check (Decorator Factory) Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst Illustrates creating a reusable custom check by defining a decorator factory. This pattern allows for checks that can be configured with arguments, such as checking permissions or specific conditions. ```python3 import discord from discord.ext import commands bot = commands.Bot(command_prefix='!') def is_owner(): async def predicate(ctx): return ctx.author.id == 316026178463072268 return commands.check(predicate) @bot.command(name='eval') @is_owner() async def _eval(ctx, *, code): """A bad example of an eval command""" await ctx.send(eval(code)) # bot.run('YOUR_BOT_TOKEN') ``` -------------------------------- ### Sync Webhook Migration Source: https://github.com/dolfies/discord.py-self/blob/master/docs/migrating.rst Migrate from the old synchronous webhook implementation to the new `SyncWebhook` class. ```python webhook = discord.Webhook.partial(123456, 'token-here', adapter=discord.RequestsWebhookAdapter()) webhook.send('Hello World', username='Foo') ``` ```python webhook = discord.SyncWebhook.partial(123456, 'token-here') webhook.send('Hello World', username='Foo') ``` -------------------------------- ### Define a Simple Bot Command Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst Defines a basic command that greets a specified user, defaulting to the command author. Requires the discord.py library. ```python3 import discord from discord.ext import commands bot = commands.Bot(command_prefix='!') @bot.command() async def wave(ctx, to: discord.User = commands.Author): await ctx.send(f'Hello {to.mention} :wave:') # bot.run('YOUR_BOT_TOKEN') ``` -------------------------------- ### Using Greedy with Optional for Flexible Commands Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst Combine Greedy with Optional to create flexible command syntaxes, allowing for optional parameters like delete_days. Be mindful of potential parsing ambiguities when mixing converters. ```python import discord import typing from discord.ext import commands @bot.command() async def ban(ctx, members: commands.Greedy[discord.Member], delete_days: typing.Optional[int] = 0, *, reason: str): """Mass bans members with an optional delete_days parameter""" delete_seconds = delete_days * 86400 # one day for member in members: await member.ban(delete_message_seconds=delete_seconds, reason=reason) ``` -------------------------------- ### on_integration_create(integration) Source: https://github.com/dolfies/discord.py-self/blob/master/docs/api.rst Triggered when an integration is created. ```APIDOC ## on_integration_create(integration) ### Description Called when an integration is created. ### Parameters - **integration** (Integration) - Required - The integration that was created. ``` -------------------------------- ### Activate virtual environment on Windows Source: https://github.com/dolfies/discord.py-self/blob/master/docs/intro.rst Activate the virtual environment on Windows using the activate.bat script. ```shell $ bot-env\Scripts\activate.bat ``` -------------------------------- ### Async Webhook Migration Source: https://github.com/dolfies/discord.py-self/blob/master/docs/migrating.rst Migrate from the old asynchronous webhook implementation to the new one by passing the session directly. ```python async with aiohttp.ClientSession() as session: webhook = discord.Webhook.from_url('url-here', adapter=discord.AsyncWebhookAdapter(session)) await webhook.send('Hello World', username='Foo') ``` ```python async with aiohttp.ClientSession() as session: webhook = discord.Webhook.from_url('url-here', session=session) await webhook.send('Hello World', username='Foo') ``` -------------------------------- ### Member Edit Comparison: Before and After Source: https://github.com/dolfies/discord.py-self/blob/master/docs/migrating.rst Illustrates the change in how member edits are handled. Previously, edits were in-place; now, they return a new updated member instance. ```python # before await member.edit(nick='new nick') await member.send(f'Your new nick is {member.nick}') ``` ```python # after updated_member = await member.edit(nick='new nick') await member.send(f'Your new nick is {updated_member.nick}') ``` -------------------------------- ### on_settings_update(before, after) Source: https://github.com/dolfies/discord.py-self/blob/master/docs/api.rst Called when your UserSettings updates. ```APIDOC ## on_settings_update(before, after) ### Description Called when your UserSettings updates, for example: changed theme, custom activity, or locale. ### Parameters - **before** (UserSettings) - Required - The settings prior to being updated. - **after** (UserSettings) - Required - The settings after being updated. ``` -------------------------------- ### Basic Member Conversion in Command Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst Demonstrates how to directly use discord.py's built-in converters to accept a discord.Member object as a command argument. The library handles the conversion from various string inputs (mention, ID, name) to a Member object. ```python @bot.command() async def joined(ctx, *, member: discord.Member): await ctx.send(f'{member} joined on {member.joined_at}') ``` -------------------------------- ### Command Extension Loading/Unloading Source: https://github.com/dolfies/discord.py-self/blob/master/docs/migrating.rst Details the asynchronous nature of extension and cog loading/unloading. ```APIDOC ## Asynchronous Extension and Cog Loading/Unloading ### Description Extension and cog loading and unloading are now asynchronous. The ``setup`` and ``teardown`` functions must be coroutines, and the corresponding Bot methods must be awaited. ### Methods - **ext.commands.Bot.load_extension**: Must be awaited. - **ext.commands.Bot.unload_extension**: Must be awaited. - **ext.commands.Bot.reload_extension**: Must be awaited. - **ext.commands.Bot.add_cog**: Must be awaited. - **ext.commands.Bot.remove_cog**: Must be awaited. ### Example (Setup Function) ```python # before def setup(bot): bot.add_cog(MyCog(bot)) # after async def setup(bot): await bot.add_cog(MyCog(bot)) ``` ### Example (Loading Extension) ```python # before bot.load_extension('my_extension') # after using setup_hook class MyBot(commands.Bot): async def setup_hook(self): await self.load_extension('my_extension') # after using async_with async def main(): async with bot: await bot.load_extension('my_extension') await bot.start(TOKEN) asyncio.run(main()) ``` ``` -------------------------------- ### Set Bot Activity on Initialization Source: https://github.com/dolfies/discord.py-self/blob/master/docs/faq.rst Set a static 'Playing' status for your bot when initializing the `discord.Client` by passing an `Activity` object to the `activity` keyword argument. ```python client = discord.Client(activity=discord.Game(name='my game')) ``` -------------------------------- ### Basic Integer Conversion Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst Use function annotations to convert arguments to integers for arithmetic operations. Requires Python 3. ```python @bot.command() async def add(ctx, a: int, b: int): await ctx.send(a + b) ``` -------------------------------- ### Command with Late Binding Default Parameter Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst Demonstrates using commands.parameter with a lambda function to provide a default value for a command parameter, enabling late binding. ```python @bot.command() async def wave(to: discord.User = commands.parameter(default=lambda ctx: ctx.author)): await ctx.send(f'Hello {to.mention} :wave:') ``` -------------------------------- ### on_invite_create(invite) Source: https://github.com/dolfies/discord.py-self/blob/master/docs/api.rst Triggered when an invite is created. ```APIDOC ## on_invite_create(invite) ### Description Called when an Invite is created. Requires manage_channels permission. ### Parameters - **invite** (Invite) - Required - The invite that was created. ``` -------------------------------- ### Asset Redesign Source: https://github.com/dolfies/discord.py-self/blob/master/docs/migrating.rst Explains the new Asset object and how it affects attributes like Guild icons. ```APIDOC ## Asset Redesign and Changes ### Description The :class:`Asset` object now centralizes all methods and attributes related to CDN assets. This redesign impacts models that previously had direct asset-related attributes and methods. ### Example: Guild Icon Changes - ``Guild.icon`` (previously :class:`str`) is now of type :class:`Asset`. Access the key using :attr:`Guild.icon.key`. - ``Guild.is_icon_animated`` is replaced by :meth:`Guild.icon.is_animated`. - ``Guild.icon_url`` is now directly available as :attr:`Guild.icon`. - ``Guild.icon_url_as`` is replaced by :meth:`Guild.icon.replace`. ### New Asset Helper Methods - :meth:`Asset.with_size` - :meth:`Asset.with_format` - :meth:`Asset.with_static_format` ``` -------------------------------- ### Run Python Bot on Windows Source: https://github.com/dolfies/discord.py-self/blob/master/docs/quickstart.rst Command to execute the Python bot script on a Windows system using the py launcher. ```shell $ py -3 example_bot.py ``` -------------------------------- ### Customizing FlagConverter with commands.flag Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst Shows how to customize flag names and default values using discord.ext.commands.flag within a FlagConverter class. ```python from typing import List class BanFlags(commands.FlagConverter): members: List[discord.Member] = commands.flag(name='member', default=lambda ctx: []) ``` -------------------------------- ### Upload file from URL Source: https://github.com/dolfies/discord.py-self/blob/master/docs/faq.rst Uploads a file from a URL by reading it with aiohttp and passing an io.BytesIO instance to discord.File. ```python import io import aiohttp async with aiohttp.ClientSession() as session: async with session.get(my_url) as resp: if resp.status != 200: return await channel.send('Could not download file...') data = io.BytesIO(await resp.read()) await channel.send(file=discord.File(data, 'cool_image.png')) ``` -------------------------------- ### Apply Library Logging to Root Logger Source: https://github.com/dolfies/discord.py-self/blob/master/docs/logging.rst Use `root_logger=True` in `client.run` to make the library's default logging configuration affect all loggers, not just the 'discord' logger. ```python client.run(token, log_handler=handler, root_logger=True) ``` -------------------------------- ### Ban Command with Tuple of Members Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst Demonstrates using Tuple[discord.Member, ...] for a flag that can be passed multiple times, allowing for a more concise input syntax compared to List. ```python from discord.ext import commands from typing import Tuple import discord class BanFlags(commands.FlagConverter): members: Tuple[discord.Member, ...] reason: str days: int = 1 ``` -------------------------------- ### discord.opus.load_opus Source: https://github.com/dolfies/discord.py-self/blob/master/docs/api.rst Loads the Opus library for audio processing. ```APIDOC ## discord.opus.load_opus(name) ### Description Loads the Opus library into the discord.py-self environment to enable audio encoding and decoding capabilities. ### Parameters - **name** (str) - Required - The path or name of the Opus library file to load. ``` -------------------------------- ### Keyword-Only Argument Command (*) Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst A command that uses a keyword-only argument (*). This captures all remaining input as a single string, useful for arguments with spaces. ```python @bot.command() async def test(ctx, *, arg): await ctx.send(arg) ``` -------------------------------- ### Custom Member Join Distance Converter Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst Use this converter to automatically calculate and provide the difference between a member's join date and account creation date to a command. It requires a custom class to hold the join and creation timestamps. ```python class JoinDistance: def __init__(self, joined, created): self.joined = joined self.created = created @property def delta(self): return self.joined - self.created class JoinDistanceConverter(commands.MemberConverter): async def convert(self, ctx, argument): member = await super().convert(ctx, argument) return JoinDistance(member.joined_at, member.created_at) @bot.command() async def delta(ctx, *, member: JoinDistanceConverter): is_new = member.delta.days < 100 if is_new: await ctx.send("Hey you're pretty new!") else: await ctx.send("Hm you're not so new.") ``` -------------------------------- ### on_premium_guild_subscription_slot_create(slot) Source: https://github.com/dolfies/discord.py-self/blob/master/docs/api.rst Called when a premium guild subscription (boost) slot is added to your account. ```APIDOC ## on_premium_guild_subscription_slot_create(slot) ### Description Called when a premium guild subscription (boost) slot is added to your account. ### Parameters - **slot** (PremiumGuildSubscriptionSlot) - The slot that was added. ``` -------------------------------- ### discord.opus.is_loaded Source: https://github.com/dolfies/discord.py-self/blob/master/docs/api.rst Checks if the Opus library has been successfully loaded. ```APIDOC ## discord.opus.is_loaded() ### Description Returns a boolean indicating whether the Opus library is currently loaded and ready for use. ``` -------------------------------- ### Converters as Generic Runtime Protocols Source: https://github.com/dolfies/discord.py-self/blob/master/docs/migrating.rst Explains the change in Converter class behavior. ```APIDOC ## Converters as Generic Runtime Protocols ### Description :class:`~ext.commands.Converter` is now a :func:`runtime-checkable ` :class:`typing.Protocol` and a :class:`typing.Generic`. This may affect user-created classes inheriting from :class:`~ext.commands.Converter`. ### Example (Converter Class) ```python # before class SomeConverterMeta(type): ... class SomeConverter(commands.Converter, metaclass=SomeConverterMeta): ... # after class SomeConverterMeta(type(commands.Converter)): ... class SomeConverter(commands.Converter, metaclass=SomeConverterMeta): ... ``` ``` -------------------------------- ### New Parameters Source: https://github.com/dolfies/discord.py-self/blob/master/docs/migrating.rst Details on newly added parameters to existing classes and methods. ```APIDOC ## New Parameters The following parameters have been added: - ``user_bot`` in :class:`~ext.commands.Bot` - Allows your bot to reply to everyone's message. ``` -------------------------------- ### on_typing Source: https://github.com/dolfies/discord.py-self/blob/master/docs/api.rst Called when someone begins typing a message. ```APIDOC ## on_typing(channel, user, when) ### Description Called when someone begins typing a message. ### Parameters - **channel** (abc.Messageable) - The location where the typing originated from. - **user** (Union[User, Member]) - The user that started typing. - **when** (datetime.datetime) - When the typing started as an aware datetime in UTC. ``` -------------------------------- ### on_directory_entry_create/update/delete(directory_entry) Source: https://github.com/dolfies/discord.py-self/blob/master/docs/api.rst Called when an entry is created, updated, or deleted in a directory channel. ```APIDOC ## on_directory_entry_create(directory_entry) ## on_directory_entry_update(directory_entry) ## on_directory_entry_delete(directory_entry) ### Description Called when an entry is created, updated, or deleted in a directory channel. ### Parameters - **directory_entry** (DirectoryEntry) - Required - The directory entry that was created, updated, or deleted. ``` -------------------------------- ### Variable Arguments Command (*args) Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst A command that accepts an arbitrary number of arguments using the *args syntax. All arguments are collected into a tuple. ```python @bot.command() async def test(ctx, *args): arguments = ', '.join(args) await ctx.send(f'{len(args)} arguments: {arguments}') ``` -------------------------------- ### Find Guild or Channel by Name using discord.utils.get Source: https://github.com/dolfies/discord.py-self/blob/master/docs/faq.rst Use discord.utils.get to find specific models like guilds or channels by their names. Ensure to check if the result is not None. ```python3 # find a guild by name guild = discord.utils.get(client.guilds, name='My Server') # make sure to check if it's found if guild is not None: # find a channel by name channel = discord.utils.get(guild.text_channels, name='cool-channel') ``` -------------------------------- ### Event Handlers Source: https://github.com/dolfies/discord.py-self/blob/master/docs/api.rst Documentation for AutoMod event listeners. ```APIDOC ## on_automod_rule_create(rule) ### Description Triggered when an AutoMod rule is created. Requires manage_guild permissions. ## on_automod_rule_update(rule) ### Description Triggered when an AutoMod rule is updated. Requires manage_guild permissions. ## on_automod_rule_delete(rule) ### Description Triggered when an AutoMod rule is deleted. Requires manage_guild permissions. ``` -------------------------------- ### on_entitlement_create(entitlement) Source: https://github.com/dolfies/discord.py-self/blob/master/docs/api.rst Called when an entitlement is added to your account. ```APIDOC ## on_entitlement_create(entitlement) ### Description Called when an entitlement is added to your account. ### Parameters - **entitlement** (Entitlement) - The entitlement that was added. ``` -------------------------------- ### Implement Local Command Error Handling Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst Shows how to handle errors specific to a command using the @command.error decorator. This is useful for providing custom error messages when a command fails, such as when a member is not found. ```python3 import discord from discord.ext import commands bot = commands.Bot(command_prefix='!') @bot.command() async def info(ctx, *, member: discord.Member): """Tells you some info about the member.""" msg = f'{member} joined on {member.joined_at} and has {len(member.roles)} roles.' await ctx.send(msg) @info.error async def info_error(ctx, error): if isinstance(error, commands.BadArgument): await ctx.send('I could not find that member...') # bot.run('YOUR_BOT_TOKEN') ``` -------------------------------- ### Ban Command with List of Members Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/commands/commands.rst Demonstrates using List[discord.Member] for a flag that can be passed multiple times. Requires specifying the flag name for each member. ```python from discord.ext import commands from typing import List import discord class BanFlags(commands.FlagConverter): members: List[discord.Member] = commands.flag(name='member') reason: str days: int = 1 @commands.command() async def ban(ctx, *, flags: BanFlags): for member in flags.members: await member.ban(reason=flags.reason, delete_message_days=flags.days) members = ', '.join(str(member) for member in flags.members) plural = f'{flags.days} days' if flags.days != 1 else f'{flags.days} day' await ctx.send(f'Banned {members} for {flags.reason!r} (deleted {plural} worth of messages)') ``` -------------------------------- ### Run task at a specific time each day Source: https://github.com/dolfies/discord.py-self/blob/master/docs/ext/tasks/index.rst This task is scheduled to run daily at a specific time (8:30 AM UTC). Ensure the `datetime.time` object includes timezone information. ```python import datetime from discord.ext import commands, tasks utc = datetime.timezone.utc # If no tzinfo is given then UTC is assumed. time = datetime.time(hour=8, minute=30, tzinfo=utc) class MyCog(commands.Cog): def __init__(self, bot): self.bot = bot self.my_task.start() def cog_unload(self): self.my_task.cancel() @tasks.loop(time=time) async def my_task(self): print("My task is running!") ``` -------------------------------- ### Webhook Changes Source: https://github.com/dolfies/discord.py-self/blob/master/docs/migrating.rst Illustrates the updated usage for asynchronous and synchronous webhooks after the rewrite. ```APIDOC ## Webhook Changes ### Description This section details the changes in webhook functionality, including the split of synchronous operations into separate classes and updated usage examples for both asynchronous and synchronous webhooks. ### Asynchronous Webhooks #### Before ```python async with aiohttp.ClientSession() as session: webhook = discord.Webhook.from_url('url-here', adapter=discord.AsyncWebhookAdapter(session)) await webhook.send('Hello World', username='Foo') ``` #### After ```python async with aiohttp.ClientSession() as session: webhook = discord.Webhook.from_url('url-here', session=session) await webhook.send('Hello World', username='Foo') ``` ### Synchronous Webhooks #### Before ```python webhook = discord.Webhook.partial(123456, 'token-here', adapter=discord.RequestsWebhookAdapter()) webhook.send('Hello World', username='Foo') ``` #### After ```python webhook = discord.SyncWebhook.partial(123456, 'token-here') webhook.send('Hello World', username='Foo') ``` ### Breaking Changes - Synchronous functionality of :class:`Webhook` and :class:`WebhookMessage` has been split to :class:`SyncWebhook` and :class:`SyncWebhookMessage`. - ``WebhookAdapter`` class has been removed and the interfaces based on it (``AsyncWebhookAdapter`` and ``RequestsWebhookAdapter``) are now considered implementation detail and should not be depended on. - ``execute`` alias for :meth:`Webhook.send`/:meth:`SyncWebhook.send` has been removed. ``` -------------------------------- ### Upload multiple files Source: https://github.com/dolfies/discord.py-self/blob/master/docs/faq.rst Uploads multiple files to Discord using the 'files' keyword argument. ```python my_files = [ discord.File('result.zip'), discord.File('teaser_graph.png'), ] await channel.send(files=my_files) ```