refactor(init): Consolidate module imports and exports

This commit refactors the `disagreement/__init__.py` file to import and export new models, enums, and components.

The primary changes are:
- Add imports and exports for `Member`, `Role`, `Attachment`, `Channel`, `ActionRow`, `Button`, `SelectOption`, `SelectMenu`, `Embed`, `PartialEmoji`, `Section`, `TextDisplay`, `Thumbnail`, `UnfurledMediaItem`, `MediaGallery`, `MediaGalleryItem`, `Container`, and `Guild` from `disagreement.models`.
- Add imports and exports for `ButtonStyle`, `ChannelType`, `MessageFlags`, `InteractionType`, `InteractionCallbackType`, and `ComponentType` from `disagreement.enums`.
- Add `Interaction` from `disagreement.interactions`.
- Add `ui` and `ext` as top-level modules.
- Update `disagreement.ext/__init__.py` to expose `app_commands`, `commands`, and `tasks`.

These changes consolidate the library's public API, making new features more accessible.
The example files were also updated to use the direct imports from the `disagreement` package or its `ext` subpackage, improving readability and consistency.
This commit is contained in:
Slipstreamm 2025-06-14 18:17:57 -06:00
parent f58ffe8321
commit b039b2e948
15 changed files with 150 additions and 95 deletions

View File

@ -15,7 +15,30 @@ __copyright__ = "Copyright 2025 Slipstream"
__version__ = "0.4.2" __version__ = "0.4.2"
from .client import Client, AutoShardedClient from .client import Client, AutoShardedClient
from .models import Message, User, Reaction, AuditLogEntry from .models import (
Message,
User,
Reaction,
AuditLogEntry,
Member,
Role,
Attachment,
Channel,
ActionRow,
Button,
SelectOption,
SelectMenu,
Embed,
PartialEmoji,
Section,
TextDisplay,
Thumbnail,
UnfurledMediaItem,
MediaGallery,
MediaGalleryItem,
Container,
Guild,
)
from .voice_client import VoiceClient from .voice_client import VoiceClient
from .audio import AudioSource, FFmpegAudioSource from .audio import AudioSource, FFmpegAudioSource
from .typing import Typing from .typing import Typing
@ -29,11 +52,22 @@ from .errors import (
) )
from .color import Color from .color import Color
from .utils import utcnow, message_pager from .utils import utcnow, message_pager
from .enums import GatewayIntent, GatewayOpcode from .enums import (
GatewayIntent,
GatewayOpcode,
ButtonStyle,
ChannelType,
MessageFlags,
InteractionType,
InteractionCallbackType,
ComponentType,
)
from .error_handler import setup_global_error_handler from .error_handler import setup_global_error_handler
from .hybrid_context import HybridContext from .hybrid_context import HybridContext
from .ext import tasks from .interactions import Interaction
from .logging_config import setup_logging from .logging_config import setup_logging
from . import ui, ext
import logging import logging
@ -45,6 +79,23 @@ __all__ = [
"User", "User",
"Reaction", "Reaction",
"AuditLogEntry", "AuditLogEntry",
"Member",
"Role",
"Attachment",
"Channel",
"ActionRow",
"Button",
"SelectOption",
"SelectMenu",
"Embed",
"PartialEmoji",
"Section",
"TextDisplay",
"Thumbnail",
"UnfurledMediaItem",
"MediaGallery",
"MediaGalleryItem",
"Container",
"VoiceClient", "VoiceClient",
"AudioSource", "AudioSource",
"FFmpegAudioSource", "FFmpegAudioSource",
@ -60,10 +111,18 @@ __all__ = [
"message_pager", "message_pager",
"GatewayIntent", "GatewayIntent",
"GatewayOpcode", "GatewayOpcode",
"ButtonStyle",
"ChannelType",
"MessageFlags",
"InteractionType",
"InteractionCallbackType",
"ComponentType",
"setup_global_error_handler", "setup_global_error_handler",
"HybridContext", "HybridContext",
"tasks", "Interaction",
"setup_logging", "setup_logging",
"ui",
"ext",
] ]

View File

@ -1 +1,3 @@
from . import app_commands, commands, tasks
__all__ = ["app_commands", "commands", "tasks"]

View File

