python-yappy 0.1.0__tar.gz → 0.1.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.
- {python_yappy-0.1.0 → python_yappy-0.1.2}/PKG-INFO +91 -36
- {python_yappy-0.1.0 → python_yappy-0.1.2}/README.md +89 -35
- {python_yappy-0.1.0 → python_yappy-0.1.2}/pyproject.toml +2 -1
- {python_yappy-0.1.0 → python_yappy-0.1.2}/pyproject.toml.orig +2 -1
- python_yappy-0.1.2/src/yappy/__init__.py +6 -0
- python_yappy-0.1.2/src/yappy/api.py +77 -0
- python_yappy-0.1.2/src/yappy/app.py +527 -0
- python_yappy-0.1.2/src/yappy/core.py +353 -0
- python_yappy-0.1.2/src/yappy/errors.py +79 -0
- python_yappy-0.1.2/src/yappy/logger.py +69 -0
- python_yappy-0.1.2/src/yappy/parser.py +154 -0
- python_yappy-0.1.2/src/yappy/utils.py +4 -0
- python_yappy-0.1.0/src/yappy/__init__.py +0 -1
- python_yappy-0.1.0/src/yappy/api.py +0 -44
- python_yappy-0.1.0/src/yappy/app.py +0 -204
- python_yappy-0.1.0/src/yappy/core.py +0 -105
- python_yappy-0.1.0/src/yappy/errors.py +0 -8
- {python_yappy-0.1.0 → python_yappy-0.1.2}/src/yappy/consts.py +0 -0
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: python-yappy
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: API Bindings for Yapper!
|
|
5
5
|
Author: H1387Lmao
|
|
6
6
|
Requires-Dist: aiohttp>=3.14.5
|
|
7
7
|
Requires-Dist: load-dotenv>=0.1.0
|
|
8
|
+
Requires-Dist: rich>=13.0
|
|
8
9
|
Requires-Dist: uv-build>=0.13.1
|
|
9
10
|
Requires-Python: >=3.14
|
|
10
11
|
Description-Content-Type: text/markdown
|
|
@@ -24,60 +25,52 @@ YapPy brings a Python-friendly interface to [Yapper](https://yapper.website), a
|
|
|
24
25
|
- **Commands** — register named commands with descriptions.
|
|
25
26
|
- **Context-based interactions** — reply to messages through a context object.
|
|
26
27
|
- **Core models** — work with `Context`, `Message`, `Channel`, and `User` objects.
|
|
27
|
-
- **
|
|
28
|
+
- **Argument validation** — type-hinted command parameters are converted for you, and mistakes get a helpful reply.
|
|
29
|
+
- **Rich logging** — coloured logs and readable tracebacks; `verbose=True` adds debug output.
|
|
28
30
|
|
|
29
31
|
## Installation
|
|
30
32
|
|
|
31
|
-
Install YapPy using your project's preferred method.
|
|
32
|
-
|
|
33
|
-
If the package is available on PyPI:
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
pip install yappy
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
If you are working from a local checkout, install the project from its repository directory:
|
|
40
|
-
|
|
41
|
-
```bash
|
|
42
|
-
pip install .
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
The example below uses [`python-dotenv`](https://pypi.org/project/python-dotenv/) to load the bot token from a `.env` file:
|
|
46
33
|
|
|
47
34
|
```bash
|
|
48
|
-
pip install python-
|
|
35
|
+
pip install python-yappy
|
|
49
36
|
```
|
|
50
37
|
|
|
51
38
|
## Quick start
|
|
52
39
|
|
|
53
|
-
|
|
40
|
+
This example uses the dotenv module from `pip install load_dotenv`
|
|
41
|
+
Create a file named `main.py`:
|
|
54
42
|
|
|
55
43
|
```python
|
|
44
|
+
from yappy import App
|
|
56
45
|
import os
|
|
57
|
-
|
|
58
46
|
from dotenv import load_dotenv
|
|
59
|
-
from yappy import App
|
|
60
|
-
|
|
61
47
|
load_dotenv()
|
|
62
|
-
|
|
63
48
|
bot = App(verbose=True)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
49
|
+
@bot.event(
|
|
50
|
+
"message"
|
|
51
|
+
)
|
|
67
52
|
async def on_message(ctx):
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
await ctx.reply("Hi!")
|
|
72
|
-
|
|
73
|
-
|
|
53
|
+
if ctx.is_bot:
|
|
54
|
+
return
|
|
55
|
+
await bot.process_command(ctx)
|
|
74
56
|
@bot.command(
|
|
75
|
-
|
|
76
|
-
description="replies with 'Pong!'"
|
|
57
|
+
name="ping",
|
|
58
|
+
description="replies with 'Pong!'"
|
|
77
59
|
)
|
|
78
60
|
async def ping(ctx):
|
|
79
|
-
|
|
61
|
+
await ctx.reply("Pong!")
|
|
80
62
|
|
|
63
|
+
@bot.command(
|
|
64
|
+
name="react",
|
|
65
|
+
description="React your message with a certain emoji!"
|
|
66
|
+
)
|
|
67
|
+
async def react(ctx, emoji: str):
|
|
68
|
+
await ctx.message.react(emoji)
|
|
69
|
+
@bot.event(
|
|
70
|
+
"ready"
|
|
71
|
+
)
|
|
72
|
+
async def on_ready():
|
|
73
|
+
print("Logged as", bot.user.name)
|
|
81
74
|
|
|
82
75
|
bot.run(os.getenv("TOKEN"))
|
|
83
76
|
```
|
|
@@ -123,7 +116,7 @@ async def on_message(ctx):
|
|
|
123
116
|
if ctx.is_bot:
|
|
124
117
|
return
|
|
125
118
|
|
|
126
|
-
await
|
|
119
|
+
await bot.process_command(ctx)
|
|
127
120
|
```
|
|
128
121
|
|
|
129
122
|
The event name and handler arguments should match the event interface supported by the installed YapPy version.
|
|
@@ -143,6 +136,66 @@ async def ping(ctx):
|
|
|
143
136
|
|
|
144
137
|
The `name` identifies the command, and `description` describes its purpose. Command registration and invocation behavior depend on the current implementation.
|
|
145
138
|
|
|
139
|
+
### Command arguments
|
|
140
|
+
|
|
141
|
+
Arguments from the message are matched to your function's parameters. Add type hints and YapPy converts them for you:
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
@bot.command(name="add", description="Adds two numbers")
|
|
145
|
+
async def add(ctx, a: int, b: int = 0):
|
|
146
|
+
await ctx.reply(f"{a} + {b} = {a + b}")
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
| Annotation | Accepts |
|
|
150
|
+
| --- | --- |
|
|
151
|
+
| `str` | the text exactly as typed (use `"quotes"` for spaces) |
|
|
152
|
+
| `int`, `float` | numbers |
|
|
153
|
+
| `bool` | `true`/`false`, `yes`/`no`, `on`/`off`, `1`/`0` |
|
|
154
|
+
| `User`, `Channel`, `Role` | a mention such as `<@123>` |
|
|
155
|
+
| *(none)* | guessed: whole numbers become `int`, decimals `float`, mentions are resolved, anything else is `str` |
|
|
156
|
+
|
|
157
|
+
Parameters with a default are optional, and `*args` collects any remaining arguments.
|
|
158
|
+
|
|
159
|
+
### Command errors
|
|
160
|
+
|
|
161
|
+
If someone uses a command the wrong way, the bot tells them instead of failing silently:
|
|
162
|
+
|
|
163
|
+
```text
|
|
164
|
+
!add
|
|
165
|
+
Missing required argument 'a'.
|
|
166
|
+
Usage: `!add <a> [b]`
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Too many arguments and values of the wrong type are handled the same way. Unknown commands are ignored, and an exception raised inside a command is logged rather than sent to chat.
|
|
170
|
+
|
|
171
|
+
To handle these yourself, register a `command_error` handler. It replaces the default replies:
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
from yappy import UnknownCommand
|
|
175
|
+
|
|
176
|
+
@bot.event("command_error")
|
|
177
|
+
async def on_command_error(ctx, error):
|
|
178
|
+
if isinstance(error, UnknownCommand):
|
|
179
|
+
return
|
|
180
|
+
await ctx.reply(str(error))
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
`error` is one of `UnknownCommand`, `MissingArgument`, `TooManyArguments`, `BadArgument` or `CommandInvokeError` (all subclasses of `yappy.CommandError`). For `CommandInvokeError`, the exception your command raised is `error.original`, and `error.command` is the command involved.
|
|
184
|
+
|
|
185
|
+
### Logging
|
|
186
|
+
|
|
187
|
+
YapPy logs through Python's `logging` module under the name `yappy` and prints it with [Rich](https://github.com/Textualize/rich). Exceptions appear as readable tracebacks. `App(verbose=True)` also shows debug output: events, HTTP requests and command invocations.
|
|
188
|
+
|
|
189
|
+
To configure logging yourself, create the app with `configure_logging=False`:
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
import logging
|
|
193
|
+
from yappy import App, setup_logging
|
|
194
|
+
|
|
195
|
+
bot = App(configure_logging=False)
|
|
196
|
+
setup_logging(level=logging.WARNING, show_locals=True) # or attach your own handlers to logging.getLogger("yappy")
|
|
197
|
+
```
|
|
198
|
+
|
|
146
199
|
### Context and models
|
|
147
200
|
|
|
148
201
|
YapPy currently provides these core models:
|
|
@@ -153,6 +206,8 @@ YapPy currently provides these core models:
|
|
|
153
206
|
| `Message` | Represents a message. |
|
|
154
207
|
| `Channel` | Represents a channel. |
|
|
155
208
|
| `User` | Represents a user. |
|
|
209
|
+
| `Guild` | Represents a guild / server |
|
|
210
|
+
| `Role` | Represents a role |
|
|
156
211
|
|
|
157
212
|
The example uses the context object (`ctx`) to check `ctx.is_bot` and send a reply with `ctx.reply(...)`. Consult the source code for the currently available attributes and methods of each model.
|
|
158
213
|
|
|
@@ -13,60 +13,52 @@ YapPy brings a Python-friendly interface to [Yapper](https://yapper.website), a
|
|
|
13
13
|
- **Commands** — register named commands with descriptions.
|
|
14
14
|
- **Context-based interactions** — reply to messages through a context object.
|
|
15
15
|
- **Core models** — work with `Context`, `Message`, `Channel`, and `User` objects.
|
|
16
|
-
- **
|
|
16
|
+
- **Argument validation** — type-hinted command parameters are converted for you, and mistakes get a helpful reply.
|
|
17
|
+
- **Rich logging** — coloured logs and readable tracebacks; `verbose=True` adds debug output.
|
|
17
18
|
|
|
18
19
|
## Installation
|
|
19
20
|
|
|
20
|
-
Install YapPy using your project's preferred method.
|
|
21
|
-
|
|
22
|
-
If the package is available on PyPI:
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
pip install yappy
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
If you are working from a local checkout, install the project from its repository directory:
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
pip install .
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
The example below uses [`python-dotenv`](https://pypi.org/project/python-dotenv/) to load the bot token from a `.env` file:
|
|
35
21
|
|
|
36
22
|
```bash
|
|
37
|
-
pip install python-
|
|
23
|
+
pip install python-yappy
|
|
38
24
|
```
|
|
39
25
|
|
|
40
26
|
## Quick start
|
|
41
27
|
|
|
42
|
-
|
|
28
|
+
This example uses the dotenv module from `pip install load_dotenv`
|
|
29
|
+
Create a file named `main.py`:
|
|
43
30
|
|
|
44
31
|
```python
|
|
32
|
+
from yappy import App
|
|
45
33
|
import os
|
|
46
|
-
|
|
47
34
|
from dotenv import load_dotenv
|
|
48
|
-
from yappy import App
|
|
49
|
-
|
|
50
35
|
load_dotenv()
|
|
51
|
-
|
|
52
36
|
bot = App(verbose=True)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
37
|
+
@bot.event(
|
|
38
|
+
"message"
|
|
39
|
+
)
|
|
56
40
|
async def on_message(ctx):
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
await ctx.reply("Hi!")
|
|
61
|
-
|
|
62
|
-
|
|
41
|
+
if ctx.is_bot:
|
|
42
|
+
return
|
|
43
|
+
await bot.process_command(ctx)
|
|
63
44
|
@bot.command(
|
|
64
|
-
|
|
65
|
-
description="replies with 'Pong!'"
|
|
45
|
+
name="ping",
|
|
46
|
+
description="replies with 'Pong!'"
|
|
66
47
|
)
|
|
67
48
|
async def ping(ctx):
|
|
68
|
-
|
|
49
|
+
await ctx.reply("Pong!")
|
|
69
50
|
|
|
51
|
+
@bot.command(
|
|
52
|
+
name="react",
|
|
53
|
+
description="React your message with a certain emoji!"
|
|
54
|
+
)
|
|
55
|
+
async def react(ctx, emoji: str):
|
|
56
|
+
await ctx.message.react(emoji)
|
|
57
|
+
@bot.event(
|
|
58
|
+
"ready"
|
|
59
|
+
)
|
|
60
|
+
async def on_ready():
|
|
61
|
+
print("Logged as", bot.user.name)
|
|
70
62
|
|
|
71
63
|
bot.run(os.getenv("TOKEN"))
|
|
72
64
|
```
|
|
@@ -112,7 +104,7 @@ async def on_message(ctx):
|
|
|
112
104
|
if ctx.is_bot:
|
|
113
105
|
return
|
|
114
106
|
|
|
115
|
-
await
|
|
107
|
+
await bot.process_command(ctx)
|
|
116
108
|
```
|
|
117
109
|
|
|
118
110
|
The event name and handler arguments should match the event interface supported by the installed YapPy version.
|
|
@@ -132,6 +124,66 @@ async def ping(ctx):
|
|
|
132
124
|
|
|
133
125
|
The `name` identifies the command, and `description` describes its purpose. Command registration and invocation behavior depend on the current implementation.
|
|
134
126
|
|
|
127
|
+
### Command arguments
|
|
128
|
+
|
|
129
|
+
Arguments from the message are matched to your function's parameters. Add type hints and YapPy converts them for you:
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
@bot.command(name="add", description="Adds two numbers")
|
|
133
|
+
async def add(ctx, a: int, b: int = 0):
|
|
134
|
+
await ctx.reply(f"{a} + {b} = {a + b}")
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
| Annotation | Accepts |
|
|
138
|
+
| --- | --- |
|
|
139
|
+
| `str` | the text exactly as typed (use `"quotes"` for spaces) |
|
|
140
|
+
| `int`, `float` | numbers |
|
|
141
|
+
| `bool` | `true`/`false`, `yes`/`no`, `on`/`off`, `1`/`0` |
|
|
142
|
+
| `User`, `Channel`, `Role` | a mention such as `<@123>` |
|
|
143
|
+
| *(none)* | guessed: whole numbers become `int`, decimals `float`, mentions are resolved, anything else is `str` |
|
|
144
|
+
|
|
145
|
+
Parameters with a default are optional, and `*args` collects any remaining arguments.
|
|
146
|
+
|
|
147
|
+
### Command errors
|
|
148
|
+
|
|
149
|
+
If someone uses a command the wrong way, the bot tells them instead of failing silently:
|
|
150
|
+
|
|
151
|
+
```text
|
|
152
|
+
!add
|
|
153
|
+
Missing required argument 'a'.
|
|
154
|
+
Usage: `!add <a> [b]`
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Too many arguments and values of the wrong type are handled the same way. Unknown commands are ignored, and an exception raised inside a command is logged rather than sent to chat.
|
|
158
|
+
|
|
159
|
+
To handle these yourself, register a `command_error` handler. It replaces the default replies:
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
from yappy import UnknownCommand
|
|
163
|
+
|
|
164
|
+
@bot.event("command_error")
|
|
165
|
+
async def on_command_error(ctx, error):
|
|
166
|
+
if isinstance(error, UnknownCommand):
|
|
167
|
+
return
|
|
168
|
+
await ctx.reply(str(error))
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
`error` is one of `UnknownCommand`, `MissingArgument`, `TooManyArguments`, `BadArgument` or `CommandInvokeError` (all subclasses of `yappy.CommandError`). For `CommandInvokeError`, the exception your command raised is `error.original`, and `error.command` is the command involved.
|
|
172
|
+
|
|
173
|
+
### Logging
|
|
174
|
+
|
|
175
|
+
YapPy logs through Python's `logging` module under the name `yappy` and prints it with [Rich](https://github.com/Textualize/rich). Exceptions appear as readable tracebacks. `App(verbose=True)` also shows debug output: events, HTTP requests and command invocations.
|
|
176
|
+
|
|
177
|
+
To configure logging yourself, create the app with `configure_logging=False`:
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
import logging
|
|
181
|
+
from yappy import App, setup_logging
|
|
182
|
+
|
|
183
|
+
bot = App(configure_logging=False)
|
|
184
|
+
setup_logging(level=logging.WARNING, show_locals=True) # or attach your own handlers to logging.getLogger("yappy")
|
|
185
|
+
```
|
|
186
|
+
|
|
135
187
|
### Context and models
|
|
136
188
|
|
|
137
189
|
YapPy currently provides these core models:
|
|
@@ -142,6 +194,8 @@ YapPy currently provides these core models:
|
|
|
142
194
|
| `Message` | Represents a message. |
|
|
143
195
|
| `Channel` | Represents a channel. |
|
|
144
196
|
| `User` | Represents a user. |
|
|
197
|
+
| `Guild` | Represents a guild / server |
|
|
198
|
+
| `Role` | Represents a role |
|
|
145
199
|
|
|
146
200
|
The example uses the context object (`ctx`) to check `ctx.is_bot` and send a reply with `ctx.reply(...)`. Consult the source code for the currently available attributes and methods of each model.
|
|
147
201
|
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "python-yappy"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.2"
|
|
4
4
|
description = "API Bindings for Yapper!"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.14"
|
|
7
7
|
dependencies = [
|
|
8
8
|
"aiohttp>=3.14.5",
|
|
9
9
|
"load-dotenv>=0.1.0",
|
|
10
|
+
"rich>=13.0",
|
|
10
11
|
"uv-build>=0.13.1",
|
|
11
12
|
]
|
|
12
13
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "python-yappy"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.2"
|
|
4
4
|
description = "API Bindings for Yapper!"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -10,6 +10,7 @@ requires-python = ">=3.14"
|
|
|
10
10
|
dependencies = [
|
|
11
11
|
"aiohttp>=3.14.5",
|
|
12
12
|
"load-dotenv>=0.1.0",
|
|
13
|
+
"rich>=13.0",
|
|
13
14
|
"uv-build>=0.13.1",
|
|
14
15
|
]
|
|
15
16
|
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
from .consts import BASE_URL
|
|
2
|
+
import aiohttp
|
|
3
|
+
import logging
|
|
4
|
+
import random
|
|
5
|
+
import asyncio
|
|
6
|
+
import time
|
|
7
|
+
|
|
8
|
+
log = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
async def api_push(session: aiohttp.ClientSession, method: str, path: str, body=None, tries=3):
|
|
11
|
+
headers = {
|
|
12
|
+
"Authorization": f"Bot {session._bearer_token}",
|
|
13
|
+
"Content-Type": "application/json"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
started = time.perf_counter()
|
|
17
|
+
try:
|
|
18
|
+
async with session.request(method, BASE_URL + path, json=body, headers=headers, timeout=40) as r:
|
|
19
|
+
r.raise_for_status()
|
|
20
|
+
data = await r.json()
|
|
21
|
+
if not path.startswith("/events"): # the long poll would be noise
|
|
22
|
+
log.debug(
|
|
23
|
+
"%s %s -> %s (%.0f ms)", method, path, r.status,
|
|
24
|
+
(time.perf_counter() - started) * 1000
|
|
25
|
+
)
|
|
26
|
+
return data
|
|
27
|
+
except aiohttp.ClientResponseError as e:
|
|
28
|
+
try:
|
|
29
|
+
err = await e.history[-1].json() if e.history else {}
|
|
30
|
+
except Exception:
|
|
31
|
+
err = {}
|
|
32
|
+
|
|
33
|
+
msg = err.get("error") if isinstance(err, dict) else None
|
|
34
|
+
busy = e.status == 503 and isinstance(err, dict) and "retry_after" in err
|
|
35
|
+
|
|
36
|
+
wait = int(e.headers.get("Retry-After") or 0) if e.status == 429 or busy else 0
|
|
37
|
+
|
|
38
|
+
if 0 < wait <= 60 and tries > 1:
|
|
39
|
+
delay = wait * (1 + random.random() * 0.5)
|
|
40
|
+
log.warning(
|
|
41
|
+
"%s on %s %s, retrying in %.1fs",
|
|
42
|
+
"Server busy" if busy else "Rate limited", method, path, delay
|
|
43
|
+
)
|
|
44
|
+
await asyncio.sleep(delay)
|
|
45
|
+
return await api_push(session, method, path, body, tries - 1)
|
|
46
|
+
|
|
47
|
+
raise RuntimeError(f"{method} {path} failed ({e.status}): {msg or e.message}") from None
|
|
48
|
+
|
|
49
|
+
class API:
|
|
50
|
+
@staticmethod
|
|
51
|
+
async def _request(session, method, path="", body=None, tries=3):
|
|
52
|
+
return await api_push(session, method, path, body, tries)
|
|
53
|
+
|
|
54
|
+
@staticmethod
|
|
55
|
+
async def get(session, path="", body=None, tries=3):
|
|
56
|
+
return await API._request(session, "GET", path, body, tries)
|
|
57
|
+
|
|
58
|
+
@staticmethod
|
|
59
|
+
async def post(session, path="", body=None, tries=3):
|
|
60
|
+
return await API._request(session, "POST", path, body, tries)
|
|
61
|
+
|
|
62
|
+
@staticmethod
|
|
63
|
+
async def put(session, path="", body=None, tries=3):
|
|
64
|
+
return await API._request(session, "PUT", path, body, tries)
|
|
65
|
+
|
|
66
|
+
@staticmethod
|
|
67
|
+
async def patch(session, path="", body=None, tries=3):
|
|
68
|
+
return await API._request(session, "PATCH", path, body, tries)
|
|
69
|
+
|
|
70
|
+
@staticmethod
|
|
71
|
+
async def delete(session, path="", body=None, tries=3):
|
|
72
|
+
return await API._request(session, "DELETE", path, body, tries)
|
|
73
|
+
|
|
74
|
+
@staticmethod
|
|
75
|
+
async def send(session, channel_id=0, body=None, tries=3):
|
|
76
|
+
return await API._request(session, "POST", f"/channels/{channel_id}/messages", body, tries)
|
|
77
|
+
|