Compare commits
2 Commits
420c57df30
...
e965a675c1
Author | SHA1 | Date | |
---|---|---|---|
|
e965a675c1 | ||
|
9237d12a24 |
@ -67,6 +67,47 @@ from .hybrid_context import HybridContext
|
||||
from .interactions import Interaction
|
||||
from .logging_config import setup_logging
|
||||
from . import ui, ext
|
||||
from .ext.app_commands import (
|
||||
AppCommand,
|
||||
AppCommandContext,
|
||||
AppCommandGroup,
|
||||
MessageCommand,
|
||||
OptionMetadata,
|
||||
SlashCommand,
|
||||
UserCommand,
|
||||
group,
|
||||
hybrid_command,
|
||||
message_command,
|
||||
slash_command,
|
||||
subcommand,
|
||||
subcommand_group,
|
||||
)
|
||||
from .ext.commands import (
|
||||
BadArgument,
|
||||
CheckAnyFailure,
|
||||
CheckFailure,
|
||||
Cog,
|
||||
Command,
|
||||
CommandContext,
|
||||
CommandError,
|
||||
CommandInvokeError,
|
||||
CommandNotFound,
|
||||
CommandOnCooldown,
|
||||
MaxConcurrencyReached,
|
||||
MissingRequiredArgument,
|
||||
ArgumentParsingError,
|
||||
check,
|
||||
check_any,
|
||||
command,
|
||||
cooldown,
|
||||
has_any_role,
|
||||
has_role,
|
||||
listener,
|
||||
max_concurrency,
|
||||
requires_permissions,
|
||||
)
|
||||
from .ext.tasks import Task, loop
|
||||
from .ui import Item, Modal, Select, TextInput, View, button, select, text_input
|
||||
|
||||
|
||||
import logging
|
||||
@ -123,6 +164,51 @@ __all__ = [
|
||||
"setup_logging",
|
||||
"ui",
|
||||
"ext",
|
||||
"AppCommand",
|
||||
"AppCommandContext",
|
||||
"AppCommandGroup",
|
||||
"MessageCommand",
|
||||
"OptionMetadata",
|
||||
"SlashCommand",
|
||||
"UserCommand",
|
||||
"group",
|
||||
"hybrid_command",
|
||||
"message_command",
|
||||
"slash_command",
|
||||
"subcommand",
|
||||
"subcommand_group",
|
||||
"BadArgument",
|
||||
"CheckAnyFailure",
|
||||
"CheckFailure",
|
||||
"Cog",
|
||||
"Command",
|
||||
"CommandContext",
|
||||
"CommandError",
|
||||
"CommandInvokeError",
|
||||
"CommandNotFound",
|
||||
"CommandOnCooldown",
|
||||
"MaxConcurrencyReached",
|
||||
"MissingRequiredArgument",
|
||||
"ArgumentParsingError",
|
||||
"check",
|
||||
"check_any",
|
||||
"command",
|
||||
"cooldown",
|
||||
"has_any_role",
|
||||
"has_role",
|
||||
"listener",
|
||||
"max_concurrency",
|
||||
"requires_permissions",
|
||||
"Task",
|
||||
"loop",
|
||||
"Item",
|
||||
"Modal",
|
||||
"Select",
|
||||
"TextInput",
|
||||
"View",
|
||||
"button",
|
||||
"select",
|
||||
"text_input",
|
||||
]
|
||||
|
||||
|
||||
|
@ -20,7 +20,7 @@ returns ``True``. Checks may be regular or async callables that accept a
|
||||
`CommandContext`.
|
||||
|
||||
```python
|
||||
from disagreement.ext.commands import command, check, CheckFailure
|
||||
from disagreement import command, check, CheckFailure
|
||||
|
||||
def is_owner(ctx):
|
||||
return ctx.author.id == "1"
|
||||
@ -40,7 +40,7 @@ Commands can be rate limited using the ``cooldown`` decorator. The example
|
||||
below restricts usage to once every three seconds per user:
|
||||
|
||||
```python
|
||||
from disagreement.ext.commands import command, cooldown
|
||||
from disagreement import command, cooldown
|
||||
|
||||
@command()
|
||||
@cooldown(1, 3.0)
|
||||
@ -56,8 +56,8 @@ Use `commands.requires_permissions` to ensure the invoking member has the
|
||||
required permissions in the channel.
|
||||
|
||||
```python
|
||||
from disagreement.ext.commands import command, requires_permissions
|
||||
from disagreement.permissions import Permissions
|
||||
from disagreement import command, requires_permissions
|
||||
from disagreement import Permissions
|
||||
|
||||
@command()
|
||||
@requires_permissions(Permissions.MANAGE_MESSAGES)
|
||||
|
@ -1,12 +1,11 @@
|
||||
# Context Menu Commands
|
||||
|
||||
`disagreement` supports Discord's user and message context menu commands. Use the
|
||||
`user_command` and `message_command` decorators from `ext.app_commands` to
|
||||
define them.
|
||||
`user_command` and `message_command` decorators to define them.
|
||||
|
||||
```python
|
||||
from disagreement.ext.app_commands import user_command, message_command, AppCommandContext
|
||||
from disagreement.models import User, Message
|
||||
from disagreement import User, Message
|
||||
from disagreement import User, Message, user_command, message_command, AppCommandContext
|
||||
|
||||
@user_command(name="User Info")
|
||||
async def user_info(ctx: AppCommandContext, user: User) -> None:
|
||||
|
@ -13,8 +13,8 @@
|
||||
|
||||
```python
|
||||
from disagreement.ext.commands import command
|
||||
from disagreement import Member
|
||||
from disagreement.ext.commands.core import CommandContext
|
||||
from disagreement.models import Member
|
||||
|
||||
@command()
|
||||
async def kick(ctx: CommandContext, target: Member):
|
||||
|
@ -4,7 +4,7 @@
|
||||
These helper methods return the embed instance so you can chain calls.
|
||||
|
||||
```python
|
||||
from disagreement.models import Embed
|
||||
from disagreement import Embed
|
||||
|
||||
embed = (
|
||||
Embed()
|
||||
|
@ -20,7 +20,7 @@ Triggered when a user's presence changes. The callback receives a `PresenceUpdat
|
||||
|
||||
```python
|
||||
@client.event
|
||||
async def on_presence_update(presence: disagreement.PresenceUpdate):
|
||||
async def on_presence_update(presence: PresenceUpdate):
|
||||
...
|
||||
```
|
||||
|
||||
@ -30,7 +30,7 @@ Dispatched when a user begins typing in a channel. The callback receives a `Typi
|
||||
|
||||
```python
|
||||
@client.event
|
||||
async def on_typing_start(typing: disagreement.TypingStart):
|
||||
async def on_typing_start(typing: TypingStart):
|
||||
...
|
||||
```
|
||||
|
||||
@ -40,7 +40,7 @@ Fired when a new member joins a guild. The callback receives a `Member` model.
|
||||
|
||||
```python
|
||||
@client.event
|
||||
async def on_guild_member_add(member: disagreement.Member):
|
||||
async def on_guild_member_add(member: Member):
|
||||
...
|
||||
```
|
||||
|
||||
@ -51,7 +51,7 @@ receives a `GuildMemberRemove` model.
|
||||
|
||||
```python
|
||||
@client.event
|
||||
async def on_guild_member_remove(event: disagreement.GuildMemberRemove):
|
||||
async def on_guild_member_remove(event: GuildMemberRemove):
|
||||
...
|
||||
```
|
||||
|
||||
@ -62,7 +62,7 @@ Dispatched when a user is banned from a guild. The callback receives a
|
||||
|
||||
```python
|
||||
@client.event
|
||||
async def on_guild_ban_add(event: disagreement.GuildBanAdd):
|
||||
async def on_guild_ban_add(event: GuildBanAdd):
|
||||
...
|
||||
```
|
||||
|
||||
@ -73,7 +73,7 @@ Dispatched when a user's ban is lifted. The callback receives a
|
||||
|
||||
```python
|
||||
@client.event
|
||||
async def on_guild_ban_remove(event: disagreement.GuildBanRemove):
|
||||
async def on_guild_ban_remove(event: GuildBanRemove):
|
||||
...
|
||||
```
|
||||
|
||||
@ -84,7 +84,7 @@ Sent when a channel's settings change. The callback receives an updated
|
||||
|
||||
```python
|
||||
@client.event
|
||||
async def on_channel_update(channel: disagreement.Channel):
|
||||
async def on_channel_update(channel: Channel):
|
||||
...
|
||||
```
|
||||
|
||||
@ -95,7 +95,7 @@ Emitted when a guild role is updated. The callback receives a
|
||||
|
||||
```python
|
||||
@client.event
|
||||
async def on_guild_role_update(event: disagreement.GuildRoleUpdate):
|
||||
async def on_guild_role_update(event: GuildRoleUpdate):
|
||||
...
|
||||
```
|
||||
|
||||
@ -138,6 +138,6 @@ Triggered when a user's voice connection state changes, such as joining or leavi
|
||||
|
||||
```python
|
||||
@client.event
|
||||
async def on_voice_state_update(state: disagreement.VoiceStateUpdate):
|
||||
async def on_voice_state_update(state: VoiceStateUpdate):
|
||||
...
|
||||
```
|
||||
|
@ -8,6 +8,8 @@ You can control the maximum number of retries and the backoff cap when construct
|
||||
These options are forwarded to `GatewayClient` as `max_retries` and `max_backoff`:
|
||||
|
||||
```python
|
||||
from disagreement import Client
|
||||
|
||||
bot = Client(
|
||||
token="your-token",
|
||||
gateway_max_retries=10,
|
||||
|
@ -24,7 +24,7 @@ other supported session argument.
|
||||
The HTTP client can list the guilds the bot user is in:
|
||||
|
||||
```python
|
||||
from disagreement.http import HTTPClient
|
||||
from disagreement import HTTPClient
|
||||
|
||||
http = HTTPClient(token="TOKEN")
|
||||
guilds = await http.get_current_user_guilds()
|
||||
|
@ -39,14 +39,14 @@ pip install "disagreement[dev]"
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
import disagreement
|
||||
from disagreement import Client, GatewayIntent
|
||||
from disagreement.ext import commands
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
|
||||
|
||||
class Basics(commands.Cog):
|
||||
def __init__(self, client: disagreement.Client) -> None:
|
||||
def __init__(self, client: Client) -> None:
|
||||
super().__init__(client)
|
||||
|
||||
@commands.command()
|
||||
@ -58,8 +58,8 @@ token = os.getenv("DISCORD_BOT_TOKEN")
|
||||
if not token:
|
||||
raise RuntimeError("DISCORD_BOT_TOKEN environment variable not set")
|
||||
|
||||
intents = disagreement.GatewayIntent.default() | disagreement.GatewayIntent.MESSAGE_CONTENT
|
||||
client = disagreement.Client(token=token, command_prefix="!", intents=intents, mention_replies=True)
|
||||
intents = GatewayIntent.default() | GatewayIntent.MESSAGE_CONTENT
|
||||
client = Client(token=token, command_prefix="!", intents=intents, mention_replies=True)
|
||||
async def main() -> None:
|
||||
client.add_cog(Basics(client))
|
||||
await client.run()
|
||||
@ -100,10 +100,10 @@ setup_logging(logging.DEBUG, file="bot.log")
|
||||
### HTTP Session Options
|
||||
|
||||
Pass additional keyword arguments to ``aiohttp.ClientSession`` using the
|
||||
``http_options`` parameter when constructing :class:`disagreement.Client`:
|
||||
``http_options`` parameter when constructing :class:`Client`:
|
||||
|
||||
```python
|
||||
client = disagreement.Client(
|
||||
client = Client(
|
||||
token=token,
|
||||
http_options={"proxy": "http://localhost:8080"},
|
||||
)
|
||||
@ -119,7 +119,7 @@ Specify default mention behaviour for all outgoing messages when constructing th
|
||||
|
||||
```python
|
||||
from disagreement.models import AllowedMentions
|
||||
client = disagreement.Client(
|
||||
client = Client(
|
||||
token=token,
|
||||
allowed_mentions=AllowedMentions.none().to_dict(),
|
||||
)
|
||||
@ -173,14 +173,15 @@ To run your bot across multiple gateway shards, pass ``shard_count`` when creati
|
||||
the client:
|
||||
|
||||
```python
|
||||
client = disagreement.Client(token=BOT_TOKEN, shard_count=2)
|
||||
client = Client(token=BOT_TOKEN, shard_count=2)
|
||||
```
|
||||
|
||||
If you want the library to determine the recommended shard count automatically,
|
||||
use ``AutoShardedClient``:
|
||||
|
||||
```python
|
||||
client = disagreement.AutoShardedClient(token=BOT_TOKEN)
|
||||
from disagreement import AutoShardedClient
|
||||
client = AutoShardedClient(token=BOT_TOKEN)
|
||||
```
|
||||
|
||||
See `examples/sharded_bot.py` for a full example.
|
||||
|
@ -8,8 +8,8 @@ Use the ``allowed_mentions`` parameter of :class:`disagreement.Client` to set a
|
||||
default for all messages:
|
||||
|
||||
```python
|
||||
from disagreement.models import AllowedMentions
|
||||
client = disagreement.Client(
|
||||
from disagreement import AllowedMentions, Client
|
||||
client = Client(
|
||||
token="YOUR_TOKEN",
|
||||
allowed_mentions=AllowedMentions.none().to_dict(),
|
||||
)
|
||||
|
@ -10,7 +10,7 @@ Each attribute of ``Permissions`` represents a single permission bit. The value
|
||||
is a power of two so multiple permissions can be combined using bitwise OR.
|
||||
|
||||
```python
|
||||
from disagreement.permissions import Permissions
|
||||
from disagreement import Permissions
|
||||
|
||||
value = Permissions.SEND_MESSAGES | Permissions.MANAGE_MESSAGES
|
||||
```
|
||||
@ -47,10 +47,10 @@ Return a list of permissions that ``current`` does not contain.
|
||||
|
||||
```python
|
||||
from disagreement.permissions import (
|
||||
Permissions,
|
||||
has_permissions,
|
||||
missing_permissions,
|
||||
)
|
||||
from disagreement import Permissions
|
||||
|
||||
current = Permissions.SEND_MESSAGES | Permissions.MANAGE_MESSAGES
|
||||
|
||||
|
@ -26,7 +26,7 @@ An activity dictionary must include a `name` and a `type` field. The type value
|
||||
Example using the provided activity classes:
|
||||
|
||||
```python
|
||||
from disagreement.models import Game
|
||||
from disagreement import Game
|
||||
|
||||
await client.change_presence(status="idle", activity=Game("with Discord"))
|
||||
```
|
||||
@ -34,7 +34,7 @@ await client.change_presence(status="idle", activity=Game("with Discord"))
|
||||
You can also specify a streaming URL:
|
||||
|
||||
```python
|
||||
from disagreement.models import Streaming
|
||||
from disagreement import Streaming
|
||||
|
||||
await client.change_presence(status="online", activity=Streaming("My Stream", "https://twitch.tv/someone"))
|
||||
```
|
||||
|
@ -48,7 +48,7 @@ The event handlers for these events receive both a `Reaction` object and the `Us
|
||||
|
||||
```python
|
||||
import disagreement
|
||||
from disagreement.models import Reaction, User, Member
|
||||
from disagreement import Reaction, User, Member
|
||||
|
||||
@client.on_event("MESSAGE_REACTION_ADD")
|
||||
async def on_reaction_add(reaction: Reaction, user: User | Member):
|
||||
|
@ -3,7 +3,7 @@
|
||||
The `Client` provides helpers to manage guild scheduled events.
|
||||
|
||||
```python
|
||||
from disagreement.client import Client
|
||||
from disagreement import Client
|
||||
|
||||
client = Client(token="TOKEN")
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
# Using Slash Commands
|
||||
|
||||
The library provides a slash command framework via the `ext.app_commands` package. Define commands with decorators and register them with Discord.
|
||||
The library provides a slash command framework to define commands with decorators and register them with Discord.
|
||||
|
||||
```python
|
||||
from disagreement.ext.app_commands import AppCommandGroup
|
||||
from disagreement import AppCommandGroup
|
||||
|
||||
bot_commands = AppCommandGroup("bot", "Bot commands")
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
# Task Loops
|
||||
|
||||
The tasks extension allows you to run functions periodically. Decorate an async function with `@tasks.loop` and start it using `.start()`.
|
||||
The tasks extension allows you to run functions periodically. Decorate an async function with `@loop` and start it using `.start()`.
|
||||
|
||||
```python
|
||||
from disagreement.ext import tasks
|
||||
from disagreement import loop
|
||||
|
||||
@tasks.loop(minutes=1.0)
|
||||
@loop(minutes=1.0)
|
||||
async def announce():
|
||||
print("Hello from a loop")
|
||||
|
||||
@ -19,7 +19,7 @@ You can provide the interval in seconds, minutes, hours or as a `datetime.timede
|
||||
```python
|
||||
import datetime
|
||||
|
||||
@tasks.loop(delta=datetime.timedelta(seconds=30))
|
||||
@loop(delta=datetime.timedelta(seconds=30))
|
||||
async def ping():
|
||||
...
|
||||
```
|
||||
@ -30,7 +30,7 @@ Handle exceptions raised by the looped coroutine using `on_error`:
|
||||
async def log_error(exc: Exception) -> None:
|
||||
print("Loop failed:", exc)
|
||||
|
||||
@tasks.loop(seconds=5.0, on_error=log_error)
|
||||
@loop(seconds=5.0, on_error=log_error)
|
||||
async def worker():
|
||||
...
|
||||
```
|
||||
@ -38,7 +38,7 @@ async def worker():
|
||||
Run setup and teardown code using `before_loop` and `after_loop`:
|
||||
|
||||
```python
|
||||
@tasks.loop(seconds=5.0)
|
||||
@loop(seconds=5.0)
|
||||
async def worker():
|
||||
...
|
||||
|
||||
@ -58,7 +58,7 @@ from datetime import datetime, timedelta
|
||||
|
||||
time_to_run = (datetime.now() + timedelta(seconds=5)).time()
|
||||
|
||||
@tasks.loop(time_of_day=time_to_run)
|
||||
@loop(time_of_day=time_to_run)
|
||||
async def daily_task():
|
||||
...
|
||||
```
|
||||
|
@ -4,7 +4,7 @@
|
||||
Use :class:`AutoArchiveDuration` to control when a thread is automatically archived.
|
||||
|
||||
```python
|
||||
from disagreement.enums import AutoArchiveDuration
|
||||
from disagreement import AutoArchiveDuration
|
||||
|
||||
await message.create_thread(
|
||||
"discussion",
|
||||
|
@ -4,9 +4,9 @@ The library exposes an async context manager to send the typing indicator for a
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
import disagreement
|
||||
from disagreement import Client
|
||||
|
||||
client = disagreement.Client(token="YOUR_TOKEN")
|
||||
client = Client(token="YOUR_TOKEN")
|
||||
|
||||
async def indicate(channel_id: str):
|
||||
async with client.typing(channel_id):
|
||||
|
@ -19,8 +19,7 @@ The library exposes three broad categories of components:
|
||||
`ActionRow` is a layout container. It may hold up to five buttons or a single select menu.
|
||||
|
||||
```python
|
||||
from disagreement.models import ActionRow, Button
|
||||
from disagreement.enums import ButtonStyle
|
||||
from disagreement import ActionRow, Button, ButtonStyle
|
||||
|
||||
row = ActionRow(components=[
|
||||
Button(style=ButtonStyle.PRIMARY, label="Click", custom_id="btn")
|
||||
@ -32,8 +31,7 @@ row = ActionRow(components=[
|
||||
Buttons provide a clickable UI element.
|
||||
|
||||
```python
|
||||
from disagreement.models import Button
|
||||
from disagreement.enums import ButtonStyle
|
||||
from disagreement import Button, ButtonStyle
|
||||
|
||||
button = Button(
|
||||
style=ButtonStyle.SUCCESS,
|
||||
@ -47,8 +45,7 @@ button = Button(
|
||||
`SelectMenu` lets the user choose one or more options. The `type` parameter controls the menu variety (`STRING_SELECT`, `USER_SELECT`, `ROLE_SELECT`, `MENTIONABLE_SELECT`, `CHANNEL_SELECT`).
|
||||
|
||||
```python
|
||||
from disagreement.models import SelectMenu, SelectOption
|
||||
from disagreement.enums import ComponentType, ChannelType
|
||||
from disagreement import SelectMenu, SelectOption, ComponentType, ChannelType
|
||||
|
||||
menu = SelectMenu(
|
||||
custom_id="example",
|
||||
@ -70,7 +67,7 @@ For channel selects you may pass `channel_types` with a list of allowed `Channel
|
||||
`Section` groups one or more `TextDisplay` components and can include an accessory `Button` or `Thumbnail`.
|
||||
|
||||
```python
|
||||
from disagreement.models import Section, TextDisplay, Thumbnail, UnfurledMediaItem
|
||||
from disagreement import Section, TextDisplay, Thumbnail, UnfurledMediaItem
|
||||
|
||||
section = Section(
|
||||
components=[
|
||||
@ -86,7 +83,7 @@ section = Section(
|
||||
`TextDisplay` simply renders markdown text.
|
||||
|
||||
```python
|
||||
from disagreement.models import TextDisplay
|
||||
from disagreement import TextDisplay
|
||||
|
||||
text_display = TextDisplay(content="**Bold text**")
|
||||
```
|
||||
@ -96,7 +93,7 @@ text_display = TextDisplay(content="**Bold text**")
|
||||
`Thumbnail` shows a small image. Set `spoiler=True` to hide the image until clicked.
|
||||
|
||||
```python
|
||||
from disagreement.models import Thumbnail, UnfurledMediaItem
|
||||
from disagreement import Thumbnail, UnfurledMediaItem
|
||||
|
||||
thumb = Thumbnail(
|
||||
media=UnfurledMediaItem(url="https://example.com/image.png"),
|
||||
@ -110,7 +107,7 @@ thumb = Thumbnail(
|
||||
`MediaGallery` holds multiple `MediaGalleryItem` objects.
|
||||
|
||||
```python
|
||||
from disagreement.models import MediaGallery, MediaGalleryItem, UnfurledMediaItem
|
||||
from disagreement import MediaGallery, MediaGalleryItem, UnfurledMediaItem
|
||||
|
||||
gallery = MediaGallery(
|
||||
items=[
|
||||
@ -125,7 +122,7 @@ gallery = MediaGallery(
|
||||
`File` displays an uploaded file. Use `spoiler=True` to mark it as a spoiler.
|
||||
|
||||
```python
|
||||
from disagreement.models import File, UnfurledMediaItem
|
||||
from disagreement import File, UnfurledMediaItem
|
||||
|
||||
file_component = File(
|
||||
file=UnfurledMediaItem(url="attachment://file.zip"),
|
||||
@ -138,7 +135,7 @@ file_component = File(
|
||||
`Separator` adds vertical spacing or an optional divider line between components.
|
||||
|
||||
```python
|
||||
from disagreement.models import Separator
|
||||
from disagreement import Separator
|
||||
|
||||
separator = Separator(divider=True, spacing=2)
|
||||
```
|
||||
@ -148,7 +145,7 @@ separator = Separator(divider=True, spacing=2)
|
||||
`Container` visually groups a set of components and can apply an accent colour or spoiler.
|
||||
|
||||
```python
|
||||
from disagreement.models import Container, TextDisplay
|
||||
from disagreement import Container, TextDisplay
|
||||
|
||||
container = Container(
|
||||
components=[TextDisplay(content="Inside a container")],
|
||||
|
@ -5,7 +5,7 @@ The `HTTPClient` includes helper methods for creating, editing and deleting Disc
|
||||
## Create a webhook
|
||||
|
||||
```python
|
||||
from disagreement.http import HTTPClient
|
||||
from disagreement import HTTPClient
|
||||
|
||||
http = HTTPClient(token="TOKEN")
|
||||
payload = {"name": "My Webhook"}
|
||||
@ -27,7 +27,7 @@ await http.delete_webhook("456")
|
||||
The methods now return a `Webhook` object directly:
|
||||
|
||||
```python
|
||||
from disagreement.models import Webhook
|
||||
from disagreement import Webhook
|
||||
|
||||
print(webhook.id, webhook.name)
|
||||
```
|
||||
@ -37,7 +37,7 @@ print(webhook.id, webhook.name)
|
||||
You can construct a `Webhook` object from an existing webhook URL without any API calls:
|
||||
|
||||
```python
|
||||
from disagreement.models import Webhook
|
||||
from disagreement import Webhook
|
||||
|
||||
webhook = Webhook.from_url("https://discord.com/api/webhooks/123/token")
|
||||
print(webhook.id, webhook.token)
|
||||
|
@ -32,11 +32,12 @@ try:
|
||||
GatewayIntent,
|
||||
Message,
|
||||
Guild,
|
||||
ext,
|
||||
AuthenticationError,
|
||||
DisagreementException,
|
||||
Cog,
|
||||
command,
|
||||
CommandContext,
|
||||
)
|
||||
from disagreement.ext import commands
|
||||
except ImportError:
|
||||
print(
|
||||
"Failed to import disagreement. Make sure it's installed or PYTHONPATH is set correctly."
|
||||
@ -87,26 +88,26 @@ client = Client(token=BOT_TOKEN, intents=intents, command_prefix="!")
|
||||
|
||||
|
||||
# --- Define a Cog for example commands ---
|
||||
class ExampleCog(commands.Cog): # Ensuring this uses commands.Cog
|
||||
class ExampleCog(Cog): # Ensuring this uses commands.Cog
|
||||
def __init__(
|
||||
self, bot_client
|
||||
): # Renamed client to bot_client to avoid conflict with self.client
|
||||
super().__init__(bot_client) # Pass the client instance to the base Cog
|
||||
|
||||
@commands.command(name="hello", aliases=["hi"])
|
||||
async def hello_command(self, ctx: commands.CommandContext, *, who: str = "world"):
|
||||
@command(name="hello", aliases=["hi"])
|
||||
async def hello_command(self, ctx: CommandContext, *, who: str = "world"):
|
||||
"""Greets someone."""
|
||||
await ctx.reply(f"Hello {ctx.author.mention} and {who}!")
|
||||
print(f"Executed 'hello' command for {ctx.author.username}, greeting {who}")
|
||||
|
||||
@commands.command()
|
||||
async def ping(self, ctx: commands.CommandContext):
|
||||
@command()
|
||||
async def ping(self, ctx: CommandContext):
|
||||
"""Responds with Pong!"""
|
||||
await ctx.reply("Pong!")
|
||||
print(f"Executed 'ping' command for {ctx.author.username}")
|
||||
|
||||
@commands.command()
|
||||
async def me(self, ctx: commands.CommandContext):
|
||||
@command()
|
||||
async def me(self, ctx: CommandContext):
|
||||
"""Shows information about the invoking user."""
|
||||
reply_content = (
|
||||
f"Hello {ctx.author.mention}!\n"
|
||||
@ -117,8 +118,8 @@ class ExampleCog(commands.Cog): # Ensuring this uses commands.Cog
|
||||
await ctx.reply(reply_content)
|
||||
print(f"Executed 'me' command for {ctx.author.username}")
|
||||
|
||||
@commands.command(name="add")
|
||||
async def add_numbers(self, ctx: commands.CommandContext, num1: int, num2: int):
|
||||
@command(name="add")
|
||||
async def add_numbers(self, ctx: CommandContext, num1: int, num2: int):
|
||||
"""Adds two numbers."""
|
||||
result = num1 + num2
|
||||
await ctx.reply(f"The sum of {num1} and {num2} is {result}.")
|
||||
@ -126,16 +127,16 @@ class ExampleCog(commands.Cog): # Ensuring this uses commands.Cog
|
||||
f"Executed 'add' command for {ctx.author.username}: {num1} + {num2} = {result}"
|
||||
)
|
||||
|
||||
@commands.command(name="say")
|
||||
async def say_something(self, ctx: commands.CommandContext, *, text_to_say: str):
|
||||
@command(name="say")
|
||||
async def say_something(self, ctx: CommandContext, *, text_to_say: str):
|
||||
"""Repeats the text you provide."""
|
||||
await ctx.reply(f"You said: {text_to_say}")
|
||||
print(
|
||||
f"Executed 'say' command for {ctx.author.username}, saying: {text_to_say}"
|
||||
)
|
||||
|
||||
@commands.command(name="whois")
|
||||
async def whois(self, ctx: commands.CommandContext, *, name: str):
|
||||
@command(name="whois")
|
||||
async def whois(self, ctx: CommandContext, *, name: str):
|
||||
"""Looks up a member by username or nickname using the guild cache."""
|
||||
if not ctx.guild:
|
||||
await ctx.reply("This command can only be used in a guild.")
|
||||
@ -149,8 +150,8 @@ class ExampleCog(commands.Cog): # Ensuring this uses commands.Cog
|
||||
else:
|
||||
await ctx.reply("Member not found in cache.")
|
||||
|
||||
@commands.command(name="quit")
|
||||
async def quit_command(self, ctx: commands.CommandContext):
|
||||
@command(name="quit")
|
||||
async def quit_command(self, ctx: CommandContext):
|
||||
"""Shuts down the bot (requires YOUR_USER_ID to be set)."""
|
||||
# Replace YOUR_USER_ID with your actual Discord User ID for a safe shutdown command
|
||||
your_user_id = "YOUR_USER_ID_REPLACE_ME" # IMPORTANT: Replace this
|
||||
|
@ -3,8 +3,6 @@ import asyncio
|
||||
from typing import Union
|
||||
from disagreement import (
|
||||
Client,
|
||||
ui,
|
||||
ext,
|
||||
HybridContext,
|
||||
Message,
|
||||
SelectOption,
|
||||
@ -27,9 +25,14 @@ from disagreement import (
|
||||
ChannelType,
|
||||
MessageFlags,
|
||||
Interaction,
|
||||
Cog,
|
||||
CommandContext,
|
||||
AppCommandContext,
|
||||
hybrid_command,
|
||||
View,
|
||||
button,
|
||||
select,
|
||||
)
|
||||
from disagreement.ext.commands import Cog, CommandContext
|
||||
from disagreement.ext.app_commands import AppCommandContext, hybrid_command
|
||||
|
||||
try:
|
||||
from dotenv import load_dotenv
|
||||
@ -69,12 +72,12 @@ STOCKS = [
|
||||
|
||||
|
||||
# Define a View class that contains our components
|
||||
class MyView(ui.View):
|
||||
class MyView(View):
|
||||
def __init__(self):
|
||||
super().__init__(timeout=180) # 180-second timeout
|
||||
self.click_count = 0
|
||||
|
||||
@ui.button(label="Click Me!", style=ButtonStyle.SUCCESS, emoji="🖱️")
|
||||
@button(label="Click Me!", style=ButtonStyle.SUCCESS, emoji="🖱️")
|
||||
async def click_me(self, interaction: Interaction):
|
||||
self.click_count += 1
|
||||
await interaction.respond(
|
||||
@ -82,7 +85,7 @@ class MyView(ui.View):
|
||||
ephemeral=True,
|
||||
)
|
||||
|
||||
@ui.select(
|
||||
@select(
|
||||
custom_id="string_select",
|
||||
placeholder="Choose an option",
|
||||
options=[
|
||||
@ -108,12 +111,12 @@ class MyView(ui.View):
|
||||
|
||||
|
||||
# View for cycling through available stocks
|
||||
class StockView(ui.View):
|
||||
class StockView(View):
|
||||
def __init__(self):
|
||||
super().__init__(timeout=180)
|
||||
self.index = 0
|
||||
|
||||
@ui.button(label="Next Stock", style=ButtonStyle.PRIMARY)
|
||||
@button(label="Next Stock", style=ButtonStyle.PRIMARY)
|
||||
async def next_stock(self, interaction: Interaction):
|
||||
self.index = (self.index + 1) % len(STOCKS)
|
||||
stock = STOCKS[self.index]
|
||||
|
@ -4,19 +4,18 @@
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from disagreement import Client, GatewayIntent
|
||||
from disagreement.ext import commands
|
||||
from disagreement import Client, GatewayIntent, Cog, command, CommandContext
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
|
||||
class Basics(commands.Cog):
|
||||
class Basics(Cog):
|
||||
def __init__(self, client: Client) -> None:
|
||||
super().__init__(client)
|
||||
|
||||
@commands.command()
|
||||
async def ping(self, ctx: commands.CommandContext) -> None:
|
||||
@command()
|
||||
async def ping(self, ctx: CommandContext) -> None:
|
||||
await ctx.reply(f"Pong! Gateway Latency: {self.client.latency_ms} ms.") # type: ignore (latency is None during static analysis)
|
||||
|
||||
|
||||
|
@ -9,8 +9,7 @@ from typing import Set
|
||||
if os.path.join(os.getcwd(), "examples") == os.path.dirname(os.path.abspath(__file__)):
|
||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||
|
||||
from disagreement import Client, GatewayIntent, Member, Message
|
||||
from disagreement.ext import commands
|
||||
from disagreement import Client, GatewayIntent, Member, Message, Cog, command, CommandContext
|
||||
|
||||
try:
|
||||
from dotenv import load_dotenv
|
||||
@ -37,21 +36,21 @@ client = Client(token=BOT_TOKEN, command_prefix="!", intents=intents)
|
||||
BANNED_WORDS: Set[str] = {"badword1", "badword2"}
|
||||
|
||||
|
||||
class ModerationCog(commands.Cog):
|
||||
class ModerationCog(Cog):
|
||||
def __init__(self, bot: Client) -> None:
|
||||
super().__init__(bot)
|
||||
|
||||
@commands.command()
|
||||
@command()
|
||||
async def kick(
|
||||
self, ctx: commands.CommandContext, member: Member, *, reason: str = ""
|
||||
self, ctx: CommandContext, member: Member, *, reason: str = ""
|
||||
) -> None:
|
||||
"""Kick a member from the guild."""
|
||||
await member.kick(reason=reason or None)
|
||||
await ctx.reply(f"Kicked {member.display_name}")
|
||||
|
||||
@commands.command()
|
||||
@command()
|
||||
async def ban(
|
||||
self, ctx: commands.CommandContext, member: Member, *, reason: str = ""
|
||||
self, ctx: CommandContext, member: Member, *, reason: str = ""
|
||||
) -> None:
|
||||
"""Ban a member from the guild."""
|
||||
await member.ban(reason=reason or None)
|
||||
|
@ -33,8 +33,10 @@ try:
|
||||
Member,
|
||||
HTTPException,
|
||||
AuthenticationError,
|
||||
Cog,
|
||||
command,
|
||||
CommandContext,
|
||||
)
|
||||
from disagreement.ext import commands
|
||||
except ImportError:
|
||||
print(
|
||||
"Failed to import disagreement. Make sure it's installed or PYTHONPATH is set correctly."
|
||||
@ -72,12 +74,12 @@ client = Client(token=BOT_TOKEN, intents=intents, command_prefix="!")
|
||||
|
||||
|
||||
# --- Define a Cog for reaction-related commands ---
|
||||
class ReactionCog(commands.Cog):
|
||||
class ReactionCog(Cog):
|
||||
def __init__(self, bot_client):
|
||||
super().__init__(bot_client)
|
||||
|
||||
@commands.command(name="react")
|
||||
async def react_command(self, ctx: commands.CommandContext):
|
||||
@command(name="react")
|
||||
async def react_command(self, ctx: CommandContext):
|
||||
"""Reacts to the command message with a thumbs up."""
|
||||
try:
|
||||
# The emoji can be a standard Unicode emoji or a custom one in the format '<:name:id>'
|
||||
|
@ -1,7 +1,7 @@
|
||||
from disagreement.ext import tasks
|
||||
from disagreement import loop
|
||||
|
||||
|
||||
@tasks.loop(seconds=2.0)
|
||||
@loop(seconds=2.0)
|
||||
async def ticker() -> None:
|
||||
print("Extension tick")
|
||||
|
||||
|
@ -8,12 +8,12 @@ import sys
|
||||
if os.path.join(os.getcwd(), "examples") == os.path.dirname(os.path.abspath(__file__)):
|
||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||
|
||||
from disagreement.ext import tasks
|
||||
from disagreement import loop
|
||||
|
||||
counter = 0
|
||||
|
||||
|
||||
@tasks.loop(seconds=1.0)
|
||||
@loop(seconds=1.0)
|
||||
async def ticker() -> None:
|
||||
global counter
|
||||
counter += 1
|
||||
|
@ -24,8 +24,15 @@ if os.path.join(os.getcwd(), "examples") == os.path.dirname(os.path.abspath(__fi
|
||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||
|
||||
try:
|
||||
from disagreement import Client, GatewayIntent, HTTPException, AuthenticationError
|
||||
from disagreement.ext import commands
|
||||
from disagreement import (
|
||||
Client,
|
||||
GatewayIntent,
|
||||
HTTPException,
|
||||
AuthenticationError,
|
||||
Cog,
|
||||
command,
|
||||
CommandContext,
|
||||
)
|
||||
except ImportError:
|
||||
print(
|
||||
"Failed to import disagreement. Make sure it's installed or PYTHONPATH is set correctly."
|
||||
@ -60,12 +67,12 @@ client = Client(token=BOT_TOKEN, intents=intents, command_prefix="!")
|
||||
|
||||
|
||||
# --- Define a Cog for the typing indicator command ---
|
||||
class TypingCog(commands.Cog):
|
||||
class TypingCog(Cog):
|
||||
def __init__(self, bot_client):
|
||||
super().__init__(bot_client)
|
||||
|
||||
@commands.command(name="typing")
|
||||
async def typing_test_command(self, ctx: commands.CommandContext):
|
||||
@command(name="typing")
|
||||
async def typing_test_command(self, ctx: CommandContext):
|
||||
"""Shows a typing indicator for 5 seconds."""
|
||||
await ctx.reply("Showing typing indicator for 5 seconds...")
|
||||
try:
|
||||
|
Loading…
x
Reference in New Issue
Block a user