@ -27,9 +27,16 @@ 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__), ".."))) sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
try: try:
import disagreement from disagreement import (
from disagreement.models import Guild Client,
from disagreement.ext import commands # Import the new commands extension GatewayIntent,
Message,
Guild,
ext,
AuthenticationError,
DisagreementException,
)
from disagreement.ext import commands
except ImportError: except ImportError:
print( print(
"Failed to import disagreement. Make sure it's installed or PYTHONPATH is set correctly." "Failed to import disagreement. Make sure it's installed or PYTHONPATH is set correctly."
@ -59,15 +66,15 @@ BOT_TOKEN = os.environ.get("DISCORD_BOT_TOKEN")
# --- Intents Configuration --- # --- Intents Configuration ---
# Define the intents your bot needs. For basic message reading and responding: # Define the intents your bot needs. For basic message reading and responding:
intents = ( intents = (
disagreement.GatewayIntent.GUILDS GatewayIntent.GUILDS
| disagreement.GatewayIntent.GUILD_MESSAGES | GatewayIntent.GUILD_MESSAGES
| disagreement.GatewayIntent.MESSAGE_CONTENT | GatewayIntent.MESSAGE_CONTENT
) # MESSAGE_CONTENT is privileged! ) # MESSAGE_CONTENT is privileged!
# If you don't need message content and only react to commands/mentions, # If you don't need message content and only react to commands/mentions,
# you might not need MESSAGE_CONTENT intent. # you might not need MESSAGE_CONTENT intent.
# intents = disagreement.GatewayIntent.default() # A good starting point without privileged intents # intents = GatewayIntent.default() # A good starting point without privileged intents
# intents |= disagreement.GatewayIntent.MESSAGE_CONTENT # Add if needed # intents |= GatewayIntent.MESSAGE_CONTENT # Add if needed
# --- Initialize the Client --- # --- Initialize the Client ---
if not BOT_TOKEN: if not BOT_TOKEN:
@ -76,7 +83,7 @@ if not BOT_TOKEN:
sys.exit(1) sys.exit(1)
# Initialize Client with a command prefix # Initialize Client with a command prefix
client = disagreement.Client(token=BOT_TOKEN, intents=intents, command_prefix="!") client = Client(token=BOT_TOKEN, intents=intents, command_prefix="!")
# --- Define a Cog for example commands --- # --- Define a Cog for example commands ---
@ -177,7 +184,7 @@ async def on_ready():
@client.event @client.event
async def on_message(message: disagreement.Message): async def on_message(message: Message):
"""Called when a message is created and received.""" """Called when a message is created and received."""
# Command processing is now handled by the CommandHandler via client._process_message_for_commands # Command processing is now handled by the CommandHandler via client._process_message_for_commands
# This on_message can be used for other message-related logic if needed, # This on_message can be used for other message-related logic if needed,
@ -210,11 +217,11 @@ async def main():
# client.add_cog is synchronous, but it schedules cog.cog_load() if it's async. # client.add_cog is synchronous, but it schedules cog.cog_load() if it's async.
await client.run() await client.run()
except disagreement.AuthenticationError: except AuthenticationError:
print( print(
"Authentication failed. Please check your bot token and ensure it's correct." "Authentication failed. Please check your bot token and ensure it's correct."
) )
except disagreement.DisagreementException as e: except DisagreementException as e:
print(f"A Disagreement library error occurred: {e}") print(f"A Disagreement library error occurred: {e}")
except KeyboardInterrupt: except KeyboardInterrupt:
print("Bot shutting down due to KeyboardInterrupt...") print("Bot shutting down due to KeyboardInterrupt...")

View File

@ -1,8 +1,11 @@
import os import os
import asyncio import asyncio
from typing import Union, Optional from typing import Union
from disagreement import Client, ui, HybridContext from disagreement import (
from disagreement.models import ( Client,
ui,
ext,
HybridContext,
Message, Message,
SelectOption, SelectOption,
User, User,
@ -19,24 +22,14 @@ from disagreement.models import (
MediaGallery, MediaGallery,
MediaGalleryItem, MediaGalleryItem,
Container, Container,
)
from disagreement.enums import (
ButtonStyle, ButtonStyle,
GatewayIntent, GatewayIntent,
ChannelType, ChannelType,
MessageFlags, MessageFlags,
InteractionCallbackType,
MessageFlags,
)
from disagreement.ext.commands.cog import Cog
from disagreement.ext.commands.core import CommandContext
from disagreement.ext.app_commands.decorators import hybrid_command, slash_command
from disagreement.ext.app_commands.context import AppCommandContext
from disagreement.interactions import (
Interaction, Interaction,
InteractionResponsePayload,
InteractionCallbackData,
) )
from disagreement.ext.commands import Cog, CommandContext
from disagreement.ext.app_commands import AppCommandContext, hybrid_command
try: try:
from dotenv import load_dotenv from dotenv import load_dotenv

View File

@ -7,13 +7,12 @@ import sys
if os.path.join(os.getcwd(), "examples") == os.path.dirname(os.path.abspath(__file__)): 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__), ".."))) sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
from disagreement.client import Client from disagreement import Client, User, Message
from disagreement.ext.app_commands import ( from disagreement.ext.app_commands import (
user_command, user_command,
message_command, message_command,
AppCommandContext, AppCommandContext,
) )
from disagreement.models import User, Message
try: try:
from dotenv import load_dotenv from dotenv import load_dotenv

