drekord 0.1.0__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.
- drekord-0.1.0/.gitignore +36 -0
- drekord-0.1.0/LICENSE +21 -0
- drekord-0.1.0/PKG-INFO +287 -0
- drekord-0.1.0/README.md +255 -0
- drekord-0.1.0/drekord/__init__.py +95 -0
- drekord-0.1.0/drekord/api.py +891 -0
- drekord-0.1.0/drekord/client.py +144 -0
- drekord-0.1.0/drekord/exceptions.py +151 -0
- drekord-0.1.0/drekord/http.py +248 -0
- drekord-0.1.0/drekord/models.py +1402 -0
- drekord-0.1.0/drekord/ui/__init__.py +81 -0
- drekord-0.1.0/drekord/ui/components.py +929 -0
- drekord-0.1.0/drekord/ui/view.py +115 -0
- drekord-0.1.0/examples/basic_usage.py +90 -0
- drekord-0.1.0/examples/components_v2_example.py +185 -0
- drekord-0.1.0/examples/webhook_example.py +65 -0
- drekord-0.1.0/pyproject.toml +65 -0
drekord-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Bytecompiled / optimized
|
|
2
|
+
*__pycache__*
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Distribution / packaging
|
|
7
|
+
build/
|
|
8
|
+
dist/
|
|
9
|
+
*.egg-info/
|
|
10
|
+
*.egg
|
|
11
|
+
|
|
12
|
+
# Virtual environments
|
|
13
|
+
.venv/
|
|
14
|
+
venv/
|
|
15
|
+
env/
|
|
16
|
+
|
|
17
|
+
# IDE
|
|
18
|
+
.vscode/
|
|
19
|
+
.idea/
|
|
20
|
+
*.swp
|
|
21
|
+
*.swo
|
|
22
|
+
|
|
23
|
+
# Testing / coverage
|
|
24
|
+
.pytest_cache/
|
|
25
|
+
htmlcov/
|
|
26
|
+
.coverage
|
|
27
|
+
.coverage.*
|
|
28
|
+
|
|
29
|
+
# mypy / ruff
|
|
30
|
+
.mypy_cache/
|
|
31
|
+
.ruff_cache/
|
|
32
|
+
|
|
33
|
+
# OS
|
|
34
|
+
.DS_Store
|
|
35
|
+
Thumbs.db
|
|
36
|
+
build.bat
|
drekord-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 drek124
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
drekord-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: drekord
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A lightweight, async Discord REST API wrapper for Python
|
|
5
|
+
Project-URL: Homepage, https://github.com/drek124/drekord
|
|
6
|
+
Project-URL: Repository, https://github.com/drek124/drekord
|
|
7
|
+
Project-URL: Issues, https://github.com/drek124/drekord/issues
|
|
8
|
+
Author-email: drek124 <drek.dev124@gmail.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: api,async,discord,rest,wrapper
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Communications :: Chat
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Requires-Dist: aiohttp>=3.9.0
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: aioresponses>=0.7; extra == 'dev'
|
|
27
|
+
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# Drekord Discord API Wrapper
|
|
34
|
+
|
|
35
|
+
A lightweight, async Discord REST API wrapper for Python.
|
|
36
|
+
|
|
37
|
+
BTW, Drekord is **not** a bot framework (like `discord.py`). It is a pure REST API client designed to be integrated into any async application that needs to interact with the Discord API, without maintaining a persistent WebSocket connection.
|
|
38
|
+
|
|
39
|
+
## Features
|
|
40
|
+
- **Pure REST:** No WebSocket gateway; just API calls
|
|
41
|
+
- **Fully async:** Built on `aiohttp` for clean `async/await` usage
|
|
42
|
+
- **Object-oriented:** Making it ez to use x)
|
|
43
|
+
- **Rate-limit aware:** Automatic retry on rate limits and transient errors
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
## Installation
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pip install drekord
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Or from source:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
git clone https://github.com/drek124/drekord.git
|
|
56
|
+
cd drekord
|
|
57
|
+
pip install -e .
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Quick Start
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
import asyncio
|
|
64
|
+
import drekord
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
async def main():
|
|
68
|
+
async with drekord.Client(token="YOUR_BOT_TOKEN") as client:
|
|
69
|
+
# Get the current bot user
|
|
70
|
+
me = await client.users.me()
|
|
71
|
+
print(f"Logged in as {me.username}")
|
|
72
|
+
|
|
73
|
+
# Send a message to a channel
|
|
74
|
+
msg = await client.messages.channel(CHANNEL_ID).send(
|
|
75
|
+
content="Hello from Drekord! 🎉"
|
|
76
|
+
)
|
|
77
|
+
print(f"Sent message {msg.id}")
|
|
78
|
+
|
|
79
|
+
# Read the last 10 messages
|
|
80
|
+
messages = await client.messages.channel(CHANNEL_ID).list(limit=10)
|
|
81
|
+
for m in messages:
|
|
82
|
+
print(f"{m.author.username}: {m.content}")
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
asyncio.run(main())
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## API Overview
|
|
89
|
+
|
|
90
|
+
All API access is through resource classes on the `Client`:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
client.users # UsersResource
|
|
94
|
+
client.guilds # GuildResource
|
|
95
|
+
client.messages # MessagesResource
|
|
96
|
+
client.channels # ChannelResource
|
|
97
|
+
client.webhooks # WebhooksResource
|
|
98
|
+
client.invites # InvitesResource
|
|
99
|
+
client.emojis # EmojiResource
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Users
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
# Current bot user
|
|
106
|
+
me = await client.users.me()
|
|
107
|
+
|
|
108
|
+
# Get any user
|
|
109
|
+
user = await client.users.get(user_id)
|
|
110
|
+
|
|
111
|
+
# Create a DM
|
|
112
|
+
dm_channel = await client.users.dm(user_id)
|
|
113
|
+
|
|
114
|
+
# Edit the bot's username/avatar
|
|
115
|
+
me = await client.users.edit({"username": "new_name"})
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Messages
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
# List messages in a channel
|
|
122
|
+
messages = await client.messages.channel(channel_id).list(limit=50)
|
|
123
|
+
|
|
124
|
+
# Send a message
|
|
125
|
+
msg = await client.messages.channel(channel_id).send(
|
|
126
|
+
content="Hello!",
|
|
127
|
+
embeds=[{"title": "My Embed", "description": "With an embed!"}],
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
# Edit a message
|
|
131
|
+
msg = await client.messages.channel(channel_id).edit(message_id, content="Edited!")
|
|
132
|
+
|
|
133
|
+
# Delete a message
|
|
134
|
+
await client.messages.channel(channel_id).delete(message_id)
|
|
135
|
+
|
|
136
|
+
# Pin / unpin
|
|
137
|
+
await client.messages.channel(channel_id).pin(message_id)
|
|
138
|
+
await client.messages.channel(channel_id).unpin(message_id)
|
|
139
|
+
|
|
140
|
+
# Bulk delete
|
|
141
|
+
await client.messages.bulk_delete(channel_id, [msg1_id, msg2_id, msg3_id])
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Guilds
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
# List bot's guilds
|
|
148
|
+
guilds = await client.guilds.list()
|
|
149
|
+
|
|
150
|
+
# Get a guild
|
|
151
|
+
guild = await client.guilds.get(guild_id)
|
|
152
|
+
print(f"{guild.name} has {guild.approximate_member_count} members")
|
|
153
|
+
|
|
154
|
+
# Edit guild settings
|
|
155
|
+
await client.guilds.edit(guild_id, {"name": "New Name"})
|
|
156
|
+
|
|
157
|
+
# Leave a guild
|
|
158
|
+
await client.guilds.leave(guild_id)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Guild Sub-Resources
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
# Channels
|
|
165
|
+
channels = await client.guilds.channels(guild_id).list()
|
|
166
|
+
new_channel = await client.guilds.channels(guild_id).create({
|
|
167
|
+
"name": "new-channel",
|
|
168
|
+
"type": 0, # text channel
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
# Members
|
|
172
|
+
members = await client.guilds.members(guild_id).list(limit=100)
|
|
173
|
+
member = await client.guilds.members(guild_id).get(user_id)
|
|
174
|
+
|
|
175
|
+
# Roles
|
|
176
|
+
roles = await client.guilds.roles(guild_id).list()
|
|
177
|
+
new_role = await client.guilds.roles(guild_id).create({"name": "Moderator", "color": 0xFF0000})
|
|
178
|
+
|
|
179
|
+
# Emojis
|
|
180
|
+
emojis = await client.guilds.emojis(guild_id).list()
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Channels
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
channel = await client.channels.get(channel_id)
|
|
187
|
+
|
|
188
|
+
# Edit a channel
|
|
189
|
+
channel = await client.channels.edit(channel_id, {"name": "renamed"})
|
|
190
|
+
|
|
191
|
+
# Set permissions
|
|
192
|
+
await client.channels.set_permissions(channel_id, overwrite_id, allow="1024", deny="0")
|
|
193
|
+
|
|
194
|
+
# Trigger typing indicator
|
|
195
|
+
await client.channels.typing(channel_id)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Webhooks
|
|
199
|
+
|
|
200
|
+
```python
|
|
201
|
+
# List webhooks in a channel
|
|
202
|
+
webhooks = await client.webhooks.channel_webhooks(channel_id)
|
|
203
|
+
|
|
204
|
+
# Create a webhook
|
|
205
|
+
webhook = await client.webhooks.create(channel_id, name="My Webhook")
|
|
206
|
+
|
|
207
|
+
# Execute a webhook (send via webhook)
|
|
208
|
+
await client.webhooks.execute(
|
|
209
|
+
webhook.id,
|
|
210
|
+
token=webhook.token,
|
|
211
|
+
content="Posted via webhook!",
|
|
212
|
+
username="Drekord Bot",
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
# Delete a webhook
|
|
216
|
+
await client.webhooks.delete(webhook.id)
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Raw Requests (Escape Hatch)
|
|
220
|
+
|
|
221
|
+
For endpoints not yet covered:
|
|
222
|
+
|
|
223
|
+
```python
|
|
224
|
+
data = await client.request("GET", "/gateway")
|
|
225
|
+
data = await client.request("POST", "/channels/123/threads", json={"name": "Thread"})
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Error Handling
|
|
229
|
+
|
|
230
|
+
Drekord raises typed exceptions for all error cases:
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
import drekord
|
|
234
|
+
|
|
235
|
+
try:
|
|
236
|
+
msg = await client.messages.channel(channel_id).send(content="Hello!")
|
|
237
|
+
except drekord.ForbiddenError:
|
|
238
|
+
print("I don't have permission to send messages here!")
|
|
239
|
+
except drekord.NotFoundError:
|
|
240
|
+
print("Channel not found!")
|
|
241
|
+
except drekord.RateLimitedError as e:
|
|
242
|
+
print(f"Rate limited! Retry after {e.retry_after}s")
|
|
243
|
+
except drekord.HTTPError as e:
|
|
244
|
+
print(f"HTTP error {e.status_code}: {e}")
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Exception Hierarchy
|
|
248
|
+
|
|
249
|
+
```
|
|
250
|
+
DrekordError
|
|
251
|
+
└── HTTPError
|
|
252
|
+
├── BadRequestError (400)
|
|
253
|
+
├── UnauthorizedError (401)
|
|
254
|
+
├── ForbiddenError (403)
|
|
255
|
+
├── NotFoundError (404)
|
|
256
|
+
├── RateLimitedError (429)
|
|
257
|
+
└── DiscordServerError (5xx)
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## Models
|
|
261
|
+
|
|
262
|
+
All API responses are returned as model objects with typed properties:
|
|
263
|
+
|
|
264
|
+
```python
|
|
265
|
+
user = await client.users.get(user_id)
|
|
266
|
+
print(user.id) # int
|
|
267
|
+
print(user.username) # str
|
|
268
|
+
print(user.global_name) # str | None
|
|
269
|
+
print(user.bot) # bool
|
|
270
|
+
print(user.avatar_url()) # str | None
|
|
271
|
+
|
|
272
|
+
guild = await client.guilds.get(guild_id)
|
|
273
|
+
print(guild.name) # str
|
|
274
|
+
print(guild.icon_url()) # str | None
|
|
275
|
+
print(guild.roles) # list[Role]
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
Models also support dict-style access for unmapped fields:
|
|
279
|
+
|
|
280
|
+
```python
|
|
281
|
+
user_data = user.raw # Get the raw dict
|
|
282
|
+
custom = user.get("custom_status") # Access any field
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## License
|
|
286
|
+
|
|
287
|
+
MIT
|
drekord-0.1.0/README.md
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
# Drekord Discord API Wrapper
|
|
2
|
+
|
|
3
|
+
A lightweight, async Discord REST API wrapper for Python.
|
|
4
|
+
|
|
5
|
+
BTW, Drekord is **not** a bot framework (like `discord.py`). It is a pure REST API client designed to be integrated into any async application that needs to interact with the Discord API, without maintaining a persistent WebSocket connection.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
- **Pure REST:** No WebSocket gateway; just API calls
|
|
9
|
+
- **Fully async:** Built on `aiohttp` for clean `async/await` usage
|
|
10
|
+
- **Object-oriented:** Making it ez to use x)
|
|
11
|
+
- **Rate-limit aware:** Automatic retry on rate limits and transient errors
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install drekord
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Or from source:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
git clone https://github.com/drek124/drekord.git
|
|
24
|
+
cd drekord
|
|
25
|
+
pip install -e .
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
import asyncio
|
|
32
|
+
import drekord
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
async def main():
|
|
36
|
+
async with drekord.Client(token="YOUR_BOT_TOKEN") as client:
|
|
37
|
+
# Get the current bot user
|
|
38
|
+
me = await client.users.me()
|
|
39
|
+
print(f"Logged in as {me.username}")
|
|
40
|
+
|
|
41
|
+
# Send a message to a channel
|
|
42
|
+
msg = await client.messages.channel(CHANNEL_ID).send(
|
|
43
|
+
content="Hello from Drekord! 🎉"
|
|
44
|
+
)
|
|
45
|
+
print(f"Sent message {msg.id}")
|
|
46
|
+
|
|
47
|
+
# Read the last 10 messages
|
|
48
|
+
messages = await client.messages.channel(CHANNEL_ID).list(limit=10)
|
|
49
|
+
for m in messages:
|
|
50
|
+
print(f"{m.author.username}: {m.content}")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
asyncio.run(main())
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## API Overview
|
|
57
|
+
|
|
58
|
+
All API access is through resource classes on the `Client`:
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
client.users # UsersResource
|
|
62
|
+
client.guilds # GuildResource
|
|
63
|
+
client.messages # MessagesResource
|
|
64
|
+
client.channels # ChannelResource
|
|
65
|
+
client.webhooks # WebhooksResource
|
|
66
|
+
client.invites # InvitesResource
|
|
67
|
+
client.emojis # EmojiResource
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Users
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
# Current bot user
|
|
74
|
+
me = await client.users.me()
|
|
75
|
+
|
|
76
|
+
# Get any user
|
|
77
|
+
user = await client.users.get(user_id)
|
|
78
|
+
|
|
79
|
+
# Create a DM
|
|
80
|
+
dm_channel = await client.users.dm(user_id)
|
|
81
|
+
|
|
82
|
+
# Edit the bot's username/avatar
|
|
83
|
+
me = await client.users.edit({"username": "new_name"})
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Messages
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
# List messages in a channel
|
|
90
|
+
messages = await client.messages.channel(channel_id).list(limit=50)
|
|
91
|
+
|
|
92
|
+
# Send a message
|
|
93
|
+
msg = await client.messages.channel(channel_id).send(
|
|
94
|
+
content="Hello!",
|
|
95
|
+
embeds=[{"title": "My Embed", "description": "With an embed!"}],
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
# Edit a message
|
|
99
|
+
msg = await client.messages.channel(channel_id).edit(message_id, content="Edited!")
|
|
100
|
+
|
|
101
|
+
# Delete a message
|
|
102
|
+
await client.messages.channel(channel_id).delete(message_id)
|
|
103
|
+
|
|
104
|
+
# Pin / unpin
|
|
105
|
+
await client.messages.channel(channel_id).pin(message_id)
|
|
106
|
+
await client.messages.channel(channel_id).unpin(message_id)
|
|
107
|
+
|
|
108
|
+
# Bulk delete
|
|
109
|
+
await client.messages.bulk_delete(channel_id, [msg1_id, msg2_id, msg3_id])
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Guilds
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
# List bot's guilds
|
|
116
|
+
guilds = await client.guilds.list()
|
|
117
|
+
|
|
118
|
+
# Get a guild
|
|
119
|
+
guild = await client.guilds.get(guild_id)
|
|
120
|
+
print(f"{guild.name} has {guild.approximate_member_count} members")
|
|
121
|
+
|
|
122
|
+
# Edit guild settings
|
|
123
|
+
await client.guilds.edit(guild_id, {"name": "New Name"})
|
|
124
|
+
|
|
125
|
+
# Leave a guild
|
|
126
|
+
await client.guilds.leave(guild_id)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Guild Sub-Resources
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
# Channels
|
|
133
|
+
channels = await client.guilds.channels(guild_id).list()
|
|
134
|
+
new_channel = await client.guilds.channels(guild_id).create({
|
|
135
|
+
"name": "new-channel",
|
|
136
|
+
"type": 0, # text channel
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
# Members
|
|
140
|
+
members = await client.guilds.members(guild_id).list(limit=100)
|
|
141
|
+
member = await client.guilds.members(guild_id).get(user_id)
|
|
142
|
+
|
|
143
|
+
# Roles
|
|
144
|
+
roles = await client.guilds.roles(guild_id).list()
|
|
145
|
+
new_role = await client.guilds.roles(guild_id).create({"name": "Moderator", "color": 0xFF0000})
|
|
146
|
+
|
|
147
|
+
# Emojis
|
|
148
|
+
emojis = await client.guilds.emojis(guild_id).list()
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Channels
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
channel = await client.channels.get(channel_id)
|
|
155
|
+
|
|
156
|
+
# Edit a channel
|
|
157
|
+
channel = await client.channels.edit(channel_id, {"name": "renamed"})
|
|
158
|
+
|
|
159
|
+
# Set permissions
|
|
160
|
+
await client.channels.set_permissions(channel_id, overwrite_id, allow="1024", deny="0")
|
|
161
|
+
|
|
162
|
+
# Trigger typing indicator
|
|
163
|
+
await client.channels.typing(channel_id)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Webhooks
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
# List webhooks in a channel
|
|
170
|
+
webhooks = await client.webhooks.channel_webhooks(channel_id)
|
|
171
|
+
|
|
172
|
+
# Create a webhook
|
|
173
|
+
webhook = await client.webhooks.create(channel_id, name="My Webhook")
|
|
174
|
+
|
|
175
|
+
# Execute a webhook (send via webhook)
|
|
176
|
+
await client.webhooks.execute(
|
|
177
|
+
webhook.id,
|
|
178
|
+
token=webhook.token,
|
|
179
|
+
content="Posted via webhook!",
|
|
180
|
+
username="Drekord Bot",
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
# Delete a webhook
|
|
184
|
+
await client.webhooks.delete(webhook.id)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Raw Requests (Escape Hatch)
|
|
188
|
+
|
|
189
|
+
For endpoints not yet covered:
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
data = await client.request("GET", "/gateway")
|
|
193
|
+
data = await client.request("POST", "/channels/123/threads", json={"name": "Thread"})
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Error Handling
|
|
197
|
+
|
|
198
|
+
Drekord raises typed exceptions for all error cases:
|
|
199
|
+
|
|
200
|
+
```python
|
|
201
|
+
import drekord
|
|
202
|
+
|
|
203
|
+
try:
|
|
204
|
+
msg = await client.messages.channel(channel_id).send(content="Hello!")
|
|
205
|
+
except drekord.ForbiddenError:
|
|
206
|
+
print("I don't have permission to send messages here!")
|
|
207
|
+
except drekord.NotFoundError:
|
|
208
|
+
print("Channel not found!")
|
|
209
|
+
except drekord.RateLimitedError as e:
|
|
210
|
+
print(f"Rate limited! Retry after {e.retry_after}s")
|
|
211
|
+
except drekord.HTTPError as e:
|
|
212
|
+
print(f"HTTP error {e.status_code}: {e}")
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Exception Hierarchy
|
|
216
|
+
|
|
217
|
+
```
|
|
218
|
+
DrekordError
|
|
219
|
+
└── HTTPError
|
|
220
|
+
├── BadRequestError (400)
|
|
221
|
+
├── UnauthorizedError (401)
|
|
222
|
+
├── ForbiddenError (403)
|
|
223
|
+
├── NotFoundError (404)
|
|
224
|
+
├── RateLimitedError (429)
|
|
225
|
+
└── DiscordServerError (5xx)
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Models
|
|
229
|
+
|
|
230
|
+
All API responses are returned as model objects with typed properties:
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
user = await client.users.get(user_id)
|
|
234
|
+
print(user.id) # int
|
|
235
|
+
print(user.username) # str
|
|
236
|
+
print(user.global_name) # str | None
|
|
237
|
+
print(user.bot) # bool
|
|
238
|
+
print(user.avatar_url()) # str | None
|
|
239
|
+
|
|
240
|
+
guild = await client.guilds.get(guild_id)
|
|
241
|
+
print(guild.name) # str
|
|
242
|
+
print(guild.icon_url()) # str | None
|
|
243
|
+
print(guild.roles) # list[Role]
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Models also support dict-style access for unmapped fields:
|
|
247
|
+
|
|
248
|
+
```python
|
|
249
|
+
user_data = user.raw # Get the raw dict
|
|
250
|
+
custom = user.get("custom_status") # Access any field
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## License
|
|
254
|
+
|
|
255
|
+
MIT
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Drekord - A lightweight, async Discord REST API wrapper.
|
|
3
|
+
|
|
4
|
+
Drekord is not a bot framework. It is a pure API client designed to be
|
|
5
|
+
integrated into any async application that needs to interact with the
|
|
6
|
+
Discord REST API — read messages, send messages, manage channels, etc.
|
|
7
|
+
|
|
8
|
+
Usage::
|
|
9
|
+
|
|
10
|
+
import drekord
|
|
11
|
+
|
|
12
|
+
async with drekord.Client(token="your_token") as client:
|
|
13
|
+
# Basic message
|
|
14
|
+
await client.messages.channel(ch).send(content="Hello!")
|
|
15
|
+
|
|
16
|
+
# With an embed
|
|
17
|
+
embed = drekord.Embed(title="Hi", description="World")
|
|
18
|
+
await client.messages.channel(ch).send(embeds=[embed])
|
|
19
|
+
|
|
20
|
+
# With Components V2
|
|
21
|
+
view = drekord.ui.LayoutView()
|
|
22
|
+
view.add_item(drekord.ui.Container(
|
|
23
|
+
drekord.ui.TextDisplay("## Hello!"),
|
|
24
|
+
drekord.ui.Separator(),
|
|
25
|
+
accent_color="#5865F2",
|
|
26
|
+
))
|
|
27
|
+
await client.messages.channel(ch).send(view=view)
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
__version__ = "0.1.0"
|
|
31
|
+
__author__ = "drek124"
|
|
32
|
+
|
|
33
|
+
from .client import Client
|
|
34
|
+
from .exceptions import (
|
|
35
|
+
DrekordError,
|
|
36
|
+
HTTPError,
|
|
37
|
+
RateLimitedError,
|
|
38
|
+
ForbiddenError,
|
|
39
|
+
NotFoundError,
|
|
40
|
+
BadRequestError,
|
|
41
|
+
UnauthorizedError,
|
|
42
|
+
DiscordServerError,
|
|
43
|
+
)
|
|
44
|
+
from .models import (
|
|
45
|
+
User,
|
|
46
|
+
Guild,
|
|
47
|
+
Channel,
|
|
48
|
+
Message,
|
|
49
|
+
Role,
|
|
50
|
+
Emoji,
|
|
51
|
+
Attachment,
|
|
52
|
+
Embed,
|
|
53
|
+
EmbedField,
|
|
54
|
+
EmbedFooter,
|
|
55
|
+
EmbedImage,
|
|
56
|
+
EmbedAuthor,
|
|
57
|
+
PermissionOverwrite,
|
|
58
|
+
GuildPreview,
|
|
59
|
+
VoiceRegion,
|
|
60
|
+
Integration,
|
|
61
|
+
AuditLogEntry,
|
|
62
|
+
Webhook,
|
|
63
|
+
Snowflake,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
__all__ = [
|
|
67
|
+
"Client",
|
|
68
|
+
"DrekordError",
|
|
69
|
+
"HTTPError",
|
|
70
|
+
"RateLimitedError",
|
|
71
|
+
"ForbiddenError",
|
|
72
|
+
"NotFoundError",
|
|
73
|
+
"BadRequestError",
|
|
74
|
+
"UnauthorizedError",
|
|
75
|
+
"DiscordServerError",
|
|
76
|
+
"User",
|
|
77
|
+
"Guild",
|
|
78
|
+
"Channel",
|
|
79
|
+
"Message",
|
|
80
|
+
"Role",
|
|
81
|
+
"Emoji",
|
|
82
|
+
"Attachment",
|
|
83
|
+
"Embed",
|
|
84
|
+
"EmbedField",
|
|
85
|
+
"EmbedFooter",
|
|
86
|
+
"EmbedImage",
|
|
87
|
+
"EmbedAuthor",
|
|
88
|
+
"PermissionOverwrite",
|
|
89
|
+
"GuildPreview",
|
|
90
|
+
"VoiceRegion",
|
|
91
|
+
"Integration",
|
|
92
|
+
"AuditLogEntry",
|
|
93
|
+
"Webhook",
|
|
94
|
+
"Snowflake",
|
|
95
|
+
]
|