disagreement 0.1.0rc3__tar.gz → 0.2.0rc1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. {disagreement-0.1.0rc3/disagreement.egg-info → disagreement-0.2.0rc1}/PKG-INFO +17 -1
  2. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/README.md +16 -0
  3. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/__init__.py +2 -2
  4. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/client.py +198 -2
  5. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/color.py +100 -1
  6. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/enums.py +63 -0
  7. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/ext/app_commands/commands.py +0 -2
  8. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/ext/app_commands/handler.py +101 -30
  9. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/ext/commands/__init__.py +4 -0
  10. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/ext/commands/core.py +51 -1
  11. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/ext/commands/decorators.py +27 -0
  12. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/ext/commands/errors.py +8 -0
  13. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/gateway.py +11 -0
  14. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/http.py +172 -6
  15. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/models.py +203 -4
  16. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1/disagreement.egg-info}/PKG-INFO +17 -1
  17. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement.egg-info/SOURCES.txt +7 -0
  18. disagreement-0.2.0rc1/docs/audit_logs.md +15 -0
  19. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/docs/caching.md +1 -0
  20. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/docs/events.md +33 -0
  21. disagreement-0.2.0rc1/docs/http_client.md +20 -0
  22. disagreement-0.2.0rc1/docs/invites.md +24 -0
  23. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/docs/message_history.md +2 -0
  24. disagreement-0.2.0rc1/docs/scheduled_events.md +26 -0
  25. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/docs/slash_commands.md +12 -0
  26. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/docs/using_components.md +1 -0
  27. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/docs/voice_client.md +11 -0
  28. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/docs/voice_features.md +1 -0
  29. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/pyproject.toml +1 -1
  30. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_color.py +3 -0
  31. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_command_checks.py +1 -0
  32. disagreement-0.2.0rc1/tests/test_max_concurrency.py +103 -0
  33. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_sharding.py +49 -1
  34. disagreement-0.2.0rc1/tests/test_stage_instance.py +63 -0
  35. disagreement-0.2.0rc1/tests/test_templates.py +42 -0
  36. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/LICENSE +0 -0
  37. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/MANIFEST.in +0 -0
  38. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/audio.py +0 -0
  39. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/cache.py +0 -0
  40. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/components.py +0 -0
  41. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/error_handler.py +0 -0
  42. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/errors.py +0 -0
  43. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/event_dispatcher.py +0 -0
  44. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/ext/__init__.py +0 -0
  45. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/ext/app_commands/__init__.py +0 -0
  46. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/ext/app_commands/context.py +0 -0
  47. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/ext/app_commands/converters.py +0 -0
  48. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/ext/app_commands/decorators.py +0 -0
  49. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/ext/app_commands/hybrid.py +0 -0
  50. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/ext/commands/cog.py +0 -0
  51. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/ext/commands/converters.py +0 -0
  52. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/ext/commands/help.py +0 -0
  53. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/ext/commands/view.py +0 -0
  54. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/ext/loader.py +0 -0
  55. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/ext/tasks.py +0 -0
  56. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/hybrid_context.py +0 -0
  57. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/i18n.py +0 -0
  58. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/interactions.py +0 -0
  59. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/logging_config.py +0 -0
  60. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/oauth.py +0 -0
  61. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/permissions.py +0 -0
  62. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/py.typed +0 -0
  63. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/rate_limiter.py +0 -0
  64. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/shard_manager.py +0 -0
  65. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/typing.py +0 -0
  66. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/ui/__init__.py +0 -0
  67. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/ui/button.py +0 -0
  68. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/ui/item.py +0 -0
  69. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/ui/modal.py +0 -0
  70. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/ui/select.py +0 -0
  71. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/ui/view.py +0 -0
  72. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/utils.py +0 -0
  73. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement/voice_client.py +0 -0
  74. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement.egg-info/dependency_links.txt +0 -0
  75. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement.egg-info/requires.txt +0 -0
  76. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/disagreement.egg-info/top_level.txt +0 -0
  77. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/docs/commands.md +0 -0
  78. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/docs/context_menus.md +0 -0
  79. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/docs/converters.md +0 -0
  80. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/docs/extension_loader.md +0 -0
  81. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/docs/gateway.md +0 -0
  82. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/docs/i18n.md +0 -0
  83. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/docs/oauth2.md +0 -0
  84. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/docs/permissions.md +0 -0
  85. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/docs/presence.md +0 -0
  86. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/docs/reactions.md +0 -0
  87. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/docs/sharding.md +0 -0
  88. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/docs/task_loop.md +0 -0
  89. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/docs/typing_indicator.md +0 -0
  90. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/docs/webhooks.md +0 -0
  91. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/examples/basic_bot.py +0 -0
  92. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/examples/component_bot.py +0 -0
  93. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/examples/context_menus.py +0 -0
  94. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/examples/extension_management.py +0 -0
  95. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/examples/hybrid_bot.py +0 -0
  96. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/examples/message_history.py +0 -0
  97. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/examples/modal_command.py +0 -0
  98. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/examples/modal_send.py +0 -0
  99. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/examples/sample_extension.py +0 -0
  100. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/examples/sharded_bot.py +0 -0
  101. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/examples/task_loop.py +0 -0
  102. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/examples/voice_bot.py +0 -0
  103. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/setup.cfg +0 -0
  104. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_additional_converters.py +0 -0
  105. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_cache.py +0 -0
  106. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_channel_permissions.py +0 -0
  107. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_client_context_manager.py +0 -0
  108. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_color_acceptance.py +0 -0
  109. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_components_factory.py +0 -0
  110. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_context.py +0 -0
  111. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_context_menus.py +0 -0
  112. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_converter_registration.py +0 -0
  113. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_converters.py +0 -0
  114. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_error_handler.py +0 -0
  115. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_errors.py +0 -0
  116. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_event_dispatcher.py +0 -0
  117. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_event_error_hook.py +0 -0
  118. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_extension_loader.py +0 -0
  119. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_gateway_backoff.py +0 -0
  120. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_gateway_intent.py +0 -0
  121. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_help_command.py +0 -0
  122. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_http_rate_limit.py +0 -0
  123. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_http_reactions.py +0 -0
  124. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_hybrid_context.py +0 -0
  125. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_i18n.py +0 -0
  126. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_interaction.py +0 -0
  127. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_logging_config.py +0 -0
  128. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_member.py +0 -0
  129. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_message_pager.py +0 -0
  130. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_modal_send.py +0 -0
  131. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_modals.py +0 -0
  132. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_oauth.py +0 -0
  133. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_permissions.py +0 -0
  134. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_presence_and_typing.py +0 -0
  135. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_presence_update.py +0 -0
  136. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_rate_limiter.py +0 -0
  137. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_reactions.py +0 -0
  138. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_send_files.py +0 -0
  139. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_slash_contexts.py +0 -0
  140. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_tasks_extension.py +0 -0
  141. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_textchannel_history.py +0 -0
  142. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_textchannel_purge.py +0 -0
  143. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_typing_indicator.py +0 -0
  144. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_ui.py +0 -0
  145. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_utils.py +0 -0
  146. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_view_layout.py +0 -0
  147. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_voice_client.py +0 -0
  148. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_wait_for.py +0 -0
  149. {disagreement-0.1.0rc3 → disagreement-0.2.0rc1}/tests/test_webhooks.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: disagreement
3
- Version: 0.1.0rc3
3
+ Version: 0.2.0rc1
4
4
  Summary: A Python library for the Discord API.
5
5
  Author-email: Slipstream <me@slipstreamm.dev>
6
6
  License: BSD 3-Clause
@@ -119,6 +119,22 @@ setup_logging(logging.INFO)
119
119
  setup_logging(logging.DEBUG, file="bot.log")
120
120
  ```
121
121
 
122
+ ### HTTP Session Options
123
+
124
+ Pass additional keyword arguments to ``aiohttp.ClientSession`` using the
125
+ ``http_options`` parameter when constructing :class:`disagreement.Client`:
126
+
127
+ ```python
128
+ client = disagreement.Client(
129
+ token=token,
130
+ http_options={"proxy": "http://localhost:8080"},
131
+ )
132
+ ```
133
+
134
+ These options are forwarded to ``HTTPClient`` when it creates the underlying
135
+ ``aiohttp.ClientSession``. You can specify a custom ``connector`` or any other
136
+ session parameter supported by ``aiohttp``.
137
+
122
138
  ### Defining Subcommands with `AppCommandGroup`
123
139
 
124
140
  ```python
@@ -86,6 +86,22 @@ setup_logging(logging.INFO)
86
86
  setup_logging(logging.DEBUG, file="bot.log")
87
87
  ```
88
88
 
89
+ ### HTTP Session Options
90
+
91
+ Pass additional keyword arguments to ``aiohttp.ClientSession`` using the
92
+ ``http_options`` parameter when constructing :class:`disagreement.Client`:
93
+
94
+ ```python
95
+ client = disagreement.Client(
96
+ token=token,
97
+ http_options={"proxy": "http://localhost:8080"},
98
+ )
99
+ ```
100
+
101
+ These options are forwarded to ``HTTPClient`` when it creates the underlying
102
+ ``aiohttp.ClientSession``. You can specify a custom ``connector`` or any other
103
+ session parameter supported by ``aiohttp``.
104
+
89
105
  ### Defining Subcommands with `AppCommandGroup`
90
106
 
91
107
  ```python
@@ -14,10 +14,10 @@ __title__ = "disagreement"
14
14
  __author__ = "Slipstream"
15
15
  __license__ = "BSD 3-Clause License"
16
16
  __copyright__ = "Copyright 2025 Slipstream"
17
- __version__ = "0.1.0rc3"
17
+ __version__ = "0.2.0rc1"
18
18
 
19
19
  from .client import Client, AutoShardedClient
20
- from .models import Message, User, Reaction
20
+ from .models import Message, User, Reaction, AuditLogEntry
21
21
  from .voice_client import VoiceClient
22
22
  from .audio import AudioSource, FFmpegAudioSource
23
23
  from .typing import Typing
@@ -12,6 +12,7 @@ from typing import (
12
12
  Any,
13
13
  TYPE_CHECKING,
14
14
  Awaitable,
15
+ AsyncIterator,
15
16
  Union,
16
17
  List,
17
18
  Dict,
@@ -22,7 +23,7 @@ from .http import HTTPClient
22
23
  from .gateway import GatewayClient
23
24
  from .shard_manager import ShardManager
24
25
  from .event_dispatcher import EventDispatcher
25
- from .enums import GatewayIntent, InteractionType, GatewayOpcode
26
+ from .enums import GatewayIntent, InteractionType, GatewayOpcode, VoiceRegion
26
27
  from .errors import DisagreementException, AuthenticationError
27
28
  from .typing import Typing
28
29
  from .ext.commands.core import CommandHandler
@@ -50,6 +51,10 @@ if TYPE_CHECKING:
50
51
  Thread,
51
52
  DMChannel,
52
53
  Webhook,
54
+ GuildTemplate,
55
+ ScheduledEvent,
56
+ AuditLogEntry,
57
+ Invite,
53
58
  )
54
59
  from .ui.view import View
55
60
  from .enums import ChannelType as EnumChannelType
@@ -72,6 +77,9 @@ class Client:
72
77
  command_prefix (Union[str, List[str], Callable[['Client', Message], Union[str, List[str]]]]):
73
78
  The prefix(es) for commands. Defaults to '!'.
74
79
  verbose (bool): If True, print raw HTTP and Gateway traffic for debugging.
80
+ http_options (Optional[Dict[str, Any]]): Extra options passed to
81
+ :class:`HTTPClient` for creating the internal
82
+ :class:`aiohttp.ClientSession`.
75
83
  """
76
84
 
77
85
  def __init__(
@@ -88,6 +96,7 @@ class Client:
88
96
  shard_count: Optional[int] = None,
89
97
  gateway_max_retries: int = 5,
90
98
  gateway_max_backoff: float = 60.0,
99
+ http_options: Optional[Dict[str, Any]] = None,
91
100
  ):
92
101
  if not token:
93
102
  raise ValueError("A bot token must be provided.")
@@ -101,7 +110,11 @@ class Client:
101
110
  setup_global_error_handler(self.loop)
102
111
 
103
112
  self.verbose: bool = verbose
104
- self._http: HTTPClient = HTTPClient(token=self.token, verbose=verbose)
113
+ self._http: HTTPClient = HTTPClient(
114
+ token=self.token,
115
+ verbose=verbose,
116
+ **(http_options or {}),
117
+ )
105
118
  self._event_dispatcher: EventDispatcher = EventDispatcher(client_instance=self)
106
119
  self._gateway: Optional[GatewayClient] = (
107
120
  None # Initialized in run() or connect()
@@ -698,6 +711,40 @@ class Client:
698
711
  self._webhooks[webhook.id] = webhook
699
712
  return webhook
700
713
 
714
+ def parse_template(self, data: Dict[str, Any]) -> "GuildTemplate":
715
+ """Parses template data into a GuildTemplate object."""
716
+
717
+ from .models import GuildTemplate
718
+
719
+ return GuildTemplate(data, client_instance=self)
720
+
721
+ def parse_scheduled_event(self, data: Dict[str, Any]) -> "ScheduledEvent":
722
+ """Parses scheduled event data and updates cache."""
723
+
724
+ from .models import ScheduledEvent
725
+
726
+ event = ScheduledEvent(data, client_instance=self)
727
+ # Cache by ID under guild if guild cache exists
728
+ guild = self._guilds.get(event.guild_id)
729
+ if guild is not None:
730
+ events = getattr(guild, "_scheduled_events", {})
731
+ events[event.id] = event
732
+ setattr(guild, "_scheduled_events", events)
733
+ return event
734
+
735
+ def parse_audit_log_entry(self, data: Dict[str, Any]) -> "AuditLogEntry":
736
+ """Parses audit log entry data."""
737
+ from .models import AuditLogEntry
738
+
739
+ return AuditLogEntry(data, client_instance=self)
740
+
741
+ def parse_invite(self, data: Dict[str, Any]) -> "Invite":
742
+ """Parses invite data into an :class:`Invite`."""
743
+
744
+ from .models import Invite
745
+
746
+ return Invite.from_dict(data)
747
+
701
748
  async def fetch_user(self, user_id: Snowflake) -> Optional["User"]:
702
749
  """Fetches a user by ID from Discord."""
703
750
  if self._closed:
@@ -1219,6 +1266,31 @@ class Client:
1219
1266
  print(f"Failed to fetch channel {channel_id}: {e}")
1220
1267
  return None
1221
1268
 
1269
+ async def fetch_audit_logs(
1270
+ self, guild_id: Snowflake, **filters: Any
1271
+ ) -> AsyncIterator["AuditLogEntry"]:
1272
+ """Fetch audit log entries for a guild."""
1273
+ if self._closed:
1274
+ raise DisagreementException("Client is closed.")
1275
+
1276
+ data = await self._http.get_audit_logs(guild_id, **filters)
1277
+ for entry in data.get("audit_log_entries", []):
1278
+ yield self.parse_audit_log_entry(entry)
1279
+
1280
+ async def fetch_voice_regions(self) -> List[VoiceRegion]:
1281
+ """Fetches available voice regions."""
1282
+
1283
+ if self._closed:
1284
+ raise DisagreementException("Client is closed.")
1285
+
1286
+ data = await self._http.get_voice_regions()
1287
+ regions = []
1288
+ for region in data:
1289
+ region_id = region.get("id")
1290
+ if region_id:
1291
+ regions.append(VoiceRegion(region_id))
1292
+ return regions
1293
+
1222
1294
  async def create_webhook(
1223
1295
  self, channel_id: Snowflake, payload: Dict[str, Any]
1224
1296
  ) -> "Webhook":
@@ -1249,6 +1321,130 @@ class Client:
1249
1321
 
1250
1322
  await self._http.delete_webhook(webhook_id)
1251
1323
 
1324
+ async def fetch_templates(self, guild_id: Snowflake) -> List["GuildTemplate"]:
1325
+ """|coro| Fetch all templates for a guild."""
1326
+
1327
+ if self._closed:
1328
+ raise DisagreementException("Client is closed.")
1329
+
1330
+ data = await self._http.get_guild_templates(guild_id)
1331
+ return [self.parse_template(t) for t in data]
1332
+
1333
+ async def create_template(
1334
+ self, guild_id: Snowflake, payload: Dict[str, Any]
1335
+ ) -> "GuildTemplate":
1336
+ """|coro| Create a template for a guild."""
1337
+
1338
+ if self._closed:
1339
+ raise DisagreementException("Client is closed.")
1340
+
1341
+ data = await self._http.create_guild_template(guild_id, payload)
1342
+ return self.parse_template(data)
1343
+
1344
+ async def sync_template(
1345
+ self, guild_id: Snowflake, template_code: str
1346
+ ) -> "GuildTemplate":
1347
+ """|coro| Sync a template to the guild's current state."""
1348
+
1349
+ if self._closed:
1350
+ raise DisagreementException("Client is closed.")
1351
+
1352
+ data = await self._http.sync_guild_template(guild_id, template_code)
1353
+ return self.parse_template(data)
1354
+
1355
+ async def delete_template(self, guild_id: Snowflake, template_code: str) -> None:
1356
+ """|coro| Delete a guild template."""
1357
+
1358
+ if self._closed:
1359
+ raise DisagreementException("Client is closed.")
1360
+
1361
+ await self._http.delete_guild_template(guild_id, template_code)
1362
+
1363
+ async def fetch_scheduled_events(
1364
+ self, guild_id: Snowflake
1365
+ ) -> List["ScheduledEvent"]:
1366
+ """|coro| Fetch all scheduled events for a guild."""
1367
+
1368
+ if self._closed:
1369
+ raise DisagreementException("Client is closed.")
1370
+
1371
+ data = await self._http.get_guild_scheduled_events(guild_id)
1372
+ return [self.parse_scheduled_event(ev) for ev in data]
1373
+
1374
+ async def fetch_scheduled_event(
1375
+ self, guild_id: Snowflake, event_id: Snowflake
1376
+ ) -> Optional["ScheduledEvent"]:
1377
+ """|coro| Fetch a single scheduled event."""
1378
+
1379
+ if self._closed:
1380
+ raise DisagreementException("Client is closed.")
1381
+
1382
+ try:
1383
+ data = await self._http.get_guild_scheduled_event(guild_id, event_id)
1384
+ return self.parse_scheduled_event(data)
1385
+ except DisagreementException as e:
1386
+ print(f"Failed to fetch scheduled event {event_id}: {e}")
1387
+ return None
1388
+
1389
+ async def create_scheduled_event(
1390
+ self, guild_id: Snowflake, payload: Dict[str, Any]
1391
+ ) -> "ScheduledEvent":
1392
+ """|coro| Create a scheduled event in a guild."""
1393
+
1394
+ if self._closed:
1395
+ raise DisagreementException("Client is closed.")
1396
+
1397
+ data = await self._http.create_guild_scheduled_event(guild_id, payload)
1398
+ return self.parse_scheduled_event(data)
1399
+
1400
+ async def edit_scheduled_event(
1401
+ self, guild_id: Snowflake, event_id: Snowflake, payload: Dict[str, Any]
1402
+ ) -> "ScheduledEvent":
1403
+ """|coro| Edit an existing scheduled event."""
1404
+
1405
+ if self._closed:
1406
+ raise DisagreementException("Client is closed.")
1407
+
1408
+ data = await self._http.edit_guild_scheduled_event(guild_id, event_id, payload)
1409
+ return self.parse_scheduled_event(data)
1410
+
1411
+ async def delete_scheduled_event(
1412
+ self, guild_id: Snowflake, event_id: Snowflake
1413
+ ) -> None:
1414
+ """|coro| Delete a scheduled event."""
1415
+
1416
+ if self._closed:
1417
+ raise DisagreementException("Client is closed.")
1418
+
1419
+ await self._http.delete_guild_scheduled_event(guild_id, event_id)
1420
+
1421
+ async def create_invite(
1422
+ self, channel_id: Snowflake, payload: Dict[str, Any]
1423
+ ) -> "Invite":
1424
+ """|coro| Create an invite for the given channel."""
1425
+
1426
+ if self._closed:
1427
+ raise DisagreementException("Client is closed.")
1428
+
1429
+ return await self._http.create_invite(channel_id, payload)
1430
+
1431
+ async def delete_invite(self, code: str) -> None:
1432
+ """|coro| Delete an invite by code."""
1433
+
1434
+ if self._closed:
1435
+ raise DisagreementException("Client is closed.")
1436
+
1437
+ await self._http.delete_invite(code)
1438
+
1439
+ async def fetch_invites(self, channel_id: Snowflake) -> List["Invite"]:
1440
+ """|coro| Fetch all invites for a channel."""
1441
+
1442
+ if self._closed:
1443
+ raise DisagreementException("Client is closed.")
1444
+
1445
+ data = await self._http.get_channel_invites(channel_id)
1446
+ return [self.parse_invite(inv) for inv in data]
1447
+
1252
1448
  # --- Application Command Methods ---
1253
1449
  async def process_interaction(self, interaction: Interaction) -> None:
1254
1450
  """Internal method to process an interaction from the gateway."""
@@ -46,11 +46,110 @@ class Color:
46
46
  def blue(cls) -> "Color":
47
47
  return cls(0x0000FF)
48
48
 
49
+ # Discord brand colors
50
+ @classmethod
51
+ def blurple(cls) -> "Color":
52
+ """Discord brand blurple (#5865F2)."""
53
+ return cls(0x5865F2)
54
+
55
+ @classmethod
56
+ def light_blurple(cls) -> "Color":
57
+ """Light blurple used by Discord (#E0E3FF)."""
58
+ return cls(0xE0E3FF)
59
+
60
+ @classmethod
61
+ def legacy_blurple(cls) -> "Color":
62
+ """Legacy Discord blurple (#7289DA)."""
63
+ return cls(0x7289DA)
64
+
65
+ # Additional assorted colors
66
+ @classmethod
67
+ def teal(cls) -> "Color":
68
+ return cls(0x1ABC9C)
69
+
70
+ @classmethod
71
+ def dark_teal(cls) -> "Color":
72
+ return cls(0x11806A)
73
+
74
+ @classmethod
75
+ def brand_green(cls) -> "Color":
76
+ return cls(0x57F287)
77
+
78
+ @classmethod
79
+ def dark_green(cls) -> "Color":
80
+ return cls(0x206694)
81
+
82
+ @classmethod
83
+ def orange(cls) -> "Color":
84
+ return cls(0xE67E22)
85
+
86
+ @classmethod
87
+ def dark_orange(cls) -> "Color":
88
+ return cls(0xA84300)
89
+
90
+ @classmethod
91
+ def brand_red(cls) -> "Color":
92
+ return cls(0xED4245)
93
+
94
+ @classmethod
95
+ def dark_red(cls) -> "Color":
96
+ return cls(0x992D22)
97
+
98
+ @classmethod
99
+ def magenta(cls) -> "Color":
100
+ return cls(0xE91E63)
101
+
102
+ @classmethod
103
+ def dark_magenta(cls) -> "Color":
104
+ return cls(0xAD1457)
105
+
106
+ @classmethod
107
+ def purple(cls) -> "Color":
108
+ return cls(0x9B59B6)
109
+
110
+ @classmethod
111
+ def dark_purple(cls) -> "Color":
112
+ return cls(0x71368A)
113
+
114
+ @classmethod
115
+ def yellow(cls) -> "Color":
116
+ return cls(0xF1C40F)
117
+
118
+ @classmethod
119
+ def dark_gold(cls) -> "Color":
120
+ return cls(0xC27C0E)
121
+
122
+ @classmethod
123
+ def light_gray(cls) -> "Color":
124
+ return cls(0x99AAB5)
125
+
126
+ @classmethod
127
+ def dark_gray(cls) -> "Color":
128
+ return cls(0x2C2F33)
129
+
130
+ @classmethod
131
+ def lighter_gray(cls) -> "Color":
132
+ return cls(0xBFBFBF)
133
+
134
+ @classmethod
135
+ def darker_gray(cls) -> "Color":
136
+ return cls(0x23272A)
137
+
138
+ @classmethod
139
+ def black(cls) -> "Color":
140
+ return cls(0x000000)
141
+
142
+ @classmethod
143
+ def white(cls) -> "Color":
144
+ return cls(0xFFFFFF)
145
+
49
146
  def to_rgb(self) -> tuple[int, int, int]:
50
147
  return ((self.value >> 16) & 0xFF, (self.value >> 8) & 0xFF, self.value & 0xFF)
51
148
 
52
149
  @classmethod
53
- def parse(cls, value: "Color | int | str | tuple[int, int, int] | None") -> "Color | None":
150
+ def parse(
151
+ cls, value: "Color | int | str | tuple[int, int, int] | None"
152
+ ) -> "Color | None":
54
153
  """Convert ``value`` to a :class:`Color` instance.
55
154
 
56
155
  Parameters
@@ -278,6 +278,62 @@ class GuildFeature(str, Enum): # Changed from IntEnum to Enum
278
278
  return str(value)
279
279
 
280
280
 
281
+ # --- Guild Scheduled Event Enums ---
282
+
283
+
284
+ class GuildScheduledEventPrivacyLevel(IntEnum):
285
+ """Privacy level for a scheduled event."""
286
+
287
+ GUILD_ONLY = 2
288
+
289
+
290
+ class GuildScheduledEventStatus(IntEnum):
291
+ """Status of a scheduled event."""
292
+
293
+ SCHEDULED = 1
294
+ ACTIVE = 2
295
+ COMPLETED = 3
296
+ CANCELED = 4
297
+
298
+
299
+ class GuildScheduledEventEntityType(IntEnum):
300
+ """Entity type for a scheduled event."""
301
+
302
+ STAGE_INSTANCE = 1
303
+ VOICE = 2
304
+ EXTERNAL = 3
305
+
306
+
307
+ class VoiceRegion(str, Enum):
308
+ """Voice region identifier."""
309
+
310
+ AMSTERDAM = "amsterdam"
311
+ BRAZIL = "brazil"
312
+ DUBAI = "dubai"
313
+ EU_CENTRAL = "eu-central"
314
+ EU_WEST = "eu-west"
315
+ EUROPE = "europe"
316
+ FRANKFURT = "frankfurt"
317
+ HONGKONG = "hongkong"
318
+ INDIA = "india"
319
+ JAPAN = "japan"
320
+ RUSSIA = "russia"
321
+ SINGAPORE = "singapore"
322
+ SOUTHAFRICA = "southafrica"
323
+ SOUTH_KOREA = "south-korea"
324
+ SYDNEY = "sydney"
325
+ US_CENTRAL = "us-central"
326
+ US_EAST = "us-east"
327
+ US_SOUTH = "us-south"
328
+ US_WEST = "us-west"
329
+ VIP_US_EAST = "vip-us-east"
330
+ VIP_US_WEST = "vip-us-west"
331
+
332
+ @classmethod
333
+ def _missing_(cls, value): # type: ignore
334
+ return str(value)
335
+
336
+
281
337
  # --- Channel Enums ---
282
338
 
283
339
 
@@ -305,6 +361,13 @@ class ChannelType(IntEnum):
305
361
  GUILD_MEDIA = 16 # (Still in development) a channel that can only contain media
306
362
 
307
363
 
364
+ class StageInstancePrivacyLevel(IntEnum):
365
+ """Privacy level of a stage instance."""
366
+
367
+ PUBLIC = 1
368
+ GUILD_ONLY = 2
369
+
370
+
308
371
  class OverwriteType(IntEnum):
309
372
  """Type of target for a permission overwrite."""
310
373
 
@@ -202,8 +202,6 @@ class MessageCommand(AppCommand):
202
202
  super().__init__(callback, type=ApplicationCommandType.MESSAGE, **kwargs)
203
203
 
204
204
 
205
-
206
-
207
205
  class AppCommandGroup:
208
206
  """
209
207
  Represents a group of application commands (subcommands or subcommand groups).