View File

@ -4,7 +4,7 @@
import asyncio import asyncio
import os import os
import disagreement from disagreement import Client, GatewayIntent
from disagreement.ext import commands from disagreement.ext import commands
from dotenv import load_dotenv from dotenv import load_dotenv
@ -12,7 +12,7 @@ load_dotenv()
class Basics(commands.Cog): class Basics(commands.Cog):
def __init__(self, client: disagreement.Client) -> None: def __init__(self, client: Client) -> None:
super().__init__(client) super().__init__(client)
@commands.command() @commands.command()
@ -24,12 +24,8 @@ token = os.getenv("DISCORD_BOT_TOKEN")
if not token: if not token:
raise RuntimeError("DISCORD_BOT_TOKEN environment variable not set") raise RuntimeError("DISCORD_BOT_TOKEN environment variable not set")
intents = ( intents = GatewayIntent.default() | GatewayIntent.MESSAGE_CONTENT
disagreement.GatewayIntent.default() | disagreement.GatewayIntent.MESSAGE_CONTENT client = Client(token=token, command_prefix="!", intents=intents, mention_replies=True)
)
client = disagreement.Client(
token=token, command_prefix="!", intents=intents, mention_replies=True
)
async def main() -> None: async def main() -> None:

View File

@ -3,32 +3,27 @@ import os
import logging import logging
from typing import Any, Optional, Literal, Union from typing import Any, Optional, Literal, Union
from disagreement import HybridContext from disagreement import (
HybridContext,
from disagreement.client import Client Client,
from disagreement.ext.commands.cog import Cog
from disagreement.ext.commands.core import CommandContext
from disagreement.ext.app_commands.decorators import (
slash_command,
user_command,
message_command,
hybrid_command,
)
from disagreement.ext.app_commands.commands import (
AppCommandGroup,
) # For defining groups
from disagreement.ext.app_commands.context import AppCommandContext # Added
from disagreement.models import (
User, User,
Member, Member,
Role, Role,
Attachment, Attachment,
Message, Message,
Channel, Channel,
) # For type hints
from disagreement.enums import (
ChannelType, ChannelType,
) # For channel option type hints, assuming it exists )
from disagreement.ext import commands
from disagreement.ext.commands import Cog, CommandContext
from disagreement.ext.app_commands import (
AppCommandContext,
AppCommandGroup,
slash_command,
user_command,
message_command,
hybrid_command,
)
# from disagreement.interactions import Interaction # Replaced by AppCommandContext # from disagreement.interactions import Interaction # Replaced by AppCommandContext

View File

@ -8,7 +8,7 @@ import sys
if os.path.join(os.getcwd(), "examples") == os.path.dirname(os.path.abspath(__file__)): 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__), ".."))) sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
from disagreement.client import Client from disagreement import Client, Channel
from disagreement.models import TextChannel from disagreement.models import TextChannel
try: try:

View File

@ -9,10 +9,9 @@ except ImportError: # pragma: no cover - example helper
load_dotenv = None load_dotenv = None
print("python-dotenv is not installed. Environment variables will not be loaded") print("python-dotenv is not installed. Environment variables will not be loaded")
from disagreement import Client, ui from disagreement import Client, ui, GatewayIntent
from disagreement.enums import GatewayIntent, TextInputStyle from disagreement.enums import TextInputStyle
from disagreement.ext.app_commands.decorators import slash_command from disagreement.ext.app_commands import slash_command, AppCommandContext
from disagreement.ext.app_commands.context import AppCommandContext
if load_dotenv: if load_dotenv:
load_dotenv() load_dotenv()

View File

@ -11,9 +11,8 @@ except ImportError: # pragma: no cover - example helper
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
from disagreement import Client, GatewayIntent, ui # type: ignore from disagreement import Client, GatewayIntent, ui
from disagreement.ext.app_commands.decorators import slash_command from disagreement.ext.app_commands import slash_command, AppCommandContext
from disagreement.ext.app_commands.context import AppCommandContext
if load_dotenv: if load_dotenv:
load_dotenv() load_dotenv()

