scurrypy 0.4.2__py3-none-any.whl → 0.5.3__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 (65) hide show
  1. scurrypy/__init__.py +376 -0
  2. {discord → scurrypy}/client_like.py +1 -1
  3. {discord → scurrypy}/dispatch/command_dispatcher.py +13 -5
  4. {discord → scurrypy}/dispatch/event_dispatcher.py +15 -15
  5. {discord → scurrypy}/events/channel_events.py +1 -1
  6. {discord → scurrypy}/events/interaction_events.py +21 -9
  7. {discord → scurrypy}/events/message_events.py +4 -4
  8. {discord → scurrypy}/http.py +1 -1
  9. {discord → scurrypy}/intents.py +1 -1
  10. scurrypy/model.py +71 -0
  11. {discord → scurrypy}/models/emoji.py +17 -1
  12. {discord → scurrypy}/models/interaction.py +5 -0
  13. scurrypy/parts/channel.py +42 -0
  14. scurrypy/parts/command.py +90 -0
  15. scurrypy/parts/components.py +224 -0
  16. scurrypy/parts/components_v2.py +144 -0
  17. scurrypy/parts/embed.py +83 -0
  18. scurrypy/parts/message.py +137 -0
  19. scurrypy/parts/modal.py +16 -0
  20. {discord → scurrypy}/parts/role.py +1 -13
  21. {discord → scurrypy}/resources/channel.py +6 -6
  22. {discord → scurrypy}/resources/guild.py +3 -4
  23. {discord → scurrypy}/resources/interaction.py +23 -22
  24. {discord → scurrypy}/resources/message.py +13 -13
  25. {scurrypy-0.4.2.dist-info → scurrypy-0.5.3.dist-info}/METADATA +19 -25
  26. scurrypy-0.5.3.dist-info/RECORD +54 -0
  27. scurrypy-0.5.3.dist-info/top_level.txt +1 -0
  28. discord/__init__.py +0 -223
  29. discord/model.py +0 -90
  30. discord/parts/action_row.py +0 -208
  31. discord/parts/channel.py +0 -20
  32. discord/parts/command.py +0 -102
  33. discord/parts/components_v2.py +0 -353
  34. discord/parts/embed.py +0 -154
  35. discord/parts/message.py +0 -194
  36. discord/parts/modal.py +0 -21
  37. scurrypy-0.4.2.dist-info/RECORD +0 -54
  38. scurrypy-0.4.2.dist-info/top_level.txt +0 -1
  39. {discord → scurrypy}/client.py +0 -0
  40. {discord → scurrypy}/config.py +0 -0
  41. {discord → scurrypy}/dispatch/__init__.py +0 -0
  42. {discord → scurrypy}/dispatch/prefix_dispatcher.py +0 -0
  43. {discord → scurrypy}/error.py +0 -0
  44. {discord → scurrypy}/events/__init__.py +0 -0
  45. {discord → scurrypy}/events/guild_events.py +0 -0
  46. {discord → scurrypy}/events/hello_event.py +0 -0
  47. {discord → scurrypy}/events/reaction_events.py +0 -0
  48. {discord → scurrypy}/events/ready_event.py +0 -0
  49. {discord → scurrypy}/gateway.py +0 -0
  50. {discord → scurrypy}/logger.py +0 -0
  51. {discord → scurrypy}/models/__init__.py +0 -0
  52. {discord → scurrypy}/models/application.py +0 -0
  53. {discord → scurrypy}/models/guild.py +0 -0
  54. {discord → scurrypy}/models/integration.py +0 -0
  55. {discord → scurrypy}/models/member.py +0 -0
  56. {discord → scurrypy}/models/role.py +0 -0
  57. {discord → scurrypy}/models/user.py +0 -0
  58. {discord → scurrypy}/parts/__init__.py +0 -0
  59. {discord → scurrypy}/parts/component_types.py +0 -0
  60. {discord → scurrypy}/resources/__init__.py +0 -0
  61. {discord → scurrypy}/resources/application.py +0 -0
  62. {discord → scurrypy}/resources/bot_emojis.py +0 -0
  63. {discord → scurrypy}/resources/user.py +0 -0
  64. {scurrypy-0.4.2.dist-info → scurrypy-0.5.3.dist-info}/WHEEL +0 -0
  65. {scurrypy-0.4.2.dist-info → scurrypy-0.5.3.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,83 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import Optional
3
+ from ..model import DataModel
4
+
5
+ @dataclass
6
+ class EmbedAuthor(DataModel):
7
+ """Embed author parameters."""
8
+
9
+ name: str
10
+ """Name of the author."""
11
+
12
+ url: Optional[str] = None
13
+ """URL of the author. http or attachment://<filename> scheme."""
14
+
15
+ icon_url: Optional[str] = None
16
+ """URL of author's icon. http or attachment://<filename> scheme."""
17
+
18
+ @dataclass
19
+ class EmbedThumbnail(DataModel):
20
+ """Embed thumbnail."""
21
+
22
+ url: str
23
+ """Thumbnail content. http or attachment://<filename> scheme."""
24
+
25
+ @dataclass
26
+ class EmbedField(DataModel):
27
+ """Embed field."""
28
+
29
+ name: str
30
+ """Name of the field."""
31
+
32
+ value: str
33
+ """Value of the field."""
34
+
35
+ inline: Optional[bool] = None
36
+ """Whether or not this field should display inline."""
37
+
38
+ @dataclass
39
+ class EmbedImage(DataModel):
40
+ """Embed image."""
41
+
42
+ url: str
43
+ """Image content. http or attachment://<filename> scheme."""
44
+
45
+ @dataclass
46
+ class EmbedFooter(DataModel):
47
+ """Embed footer."""
48
+ text: str
49
+ """Footer text."""
50
+
51
+ icon_url: Optional[str] = None
52
+ """URL of the footer icon. http or attachment://<filename> scheme."""
53
+
54
+ @dataclass
55
+ class EmbedPart(DataModel):
56
+ """Represents the Embed portion of a message."""
57
+
58
+ title: Optional[str] = None
59
+ """This embed's title."""
60
+
61
+ description: Optional[str] = None
62
+ """This embed's description."""
63
+
64
+ timestamp: Optional[str] = None
65
+ """Timestamp of when the embed was sent."""
66
+
67
+ color: Optional[int] = None
68
+ """Embed's accent color."""
69
+
70
+ author: Optional[EmbedAuthor] = None
71
+ """Embed's author."""
72
+
73
+ thumbnail: Optional[EmbedThumbnail] = None
74
+ """Embed's thumbnail attachment."""
75
+
76
+ image: Optional[EmbedImage] = None
77
+ """Embed's image attachment."""
78
+
79
+ fields: Optional[list[EmbedField]] = field(default_factory=list)
80
+ """List of embed's fields."""
81
+
82
+ footer: Optional[EmbedFooter] = None
83
+ """Embed's footer."""
@@ -0,0 +1,137 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import Optional, TypedDict, Unpack
3
+ from ..model import DataModel
4
+ from .embed import EmbedPart
5
+ from .components import ActionRowPart
6
+ from .components_v2 import ContainerPart
7
+
8
+ class MessageFlags:
9
+ """Flags that can be applied to a message."""
10
+
11
+ CROSSPOSTED = 1 << 0
12
+ """Message has been published."""
13
+
14
+ IS_CROSSPOST = 1 << 1
15
+ """Message originated from another channel."""
16
+
17
+ SUPPRESS_EMBEDS = 1 << 2
18
+ """Hide embeds (if any)."""
19
+
20
+ EPHEMERAL = 1 << 6
21
+ """Only visible to the invoking user."""
22
+
23
+ LOADING = 1 << 7
24
+ """Thinking response."""
25
+
26
+ IS_COMPONENTS_V2 = 1 << 15
27
+ """This message includes Discord's V2 Components."""
28
+
29
+ class MessageFlagParams(TypedDict, total=False):
30
+ """Parameters for setting message flags. See [`MessageFlags`][scurrypy.parts.message.MessageFlags]."""
31
+ crossposted: bool
32
+ is_crosspost: bool
33
+ suppress_embeds: bool
34
+ ephemeral: bool
35
+ loading: bool
36
+ is_components_v2: bool
37
+
38
+ class MessageReferenceTypes:
39
+ """Constants associated with how reference data is populated."""
40
+
41
+ DEFAULT = 0
42
+ """Standard reference used by replies."""
43
+
44
+ FORWARD = 1
45
+ """Reference used to point to a message at a point in time."""
46
+
47
+ @dataclass
48
+ class MessageReference(DataModel):
49
+ """Represents the Message Reference object."""
50
+
51
+ message_id: int
52
+ """ID of the originating message."""
53
+
54
+ channel_id: int
55
+ """
56
+ Channel ID of the originating message.
57
+ !!! note
58
+ Optional for default type, but REQUIRED for forwards.
59
+ """
60
+
61
+ type: int = MessageReferenceTypes.DEFAULT
62
+ """Type of reference. Defaults to `DEFAULT`. See [`MessageReferenceTypes`][scurrypy.parts.message.MessageReferenceTypes]."""
63
+
64
+ @dataclass
65
+ class Attachment(DataModel):
66
+ """Represents an attachment."""
67
+
68
+ id: int
69
+ """User-defined ID for the attachment."""
70
+
71
+ path: str
72
+ """Relative path to the file."""
73
+
74
+ filename: str
75
+ """Name of the file."""
76
+
77
+ description: str
78
+ """Description of the file."""
79
+
80
+ def to_dict(self):
81
+ return {
82
+ 'id': self.id,
83
+ 'filename': self.filename,
84
+ 'description': self.description
85
+ }
86
+
87
+ @dataclass
88
+ class MessagePart(DataModel):
89
+ """Describes expected params when editing/creating a message."""
90
+
91
+ content: Optional[str] = None
92
+ """Message text content."""
93
+
94
+ flags: Optional[int] = 0
95
+ """Message flags. See [`MessageFlags`][scurrypy.parts.message.MessageFlags]."""
96
+
97
+ components: Optional[list[ActionRowPart | ContainerPart]] = field(default_factory=list)
98
+ """Components to be attached to this message."""
99
+
100
+ attachments: Optional[list[Attachment]] = field(default_factory=list)
101
+ """Attachments to be attached to this message."""
102
+
103
+ embeds: Optional[list[EmbedPart]] = field(default_factory=list)
104
+ """Embeds to be attached to this message."""
105
+
106
+ message_reference: Optional[MessageReference] = None
107
+ """Message reference if reply."""
108
+
109
+ def set_flags(self, **flags: Unpack[MessageFlagParams]):
110
+ """Set this message's flags using MessageFlagParams.
111
+
112
+ Args:
113
+ flags (Unpack[MessageFlagParams]): message flags to set. (set respective flag to True to toggle.)
114
+
115
+ Raises:
116
+ (ValueError): invalid flag
117
+
118
+ Returns:
119
+ (MessagePart): self
120
+ """
121
+ _flag_map = {
122
+ 'crossposted': MessageFlags.CROSSPOSTED,
123
+ 'is_crosspost': MessageFlags.IS_CROSSPOST,
124
+ 'suppress_embeds': MessageFlags.SUPPRESS_EMBEDS,
125
+ 'ephemeral': MessageFlags.EPHEMERAL,
126
+ 'loading': MessageFlags.LOADING,
127
+ 'is_components_v2': MessageFlags.IS_COMPONENTS_V2,
128
+ }
129
+
130
+ # each flag maps to a specific combined bit!
131
+ for name, value in flags.items():
132
+ if name not in _flag_map:
133
+ raise ValueError(f"Invalid flag: {name}")
134
+ if value:
135
+ self.flags |= _flag_map[name]
136
+
137
+ return self
@@ -0,0 +1,16 @@
1
+ from dataclasses import dataclass, field
2
+ from ..model import DataModel
3
+ from .components_v2 import Label
4
+
5
+ @dataclass
6
+ class ModalPart(DataModel):
7
+ """Represents the Modal object."""
8
+
9
+ title: str
10
+ """Title of the popup modal."""
11
+
12
+ custom_id: str = None
13
+ """ID for the modal."""
14
+
15
+ components: list[Label] = field(default_factory=list)
16
+ """1 to 5 components that make up the modal."""
@@ -1,6 +1,6 @@
1
1
  from dataclasses import dataclass
2
2
  from typing import Optional
3
- from discord.model import DataModel
3
+ from ..model import DataModel
4
4
 
5
5
  from ..models.role import RoleColors
6
6
 
@@ -25,15 +25,3 @@ class Role(DataModel):
25
25
 
26
26
  unicode_emoji: Optional[str] = None
27
27
  """Unicode emoji of the role."""
28
-
29
- def set_color(self, hex: str):
30
- """Set this role's color with a hex. (format: #FFFFFF)
31
-
32
- Args:
33
- hex (str): color as a hex code
34
-
35
- Returns:
36
- (Role): self
37
- """
38
- self.color=int(hex.strip('#'), 16)
39
- return self
@@ -6,7 +6,7 @@ from ..model import DataModel
6
6
  from .message import Message
7
7
 
8
8
  from ..parts.channel import GuildChannel
9
- from ..parts.message import MessageBuilder
9
+ from ..parts.message import MessagePart
10
10
 
11
11
  class MessagesFetchParams(TypedDict, total=False):
12
12
  """Params when fetching guild channel messages."""
@@ -132,7 +132,7 @@ class Channel(DataModel):
132
132
 
133
133
  return [Message.from_dict(msg, self._http) for msg in data]
134
134
 
135
- async def send(self, message: str | MessageBuilder):
135
+ async def send(self, message: str | MessagePart):
136
136
  """
137
137
  Send a message to this channel.
138
138
 
@@ -140,15 +140,15 @@ class Channel(DataModel):
140
140
  * SEND_MESSAGES → required to create a message in this channel
141
141
 
142
142
  Args:
143
- message (str | MessageBuilder): can be just text or the MessageBuilder for dynamic messages
143
+ message (str | MessagePart): can be just text or the MessagePart for dynamic messages
144
144
 
145
145
  Returns:
146
146
  (Message): The created Message object
147
147
  """
148
148
  if isinstance(message, str):
149
- message = MessageBuilder(content=message)
149
+ message = MessagePart(content=message)
150
150
 
151
- data = await self._http.request("POST", f"/channels/{self.id}/messages", data=message._to_dict())
151
+ data = await self._http.request("POST", f"/channels/{self.id}/messages", data=message.to_dict())
152
152
 
153
153
  return Message.from_dict(data, self._http)
154
154
 
@@ -164,7 +164,7 @@ class Channel(DataModel):
164
164
  Returns:
165
165
  (Channel): The updated channel object
166
166
  """
167
- data = await self._http.request("PATCH", f"/channels/{self.id}", data=channel._to_dict())
167
+ data = await self._http.request("PATCH", f"/channels/{self.id}", data=channel.to_dict())
168
168
  self._update(data)
169
169
 
170
170
  return self
@@ -1,6 +1,5 @@
1
1
  from dataclasses import dataclass
2
2
  from typing import Optional, TypedDict, Unpack
3
- from urllib.parse import urlencode
4
3
 
5
4
  from ..http import HTTPClient
6
5
  from ..model import DataModel
@@ -137,7 +136,7 @@ class Guild(DataModel):
137
136
  Returns:
138
137
  (Channel): the created channel
139
138
  """
140
- data = await self._http.request('POST', f'/guilds/{self.id}/channels', data=channel._to_dict())
139
+ data = await self._http.request('POST', f'/guilds/{self.id}/channels', data=channel.to_dict())
141
140
 
142
141
  return Channel.from_dict(data, self._http)
143
142
 
@@ -234,7 +233,7 @@ class Guild(DataModel):
234
233
  Returns:
235
234
  (RoleModel): new role data
236
235
  """
237
- data = await self._http.request('POST', f'/guilds/{self.id}/roles', data=role._to_dict())
236
+ data = await self._http.request('POST', f'/guilds/{self.id}/roles', data=role.to_dict())
238
237
 
239
238
  return RoleModel.from_dict(data)
240
239
 
@@ -250,7 +249,7 @@ class Guild(DataModel):
250
249
  Returns:
251
250
  (RoleModel): role with changes
252
251
  """
253
- data = await self._http.request('PATCH', f'/guilds/{self.id}/roles/{role_id}', data=role._to_dict())
252
+ data = await self._http.request('PATCH', f'/guilds/{self.id}/roles/{role_id}', data=role.to_dict())
254
253
 
255
254
  return RoleModel.from_dict(data)
256
255
 
@@ -4,8 +4,8 @@ from typing import Optional, Unpack
4
4
  from ..http import HTTPClient
5
5
  from ..model import DataModel
6
6
 
7
- from ..parts.modal import ModalBuilder
8
- from ..parts.message import *
7
+ from ..parts.modal import ModalPart
8
+ from ..parts.message import MessagePart, MessageFlagParams
9
9
 
10
10
  from ..models.guild import GuildModel
11
11
  from ..models.member import MemberModel
@@ -38,8 +38,9 @@ class InteractionCallbackTypes:
38
38
  """Acknowledge an interaction and edit a response later. User sees a loading state."""
39
39
 
40
40
  DEFERRED_UPDATE_MESSAGE = 6
41
- """Acknowledge an interaction and edit the original message later.
42
- The user does NOT see a loading state. (Components only)
41
+ """
42
+ Acknowledge an interaction and edit the original message later.
43
+ The user does NOT see a loading state. (Components only)
43
44
  """
44
45
 
45
46
  UPDATE_MESSAGE = 7
@@ -68,7 +69,7 @@ class Interaction(DataModel):
68
69
  """HTTP session for requests."""
69
70
 
70
71
  type: int
71
- """Type of interaction."""
72
+ """Type of interaction. See [`InteractionTypes`][scurrypy.dispatch.command_dispatcher.InteractionTypes]."""
72
73
 
73
74
  channel_id: int
74
75
  """ID of the channel where the interaction was sent."""
@@ -97,24 +98,24 @@ class Interaction(DataModel):
97
98
  channel: Optional[Channel] = None
98
99
  """Partial channel object the interaction was invoked."""
99
100
 
100
- async def respond(self, message: str | MessageBuilder, with_response: bool = False, **flags: Unpack[MessageFlagParams]):
101
+ async def respond(self, message: str | MessagePart, with_response: bool = False, **flags: Unpack[MessageFlagParams]):
101
102
  """Create a message in response to an interaction.
102
103
 
103
104
  Args:
104
- message (str | MessageBuilder): content as a string or from MessageBuilder
105
+ message (str | MessagePart): content as a string or from MessagePart
105
106
  with_response (bool, optional): if the interaction data should be returned. Defaults to False.
106
107
 
107
108
  Raises:
108
109
  TypeError: invalid type
109
110
  """
110
111
  if isinstance(message, str):
111
- message = MessageBuilder(content=message).set_flags(**flags)
112
- elif not isinstance(message, MessageBuilder):
113
- raise TypeError(f"Interaction.respond expects type str or MessageBuilder, got {type(message).__name__}")
112
+ message = MessagePart(content=message).set_flags(**flags)
113
+ elif not isinstance(message, MessagePart):
114
+ raise TypeError(f"Interaction.respond expects type str or MessagePart, got {type(message).__name__}")
114
115
 
115
116
  content = {
116
117
  'type': InteractionCallbackTypes.CHANNEL_MESSAGE_WITH_SOURCE,
117
- 'data': message._to_dict()
118
+ 'data': message.to_dict()
118
119
  }
119
120
 
120
121
  params = {'with_response': with_response}
@@ -129,23 +130,23 @@ class Interaction(DataModel):
129
130
  if with_response:
130
131
  return InteractionCallbackModel.from_dict(data, self._http)
131
132
 
132
- async def update(self, message: str | MessageBuilder, **flags: Unpack[MessageFlagParams]):
133
+ async def update(self, message: str | MessagePart, **flags: Unpack[MessageFlagParams]):
133
134
  """Update a message in response to an interaction.
134
135
 
135
136
  Args:
136
- message (str | MessageBuilder): content as a string or from MessageBuilder
137
+ message (str | MessagePart): content as a string or from MessagePart
137
138
 
138
139
  Raises:
139
140
  TypeError: invalid type
140
141
  """
141
142
  if isinstance(message, str):
142
- message = MessageBuilder(content=message).set_flags(**flags)
143
- elif not isinstance(message, MessageBuilder):
144
- raise TypeError(f"Interaction.update expects type str or MessageBuilder, got {type(message).__name__}")
143
+ message = MessagePart(content=message).set_flags(**flags)
144
+ elif not isinstance(message, MessagePart):
145
+ raise TypeError(f"Interaction.update expects type str or MessagePart, got {type(message).__name__}")
145
146
 
146
147
  content = {
147
148
  'type': InteractionCallbackTypes.UPDATE_MESSAGE,
148
- 'data': message._to_dict()
149
+ 'data': message.to_dict()
149
150
  }
150
151
 
151
152
  await self._http.request(
@@ -154,21 +155,21 @@ class Interaction(DataModel):
154
155
  data=content,
155
156
  files=[fp.path for fp in message.attachments])
156
157
 
157
- async def respond_modal(self, modal: ModalBuilder):
158
+ async def respond_modal(self, modal: ModalPart):
158
159
  """Create a modal in response to an interaction.
159
160
 
160
161
  Args:
161
- modal (ModalBuilder): modal data
162
+ modal (ModalPart): modal data
162
163
 
163
164
  Raises:
164
165
  TypeError: invalid type
165
166
  """
166
- if not isinstance(modal, ModalBuilder):
167
- raise TypeError(f"Interaction.respond_modal expects type ModalBuilder, got {type(modal).__name__}")
167
+ if not isinstance(modal, ModalPart):
168
+ raise TypeError(f"Interaction.respond_modal expects type ModalPart, got {type(modal).__name__}")
168
169
 
169
170
  content = {
170
171
  'type': InteractionCallbackTypes.MODAL,
171
- 'data': modal._to_dict()
172
+ 'data': modal.to_dict()
172
173
  }
173
174
 
174
175
  await self._http.request(
@@ -6,7 +6,7 @@ from ..model import DataModel
6
6
 
7
7
  from ..models.user import UserModel
8
8
  from ..models.emoji import EmojiModel
9
- from ..parts.message import MessageBuilder
9
+ from ..parts.message import MessagePart
10
10
 
11
11
  @dataclass
12
12
  class Message(DataModel):
@@ -50,67 +50,67 @@ class Message(DataModel):
50
50
 
51
51
  return Message.from_dict(data, self._http)
52
52
 
53
- async def send(self, message: str | MessageBuilder):
53
+ async def send(self, message: str | MessagePart):
54
54
  """Sends a new message to the current channel.
55
55
 
56
56
  Permissions:
57
57
  * SEND_MESSAGES → required to senf your own messages
58
58
 
59
59
  Args:
60
- message (str | MessageBuilder): can be just text or the MessageBuilder for dynamic messages
60
+ message (str | MessagePart): can be just text or the MessagePart for dynamic messages
61
61
 
62
62
  Returns:
63
63
  (Message): the new Message object with all fields populated
64
64
  """
65
65
  if isinstance(message, str):
66
- message = MessageBuilder(content=message)
66
+ message = MessagePart(content=message)
67
67
 
68
68
  data = await self._http.request(
69
69
  "POST",
70
70
  f"/channels/{self.channel_id}/messages",
71
- data=message._to_dict(),
71
+ data=message.to_dict(),
72
72
  files=[fp.path for fp in message.attachments] if message.attachments else None
73
73
  )
74
74
  return Message.from_dict(data, self._http)
75
75
 
76
- async def edit(self, message: str | MessageBuilder):
76
+ async def edit(self, message: str | MessagePart):
77
77
  """Edits this message.
78
78
 
79
79
  Permissions:
80
80
  * MANAGE_MESSAGES → ONLY if editing another user's message
81
81
 
82
82
  Args:
83
- message (str | MessageBuilder): can be just text or the MessageBuilder for dynamic messages
83
+ message (str | MessagePart): can be just text or the MessagePart for dynamic messages
84
84
  """
85
85
  if isinstance(message, str):
86
- message = MessageBuilder(content=message)
86
+ message = MessagePart(content=message)
87
87
 
88
88
  data = await self._http.request(
89
89
  "PATCH",
90
90
  f"/channels/{self.channel_id}/messages/{self.id}",
91
- data=message._to_dict(),
91
+ data=message.to_dict(),
92
92
  files=[fp.path for fp in message.attachments] if message.attachments else None)
93
93
 
94
94
  self._update(data)
95
95
 
96
- async def reply(self, message: str | MessageBuilder):
96
+ async def reply(self, message: str | MessagePart):
97
97
  """Reply to this message with a new message.
98
98
 
99
99
  Permissions:
100
100
  * SEND_MESSAGES → required to send the message
101
101
 
102
102
  Args:
103
- message (str | MessageBuilder): the new message
103
+ message (str | MessagePart): the new message
104
104
  """
105
105
  if isinstance(message, str):
106
- message = MessageBuilder(content=message)
106
+ message = MessagePart(content=message)
107
107
 
108
108
  message = message._set_reference(self.id, self.channel_id)
109
109
 
110
110
  await self._http.request(
111
111
  'POST',
112
112
  f"/channels/{self.channel_id}/messages",
113
- data=message._to_dict(),
113
+ data=message.to_dict(),
114
114
  files=[fp.path for fp in message.attachments] if message.attachments else None)
115
115
 
116
116
  async def crosspost(self):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scurrypy
3
- Version: 0.4.2
3
+ Version: 0.5.3
4
4
  Summary: Dataclass-driven Discord API Wrapper in Python
5
5
  Author: Furmissile
6
6
  Requires-Python: >=3.10
@@ -8,7 +8,7 @@ Description-Content-Type: text/markdown
8
8
  License-File: LICENSE
9
9
  Dynamic: license-file
10
10
 
11
- # __Welcome to ScurryPy__
11
+ # __ScurryPy__
12
12
 
13
13
  [![PyPI version](https://badge.fury.io/py/scurrypy.svg)](https://badge.fury.io/py/scurrypy)
14
14
 
@@ -20,22 +20,17 @@ A dataclass-driven Discord API wrapper in Python!
20
20
 
21
21
  While this wrapper is mainly used for various squirrel-related shenanigans, it can also be used for more generic bot purposes.
22
22
 
23
- ---
24
-
25
23
  ## Features
26
- * Command and event handling
27
- * Declarative style using decorators
28
- * Supports both legacy and new features
29
- * Respects Discord’s rate limits
30
-
31
- ---
24
+ * Command, and event handling
25
+ * Unix shell-style wildcards for component routing
26
+ * Declarative style using decorators
27
+ * Supports both legacy and new features
28
+ * Respects Discord’s rate limits
32
29
 
33
- ## Some Things to Consider...
30
+ ## Notes & Early Status
34
31
  * This is an early version — feedback, ideas, and contributions are very welcome! That said, there may be bumps along the way, so expect occasional bugs and quirks.
35
32
  * Certain features are not yet supported, while others are intentionally omitted. See the [docs](https://furmissile.github.io/scurrypy) for full details.
36
33
 
37
- ---
38
-
39
34
  ## Getting Started
40
35
  *Note: This section also appears in the documentation, but here are complete examples ready to use with your bot credentials.*
41
36
 
@@ -51,24 +46,24 @@ The following demonstrates building and responding to a slash command.
51
46
  *Note: Adjust `dotenv_path` if your `.env` file is not in the same directory as this script.*
52
47
 
53
48
  ```py
54
- import discord, os
49
+ import scurrypy, os
55
50
  from dotenv import load_dotenv
56
51
 
57
52
  load_dotenv(dotenv_path='./path/to/env')
58
53
 
59
- client = discord.Client(
54
+ client = scurrypy.Client(
60
55
  token=os.getenv("DISCORD_TOKEN"),
61
- application_id=APPLICATION_ID # replace with your bot's user ID
56
+ application_id=APPLICATION_ID # your bots application ID
62
57
  )
63
58
 
64
59
  @client.command(
65
- command=discord.SlashCommand(
60
+ command=scurrypy.SlashCommand(
66
61
  name='example',
67
62
  description='Demonstrate the minimal slash command!'
68
63
  ),
69
64
  guild_ids=GUILD_ID # must be a guild ID your bot is in
70
65
  )
71
- async def example(bot: discord.Client, event: discord.InteractionEvent):
66
+ async def example(bot: scurrypy.Client, event: scurrypy.InteractionEvent):
72
67
  await event.interaction.respond(f'Hello, {event.interaction.member.user.username}!')
73
68
 
74
69
  client.run()
@@ -77,20 +72,20 @@ client.run()
77
72
  ## Minimal Prefix Command (Legacy)
78
73
  The following demonstrates building and responding to a message prefix command.
79
74
  ```py
80
- import discord, os
75
+ import scurrypy, os
81
76
  from dotenv import load_dotenv
82
77
 
83
78
  load_dotenv(dotenv_path='./path/to/env')
84
79
 
85
- client = discord.Client(
80
+ client = scurrypy.Client(
86
81
  token=os.getenv("DISCORD_TOKEN"),
87
- application_id=APPLICATION_ID, # replace with your bot's user ID
88
- intents=discord.set_intents(message_content=True),
82
+ application_id=APPLICATION_ID # your bots application ID
83
+ intents=scurrypy.set_intents(message_content=True),
89
84
  prefix='!' # your custom prefix
90
85
  )
91
86
 
92
87
  @client.prefix_command
93
- async def ping(bot: discord.Client, event: discord.MessageCreateEvent):
88
+ async def ping(bot: scurrypy.Client, event: scurrypy.MessageCreateEvent):
94
89
  # The function name is the name of the command
95
90
  await event.message.send("Pong!")
96
91
 
@@ -126,5 +121,4 @@ If you plan to make substantial changes or release your own variant:
126
121
  See the [License](./LICENSE) for details.
127
122
 
128
123
  ## Like What You See?
129
- Check out the full [documentation](https://furmissile.github.io/scurrypy)
130
- for more examples, guides, and API reference!
124
+ Explore the full [documentation](https://furmissile.github.io/scurrypy) for more examples, guides, and API reference.