refactor(api): Re-export common symbols from top-level package
Some checks failed
Deploy MkDocs / deploy (push) Has been cancelled
Some checks failed
Deploy MkDocs / deploy (push) Has been cancelled
Makes commonly used classes, functions, and decorators from `disagreement.ext` and `disagreement.ui` submodules directly accessible under the `disagreement` namespace. This change simplifies import statements for users, leading to cleaner and more concise code. Documentation and examples have been updated to reflect these new, simplified import paths.
This commit is contained in:
parent
9237d12a24
commit
e965a675c1
@ -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,7 +56,7 @@ 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 import command, requires_permissions
|
||||
from disagreement import Permissions
|
||||
|
||||
@command()
|
||||
|
@ -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 import User, Message
|
||||
from disagreement.ext.app_commands import user_command, message_command, AppCommandContext
|
||||
from disagreement import User, Message, user_command, message_command, AppCommandContext
|
||||
|
||||
@user_command(name="User Info")
|
||||
async def user_info(ctx: AppCommandContext, user: User) -> None:
|
||||
|
@ -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():
|
||||
...
|
||||
```
|
||||
|
@ -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