View File

@ -9,9 +9,8 @@ from typing import Set
if os.path.join(os.getcwd(), "examples") == os.path.dirname(os.path.abspath(__file__)): 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__), ".."))) sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
import disagreement from disagreement import Client, GatewayIntent, Member, Message
from disagreement.ext import commands from disagreement.ext import commands
from disagreement.models import Member, Message
try: try:
from dotenv import load_dotenv from dotenv import load_dotenv
@ -28,18 +27,18 @@ if not BOT_TOKEN:
sys.exit(1) sys.exit(1)
intents = ( intents = (
disagreement.GatewayIntent.GUILDS GatewayIntent.GUILDS
| disagreement.GatewayIntent.GUILD_MESSAGES | GatewayIntent.GUILD_MESSAGES
| disagreement.GatewayIntent.MESSAGE_CONTENT | GatewayIntent.MESSAGE_CONTENT
) )
client = disagreement.Client(token=BOT_TOKEN, command_prefix="!", intents=intents) client = Client(token=BOT_TOKEN, command_prefix="!", intents=intents)
# Simple list of banned words # Simple list of banned words
BANNED_WORDS: Set[str] = {"badword1", "badword2"} BANNED_WORDS: Set[str] = {"badword1", "badword2"}
class ModerationCog(commands.Cog): class ModerationCog(commands.Cog):
def __init__(self, bot: disagreement.Client) -> None: def __init__(self, bot: Client) -> None:
super().__init__(bot) super().__init__(bot)
@commands.command() @commands.command()

View File

@ -25,9 +25,16 @@ 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__), ".."))) sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
try: try:
import disagreement from disagreement import (
Client,
GatewayIntent,
Reaction,
User,
Member,
HTTPException,
AuthenticationError,
)
from disagreement.ext import commands from disagreement.ext import commands
from disagreement.models import Reaction, User, Member
except ImportError: except ImportError:
print( print(
"Failed to import disagreement. Make sure it's installed or PYTHONPATH is set correctly." "Failed to import disagreement. Make sure it's installed or PYTHONPATH is set correctly."
@ -50,10 +57,10 @@ BOT_TOKEN = os.environ.get("DISCORD_BOT_TOKEN")
# We need GUILDS for server context, GUILD_MESSAGES to receive messages, # We need GUILDS for server context, GUILD_MESSAGES to receive messages,
# and GUILD_MESSAGE_REACTIONS to listen for reaction events. # and GUILD_MESSAGE_REACTIONS to listen for reaction events.
intents = ( intents = (
disagreement.GatewayIntent.GUILDS GatewayIntent.GUILDS
| disagreement.GatewayIntent.GUILD_MESSAGES | GatewayIntent.GUILD_MESSAGES
| disagreement.GatewayIntent.GUILD_MESSAGE_REACTIONS | GatewayIntent.GUILD_MESSAGE_REACTIONS
| disagreement.GatewayIntent.MESSAGE_CONTENT # For commands | GatewayIntent.MESSAGE_CONTENT # For commands
) )
# --- Initialize the Client --- # --- Initialize the Client ---
@ -61,7 +68,7 @@ if not BOT_TOKEN:
print("Error: The DISCORD_BOT_TOKEN environment variable is not set.") print("Error: The DISCORD_BOT_TOKEN environment variable is not set.")
sys.exit(1) sys.exit(1)
client = disagreement.Client(token=BOT_TOKEN, intents=intents, command_prefix="!") client = Client(token=BOT_TOKEN, intents=intents, command_prefix="!")
# --- Define a Cog for reaction-related commands --- # --- Define a Cog for reaction-related commands ---
@ -76,7 +83,7 @@ class ReactionCog(commands.Cog):
# The emoji can be a standard Unicode emoji or a custom one in the format '<:name:id>' # The emoji can be a standard Unicode emoji or a custom one in the format '<:name:id>'
await ctx.message.add_reaction("👍") await ctx.message.add_reaction("👍")
print(f"Reacted to command from {ctx.author.username}") print(f"Reacted to command from {ctx.author.username}")
except disagreement.HTTPException as e: except HTTPException as e:
print(f"Failed to add reaction: {e}") print(f"Failed to add reaction: {e}")
await ctx.reply( await ctx.reply(
"I couldn't add the reaction. I might be missing permissions." "I couldn't add the reaction. I might be missing permissions."
@ -133,7 +140,7 @@ async def main():
try: try:
client.add_cog(ReactionCog(client)) client.add_cog(ReactionCog(client))
await client.run() await client.run()
except disagreement.AuthenticationError: except AuthenticationError:
print("Authentication failed. Check your bot token.") print("Authentication failed. Check your bot token.")
except Exception as e: except Exception as e:
print(f"An unexpected error occurred: {e}") print(f"An unexpected error occurred: {e}")

View File

@ -8,7 +8,7 @@ import sys
if os.path.join(os.getcwd(), "examples") == os.path.dirname(os.path.abspath(__file__)): 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__), ".."))) sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
import disagreement from disagreement import Client
try: try:
from dotenv import load_dotenv from dotenv import load_dotenv
@ -23,7 +23,7 @@ TOKEN = os.environ.get("DISCORD_BOT_TOKEN")
if not TOKEN: if not TOKEN:
raise RuntimeError("DISCORD_BOT_TOKEN environment variable not set") raise RuntimeError("DISCORD_BOT_TOKEN environment variable not set")
client = disagreement.Client(token=TOKEN, shard_count=2) client = Client(token=TOKEN, shard_count=2)
@client.event @client.event

