scurrypy 0.1.0__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.

Potentially problematic release.


This version of scurrypy might be problematic. Click here for more details.

Files changed (52) hide show
  1. discord/__init__.py +9 -0
  2. discord/client.py +312 -0
  3. discord/dispatch/__init__.py +1 -0
  4. discord/dispatch/command_dispatcher.py +156 -0
  5. discord/dispatch/event_dispatcher.py +85 -0
  6. discord/dispatch/prefix_dispatcher.py +53 -0
  7. discord/error.py +63 -0
  8. discord/events/__init__.py +33 -0
  9. discord/events/channel_events.py +52 -0
  10. discord/events/guild_events.py +38 -0
  11. discord/events/hello_event.py +9 -0
  12. discord/events/interaction_events.py +145 -0
  13. discord/events/message_events.py +43 -0
  14. discord/events/reaction_events.py +99 -0
  15. discord/events/ready_event.py +30 -0
  16. discord/gateway.py +175 -0
  17. discord/http.py +292 -0
  18. discord/intents.py +87 -0
  19. discord/logger.py +147 -0
  20. discord/model.py +88 -0
  21. discord/models/__init__.py +8 -0
  22. discord/models/application.py +37 -0
  23. discord/models/emoji.py +34 -0
  24. discord/models/guild.py +35 -0
  25. discord/models/integration.py +23 -0
  26. discord/models/member.py +27 -0
  27. discord/models/role.py +53 -0
  28. discord/models/user.py +15 -0
  29. discord/parts/__init__.py +28 -0
  30. discord/parts/action_row.py +258 -0
  31. discord/parts/attachment.py +18 -0
  32. discord/parts/channel.py +20 -0
  33. discord/parts/command.py +102 -0
  34. discord/parts/component_types.py +5 -0
  35. discord/parts/components_v2.py +270 -0
  36. discord/parts/embed.py +154 -0
  37. discord/parts/message.py +179 -0
  38. discord/parts/modal.py +21 -0
  39. discord/parts/role.py +39 -0
  40. discord/resources/__init__.py +10 -0
  41. discord/resources/application.py +94 -0
  42. discord/resources/bot_emojis.py +49 -0
  43. discord/resources/channel.py +192 -0
  44. discord/resources/guild.py +265 -0
  45. discord/resources/interaction.py +155 -0
  46. discord/resources/message.py +223 -0
  47. discord/resources/user.py +111 -0
  48. scurrypy-0.1.0.dist-info/METADATA +8 -0
  49. scurrypy-0.1.0.dist-info/RECORD +52 -0
  50. scurrypy-0.1.0.dist-info/WHEEL +5 -0
  51. scurrypy-0.1.0.dist-info/licenses/LICENSE +5 -0
  52. scurrypy-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,94 @@
1
+ from dataclasses import dataclass
2
+ from typing import Optional
3
+
4
+ from ..http import HTTPClient
5
+ from ..model import DataModel
6
+
7
+ from ..models.user import UserModel
8
+ from ..models.guild import GuildModel
9
+
10
+ class ApplicationFlags:
11
+ """Application flags (bitwise constants)."""
12
+
13
+ GATEWAY_PRESENCE = 1 << 12
14
+ """Privileged intent to receive presence_update events."""
15
+
16
+ GATEWAY_PRESENCE_LIMITED = 1 << 13
17
+ """Intent to receive presence_update events."""
18
+
19
+ GATEWAY_GUILD_MEMBERS = 1 << 14
20
+ """Privileged intent to receive member-related events."""
21
+
22
+ GATEWAY_GUILD_MEMBERS_LIMITED = 1 << 15
23
+ """Intent to receive member-related events."""
24
+
25
+ VERIFICATION_PENDING_GUILD_LIMIT = 1 << 16
26
+ """Indicates unusual growth of an app that prevents verification."""
27
+
28
+ GATEWAY_MESSAGE_CONTENT = 1 << 18
29
+ """Privileged intent to receive message content."""
30
+
31
+ GATEWAY_MESSAGE_CONTENT_LIMITED = 1 << 19
32
+ """Intent to receive message content."""
33
+
34
+ @dataclass
35
+ class Application(DataModel):
36
+ """Represents a Discord application."""
37
+
38
+ id: int
39
+ """ID of the application."""
40
+
41
+ _http: HTTPClient
42
+ """HTTP session for requests."""
43
+
44
+ name: str = None
45
+ """Name of the application."""
46
+
47
+ icon: Optional[str] = None
48
+ """Icon hash of the application."""
49
+
50
+ description: Optional[str] = None
51
+ """Description of the application."""
52
+
53
+ bot_public: Optional[bool] = None
54
+ """If the application is public."""
55
+
56
+ bot_require_code_grant: Optional[bool] = None
57
+ """If full OAuth2 code grant is required."""
58
+
59
+ bot: Optional[UserModel] = None
60
+ """Partial bot user object of the application."""
61
+
62
+ terms_of_service_url: Optional[str] = None
63
+ """Terms of Service URL of the application"""
64
+
65
+ privacy_policy: Optional[str] = None
66
+ """Privacy Policy URL of the application."""
67
+
68
+ owner: Optional[UserModel] = None
69
+ """Partial user object of the owner of the application."""
70
+
71
+ guild_id: Optional[int] = None
72
+ """Guild ID associated with the application."""
73
+
74
+ guild: Optional[GuildModel] = None
75
+ """Partial guild object of the associated guild."""
76
+
77
+ cover_image: Optional[str] = None
78
+ """Image hash of rich presence invite cover."""
79
+
80
+ flags: Optional[int] = None
81
+ """Public flags of the application."""
82
+
83
+ approximate_guild_count: Optional[int] = None
84
+ """Approximate guild count of the guilds that installed the application."""
85
+
86
+ def fetch(self):
87
+ """Fetch this application's data.
88
+
89
+ Returns:
90
+ (Application): the Application data
91
+ """
92
+ data = self._http.request('GET', '/applications/@me')
93
+
94
+ return Application.from_dict(data, self._http)
@@ -0,0 +1,49 @@
1
+ from ..http import HTTPClient
2
+ from ..models.emoji import EmojiModel
3
+
4
+ class BotEmojis:
5
+ """Represents a collection of the bot's emojis."""
6
+
7
+ def __init__(self, _http: HTTPClient, application_id: int):
8
+
9
+ self._http = _http
10
+ """HTTP session for requests."""
11
+
12
+ self.application_id = application_id
13
+ """Bot's application ID."""
14
+
15
+ self._cache: dict[int, EmojiModel] = {}
16
+ """Cache of bot's repository emojis mapped by id."""
17
+
18
+ async def fetch_all(self):
19
+ """Fetches all the bot's emojis from its repository."""
20
+ data = await self._http.request('GET', f'/applications/{self.application_id}/emojis')
21
+ items = data.get('items', [])
22
+ for e in items:
23
+ emoji = EmojiModel.from_dict(e)
24
+ self._cache[emoji.name] = emoji
25
+
26
+ async def fetch(self, emoji_id: int):
27
+ """Fetches a single emoji from the bot's repository.
28
+
29
+ Args:
30
+ emoji_id (int): the emoji's id
31
+
32
+ Returns:
33
+ (EmojiModel): the new EmojiModel object with all fields populated
34
+ """
35
+ data = await self._http.request("GET", f"/applications/{self.application_id}/emojis/{emoji_id}")
36
+ emoji = EmojiModel.from_dict(data)
37
+ self._cache[emoji.id] = emoji # also add it to the cache
38
+ return emoji
39
+
40
+ def get_emoji(self, name: str) -> EmojiModel:
41
+ """Get an emoji from this resource's cache by name.
42
+
43
+ Args:
44
+ name (str): name of the emoji
45
+
46
+ Returns:
47
+ (EmojiModel): the new EmojiModel object with all fields populated
48
+ """
49
+ return self._cache.get(name, EmojiModel('❓'))
@@ -0,0 +1,192 @@
1
+ from dataclasses import dataclass
2
+ from typing import TypedDict, Unpack, Optional
3
+
4
+ from ..http import HTTPClient
5
+ from ..model import DataModel
6
+ from .message import Message
7
+
8
+ from ..parts.channel import GuildChannel
9
+ from ..parts.message import MessageBuilder
10
+
11
+ class MessagesFetchParams(TypedDict, total=False):
12
+ """Params when fetching guild channel messages."""
13
+
14
+ limit: int
15
+ """Max number of messages to return. Range 1 - 100. Default 50."""
16
+
17
+ before: int
18
+ """Get messages before this message ID."""
19
+
20
+ after: int
21
+ """Get messages after this message ID."""
22
+
23
+ around: int
24
+ """Get messages around this message ID."""
25
+
26
+ class PinsFetchParams(TypedDict, total=False):
27
+ """Params when fetching pinned messages."""
28
+
29
+ before: str
30
+ """Get pinned messages before this ISO8601 timestamp."""
31
+
32
+ limit: int
33
+ """Max number of pinned messages to return. Range 1 - 50. Default 50."""
34
+
35
+ @dataclass
36
+ class PinnedMessage(DataModel):
37
+ """Pinned message data."""
38
+
39
+ message: Message
40
+ """Message resource of the pinned message."""
41
+
42
+ pinned_at: Optional[str] = None
43
+ """ISO8601 timestamp of when the message was pinned."""
44
+
45
+ @dataclass
46
+ class Channel(DataModel):
47
+ """Represents a Discord guild channel."""
48
+
49
+ id: int
50
+ """ID of the channel."""
51
+
52
+ _http: HTTPClient
53
+ """HTTP session for requests."""
54
+
55
+ type: Optional[int] = None
56
+ """Type of channel."""
57
+
58
+ guild_id: Optional[int] = None
59
+ """Guild ID of the channel."""
60
+
61
+ parent_id: Optional[int] = None
62
+ """Category ID of the channel."""
63
+
64
+ position: Optional[int] = None
65
+ """Position of the channel."""
66
+
67
+ name: Optional[str] = None
68
+ """Name of the channel."""
69
+
70
+ topic: Optional[str] = None
71
+ """Topic of the channel."""
72
+
73
+ nsfw: Optional[bool] = None
74
+ """If the channel is flagged NSFW."""
75
+
76
+ last_message_id: Optional[int] = None
77
+ """ID of the last message sent in the channel."""
78
+
79
+ last_pin_timestamp: Optional[str] = None
80
+ """ISO8601 timestamp of the last pinned messsage in the channel."""
81
+
82
+ rate_limit_per_user: Optional[int] = None
83
+ """Seconds user must wait between sending messages in the channel."""
84
+
85
+ def _update(self, data: dict):
86
+ """Update this channel in place.
87
+
88
+ Args:
89
+ data (dict): channel data as a dict
90
+ """
91
+ self.__dict__.update(Channel.from_dict(data, self._http).__dict__)
92
+
93
+ async def fetch(self):
94
+ """Fetch the full channel data from Discord.
95
+
96
+ Returns:
97
+ (Channel): A new Channel object with all fields populated
98
+ """
99
+ data = await self._http.request("GET", f"/channels/{self.id}")
100
+
101
+ # Hydrate a new Channel object with HTTP client
102
+ return Channel.from_dict(data, self._http)
103
+
104
+ async def fetch_messages(self, **kwargs: Unpack[MessagesFetchParams]):
105
+ """Fetches this channel's messages.
106
+
107
+ Permissions:
108
+ * VIEW_CHANNEL → required to access channel messages
109
+ * READ_MESSAGE_HISTORY → required for user, otherwise no messages are returned
110
+
111
+ Args:
112
+ **kwargs: field-specific data
113
+ !!! note
114
+ if no kwargs are provided, default to 50 fetched messages limit.
115
+
116
+ Returns:
117
+ (list[Message]): queried messages
118
+ """
119
+ # Set default limit if user didn't supply one
120
+ params = {"limit": 50, **kwargs}
121
+
122
+ data = await self._http.request('GET', f'/channels/{self.id}/messages', params=params)
123
+
124
+ return [Message.from_dict(msg, self._http) for msg in data]
125
+
126
+ async def send(self, message: str | MessageBuilder):
127
+ """
128
+ Send a message to this channel.
129
+
130
+ Permissions:
131
+ * SEND_MESSAGES → required to create a message in this channel
132
+
133
+ Args:
134
+ message (str | MessageBuilder): can be just text or the MessageBuilder for dynamic messages
135
+
136
+ Returns:
137
+ (Message): The created Message object
138
+ """
139
+ if isinstance(message, str):
140
+ message = MessageBuilder(content=message)
141
+
142
+ data = await self._http.request("POST", f"/channels/{self.id}/messages", message._to_dict())
143
+
144
+ return Message.from_dict(data, self._http)
145
+
146
+ async def edit(self, channel: GuildChannel):
147
+ """Edit this channel's settings.
148
+
149
+ Permissions:
150
+ * MANAGE_CHANNELS → required to edit this channel
151
+
152
+ Args:
153
+ channel (GuildChannel): channel changes
154
+
155
+ Returns:
156
+ (Channel): The updated channel object
157
+ """
158
+ data = await self._http.request("PATCH", f"/channels/{self.id}", data=channel._to_dict())
159
+ self._update(data)
160
+
161
+ return self
162
+
163
+ async def fetch_pins(self, **kwargs: Unpack[PinsFetchParams]):
164
+ """Get this channel's pinned messages.
165
+
166
+ Permissions:
167
+ * VIEW_CHANNEL → required to access pinned messages
168
+ * READ_MESSAGE_HISTORY → required for reading pinned messages
169
+
170
+ Args:
171
+ kwargs: field-specific data
172
+ !!! note
173
+ If no kwargs are provided, default to 50 fetched messages limit.
174
+
175
+ Returns:
176
+ (list[PinnedMessage]): list of pinned messages
177
+ """
178
+ # Set default limit if user didn't supply one
179
+ params = {"limit": 50, **kwargs}
180
+
181
+ data = await self._http.request('GET', f'/channels/{self.id}/pins', params=params)
182
+
183
+ pins = [Message.from_dict(item, self._http) for item in data]
184
+ return pins
185
+
186
+ async def delete(self):
187
+ """Deletes this channel from the server.
188
+
189
+ Permissions:
190
+ * MANAGE_CHANNELS → required to delete this channel
191
+ """
192
+ await self._http.request("DELETE", f"/channels/{self.id}")
@@ -0,0 +1,265 @@
1
+ from dataclasses import dataclass
2
+ from typing import Optional, TypedDict, Unpack
3
+
4
+ from ..http import HTTPClient
5
+ from ..model import DataModel
6
+
7
+ from .channel import Channel
8
+
9
+ from ..parts.channel import GuildChannel
10
+ from ..parts.role import Role
11
+
12
+ from ..models.emoji import EmojiModel
13
+ from ..models.member import MemberModel
14
+ from ..models.role import RoleModel
15
+
16
+ class FetchGuildMembersParams(TypedDict, total=False):
17
+ """Params when fetching guild members."""
18
+
19
+ limit: int
20
+ """Max number of members to return Range 1 - 1000. Default 1."""
21
+
22
+ after: int
23
+ """Highest user id in previous page."""
24
+
25
+ class FetchGuildParams(TypedDict, total=False):
26
+ """Params when fetching a guild."""
27
+
28
+ with_counts: Optional[bool]
29
+ """If True, return the approximate member and presence counts for the guild."""
30
+
31
+ @dataclass
32
+ class Guild(DataModel):
33
+ """Represents a Discord guild."""
34
+ id: int
35
+ """ID of the guild."""
36
+
37
+ _http: HTTPClient
38
+ """HTTP session for requests."""
39
+
40
+ name: str = None
41
+ """Name of the guild."""
42
+
43
+ icon: str = None
44
+ """Image hash of the guild's icon."""
45
+
46
+ splash: str = None
47
+ """Image hash of the guild's splash."""
48
+
49
+ owner: Optional[bool] = None
50
+ """If the member is the owner. (Get Current User Guilds)"""
51
+
52
+ owner_id: int = None
53
+ """OD of the owner of the guild."""
54
+
55
+ roles: list[int] = None
56
+ """List of IDs registered in the guild."""
57
+
58
+ emojis: list[EmojiModel] = None
59
+ """List of emojis registered in the guild."""
60
+
61
+ mfa_level: int = None
62
+ """Required MFA level of the guild."""
63
+
64
+ application_id: int = None
65
+ """ID of the application if the guild is created by a bot."""
66
+
67
+ system_channel_id: int = None
68
+ """Channel ID where system messages go (e.g., welcome messages, boost events)."""
69
+
70
+ system_channel_flags: int = None
71
+ """System channel flags."""
72
+
73
+ rules_channel_id: int = None
74
+ """Channel ID where rules are posted."""
75
+
76
+ max_members: Optional[int] = None
77
+ """Maximum member capacity for the guild."""
78
+
79
+ description: str = None
80
+ """Description of the guild."""
81
+
82
+ banner: str = None
83
+ """Image hash of the guild's banner."""
84
+
85
+ preferred_locale: str = None
86
+ """Preferred locale of the guild."""
87
+
88
+ public_updates_channel_id: int = None
89
+ """Channel ID of announcement or public updates."""
90
+
91
+ approximate_member_count: int = None
92
+ """Approximate number of members in the guild."""
93
+
94
+ nsfw_level: int = None
95
+ """NSFW level of the guild."""
96
+
97
+ safety_alerts_channel_id: int = None
98
+ """Channel ID for safety alerts."""
99
+
100
+ async def fetch(self, **kwargs: Unpack[FetchGuildParams]):
101
+ """Fetch the Guild object by the given ID.
102
+
103
+ Args:
104
+ kwargs: field-specific data
105
+ !!! note
106
+ If no kwargs are provided, default to with_counts = False
107
+
108
+ Returns:
109
+ (Guild): the Guild object
110
+ """
111
+ params = {'with_counts': False, **kwargs}
112
+
113
+ data = await self._http.request('GET', f'/guilds/{self.id}', params=params)
114
+
115
+ return Guild.from_dict(data, self._http)
116
+
117
+ async def fetch_channels(self):
118
+ """Fetch this guild's channels.
119
+
120
+ Returns:
121
+ (list[Channel]): list of the guild's channels
122
+ """
123
+ data = await self._http.request('GET', f'guilds/{self.id}/channels')
124
+
125
+ return [Channel.from_dict(channel, self._http) for channel in data]
126
+
127
+ async def create_channel(self, channel: GuildChannel):
128
+ """Create a channel in this guild.
129
+
130
+ Permissions:
131
+ * MANAGE_CHANNELS → required to create a channel
132
+
133
+ Args:
134
+ channel (GuildChannel): the buildable guild channel
135
+
136
+ Returns:
137
+ (Channel): the created channel
138
+ """
139
+ data = await self._http.request('POST', f'/guilds/{self.id}/channels', channel._to_dict())
140
+
141
+ return Channel.from_dict(data, self._http)
142
+
143
+ async def fetch_guild_member(self, user_id: int):
144
+ """Fetch a member in this guild.
145
+ !!! warning "Important"
146
+ Requires the GUILD_MEMBERS privileged intent!
147
+
148
+ Args:
149
+ user_id (int): user id of the member to fetch
150
+
151
+ Returns:
152
+ (MemberModel): member's data
153
+ """
154
+ data = await self._http.request('GET', f'/guilds/{self.id}/members/{user_id}')
155
+
156
+ return MemberModel.from_dict(data)
157
+
158
+ async def fetch_guild_members(self, **kwargs: Unpack[FetchGuildMembersParams]):
159
+ """Fetch guild members in this guild.
160
+ !!! warning "Important"
161
+ Requires the GUILD_MEMBERS privileged intent!
162
+
163
+ Args:
164
+ **kwargs: field-specific data
165
+ !!! note
166
+ If no kwargs are provided, default to 1 guild member limit.
167
+
168
+ Returns:
169
+ (list[MemberModel]): list of member data
170
+ """
171
+ params = {"limit": 1, **kwargs}
172
+
173
+ data = await self._http.request('GET', f'/guilds/{self.id}/members', params=params)
174
+
175
+ return [MemberModel.from_dict(member) for member in data]
176
+
177
+ async def add_guild_member_role(self, user_id: int, role_id: int):
178
+ """Append a role to a guild member of this guild.
179
+
180
+ Permissions:
181
+ * MANAGE_ROLES → required to add a role to the user
182
+
183
+ Args:
184
+ user_id (int): id of the member for the role
185
+ role_id (int): id of the role to append
186
+ """
187
+ await self._http.request('PUT', f'/guilds/{self.id}/members/{user_id}/roles/{role_id}')
188
+
189
+ async def remove_guild_member_role(self, user_id: int, role_id: int):
190
+ """Remove a role from a guild member of this guild.
191
+
192
+ Permissions:
193
+ * MANAGE_ROLES → required to remove a role from the user
194
+
195
+ Args:
196
+ user_id (int): id of the member with the role
197
+ role_id (int): id of the role to remove
198
+ """
199
+ await self._http.request('DELETE', f'/guilds/{self.id}/members/{user_id}/roles/{role_id}')
200
+
201
+ async def fetch_guild_role(self, role_id: int):
202
+ """Fetch a role in this guild.
203
+
204
+ Args:
205
+ role_id (int): id of the role to fetch
206
+
207
+ Returns:
208
+ (RoleModel): fetched role's data
209
+ """
210
+ data = await self._http.request('GET', f'/guilds/{self.id}/roles/{role_id}')
211
+
212
+ return RoleModel.from_dict(data)
213
+
214
+ async def fetch_guild_roles(self):
215
+ """Fetch all roles in this guild.
216
+
217
+ Returns:
218
+ (list[RoleModel]): list of fetched roles' data
219
+ """
220
+ data = await self._http.request('GET', f'/guilds/{self.id}/roles')
221
+
222
+ return [RoleModel.from_dict(role) for role in data]
223
+
224
+ async def create_guild_role(self, role: Role):
225
+ """Create a role in this guild.
226
+
227
+ Permissions:
228
+ * MANAGE_ROLES → required to add a role to the guild
229
+
230
+ Args:
231
+ role (Role): role to create
232
+
233
+ Returns:
234
+ (RoleModel): new role data
235
+ """
236
+ data = await self._http.request('POST', f'/guilds/{self.id}/roles', role._to_dict())
237
+
238
+ return RoleModel.from_dict(data)
239
+
240
+ async def modify_guild_role(self, role_id: int, role: Role):
241
+ """Modify a role in this guild.
242
+
243
+ Permissions:
244
+ * MANAGE_ROLES → required to modify a role in the guild
245
+
246
+ Args:
247
+ role (Role): role with changes
248
+
249
+ Returns:
250
+ (RoleModel): role with changes
251
+ """
252
+ data = await self._http.request('PATCH', f'/guilds/{self.id}/roles/{role_id}', role._to_dict())
253
+
254
+ return RoleModel.from_dict(data)
255
+
256
+ async def delete_guild_role(self, role_id: int):
257
+ """Delete a role in this guild.
258
+
259
+ Permissions:
260
+ * MANAGE_ROLES → required to delete a role in the guild
261
+
262
+ Args:
263
+ role_id (int): id of role to delete
264
+ """
265
+ await self._http.request('DELETE', f'/guilds/{self.id}/roles/{role_id}')