scurrypy 0.6.5__tar.gz → 0.7.2__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.
- {scurrypy-0.6.5/scurrypy.egg-info → scurrypy-0.7.2}/PKG-INFO +32 -28
- {scurrypy-0.6.5 → scurrypy-0.7.2}/README.md +31 -27
- {scurrypy-0.6.5 → scurrypy-0.7.2}/pyproject.toml +4 -2
- scurrypy-0.7.2/scurrypy/__init__.py +16 -0
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/client.py +13 -9
- scurrypy-0.7.2/scurrypy/core/__init__.py +16 -0
- {scurrypy-0.6.5/scurrypy → scurrypy-0.7.2/scurrypy/core}/http.py +28 -54
- {scurrypy-0.6.5/scurrypy → scurrypy-0.7.2/scurrypy/core}/intents.py +1 -1
- scurrypy-0.7.2/scurrypy/dispatch/__init__.py +7 -0
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/dispatch/command_dispatcher.py +1 -1
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/dispatch/event_dispatcher.py +4 -1
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/dispatch/prefix_dispatcher.py +1 -1
- scurrypy-0.7.2/scurrypy/events/__init__.py +62 -0
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/events/channel_events.py +1 -1
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/events/gateway_events.py +1 -1
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/events/guild_events.py +21 -1
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/events/hello_event.py +1 -1
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/events/interaction_events.py +1 -1
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/events/message_events.py +1 -1
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/events/reaction_events.py +1 -1
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/events/ready_event.py +1 -1
- scurrypy-0.7.2/scurrypy/models/__init__.py +15 -0
- scurrypy-0.7.2/scurrypy/models/emoji.py +50 -0
- scurrypy-0.7.2/scurrypy/models/guild.py +37 -0
- scurrypy-0.7.2/scurrypy/models/interaction.py +31 -0
- scurrypy-0.7.2/scurrypy/models/role.py +54 -0
- scurrypy-0.7.2/scurrypy/models/user.py +95 -0
- scurrypy-0.7.2/scurrypy/parts/__init__.py +79 -0
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/parts/channel.py +1 -1
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/parts/command.py +1 -1
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/parts/components.py +1 -1
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/parts/components_v2.py +1 -1
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/parts/embed.py +1 -1
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/parts/message.py +1 -1
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/parts/modal.py +1 -1
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/parts/role.py +1 -1
- scurrypy-0.7.2/scurrypy/resources/__init__.py +45 -0
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/resources/application.py +2 -2
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/resources/bot_emojis.py +1 -1
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/resources/channel.py +2 -2
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/resources/guild.py +2 -2
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/resources/interaction.py +2 -2
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/resources/message.py +13 -5
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/resources/user.py +2 -2
- {scurrypy-0.6.5 → scurrypy-0.7.2/scurrypy.egg-info}/PKG-INFO +32 -28
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy.egg-info/SOURCES.txt +15 -9
- scurrypy-0.6.5/scurrypy/__init__.py +0 -429
- scurrypy-0.6.5/scurrypy/dispatch/__init__.py +0 -1
- scurrypy-0.6.5/scurrypy/events/__init__.py +0 -1
- scurrypy-0.6.5/scurrypy/models.py +0 -258
- scurrypy-0.6.5/scurrypy/parts/__init__.py +0 -2
- scurrypy-0.6.5/scurrypy/resources/__init__.py +0 -1
- {scurrypy-0.6.5 → scurrypy-0.7.2}/LICENSE +0 -0
- {scurrypy-0.6.5/scurrypy → scurrypy-0.7.2/scurrypy/core}/client_like.py +0 -0
- {scurrypy-0.6.5/scurrypy → scurrypy-0.7.2/scurrypy/core}/config.py +0 -0
- {scurrypy-0.6.5/scurrypy → scurrypy-0.7.2/scurrypy/core}/error.py +0 -0
- {scurrypy-0.6.5/scurrypy → scurrypy-0.7.2/scurrypy/core}/gateway.py +0 -0
- {scurrypy-0.6.5/scurrypy → scurrypy-0.7.2/scurrypy/core}/logger.py +0 -0
- {scurrypy-0.6.5/scurrypy → scurrypy-0.7.2/scurrypy/core}/model.py +0 -0
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy/parts/component_types.py +0 -0
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy.egg-info/dependency_links.txt +0 -0
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy.egg-info/requires.txt +0 -0
- {scurrypy-0.6.5 → scurrypy-0.7.2}/scurrypy.egg-info/top_level.txt +0 -0
- {scurrypy-0.6.5 → scurrypy-0.7.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scurrypy
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.2
|
|
4
4
|
Summary: Dataclass-driven Discord API Wrapper in Python
|
|
5
5
|
Author: Furmissile
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -10,16 +10,17 @@ Requires-Dist: aiohttp>=3.8.0
|
|
|
10
10
|
Requires-Dist: websockets>=11.0.0
|
|
11
11
|
Dynamic: license-file
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
## __<center> ScurryPy </center>__
|
|
14
14
|
|
|
15
15
|
[](https://badge.fury.io/py/scurrypy)
|
|
16
16
|
|
|
17
|
-
A
|
|
17
|
+
A lightweight, fully readable Discord API framework built to accommodate everything from basic bots to custom frameworks.
|
|
18
18
|
|
|
19
|
-
While
|
|
19
|
+
While ScurryPy powers many squirrel-related shenanigans, it works just as well for game bots, interactive components, and educational projects.
|
|
20
20
|
|
|
21
21
|
## Features
|
|
22
|
-
* Easy to extend
|
|
22
|
+
* Easy to extend and build frameworks on top
|
|
23
|
+
* Lightweight core (<1000 lines)
|
|
23
24
|
* Command, and event handling
|
|
24
25
|
* Unix shell-style wildcards for component routing
|
|
25
26
|
* Declarative style using decorators
|
|
@@ -28,29 +29,6 @@ While this wrapper is mainly used for various squirrel-related shenanigans, it c
|
|
|
28
29
|
* No `__future__` hacks to avoid circular import
|
|
29
30
|
* Capable of sharding
|
|
30
31
|
|
|
31
|
-
## Benchmarks
|
|
32
|
-
Not convinced ScurryPy has a place among top libraries? See the benchmarks below!
|
|
33
|
-
|
|
34
|
-
### Test Environment
|
|
35
|
-
|
|
36
|
-
- **Python**: 3.11.6
|
|
37
|
-
- **OS**: Windows 11
|
|
38
|
-
- **Method**: New Python process per measurement
|
|
39
|
-
- **Tool**: See benchmarks folder
|
|
40
|
-
|
|
41
|
-
### Results Summary
|
|
42
|
-
|
|
43
|
-
```
|
|
44
|
-
Library Time (ms) Memory Δ (MB) Objects
|
|
45
|
-
--------------------------------------------------------
|
|
46
|
-
scurrypy 8.9 0.44 1417
|
|
47
|
-
hikari 1710.3 27.67 53658
|
|
48
|
-
discord 252.5 7.64 14099
|
|
49
|
-
disnake 185.9 6.31 12111
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
*(See `benchmark.py` for how this test was done.)*
|
|
53
|
-
|
|
54
32
|
## Getting Started
|
|
55
33
|
|
|
56
34
|
*Note: This section also appears in the documentation, but here are complete examples ready to use with your bot credentials.*
|
|
@@ -106,5 +84,31 @@ async def on_ping(bot: scurrypy.Client, event: scurrypy.MessageCreateEvent):
|
|
|
106
84
|
client.run()
|
|
107
85
|
```
|
|
108
86
|
|
|
87
|
+
## Building on Top of ScurryPy
|
|
88
|
+
|
|
89
|
+
ScurryPy is designed to be easy to extend with your own abstractions.
|
|
90
|
+
|
|
91
|
+
The following demonstrates integrating a custom cache into your client configuration:
|
|
92
|
+
|
|
93
|
+
```py
|
|
94
|
+
class CacheProtocol(Protocol):
|
|
95
|
+
async def get_user(self, user_id: int) ...
|
|
96
|
+
|
|
97
|
+
# and the rest...
|
|
98
|
+
|
|
99
|
+
class MyCache(CacheProtocol):
|
|
100
|
+
# your implementation...
|
|
101
|
+
|
|
102
|
+
class MyConfig(BaseConfig):
|
|
103
|
+
cache: MyCache
|
|
104
|
+
# other stuff here...
|
|
105
|
+
|
|
106
|
+
client = scurrypy.Client(
|
|
107
|
+
token = 'your-token',
|
|
108
|
+
application_id = 123456789012345,
|
|
109
|
+
config = MyConfig()
|
|
110
|
+
)
|
|
111
|
+
```
|
|
112
|
+
|
|
109
113
|
## Like What You See?
|
|
110
114
|
Explore the full [documentation](https://furmissile.github.io/scurrypy) for more examples, guides, and API reference.
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
## __<center> ScurryPy </center>__
|
|
2
2
|
|
|
3
3
|
[](https://badge.fury.io/py/scurrypy)
|
|
4
4
|
|
|
5
|
-
A
|
|
5
|
+
A lightweight, fully readable Discord API framework built to accommodate everything from basic bots to custom frameworks.
|
|
6
6
|
|
|
7
|
-
While
|
|
7
|
+
While ScurryPy powers many squirrel-related shenanigans, it works just as well for game bots, interactive components, and educational projects.
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
|
-
* Easy to extend
|
|
10
|
+
* Easy to extend and build frameworks on top
|
|
11
|
+
* Lightweight core (<1000 lines)
|
|
11
12
|
* Command, and event handling
|
|
12
13
|
* Unix shell-style wildcards for component routing
|
|
13
14
|
* Declarative style using decorators
|
|
@@ -16,29 +17,6 @@ While this wrapper is mainly used for various squirrel-related shenanigans, it c
|
|
|
16
17
|
* No `__future__` hacks to avoid circular import
|
|
17
18
|
* Capable of sharding
|
|
18
19
|
|
|
19
|
-
## Benchmarks
|
|
20
|
-
Not convinced ScurryPy has a place among top libraries? See the benchmarks below!
|
|
21
|
-
|
|
22
|
-
### Test Environment
|
|
23
|
-
|
|
24
|
-
- **Python**: 3.11.6
|
|
25
|
-
- **OS**: Windows 11
|
|
26
|
-
- **Method**: New Python process per measurement
|
|
27
|
-
- **Tool**: See benchmarks folder
|
|
28
|
-
|
|
29
|
-
### Results Summary
|
|
30
|
-
|
|
31
|
-
```
|
|
32
|
-
Library Time (ms) Memory Δ (MB) Objects
|
|
33
|
-
--------------------------------------------------------
|
|
34
|
-
scurrypy 8.9 0.44 1417
|
|
35
|
-
hikari 1710.3 27.67 53658
|
|
36
|
-
discord 252.5 7.64 14099
|
|
37
|
-
disnake 185.9 6.31 12111
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
*(See `benchmark.py` for how this test was done.)*
|
|
41
|
-
|
|
42
20
|
## Getting Started
|
|
43
21
|
|
|
44
22
|
*Note: This section also appears in the documentation, but here are complete examples ready to use with your bot credentials.*
|
|
@@ -94,5 +72,31 @@ async def on_ping(bot: scurrypy.Client, event: scurrypy.MessageCreateEvent):
|
|
|
94
72
|
client.run()
|
|
95
73
|
```
|
|
96
74
|
|
|
75
|
+
## Building on Top of ScurryPy
|
|
76
|
+
|
|
77
|
+
ScurryPy is designed to be easy to extend with your own abstractions.
|
|
78
|
+
|
|
79
|
+
The following demonstrates integrating a custom cache into your client configuration:
|
|
80
|
+
|
|
81
|
+
```py
|
|
82
|
+
class CacheProtocol(Protocol):
|
|
83
|
+
async def get_user(self, user_id: int) ...
|
|
84
|
+
|
|
85
|
+
# and the rest...
|
|
86
|
+
|
|
87
|
+
class MyCache(CacheProtocol):
|
|
88
|
+
# your implementation...
|
|
89
|
+
|
|
90
|
+
class MyConfig(BaseConfig):
|
|
91
|
+
cache: MyCache
|
|
92
|
+
# other stuff here...
|
|
93
|
+
|
|
94
|
+
client = scurrypy.Client(
|
|
95
|
+
token = 'your-token',
|
|
96
|
+
application_id = 123456789012345,
|
|
97
|
+
config = MyConfig()
|
|
98
|
+
)
|
|
99
|
+
```
|
|
100
|
+
|
|
97
101
|
## Like What You See?
|
|
98
102
|
Explore the full [documentation](https://furmissile.github.io/scurrypy) for more examples, guides, and API reference.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "scurrypy"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.7.2"
|
|
8
8
|
|
|
9
9
|
description = "Dataclass-driven Discord API Wrapper in Python"
|
|
10
10
|
readme = "README.md"
|
|
@@ -21,5 +21,7 @@ packages = [
|
|
|
21
21
|
"scurrypy.dispatch",
|
|
22
22
|
"scurrypy.events",
|
|
23
23
|
"scurrypy.resources",
|
|
24
|
-
"scurrypy.parts"
|
|
24
|
+
"scurrypy.parts",
|
|
25
|
+
"scurrypy.core",
|
|
26
|
+
"scurrypy.models"
|
|
25
27
|
]
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# scurrypy
|
|
2
|
+
|
|
3
|
+
from .client import Client
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
# top-level modules
|
|
7
|
+
"Client"
|
|
8
|
+
]
|
|
9
|
+
|
|
10
|
+
# imports listed __all__ libs
|
|
11
|
+
from .events import *
|
|
12
|
+
from .parts import *
|
|
13
|
+
from .resources import *
|
|
14
|
+
from .dispatch import *
|
|
15
|
+
from .models import *
|
|
16
|
+
from .core import *
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
|
|
3
|
-
from .config import BaseConfig
|
|
4
|
-
from .intents import Intents
|
|
5
|
-
from .gateway import GatewayClient
|
|
6
|
-
from .client_like import ClientLike
|
|
3
|
+
from .core.config import BaseConfig
|
|
4
|
+
from .core.intents import Intents
|
|
5
|
+
from .core.gateway import GatewayClient
|
|
6
|
+
from .core.client_like import ClientLike
|
|
7
7
|
|
|
8
8
|
from .parts.command import SlashCommand, MessageCommand, UserCommand
|
|
9
9
|
|
|
@@ -18,6 +18,7 @@ class Client(ClientLike):
|
|
|
18
18
|
intents: int = Intents.DEFAULT,
|
|
19
19
|
config: BaseConfig = None,
|
|
20
20
|
debug_mode: bool = False,
|
|
21
|
+
sync_commands: bool = True,
|
|
21
22
|
prefix = None,
|
|
22
23
|
quiet: bool = False
|
|
23
24
|
):
|
|
@@ -27,6 +28,7 @@ class Client(ClientLike):
|
|
|
27
28
|
application_id (int): the bot's user ID
|
|
28
29
|
intents (int, optional): gateway intents. Defaults to Intents.DEFAULT.
|
|
29
30
|
config (BaseConfig, optional): user-defined config data
|
|
31
|
+
sync_commands (bool, optional): toggle registering commands. Defaults to True.
|
|
30
32
|
debug_mode (bool, optional): toggle debug messages. Defaults to False.
|
|
31
33
|
prefix (str, optional): set message prefix if using command prefixes
|
|
32
34
|
quiet (bool, optional): if INFO, DEBUG, and WARN should be logged
|
|
@@ -36,8 +38,8 @@ class Client(ClientLike):
|
|
|
36
38
|
if not application_id:
|
|
37
39
|
raise ValueError("Application ID is required")
|
|
38
40
|
|
|
39
|
-
from .logger import Logger
|
|
40
|
-
from .http import HTTPClient
|
|
41
|
+
from .core.logger import Logger
|
|
42
|
+
from .core.http import HTTPClient
|
|
41
43
|
from .resources.bot_emojis import BotEmojis
|
|
42
44
|
from .dispatch.event_dispatcher import EventDispatcher
|
|
43
45
|
from .dispatch.prefix_dispatcher import PrefixDispatcher
|
|
@@ -47,6 +49,7 @@ class Client(ClientLike):
|
|
|
47
49
|
self.intents = intents
|
|
48
50
|
self.application_id = application_id
|
|
49
51
|
self.config = config
|
|
52
|
+
self.sync_commands = sync_commands
|
|
50
53
|
|
|
51
54
|
self._logger = Logger(debug_mode, quiet)
|
|
52
55
|
|
|
@@ -282,11 +285,12 @@ class Client(ClientLike):
|
|
|
282
285
|
await hook(self)
|
|
283
286
|
self._logger.log_high_priority("Hooks set up.")
|
|
284
287
|
|
|
285
|
-
|
|
288
|
+
if self.sync_commands:
|
|
289
|
+
await self.command_dispatcher.register_guild_commands()
|
|
286
290
|
|
|
287
|
-
|
|
291
|
+
await self.command_dispatcher.register_global_commands()
|
|
288
292
|
|
|
289
|
-
|
|
293
|
+
self._logger.log_high_priority("Commands set up.")
|
|
290
294
|
|
|
291
295
|
tasks = await asyncio.create_task(self._start_shards())
|
|
292
296
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# scurrypy/core
|
|
2
|
+
|
|
3
|
+
# from .client_like import ClientLike
|
|
4
|
+
from .config import BaseConfig
|
|
5
|
+
# from .error import DiscordError
|
|
6
|
+
# from .gateway import GatewayClient
|
|
7
|
+
# from .http import HTTPClient
|
|
8
|
+
from .intents import Intents, set_intents
|
|
9
|
+
from .logger import Logger
|
|
10
|
+
# from .model import DataModel
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"BaseConfig",
|
|
14
|
+
"Intents", 'set_intents',
|
|
15
|
+
"Logger"
|
|
16
|
+
]
|
|
@@ -171,54 +171,6 @@ class HTTPClient:
|
|
|
171
171
|
bucket.sleep_task = None
|
|
172
172
|
self.logger.log_high_priority(f"Bucket {endpoint} reset after {bucket.reset_after}s")
|
|
173
173
|
|
|
174
|
-
async def _make_payload(self, data: dict, files: list):
|
|
175
|
-
"""Return (data, headers) for aiohttp request — supports multipart.
|
|
176
|
-
|
|
177
|
-
Args:
|
|
178
|
-
data (dict): request data
|
|
179
|
-
files (list): relevant files
|
|
180
|
-
|
|
181
|
-
Returns:
|
|
182
|
-
(tuple[aiohttp.FormData, dict]): form data and headers
|
|
183
|
-
"""
|
|
184
|
-
headers = {}
|
|
185
|
-
if not files:
|
|
186
|
-
return data, headers
|
|
187
|
-
|
|
188
|
-
form = aiohttp.FormData()
|
|
189
|
-
if data:
|
|
190
|
-
form.add_field("payload_json", json.dumps(data))
|
|
191
|
-
|
|
192
|
-
for idx, file_path in enumerate(files):
|
|
193
|
-
async with aiofiles.open(file_path, 'rb') as f:
|
|
194
|
-
data = await f.read()
|
|
195
|
-
form.add_field(
|
|
196
|
-
f'files[{idx}]',
|
|
197
|
-
data,
|
|
198
|
-
filename=file_path.split('/')[-1],
|
|
199
|
-
content_type='application/octet-stream'
|
|
200
|
-
)
|
|
201
|
-
|
|
202
|
-
return form, headers
|
|
203
|
-
|
|
204
|
-
async def _prepare_payload(self, item: RequestItem):
|
|
205
|
-
"""Prepares the payload based on `RequestItem`.
|
|
206
|
-
|
|
207
|
-
Args:
|
|
208
|
-
item (RequestItem): the request object
|
|
209
|
-
|
|
210
|
-
Returns:
|
|
211
|
-
(dict): kwargs to pass to session.request
|
|
212
|
-
"""
|
|
213
|
-
kwargs = {}
|
|
214
|
-
if item.files and any(item.files):
|
|
215
|
-
payload, headers = await self._make_payload(item.data, item.files)
|
|
216
|
-
kwargs = {"data": payload, "headers": headers}
|
|
217
|
-
else:
|
|
218
|
-
kwargs = {"json": item.data}
|
|
219
|
-
|
|
220
|
-
return kwargs
|
|
221
|
-
|
|
222
174
|
async def _check_global_rate_limit(self):
|
|
223
175
|
"""Checks if the global rate limit is after now (active)."""
|
|
224
176
|
now = asyncio.get_event_loop().time()
|
|
@@ -291,6 +243,34 @@ class HTTPClient:
|
|
|
291
243
|
elif bucket.sleep_task and not bucket.sleep_task.done():
|
|
292
244
|
await bucket.sleep_task
|
|
293
245
|
|
|
246
|
+
async def _prepare_payload(self, item: RequestItem):
|
|
247
|
+
"""Prepares the payload based on `RequestItem`.
|
|
248
|
+
|
|
249
|
+
Args:
|
|
250
|
+
item (RequestItem): the request object
|
|
251
|
+
|
|
252
|
+
Returns:
|
|
253
|
+
(dict): kwargs to pass to session.request
|
|
254
|
+
"""
|
|
255
|
+
if item.files and any(item.files):
|
|
256
|
+
# payload = await self._make_payload(item.data, item.files)
|
|
257
|
+
form = aiohttp.FormData()
|
|
258
|
+
form.add_field("payload_json", json.dumps(item.data))
|
|
259
|
+
|
|
260
|
+
for idx, file_path in enumerate(item.files):
|
|
261
|
+
async with aiofiles.open(file_path, 'rb') as f:
|
|
262
|
+
f_data = await f.read()
|
|
263
|
+
form.add_field(
|
|
264
|
+
f'files[{idx}]',
|
|
265
|
+
f_data,
|
|
266
|
+
filename=file_path.split('/')[-1],
|
|
267
|
+
content_type='application/octet-stream'
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
return {"data": form}
|
|
271
|
+
|
|
272
|
+
return {"json": item.data}
|
|
273
|
+
|
|
294
274
|
async def _send(self, item: RequestItem):
|
|
295
275
|
"""Core HTTP request executor.
|
|
296
276
|
|
|
@@ -312,25 +292,19 @@ class HTTPClient:
|
|
|
312
292
|
|
|
313
293
|
kwargs = await self._prepare_payload(item)
|
|
314
294
|
|
|
315
|
-
# --- SEND REQUEST ---
|
|
316
|
-
|
|
317
295
|
url = f"{self.BASE.rstrip('/')}/{item.endpoint.lstrip('/')}"
|
|
318
296
|
|
|
319
297
|
async with self.session.request(
|
|
320
298
|
method=item.method, url=url, params=item.params, timeout=15, **kwargs
|
|
321
299
|
) as resp:
|
|
322
300
|
|
|
323
|
-
# Update global rate limit if triggered
|
|
324
301
|
if resp.headers.get("X-RateLimit-Global") == "true":
|
|
325
302
|
retry_after = float(resp.headers.get("Retry-After", 0))
|
|
326
303
|
self.global_reset = asyncio.get_event_loop().time() + retry_after
|
|
327
304
|
|
|
328
|
-
# Bucket handling (endpoint-specific rate limits)
|
|
329
305
|
bucket_id = resp.headers.get('x-ratelimit-bucket')
|
|
330
306
|
|
|
331
307
|
if bucket_id:
|
|
332
|
-
# grab lock from dict of bucket locks with a lock on dict access
|
|
333
308
|
await self._update_bucket_rate_limit(resp, bucket_id, item.endpoint)
|
|
334
309
|
|
|
335
|
-
# Handle response
|
|
336
310
|
return await self._parse_response(resp)
|
|
@@ -54,7 +54,7 @@ class IntentFlagParams(TypedDict, total=False):
|
|
|
54
54
|
message_content: bool
|
|
55
55
|
|
|
56
56
|
def set_intents(**flags: Unpack[IntentFlagParams]):
|
|
57
|
-
"""Set bot intents. See [`Intents`][scurrypy.intents.Intents]
|
|
57
|
+
"""Set bot intents. See [`Intents`][scurrypy.core.intents.Intents]
|
|
58
58
|
`Intents.DEFAULT` = (GUILDS | GUILD_MESSAGES) will also be set.
|
|
59
59
|
|
|
60
60
|
Args:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fnmatch
|
|
2
2
|
|
|
3
|
-
from ..client_like import ClientLike
|
|
3
|
+
from ..core.client_like import ClientLike
|
|
4
4
|
|
|
5
5
|
from ..events.interaction_events import ApplicationCommandData, MessageComponentData, ModalData, InteractionEvent
|
|
6
6
|
from ..resources.interaction import Interaction, InteractionDataTypes
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import importlib
|
|
2
|
-
from ..client_like import ClientLike
|
|
2
|
+
from ..core.client_like import ClientLike
|
|
3
3
|
|
|
4
4
|
from ..resources.message import Message
|
|
5
5
|
|
|
@@ -12,6 +12,8 @@ class EventDispatcher:
|
|
|
12
12
|
'GUILD_CREATE': ('scurrypy.events.guild_events', 'GuildCreateEvent'),
|
|
13
13
|
'GUILD_UPDATE': ('scurrypy.events.guild_events', 'GuildUpdateEvent'),
|
|
14
14
|
'GUILD_DELETE': ('scurrypy.events.guild_events', 'GuildDeleteEvent'),
|
|
15
|
+
'GUILD_MEMBER_ADD': ('scurrypy.events.guild_events', 'GuildMemberAddEvent'),
|
|
16
|
+
'GUILD_MEMBER_REMOVE': ('scurrypy.events.guild_events', 'GuildMemberRemoveEvent'),
|
|
15
17
|
|
|
16
18
|
'CHANNEL_CREATE': ('scurrypy.events.channel_events', 'GuildChannelCreateEvent'),
|
|
17
19
|
'CHANNEL_UPDATE': ('scurrypy.events.channel_events', 'GuildChannelUpdateEvent'),
|
|
@@ -90,6 +92,7 @@ class EventDispatcher:
|
|
|
90
92
|
|
|
91
93
|
handler = self._handlers.get(event_name, None)
|
|
92
94
|
if handler:
|
|
95
|
+
print(data)
|
|
93
96
|
obj = cls.from_dict(data, self._http)
|
|
94
97
|
obj.config = self.config
|
|
95
98
|
await handler(self.bot, obj)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# scurrypy/events
|
|
2
|
+
|
|
3
|
+
from .channel_events import (
|
|
4
|
+
# GuildChannelEvent,
|
|
5
|
+
GuildChannelCreateEvent,
|
|
6
|
+
GuildChannelUpdateEvent,
|
|
7
|
+
GuildChannelDeleteEvent,
|
|
8
|
+
ChannelPinsUpdateEvent,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
# from .gateway_events import (
|
|
12
|
+
# SessionStartLimit,
|
|
13
|
+
# GatewayEvent
|
|
14
|
+
# )
|
|
15
|
+
|
|
16
|
+
from .guild_events import (
|
|
17
|
+
# GuildEvent,
|
|
18
|
+
GuildCreateEvent,
|
|
19
|
+
GuildUpdateEvent,
|
|
20
|
+
GuildDeleteEvent,
|
|
21
|
+
|
|
22
|
+
GuildMemberAddEvent,
|
|
23
|
+
GuildMemberRemoveEvent
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
# from .hello_event import HelloEvent
|
|
27
|
+
|
|
28
|
+
from .interaction_events import (
|
|
29
|
+
# ApplicationCommandOptionData,
|
|
30
|
+
# ApplicationCommandData,
|
|
31
|
+
# MessageComponentData,
|
|
32
|
+
# ModalComponentData,
|
|
33
|
+
# ModalComponent,
|
|
34
|
+
# ModalData,
|
|
35
|
+
InteractionEvent
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
from .message_events import (
|
|
39
|
+
MessageCreateEvent,
|
|
40
|
+
MessageUpdateEvent,
|
|
41
|
+
MessageDeleteEvent,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
from .reaction_events import (
|
|
45
|
+
ReactionType,
|
|
46
|
+
ReactionAddEvent,
|
|
47
|
+
ReactionRemoveEvent,
|
|
48
|
+
ReactionRemoveEmojiEvent,
|
|
49
|
+
ReactionRemoveAllEvent,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
from .ready_event import ReadyEvent
|
|
53
|
+
|
|
54
|
+
__all__ = [
|
|
55
|
+
"GuildChannelCreateEvent", "GuildChannelUpdateEvent", "GuildChannelDeleteEvent", "ChannelPinsUpdateEvent",
|
|
56
|
+
"GuildCreateEvent", "GuildUpdateEvent", "GuildDeleteEvent",
|
|
57
|
+
"GuildMemberAddEvent", "GuildMemberRemoveEvent",
|
|
58
|
+
"InteractionEvent",
|
|
59
|
+
"MessageCreateEvent", "MessageUpdateEvent", "MessageDeleteEvent",
|
|
60
|
+
"ReactionType", "ReactionAddEvent", "ReactionRemoveEvent", "ReactionRemoveEmojiEvent", "ReactionRemoveAllEvent",
|
|
61
|
+
"ReadyEvent"
|
|
62
|
+
]
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
|
-
from ..model import DataModel
|
|
2
|
+
from ..core.model import DataModel
|
|
3
3
|
|
|
4
4
|
from ..models import MemberModel
|
|
5
5
|
from ..resources.channel import Channel
|
|
@@ -34,3 +34,23 @@ class GuildUpdateEvent(GuildEvent):
|
|
|
34
34
|
class GuildDeleteEvent(GuildEvent):
|
|
35
35
|
"""Received when the bot has left a guild or the guild was deleted."""
|
|
36
36
|
pass
|
|
37
|
+
|
|
38
|
+
from ..models.user import MemberModel, UserModel
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class GuildMemberAddEvent(MemberModel):
|
|
42
|
+
"""Received when a member joins a guild the bot is in."""
|
|
43
|
+
|
|
44
|
+
guild_id: int
|
|
45
|
+
"""ID of the guild."""
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@dataclass
|
|
49
|
+
class GuildMemberRemoveEvent(DataModel):
|
|
50
|
+
"""Received when a member leaves or is kicked/banned from a guild the bot is in."""
|
|
51
|
+
|
|
52
|
+
guild_id: int
|
|
53
|
+
"""ID of the guild."""
|
|
54
|
+
|
|
55
|
+
user: UserModel
|
|
56
|
+
"""User object of the user leaving the guild."""
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# scurrypy/models
|
|
2
|
+
|
|
3
|
+
from .emoji import EmojiModel
|
|
4
|
+
from .guild import ReadyGuildModel, GuildModel
|
|
5
|
+
from .interaction import InteractionCallbackDataModel, InteractionCallbackModel
|
|
6
|
+
from .role import RoleColors, RoleModel
|
|
7
|
+
from .user import UserModel, MemberModel, ApplicationModel, IntegrationModel
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"EmojiModel",
|
|
11
|
+
"ReadyGuildModel", "GuildModel",
|
|
12
|
+
"InteractionCallbackDataModel", "InteractionCallbackModel",
|
|
13
|
+
"RoleColors", "RoleModel",
|
|
14
|
+
"UserModel", "MemberModel", "ApplicationModel", "IntegrationModel"
|
|
15
|
+
]
|