View File

@ -24,7 +24,7 @@ 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__), ".."))) sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
try: try:
import disagreement from disagreement import Client, GatewayIntent, HTTPException, AuthenticationError
from disagreement.ext import commands from disagreement.ext import commands
except ImportError: except ImportError:
print( print(
@ -46,9 +46,9 @@ BOT_TOKEN = os.environ.get("DISCORD_BOT_TOKEN")
# --- Intents Configuration --- # --- Intents Configuration ---
intents = ( intents = (
disagreement.GatewayIntent.GUILDS GatewayIntent.GUILDS
| disagreement.GatewayIntent.GUILD_MESSAGES | GatewayIntent.GUILD_MESSAGES
| disagreement.GatewayIntent.MESSAGE_CONTENT | GatewayIntent.MESSAGE_CONTENT
) )
# --- Initialize the Client --- # --- Initialize the Client ---
@ -56,7 +56,7 @@ if not BOT_TOKEN:
print("Error: The DISCORD_BOT_TOKEN environment variable is not set.") print("Error: The DISCORD_BOT_TOKEN environment variable is not set.")
sys.exit(1) sys.exit(1)
client = disagreement.Client(token=BOT_TOKEN, intents=intents, command_prefix="!") client = Client(token=BOT_TOKEN, intents=intents, command_prefix="!")
# --- Define a Cog for the typing indicator command --- # --- Define a Cog for the typing indicator command ---
@ -76,7 +76,7 @@ class TypingCog(commands.Cog):
await asyncio.sleep(5) await asyncio.sleep(5)
print("Typing indicator stopped.") print("Typing indicator stopped.")
await ctx.send("Done!") await ctx.send("Done!")
except disagreement.HTTPException as e: except HTTPException as e:
print(f"Failed to send typing indicator: {e}") print(f"Failed to send typing indicator: {e}")
await ctx.reply( await ctx.reply(
"I couldn't show the typing indicator. I might be missing permissions." "I couldn't show the typing indicator. I might be missing permissions."
@ -104,7 +104,7 @@ async def main():
try: try:
client.add_cog(TypingCog(client)) client.add_cog(TypingCog(client))
await client.run() await client.run()
except disagreement.AuthenticationError: except AuthenticationError:
print("Authentication failed. Check your bot token.") print("Authentication failed. Check your bot token.")
except Exception as e: except Exception as e:
print(f"An unexpected error occurred: {e}") print(f"An unexpected error occurred: {e}")

View File

@ -16,7 +16,7 @@ except ImportError: # pragma: no cover - example helper
load_dotenv = None load_dotenv = None
print("python-dotenv is not installed. Environment variables will not be loaded") print("python-dotenv is not installed. Environment variables will not be loaded")
import disagreement from disagreement import Client
if load_dotenv: if load_dotenv:
load_dotenv() load_dotenv()
@ -39,7 +39,7 @@ CHANNEL_ID = cast(str, _CHANNEL_ID)
async def main() -> None: async def main() -> None:
client = disagreement.Client(TOKEN) client = Client(TOKEN)
await client.connect() await client.connect()
voice = await client.join_voice(GUILD_ID, CHANNEL_ID) voice = await client.join_voice(GUILD_ID, CHANNEL_ID)
try: try: