disagreement 0.1.0rc2__py3-none-any.whl → 0.2.0rc1__py3-none-any.whl
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.
- disagreement/__init__.py +9 -5
- disagreement/client.py +198 -6
- disagreement/color.py +100 -1
- disagreement/enums.py +63 -0
- disagreement/ext/app_commands/commands.py +0 -2
- disagreement/ext/app_commands/handler.py +118 -34
- disagreement/ext/app_commands/hybrid.py +1 -1
- disagreement/ext/commands/__init__.py +4 -0
- disagreement/ext/commands/cog.py +15 -6
- disagreement/ext/commands/core.py +71 -11
- disagreement/ext/commands/decorators.py +27 -0
- disagreement/ext/commands/errors.py +8 -0
- disagreement/gateway.py +113 -63
- disagreement/http.py +191 -10
- disagreement/models.py +206 -10
- disagreement/py.typed +0 -0
- {disagreement-0.1.0rc2.dist-info → disagreement-0.2.0rc1.dist-info}/METADATA +17 -1
- {disagreement-0.1.0rc2.dist-info → disagreement-0.2.0rc1.dist-info}/RECORD +21 -20
- {disagreement-0.1.0rc2.dist-info → disagreement-0.2.0rc1.dist-info}/WHEEL +0 -0
- {disagreement-0.1.0rc2.dist-info → disagreement-0.2.0rc1.dist-info}/licenses/LICENSE +0 -0
- {disagreement-0.1.0rc2.dist-info → disagreement-0.2.0rc1.dist-info}/top_level.txt +0 -0
disagreement/http.py
CHANGED
@@ -5,6 +5,7 @@ HTTP client for interacting with the Discord REST API.
|
|
5
5
|
"""
|
6
6
|
|
7
7
|
import asyncio
|
8
|
+
import logging
|
8
9
|
import aiohttp # pylint: disable=import-error
|
9
10
|
import json
|
10
11
|
from urllib.parse import quote
|
@@ -22,12 +23,14 @@ from .interactions import InteractionResponsePayload
|
|
22
23
|
|
23
24
|
if TYPE_CHECKING:
|
24
25
|
from .client import Client
|
25
|
-
from .models import Message, Webhook, File
|
26
|
+
from .models import Message, Webhook, File, StageInstance, Invite
|
26
27
|
from .interactions import ApplicationCommand, Snowflake
|
27
28
|
|
28
29
|
# Discord API constants
|
29
30
|
API_BASE_URL = "https://discord.com/api/v10" # Using API v10
|
30
31
|
|
32
|
+
logger = logging.getLogger(__name__)
|
33
|
+
|
31
34
|
|
32
35
|
class HTTPClient:
|
33
36
|
"""Handles HTTP requests to the Discord API."""
|
@@ -37,12 +40,27 @@ class HTTPClient:
|
|
37
40
|
token: str,
|
38
41
|
client_session: Optional[aiohttp.ClientSession] = None,
|
39
42
|
verbose: bool = False,
|
43
|
+
**session_kwargs: Any,
|
40
44
|
):
|
45
|
+
"""Create a new HTTP client.
|
46
|
+
|
47
|
+
Parameters
|
48
|
+
----------
|
49
|
+
token:
|
50
|
+
Bot token for authentication.
|
51
|
+
client_session:
|
52
|
+
Optional existing :class:`aiohttp.ClientSession`.
|
53
|
+
verbose:
|
54
|
+
If ``True``, log HTTP requests and responses.
|
55
|
+
**session_kwargs:
|
56
|
+
Additional options forwarded to :class:`aiohttp.ClientSession`, such
|
57
|
+
as ``proxy`` or ``connector``.
|
58
|
+
"""
|
59
|
+
|
41
60
|
self.token = token
|
42
|
-
self._session: Optional[aiohttp.ClientSession] =
|
43
|
-
|
44
|
-
)
|
45
|
-
self.user_agent = f"DiscordBot (https://github.com/yourusername/disagreement, {__version__})" # Customize URL
|
61
|
+
self._session: Optional[aiohttp.ClientSession] = client_session
|
62
|
+
self._session_kwargs: Dict[str, Any] = session_kwargs
|
63
|
+
self.user_agent = f"DiscordBot (https://github.com/Slipstreamm/disagreement, {__version__})" # Customize URL
|
46
64
|
|
47
65
|
self.verbose = verbose
|
48
66
|
|
@@ -50,7 +68,7 @@ class HTTPClient:
|
|
50
68
|
|
51
69
|
async def _ensure_session(self):
|
52
70
|
if self._session is None or self._session.closed:
|
53
|
-
self._session = aiohttp.ClientSession()
|
71
|
+
self._session = aiohttp.ClientSession(**self._session_kwargs)
|
54
72
|
|
55
73
|
async def close(self):
|
56
74
|
"""Closes the underlying aiohttp.ClientSession."""
|
@@ -86,7 +104,13 @@ class HTTPClient:
|
|
86
104
|
final_headers.update(custom_headers)
|
87
105
|
|
88
106
|
if self.verbose:
|
89
|
-
|
107
|
+
logger.debug(
|
108
|
+
"HTTP REQUEST: %s %s | payload=%s params=%s",
|
109
|
+
method,
|
110
|
+
url,
|
111
|
+
payload,
|
112
|
+
params,
|
113
|
+
)
|
90
114
|
|
91
115
|
route = f"{method.upper()}:{endpoint}"
|
92
116
|
|
@@ -119,7 +143,9 @@ class HTTPClient:
|
|
119
143
|
) # Fallback to text if JSON parsing fails
|
120
144
|
|
121
145
|
if self.verbose:
|
122
|
-
|
146
|
+
logger.debug(
|
147
|
+
"HTTP RESPONSE: %s %s | %s", response.status, url, data
|
148
|
+
)
|
123
149
|
|
124
150
|
self._rate_limiter.release(route, response.headers)
|
125
151
|
|
@@ -150,8 +176,12 @@ class HTTPClient:
|
|
150
176
|
)
|
151
177
|
|
152
178
|
if attempt < 4: # Don't log on the last attempt before raising
|
153
|
-
|
154
|
-
|
179
|
+
logger.warning(
|
180
|
+
"%s Retrying after %ss (Attempt %s/5). Global: %s",
|
181
|
+
error_message,
|
182
|
+
retry_after,
|
183
|
+
attempt + 1,
|
184
|
+
is_global,
|
155
185
|
)
|
156
186
|
continue # Retry the request
|
157
187
|
else: # Last attempt failed
|
@@ -394,6 +424,30 @@ class HTTPClient:
|
|
394
424
|
"""Fetches a channel by ID."""
|
395
425
|
return await self.request("GET", f"/channels/{channel_id}")
|
396
426
|
|
427
|
+
async def get_channel_invites(
|
428
|
+
self, channel_id: "Snowflake"
|
429
|
+
) -> List[Dict[str, Any]]:
|
430
|
+
"""Fetches the invites for a channel."""
|
431
|
+
|
432
|
+
return await self.request("GET", f"/channels/{channel_id}/invites")
|
433
|
+
|
434
|
+
async def create_invite(
|
435
|
+
self, channel_id: "Snowflake", payload: Dict[str, Any]
|
436
|
+
) -> "Invite":
|
437
|
+
"""Creates an invite for a channel."""
|
438
|
+
|
439
|
+
data = await self.request(
|
440
|
+
"POST", f"/channels/{channel_id}/invites", payload=payload
|
441
|
+
)
|
442
|
+
from .models import Invite
|
443
|
+
|
444
|
+
return Invite.from_dict(data)
|
445
|
+
|
446
|
+
async def delete_invite(self, code: str) -> None:
|
447
|
+
"""Deletes an invite by code."""
|
448
|
+
|
449
|
+
await self.request("DELETE", f"/invites/{code}")
|
450
|
+
|
397
451
|
async def create_webhook(
|
398
452
|
self, channel_id: "Snowflake", payload: Dict[str, Any]
|
399
453
|
) -> "Webhook":
|
@@ -574,6 +628,87 @@ class HTTPClient:
|
|
574
628
|
"""Fetches a guild object for a given guild ID."""
|
575
629
|
return await self.request("GET", f"/guilds/{guild_id}")
|
576
630
|
|
631
|
+
async def get_guild_templates(self, guild_id: "Snowflake") -> List[Dict[str, Any]]:
|
632
|
+
"""Fetches all templates for the given guild."""
|
633
|
+
return await self.request("GET", f"/guilds/{guild_id}/templates")
|
634
|
+
|
635
|
+
async def create_guild_template(
|
636
|
+
self, guild_id: "Snowflake", payload: Dict[str, Any]
|
637
|
+
) -> Dict[str, Any]:
|
638
|
+
"""Creates a guild template."""
|
639
|
+
return await self.request(
|
640
|
+
"POST", f"/guilds/{guild_id}/templates", payload=payload
|
641
|
+
)
|
642
|
+
|
643
|
+
async def sync_guild_template(
|
644
|
+
self, guild_id: "Snowflake", template_code: str
|
645
|
+
) -> Dict[str, Any]:
|
646
|
+
"""Syncs a guild template to the guild's current state."""
|
647
|
+
return await self.request(
|
648
|
+
"PUT",
|
649
|
+
f"/guilds/{guild_id}/templates/{template_code}",
|
650
|
+
)
|
651
|
+
|
652
|
+
async def delete_guild_template(
|
653
|
+
self, guild_id: "Snowflake", template_code: str
|
654
|
+
) -> None:
|
655
|
+
"""Deletes a guild template."""
|
656
|
+
await self.request("DELETE", f"/guilds/{guild_id}/templates/{template_code}")
|
657
|
+
|
658
|
+
async def get_guild_scheduled_events(
|
659
|
+
self, guild_id: "Snowflake"
|
660
|
+
) -> List[Dict[str, Any]]:
|
661
|
+
"""Returns a list of scheduled events for the guild."""
|
662
|
+
|
663
|
+
return await self.request("GET", f"/guilds/{guild_id}/scheduled-events")
|
664
|
+
|
665
|
+
async def get_guild_scheduled_event(
|
666
|
+
self, guild_id: "Snowflake", event_id: "Snowflake"
|
667
|
+
) -> Dict[str, Any]:
|
668
|
+
"""Returns a guild scheduled event."""
|
669
|
+
|
670
|
+
return await self.request(
|
671
|
+
"GET", f"/guilds/{guild_id}/scheduled-events/{event_id}"
|
672
|
+
)
|
673
|
+
|
674
|
+
async def create_guild_scheduled_event(
|
675
|
+
self, guild_id: "Snowflake", payload: Dict[str, Any]
|
676
|
+
) -> Dict[str, Any]:
|
677
|
+
"""Creates a guild scheduled event."""
|
678
|
+
|
679
|
+
return await self.request(
|
680
|
+
"POST", f"/guilds/{guild_id}/scheduled-events", payload=payload
|
681
|
+
)
|
682
|
+
|
683
|
+
async def edit_guild_scheduled_event(
|
684
|
+
self, guild_id: "Snowflake", event_id: "Snowflake", payload: Dict[str, Any]
|
685
|
+
) -> Dict[str, Any]:
|
686
|
+
"""Edits a guild scheduled event."""
|
687
|
+
|
688
|
+
return await self.request(
|
689
|
+
"PATCH",
|
690
|
+
f"/guilds/{guild_id}/scheduled-events/{event_id}",
|
691
|
+
payload=payload,
|
692
|
+
)
|
693
|
+
|
694
|
+
async def delete_guild_scheduled_event(
|
695
|
+
self, guild_id: "Snowflake", event_id: "Snowflake"
|
696
|
+
) -> None:
|
697
|
+
"""Deletes a guild scheduled event."""
|
698
|
+
|
699
|
+
await self.request("DELETE", f"/guilds/{guild_id}/scheduled-events/{event_id}")
|
700
|
+
|
701
|
+
async def get_audit_logs(
|
702
|
+
self, guild_id: "Snowflake", **filters: Any
|
703
|
+
) -> Dict[str, Any]:
|
704
|
+
"""Fetches audit log entries for a guild."""
|
705
|
+
params = {k: v for k, v in filters.items() if v is not None}
|
706
|
+
return await self.request(
|
707
|
+
"GET",
|
708
|
+
f"/guilds/{guild_id}/audit-logs",
|
709
|
+
params=params if params else None,
|
710
|
+
)
|
711
|
+
|
577
712
|
# Add other methods like:
|
578
713
|
# async def get_guild(self, guild_id: str) -> Dict[str, Any]: ...
|
579
714
|
# async def create_reaction(self, channel_id: str, message_id: str, emoji: str) -> None: ...
|
@@ -858,3 +993,49 @@ class HTTPClient:
|
|
858
993
|
async def trigger_typing(self, channel_id: str) -> None:
|
859
994
|
"""Sends a typing indicator to the specified channel."""
|
860
995
|
await self.request("POST", f"/channels/{channel_id}/typing")
|
996
|
+
|
997
|
+
async def start_stage_instance(
|
998
|
+
self, payload: Dict[str, Any], reason: Optional[str] = None
|
999
|
+
) -> "StageInstance":
|
1000
|
+
"""Starts a stage instance."""
|
1001
|
+
|
1002
|
+
headers = {"X-Audit-Log-Reason": reason} if reason else None
|
1003
|
+
data = await self.request(
|
1004
|
+
"POST", "/stage-instances", payload=payload, custom_headers=headers
|
1005
|
+
)
|
1006
|
+
from .models import StageInstance
|
1007
|
+
|
1008
|
+
return StageInstance(data)
|
1009
|
+
|
1010
|
+
async def edit_stage_instance(
|
1011
|
+
self,
|
1012
|
+
channel_id: "Snowflake",
|
1013
|
+
payload: Dict[str, Any],
|
1014
|
+
reason: Optional[str] = None,
|
1015
|
+
) -> "StageInstance":
|
1016
|
+
"""Edits an existing stage instance."""
|
1017
|
+
|
1018
|
+
headers = {"X-Audit-Log-Reason": reason} if reason else None
|
1019
|
+
data = await self.request(
|
1020
|
+
"PATCH",
|
1021
|
+
f"/stage-instances/{channel_id}",
|
1022
|
+
payload=payload,
|
1023
|
+
custom_headers=headers,
|
1024
|
+
)
|
1025
|
+
from .models import StageInstance
|
1026
|
+
|
1027
|
+
return StageInstance(data)
|
1028
|
+
|
1029
|
+
async def end_stage_instance(
|
1030
|
+
self, channel_id: "Snowflake", reason: Optional[str] = None
|
1031
|
+
) -> None:
|
1032
|
+
"""Ends a stage instance."""
|
1033
|
+
|
1034
|
+
headers = {"X-Audit-Log-Reason": reason} if reason else None
|
1035
|
+
await self.request(
|
1036
|
+
"DELETE", f"/stage-instances/{channel_id}", custom_headers=headers
|
1037
|
+
)
|
1038
|
+
|
1039
|
+
async def get_voice_regions(self) -> List[Dict[str, Any]]:
|
1040
|
+
"""Returns available voice regions."""
|
1041
|
+
return await self.request("GET", "/voice/regions")
|
disagreement/models.py
CHANGED
@@ -4,12 +4,13 @@
|
|
4
4
|
Data models for Discord objects.
|
5
5
|
"""
|
6
6
|
|
7
|
-
import json
|
8
|
-
import asyncio
|
9
|
-
import aiohttp # pylint: disable=import-error
|
10
7
|
import asyncio
|
8
|
+
import json
|
9
|
+
from dataclasses import dataclass
|
11
10
|
from typing import Any, AsyncIterator, Dict, List, Optional, TYPE_CHECKING, Union
|
12
11
|
|
12
|
+
import aiohttp # pylint: disable=import-error
|
13
|
+
from .color import Color
|
13
14
|
from .errors import DisagreementException, HTTPException
|
14
15
|
from .enums import ( # These enums will need to be defined in disagreement/enums.py
|
15
16
|
VerificationLevel,
|
@@ -22,10 +23,12 @@ from .enums import ( # These enums will need to be defined in disagreement/enum
|
|
22
23
|
ChannelType,
|
23
24
|
ComponentType,
|
24
25
|
ButtonStyle, # Added for Button
|
26
|
+
GuildScheduledEventPrivacyLevel,
|
27
|
+
GuildScheduledEventStatus,
|
28
|
+
GuildScheduledEventEntityType,
|
25
29
|
# SelectMenuType will be part of ComponentType or a new enum if needed
|
26
30
|
)
|
27
31
|
from .permissions import Permissions
|
28
|
-
from .color import Color
|
29
32
|
|
30
33
|
|
31
34
|
if TYPE_CHECKING:
|
@@ -1087,7 +1090,6 @@ class TextChannel(Channel):
|
|
1087
1090
|
)
|
1088
1091
|
self.last_pin_timestamp: Optional[str] = data.get("last_pin_timestamp")
|
1089
1092
|
|
1090
|
-
|
1091
1093
|
def history(
|
1092
1094
|
self,
|
1093
1095
|
*,
|
@@ -1143,7 +1145,6 @@ class TextChannel(Channel):
|
|
1143
1145
|
self._client._messages.pop(mid, None)
|
1144
1146
|
return ids
|
1145
1147
|
|
1146
|
-
|
1147
1148
|
def __repr__(self) -> str:
|
1148
1149
|
return f"<TextChannel id='{self.id}' name='{self.name}' guild_id='{self.guild_id}'>"
|
1149
1150
|
|
@@ -1162,6 +1163,85 @@ class VoiceChannel(Channel):
|
|
1162
1163
|
return f"<VoiceChannel id='{self.id}' name='{self.name}' guild_id='{self.guild_id}'>"
|
1163
1164
|
|
1164
1165
|
|
1166
|
+
class StageChannel(VoiceChannel):
|
1167
|
+
"""Represents a guild stage channel."""
|
1168
|
+
|
1169
|
+
def __repr__(self) -> str:
|
1170
|
+
return f"<StageChannel id='{self.id}' name='{self.name}' guild_id='{self.guild_id}'>"
|
1171
|
+
|
1172
|
+
async def start_stage_instance(
|
1173
|
+
self,
|
1174
|
+
topic: str,
|
1175
|
+
*,
|
1176
|
+
privacy_level: int = 2,
|
1177
|
+
reason: Optional[str] = None,
|
1178
|
+
guild_scheduled_event_id: Optional[str] = None,
|
1179
|
+
) -> "StageInstance":
|
1180
|
+
if not hasattr(self._client, "_http"):
|
1181
|
+
raise DisagreementException("Client missing HTTP for stage instance")
|
1182
|
+
|
1183
|
+
payload: Dict[str, Any] = {
|
1184
|
+
"channel_id": self.id,
|
1185
|
+
"topic": topic,
|
1186
|
+
"privacy_level": privacy_level,
|
1187
|
+
}
|
1188
|
+
if guild_scheduled_event_id is not None:
|
1189
|
+
payload["guild_scheduled_event_id"] = guild_scheduled_event_id
|
1190
|
+
|
1191
|
+
instance = await self._client._http.start_stage_instance(payload, reason=reason)
|
1192
|
+
instance._client = self._client
|
1193
|
+
return instance
|
1194
|
+
|
1195
|
+
async def edit_stage_instance(
|
1196
|
+
self,
|
1197
|
+
*,
|
1198
|
+
topic: Optional[str] = None,
|
1199
|
+
privacy_level: Optional[int] = None,
|
1200
|
+
reason: Optional[str] = None,
|
1201
|
+
) -> "StageInstance":
|
1202
|
+
if not hasattr(self._client, "_http"):
|
1203
|
+
raise DisagreementException("Client missing HTTP for stage instance")
|
1204
|
+
|
1205
|
+
payload: Dict[str, Any] = {}
|
1206
|
+
if topic is not None:
|
1207
|
+
payload["topic"] = topic
|
1208
|
+
if privacy_level is not None:
|
1209
|
+
payload["privacy_level"] = privacy_level
|
1210
|
+
|
1211
|
+
instance = await self._client._http.edit_stage_instance(
|
1212
|
+
self.id, payload, reason=reason
|
1213
|
+
)
|
1214
|
+
instance._client = self._client
|
1215
|
+
return instance
|
1216
|
+
|
1217
|
+
async def end_stage_instance(self, *, reason: Optional[str] = None) -> None:
|
1218
|
+
if not hasattr(self._client, "_http"):
|
1219
|
+
raise DisagreementException("Client missing HTTP for stage instance")
|
1220
|
+
|
1221
|
+
await self._client._http.end_stage_instance(self.id, reason=reason)
|
1222
|
+
|
1223
|
+
|
1224
|
+
class StageInstance:
|
1225
|
+
"""Represents a stage instance."""
|
1226
|
+
|
1227
|
+
def __init__(
|
1228
|
+
self, data: Dict[str, Any], client_instance: Optional["Client"] = None
|
1229
|
+
) -> None:
|
1230
|
+
self._client = client_instance
|
1231
|
+
self.id: str = data["id"]
|
1232
|
+
self.guild_id: Optional[str] = data.get("guild_id")
|
1233
|
+
self.channel_id: str = data["channel_id"]
|
1234
|
+
self.topic: str = data["topic"]
|
1235
|
+
self.privacy_level: int = data.get("privacy_level", 2)
|
1236
|
+
self.discoverable_disabled: bool = data.get("discoverable_disabled", False)
|
1237
|
+
self.guild_scheduled_event_id: Optional[str] = data.get(
|
1238
|
+
"guild_scheduled_event_id"
|
1239
|
+
)
|
1240
|
+
|
1241
|
+
def __repr__(self) -> str:
|
1242
|
+
return f"<StageInstance id='{self.id}' channel_id='{self.channel_id}'>"
|
1243
|
+
|
1244
|
+
|
1165
1245
|
class CategoryChannel(Channel):
|
1166
1246
|
"""Represents a guild category channel."""
|
1167
1247
|
|
@@ -1436,6 +1516,33 @@ class Webhook:
|
|
1436
1516
|
return self._client.parse_message(message_data)
|
1437
1517
|
|
1438
1518
|
|
1519
|
+
class GuildTemplate:
|
1520
|
+
"""Represents a guild template."""
|
1521
|
+
|
1522
|
+
def __init__(
|
1523
|
+
self, data: Dict[str, Any], client_instance: Optional["Client"] = None
|
1524
|
+
):
|
1525
|
+
self._client = client_instance
|
1526
|
+
self.code: str = data["code"]
|
1527
|
+
self.name: str = data["name"]
|
1528
|
+
self.description: Optional[str] = data.get("description")
|
1529
|
+
self.usage_count: int = data.get("usage_count", 0)
|
1530
|
+
self.creator_id: str = data.get("creator_id", "")
|
1531
|
+
self.creator: Optional[User] = (
|
1532
|
+
User(data["creator"]) if data.get("creator") else None
|
1533
|
+
)
|
1534
|
+
self.created_at: Optional[str] = data.get("created_at")
|
1535
|
+
self.updated_at: Optional[str] = data.get("updated_at")
|
1536
|
+
self.source_guild_id: Optional[str] = data.get("source_guild_id")
|
1537
|
+
self.serialized_source_guild: Dict[str, Any] = data.get(
|
1538
|
+
"serialized_source_guild", {}
|
1539
|
+
)
|
1540
|
+
self.is_dirty: Optional[bool] = data.get("is_dirty")
|
1541
|
+
|
1542
|
+
def __repr__(self) -> str:
|
1543
|
+
return f"<GuildTemplate code='{self.code}' name='{self.name}'>"
|
1544
|
+
|
1545
|
+
|
1439
1546
|
# --- Message Components ---
|
1440
1547
|
|
1441
1548
|
|
@@ -1981,6 +2088,77 @@ class Reaction:
|
|
1981
2088
|
return f"<Reaction message_id='{self.message_id}' user_id='{self.user_id}' emoji='{emoji_value}'>"
|
1982
2089
|
|
1983
2090
|
|
2091
|
+
class ScheduledEvent:
|
2092
|
+
"""Represents a guild scheduled event."""
|
2093
|
+
|
2094
|
+
def __init__(
|
2095
|
+
self, data: Dict[str, Any], client_instance: Optional["Client"] = None
|
2096
|
+
):
|
2097
|
+
self._client = client_instance
|
2098
|
+
self.id: str = data["id"]
|
2099
|
+
self.guild_id: str = data["guild_id"]
|
2100
|
+
self.channel_id: Optional[str] = data.get("channel_id")
|
2101
|
+
self.creator_id: Optional[str] = data.get("creator_id")
|
2102
|
+
self.name: str = data["name"]
|
2103
|
+
self.description: Optional[str] = data.get("description")
|
2104
|
+
self.scheduled_start_time: str = data["scheduled_start_time"]
|
2105
|
+
self.scheduled_end_time: Optional[str] = data.get("scheduled_end_time")
|
2106
|
+
self.privacy_level: GuildScheduledEventPrivacyLevel = (
|
2107
|
+
GuildScheduledEventPrivacyLevel(data["privacy_level"])
|
2108
|
+
)
|
2109
|
+
self.status: GuildScheduledEventStatus = GuildScheduledEventStatus(
|
2110
|
+
data["status"]
|
2111
|
+
)
|
2112
|
+
self.entity_type: GuildScheduledEventEntityType = GuildScheduledEventEntityType(
|
2113
|
+
data["entity_type"]
|
2114
|
+
)
|
2115
|
+
self.entity_id: Optional[str] = data.get("entity_id")
|
2116
|
+
self.entity_metadata: Optional[Dict[str, Any]] = data.get("entity_metadata")
|
2117
|
+
self.creator: Optional[User] = (
|
2118
|
+
User(data["creator"]) if data.get("creator") else None
|
2119
|
+
)
|
2120
|
+
self.user_count: Optional[int] = data.get("user_count")
|
2121
|
+
self.image: Optional[str] = data.get("image")
|
2122
|
+
|
2123
|
+
def __repr__(self) -> str:
|
2124
|
+
return f"<ScheduledEvent id='{self.id}' name='{self.name}'>"
|
2125
|
+
|
2126
|
+
|
2127
|
+
@dataclass
|
2128
|
+
class Invite:
|
2129
|
+
"""Represents a Discord invite."""
|
2130
|
+
|
2131
|
+
code: str
|
2132
|
+
channel_id: Optional[str]
|
2133
|
+
guild_id: Optional[str]
|
2134
|
+
inviter_id: Optional[str]
|
2135
|
+
uses: Optional[int]
|
2136
|
+
max_uses: Optional[int]
|
2137
|
+
max_age: Optional[int]
|
2138
|
+
temporary: Optional[bool]
|
2139
|
+
created_at: Optional[str]
|
2140
|
+
|
2141
|
+
@classmethod
|
2142
|
+
def from_dict(cls, data: Dict[str, Any]) -> "Invite":
|
2143
|
+
channel = data.get("channel")
|
2144
|
+
guild = data.get("guild")
|
2145
|
+
inviter = data.get("inviter")
|
2146
|
+
return cls(
|
2147
|
+
code=data["code"],
|
2148
|
+
channel_id=(channel or {}).get("id") if channel else data.get("channel_id"),
|
2149
|
+
guild_id=(guild or {}).get("id") if guild else data.get("guild_id"),
|
2150
|
+
inviter_id=(inviter or {}).get("id"),
|
2151
|
+
uses=data.get("uses"),
|
2152
|
+
max_uses=data.get("max_uses"),
|
2153
|
+
max_age=data.get("max_age"),
|
2154
|
+
temporary=data.get("temporary"),
|
2155
|
+
created_at=data.get("created_at"),
|
2156
|
+
)
|
2157
|
+
|
2158
|
+
def __repr__(self) -> str:
|
2159
|
+
return f"<Invite code='{self.code}' guild_id='{self.guild_id}' channel_id='{self.channel_id}'>"
|
2160
|
+
|
2161
|
+
|
1984
2162
|
class GuildMemberRemove:
|
1985
2163
|
"""Represents a GUILD_MEMBER_REMOVE event."""
|
1986
2164
|
|
@@ -2039,6 +2217,25 @@ class GuildRoleUpdate:
|
|
2039
2217
|
return f"<GuildRoleUpdate guild_id='{self.guild_id}' role_id='{self.role.id}'>"
|
2040
2218
|
|
2041
2219
|
|
2220
|
+
class AuditLogEntry:
|
2221
|
+
"""Represents a single entry in a guild's audit log."""
|
2222
|
+
|
2223
|
+
def __init__(
|
2224
|
+
self, data: Dict[str, Any], client_instance: Optional["Client"] = None
|
2225
|
+
) -> None:
|
2226
|
+
self._client = client_instance
|
2227
|
+
self.id: str = data["id"]
|
2228
|
+
self.user_id: Optional[str] = data.get("user_id")
|
2229
|
+
self.target_id: Optional[str] = data.get("target_id")
|
2230
|
+
self.action_type: int = data["action_type"]
|
2231
|
+
self.reason: Optional[str] = data.get("reason")
|
2232
|
+
self.changes: List[Dict[str, Any]] = data.get("changes", [])
|
2233
|
+
self.options: Optional[Dict[str, Any]] = data.get("options")
|
2234
|
+
|
2235
|
+
def __repr__(self) -> str:
|
2236
|
+
return f"<AuditLogEntry id='{self.id}' action_type={self.action_type} user_id='{self.user_id}'>"
|
2237
|
+
|
2238
|
+
|
2042
2239
|
def channel_factory(data: Dict[str, Any], client: "Client") -> Channel:
|
2043
2240
|
"""Create a channel object from raw API data."""
|
2044
2241
|
channel_type = data.get("type")
|
@@ -2048,11 +2245,10 @@ def channel_factory(data: Dict[str, Any], client: "Client") -> Channel:
|
|
2048
2245
|
ChannelType.GUILD_ANNOUNCEMENT.value,
|
2049
2246
|
):
|
2050
2247
|
return TextChannel(data, client)
|
2051
|
-
if channel_type
|
2052
|
-
ChannelType.GUILD_VOICE.value,
|
2053
|
-
ChannelType.GUILD_STAGE_VOICE.value,
|
2054
|
-
):
|
2248
|
+
if channel_type == ChannelType.GUILD_VOICE.value:
|
2055
2249
|
return VoiceChannel(data, client)
|
2250
|
+
if channel_type == ChannelType.GUILD_STAGE_VOICE.value:
|
2251
|
+
return StageChannel(data, client)
|
2056
2252
|
if channel_type == ChannelType.GUILD_CATEGORY.value:
|
2057
2253
|
return CategoryChannel(data, client)
|
2058
2254
|
if channel_type in (
|
disagreement/py.typed
ADDED
File without changes
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: disagreement
|
3
|
-
Version: 0.
|
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
|
@@ -1,22 +1,23 @@
|
|
1
|
-
disagreement/__init__.py,sha256=
|
1
|
+
disagreement/__init__.py,sha256=tZlZwEhqnBj3CEfPX2BWXXvGIc5OIiLtzuybRG7w1wA,1184
|
2
2
|
disagreement/audio.py,sha256=P6inobI8CNhNVkaRKU58RMYtLq1RrSREioF0Mui5VlA,3351
|
3
3
|
disagreement/cache.py,sha256=juabGFl4naQih5OUIVN2aN-vAfw2ZC2cI38s4nGEn8U,1525
|
4
|
-
disagreement/client.py,sha256=
|
5
|
-
disagreement/color.py,sha256=
|
4
|
+
disagreement/client.py,sha256=WJ1xLiXMha0_9i0rUDxXiMWXSG80_fXylq3Qmf9rr7k,59855
|
5
|
+
disagreement/color.py,sha256=0RumZU9geS51rmmywwotmkXFc8RyQghOviRGGrHmvW4,4495
|
6
6
|
disagreement/components.py,sha256=tEYJ2RHVpIFtZuPPxZ0v8ssUw_x7ybhYBzHNsRiXXvU,5250
|
7
|
-
disagreement/enums.py,sha256=
|
7
|
+
disagreement/enums.py,sha256=Km9rzmbkYdBpba3fDAv9YYtXDROoRpKuQfkMavsiY0s,11069
|
8
8
|
disagreement/error_handler.py,sha256=c2lb6aTMnhTtITQuR6axZUtEaasYKUgmdSxAHEkeq50,1028
|
9
9
|
disagreement/errors.py,sha256=XiYVPy8uFUGVi_EIf81yK7QbC7KyN4JHplSJSWw2RRk,3185
|
10
10
|
disagreement/event_dispatcher.py,sha256=mp4LVhIj0SW1P2NruqbYpZoYH33X5rXvkAl3-RK40kE,11460
|
11
|
-
disagreement/gateway.py,sha256=
|
12
|
-
disagreement/http.py,sha256=
|
11
|
+
disagreement/gateway.py,sha256=AxfGsSxu4eOWwpL3LQiNfcQVR3hyj33N9KfaPy0h8OU,24487
|
12
|
+
disagreement/http.py,sha256=TOGF2LBnsg4hTrP0sFBscKz1VVM_qZ8eoPZfBoQQPQw,37063
|
13
13
|
disagreement/hybrid_context.py,sha256=VYCmcreTZdPBU9v-Cy48W38vgWO2t8nM2ulC6_z4HjU,1095
|
14
14
|
disagreement/i18n.py,sha256=1L4rcFuKP0XjHk9dVwbNh4BkLk2ZlxxZ_-tecGWa9S0,718
|
15
15
|
disagreement/interactions.py,sha256=aUZwwEOLsEds15i6G-rxmSSDCDmaxz_cfoTYS4tv6Ao,21735
|
16
16
|
disagreement/logging_config.py,sha256=4q6baQPE6X_0lfaBTFMU1uqc03x5SbJqo2hsApdDFac,686
|
17
|
-
disagreement/models.py,sha256=
|
17
|
+
disagreement/models.py,sha256=Km75XDUiRV3gzhSPYDm2AByQEw2koZ-gyY1urvYffTE,82512
|
18
18
|
disagreement/oauth.py,sha256=TfDdCwg1J7osM9wDi61dtNBA5BrQk5DeQrrHsYycH34,2810
|
19
19
|
disagreement/permissions.py,sha256=7g5cIlg-evHXOL0-pmtT5EwqcB-stXot1HZSLz724sE,3008
|
20
|
+
disagreement/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
20
21
|
disagreement/rate_limiter.py,sha256=ubwR_UTPs2MotipBdtqpgwQKx0IHt2I3cdfFcXTFv7g,2521
|
21
22
|
disagreement/shard_manager.py,sha256=e9F8tx_4IEOlTX3-S3t51lfJToc6Ue3RVBzoNAiVKxs,2161
|
22
23
|
disagreement/typing.py,sha256=_1oFWfZ4HyH5Q3bnF7CO24s79z-3_B5Qb69kWiwLhhU,1242
|
@@ -26,18 +27,18 @@ disagreement/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
|
|
26
27
|
disagreement/ext/loader.py,sha256=9_uULvNAa-a6UiaeQhWglwgIrHEPKbf9bnWtSL1KV5Q,1408
|
27
28
|
disagreement/ext/tasks.py,sha256=b14KI-btikbrjPlD76md3Ggt6znrxPqr7TDarU4PYBg,7269
|
28
29
|
disagreement/ext/app_commands/__init__.py,sha256=mnQLIuGP9SzqGMPEn5YgOh2eIU7lcYoDXP06vtXZfTA,1014
|
29
|
-
disagreement/ext/app_commands/commands.py,sha256=
|
30
|
+
disagreement/ext/app_commands/commands.py,sha256=xjrVPScEezdVxVq524_E2Gm2sTa-yq44TbGMu0gyA2o,19018
|
30
31
|
disagreement/ext/app_commands/context.py,sha256=Xcm4Ka5K5uTQGviixF5LeCDdOdF9YQS5F7lZi2m--8s,20831
|
31
32
|
disagreement/ext/app_commands/converters.py,sha256=J1VEmo-7H9K7kGPJodu5FX4RmFFI1BuzhlQAEs2MsD4,21036
|
32
33
|
disagreement/ext/app_commands/decorators.py,sha256=dKiD4ZEsafRoPvfgn9zuQ9vvXXo2qYTMquHvyUM1604,23251
|
33
|
-
disagreement/ext/app_commands/handler.py,sha256=
|
34
|
-
disagreement/ext/app_commands/hybrid.py,sha256=
|
35
|
-
disagreement/ext/commands/__init__.py,sha256=
|
36
|
-
disagreement/ext/commands/cog.py,sha256
|
34
|
+
disagreement/ext/app_commands/handler.py,sha256=KCMi5NEusuyLYo7Vk4sqLqXAJI5r3ppI0MNLUh0kU2c,28781
|
35
|
+
disagreement/ext/app_commands/hybrid.py,sha256=u3kHNbVfY3-liymgzEIkFO5YV3WM_DqwytzdN9EXWMY,3330
|
36
|
+
disagreement/ext/commands/__init__.py,sha256=miejXIfft2kq2Q4Lej28awSgQXIEEeEuaBhR3M7f9tk,1230
|
37
|
+
disagreement/ext/commands/cog.py,sha256=-F2ZOXXC07r96xlt9NomRgqlIqlcxzBiha2Zhg1DVp4,6845
|
37
38
|
disagreement/ext/commands/converters.py,sha256=mh8xJr1FIiah6bdYy0KsdccfYcPii2Yc_IdhzCTw5uE,5864
|
38
|
-
disagreement/ext/commands/core.py,sha256=
|
39
|
-
disagreement/ext/commands/decorators.py,sha256=
|
40
|
-
disagreement/ext/commands/errors.py,sha256=
|
39
|
+
disagreement/ext/commands/core.py,sha256=4AO-U9xFyDetWeQUZiqX_g4zZfue0-9s8QBnHIb2BTc,21265
|
40
|
+
disagreement/ext/commands/decorators.py,sha256=fOhppBae8gt-9QI1YqUzDctwOXmMBdAK_JaUJLNWHww,7427
|
41
|
+
disagreement/ext/commands/errors.py,sha256=L6losXKye62BqDl42fXxgkuAkG92W-OcqH9uwEgabb8,2301
|
41
42
|
disagreement/ext/commands/help.py,sha256=yw0ydupOsPwmnhsIIoxa93xjj9MAcBcGfD8BXa7V8G8,1456
|
42
43
|
disagreement/ext/commands/view.py,sha256=3Wo4gGJX9fb65qw8yHFwMjnAeJvMJAx19rZNHz-ZDUs,3315
|
43
44
|
disagreement/ui/__init__.py,sha256=PLA6eHiq9cu7JDOKS-7MKtaFhlqswjbI4AEUlpnbgO0,307
|
@@ -46,8 +47,8 @@ disagreement/ui/item.py,sha256=bm-EmQEZpe8Kt8JrRw-o0uQdccgjErORcFsBqaXOcV8,1112
|
|
46
47
|
disagreement/ui/modal.py,sha256=w0ZEVslXzx2-RWUP4jdVB54zDuT81jpueVWZ70byFnI,4137
|
47
48
|
disagreement/ui/select.py,sha256=XjWRlWkA09QZaDDLn-wDDOWIuj0Mb4VCWJEOAaExZXw,3018
|
48
49
|
disagreement/ui/view.py,sha256=QhWoYt39QKXwl1X6Mkm5gNNEqd8bt7O505lSpiG0L04,5567
|
49
|
-
disagreement-0.
|
50
|
-
disagreement-0.
|
51
|
-
disagreement-0.
|
52
|
-
disagreement-0.
|
53
|
-
disagreement-0.
|
50
|
+
disagreement-0.2.0rc1.dist-info/licenses/LICENSE,sha256=zfmtgJhVFHnqT7a8LAQFthXu5bP7EEHmEL99trV66Ew,1474
|
51
|
+
disagreement-0.2.0rc1.dist-info/METADATA,sha256=ZEw0xKaAbZyXurATHmXCYwODfC6pr98jo27SlubhC_Q,5382
|
52
|
+
disagreement-0.2.0rc1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
53
|
+
disagreement-0.2.0rc1.dist-info/top_level.txt,sha256=t7FY_3iaYhdB6X6y9VybJ2j7UZbVeRUe9wRgH8d5Gtk,13
|
54
|
+
disagreement-0.2.0rc1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|