matrix-python 1.4.8a0__py3-none-any.whl → 1.4.10a0__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.
- matrix/_version.py +2 -2
- matrix/checks.py +12 -4
- matrix/command.py +45 -48
- matrix/context.py +0 -3
- matrix/extension.py +17 -9
- matrix/group.py +15 -7
- matrix/help/help_command.py +62 -72
- matrix/help/pagination.py +4 -22
- matrix/protocols.py +4 -0
- matrix/registry.py +74 -11
- matrix/scheduler.py +7 -9
- {matrix_python-1.4.8a0.dist-info → matrix_python-1.4.10a0.dist-info}/METADATA +60 -39
- matrix_python-1.4.10a0.dist-info/RECORD +25 -0
- matrix_python-1.4.8a0.dist-info/RECORD +0 -25
- {matrix_python-1.4.8a0.dist-info → matrix_python-1.4.10a0.dist-info}/WHEEL +0 -0
- {matrix_python-1.4.8a0.dist-info → matrix_python-1.4.10a0.dist-info}/top_level.txt +0 -0
matrix/_version.py
CHANGED
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '1.4.
|
|
22
|
-
__version_tuple__ = version_tuple = (1, 4,
|
|
21
|
+
__version__ = version = '1.4.10a0'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 4, 10, 'a0')
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
matrix/checks.py
CHANGED
|
@@ -8,10 +8,18 @@ def cooldown(rate: int, period: float) -> Callable:
|
|
|
8
8
|
"""
|
|
9
9
|
Decorator to cooldown a command.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
## Example
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
@cooldown(rate=3, period=10)
|
|
15
|
+
@bot.command("hello")
|
|
16
|
+
async def hello(ctx: Context) -> None:
|
|
17
|
+
await ctx.reply("Hello!")
|
|
18
|
+
|
|
19
|
+
@hello.error(CooldownError)
|
|
20
|
+
async def hello_error(ctx: Context, error: CooldownError) -> None:
|
|
21
|
+
await ctx.reply(f"Slow down! Try again in {error.retry:.1f}s.")
|
|
22
|
+
```
|
|
15
23
|
"""
|
|
16
24
|
|
|
17
25
|
def wrapper(cmd: "Command") -> "Command":
|
matrix/command.py
CHANGED
|
@@ -30,19 +30,6 @@ ErrorCallback = Callable[["Context", Exception], Coroutine[Any, Any, Any]]
|
|
|
30
30
|
class Command:
|
|
31
31
|
"""
|
|
32
32
|
Represents a command that can be executed with a context and arguments.
|
|
33
|
-
|
|
34
|
-
:param func: The coroutine that is executed when the command is invoked.
|
|
35
|
-
:type func: Callable[..., Coroutine[Any, Any, Any]]
|
|
36
|
-
|
|
37
|
-
:param name: Optional name. Defaults to the function's name.
|
|
38
|
-
:param description: Optional description of what the command does.
|
|
39
|
-
:param prefix: Optional prefix for the command.
|
|
40
|
-
:param parent: Optional parent command name for subcommands.
|
|
41
|
-
:param usage: Optional usage string for the command.
|
|
42
|
-
:param cooldown: Optional cooldown settings as a tuple of (rate, period).
|
|
43
|
-
|
|
44
|
-
:raises TypeError: If the provided name is not a string.
|
|
45
|
-
:raises TypeError: If the provided callback is not a coroutine.
|
|
46
33
|
"""
|
|
47
34
|
|
|
48
35
|
def __init__(
|
|
@@ -85,9 +72,6 @@ class Command:
|
|
|
85
72
|
def callback(self) -> Callback:
|
|
86
73
|
"""
|
|
87
74
|
Returns the coroutine function for this command.
|
|
88
|
-
|
|
89
|
-
:return: The command's coroutine function.
|
|
90
|
-
:rtype: Callback
|
|
91
75
|
"""
|
|
92
76
|
return self._callback
|
|
93
77
|
|
|
@@ -96,10 +80,6 @@ class Command:
|
|
|
96
80
|
"""
|
|
97
81
|
Sets the coroutine function for the command and extracts type
|
|
98
82
|
hints and parameters.
|
|
99
|
-
|
|
100
|
-
:param func: The coroutine function to use.
|
|
101
|
-
:type func: Callback
|
|
102
|
-
:raises TypeError: If the provided function is not a coroutine.
|
|
103
83
|
"""
|
|
104
84
|
if not inspect.iscoroutinefunction(func):
|
|
105
85
|
raise TypeError("Commands must be coroutines")
|
|
@@ -113,9 +93,6 @@ class Command:
|
|
|
113
93
|
def _build_help(self) -> str:
|
|
114
94
|
"""
|
|
115
95
|
Returns the help text for the command.
|
|
116
|
-
|
|
117
|
-
:return: The help text for the command.
|
|
118
|
-
:rtype: str
|
|
119
96
|
"""
|
|
120
97
|
default_help = f"{self.description}\n\nusage: {self.usage}"
|
|
121
98
|
return inspect.cleandoc(default_help)
|
|
@@ -124,9 +101,6 @@ class Command:
|
|
|
124
101
|
"""
|
|
125
102
|
Builds and returns the default usage string for the command.
|
|
126
103
|
set at the command initalization.
|
|
127
|
-
|
|
128
|
-
:return: A usage string.
|
|
129
|
-
:rtype: str
|
|
130
104
|
"""
|
|
131
105
|
params = " ".join(f"[{p.name}]" for p in self.params)
|
|
132
106
|
command_name = self.name
|
|
@@ -186,10 +160,17 @@ class Command:
|
|
|
186
160
|
"""
|
|
187
161
|
Register a check callback
|
|
188
162
|
|
|
189
|
-
|
|
190
|
-
|
|
163
|
+
## Example
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
@bot.command("secret")
|
|
167
|
+
async def secret(ctx: Context) -> None:
|
|
168
|
+
await ctx.reply("Access granted!")
|
|
191
169
|
|
|
192
|
-
|
|
170
|
+
@secret.check
|
|
171
|
+
async def is_allowed(ctx: Context) -> bool:
|
|
172
|
+
return ctx.sender == "@admin:matrix.org"
|
|
173
|
+
```
|
|
193
174
|
"""
|
|
194
175
|
if not inspect.iscoroutinefunction(func):
|
|
195
176
|
raise TypeError("Checks must be coroutine")
|
|
@@ -227,10 +208,17 @@ class Command:
|
|
|
227
208
|
"""
|
|
228
209
|
Registers a coroutine to be called before the command is invoked.
|
|
229
210
|
|
|
230
|
-
|
|
231
|
-
:type func: Callback
|
|
211
|
+
## Example
|
|
232
212
|
|
|
233
|
-
|
|
213
|
+
```python
|
|
214
|
+
@bot.command("ping")
|
|
215
|
+
async def ping(ctx: Context) -> None:
|
|
216
|
+
await ctx.reply("Pong!")
|
|
217
|
+
|
|
218
|
+
@ping.before_invoke
|
|
219
|
+
async def before_ping(ctx: Context) -> None:
|
|
220
|
+
print(f"ping invoked by {ctx.sender}")
|
|
221
|
+
```
|
|
234
222
|
"""
|
|
235
223
|
|
|
236
224
|
if not inspect.iscoroutinefunction(func):
|
|
@@ -242,10 +230,17 @@ class Command:
|
|
|
242
230
|
"""
|
|
243
231
|
Registers a coroutine to be called after the command is invoked.
|
|
244
232
|
|
|
245
|
-
|
|
246
|
-
|
|
233
|
+
## Example
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
@bot.command("ping")
|
|
237
|
+
async def ping(ctx: Context) -> None:
|
|
238
|
+
await ctx.reply("Pong!")
|
|
247
239
|
|
|
248
|
-
|
|
240
|
+
@ping.after_invoke
|
|
241
|
+
async def after_ping(ctx: Context) -> None:
|
|
242
|
+
print(f"ping completed for {ctx.sender}")
|
|
243
|
+
```
|
|
249
244
|
"""
|
|
250
245
|
|
|
251
246
|
if not inspect.iscoroutinefunction(func):
|
|
@@ -257,11 +252,21 @@ class Command:
|
|
|
257
252
|
"""
|
|
258
253
|
Decorator used to register an error handler for this command.
|
|
259
254
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
:
|
|
255
|
+
## Example
|
|
256
|
+
|
|
257
|
+
```python
|
|
258
|
+
@bot.command("div")
|
|
259
|
+
async def div(ctx: Context, a: int, b: int) -> None:
|
|
260
|
+
await ctx.reply(f"{a / b}")
|
|
261
|
+
|
|
262
|
+
@div.error(ZeroDivisionError)
|
|
263
|
+
async def div_error(ctx: Context, error: ZeroDivisionError) -> None:
|
|
264
|
+
await ctx.reply("Cannot divide by zero!")
|
|
265
|
+
|
|
266
|
+
@div.error(MissingArgumentError)
|
|
267
|
+
async def div_missing(ctx: Context, error: MissingArgumentError) -> None:
|
|
268
|
+
await ctx.reply(f"Missing argument: {error}")
|
|
269
|
+
```
|
|
265
270
|
"""
|
|
266
271
|
|
|
267
272
|
def wrapper(func: ErrorCallback) -> Callable:
|
|
@@ -279,11 +284,6 @@ class Command:
|
|
|
279
284
|
async def on_error(self, ctx: "Context", error: Exception) -> None:
|
|
280
285
|
"""
|
|
281
286
|
Executes the registered error handler if present.
|
|
282
|
-
|
|
283
|
-
:param ctx: The command execution context.
|
|
284
|
-
:type ctx: Context
|
|
285
|
-
:param error: The exception that was raised.
|
|
286
|
-
:type error: Exception
|
|
287
287
|
"""
|
|
288
288
|
|
|
289
289
|
if handler := self._error_handlers.get(type(error)):
|
|
@@ -322,9 +322,6 @@ class Command:
|
|
|
322
322
|
async def __call__(self, ctx: "Context") -> None:
|
|
323
323
|
"""
|
|
324
324
|
Execute the command with parsed arguments.
|
|
325
|
-
|
|
326
|
-
:param ctx: The command execution context.
|
|
327
|
-
:type ctx: Context
|
|
328
325
|
"""
|
|
329
326
|
await self._invoke(ctx)
|
|
330
327
|
|
matrix/context.py
CHANGED
matrix/extension.py
CHANGED
|
@@ -1,21 +1,31 @@
|
|
|
1
1
|
import inspect
|
|
2
2
|
import logging
|
|
3
|
-
from typing import Callable
|
|
3
|
+
from typing import Callable
|
|
4
4
|
|
|
5
5
|
from matrix.protocols import BotLike
|
|
6
6
|
from matrix.registry import Registry
|
|
7
|
+
from matrix.config import Config
|
|
7
8
|
from matrix.room import Room
|
|
8
9
|
|
|
9
10
|
logger = logging.getLogger(__name__)
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
class Extension(Registry):
|
|
13
|
-
def __init__(self, name: str, prefix:
|
|
14
|
+
def __init__(self, name: str, prefix: str | None = None) -> None:
|
|
14
15
|
super().__init__(name, prefix=prefix)
|
|
15
16
|
|
|
16
|
-
self.
|
|
17
|
-
self._on_load:
|
|
18
|
-
self._on_unload:
|
|
17
|
+
self._bot: BotLike | None = None
|
|
18
|
+
self._on_load: Callable | None = None
|
|
19
|
+
self._on_unload: Callable | None = None
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def bot(self) -> BotLike:
|
|
23
|
+
assert self._bot, "Extension is not loaded"
|
|
24
|
+
return self._bot
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def config(self) -> Config:
|
|
28
|
+
return self.bot.config
|
|
19
29
|
|
|
20
30
|
def get_room(self, room_id: str) -> Room | None:
|
|
21
31
|
"""Retrieve a `Room` instance by its Matrix room ID.
|
|
@@ -31,12 +41,10 @@ class Extension(Registry):
|
|
|
31
41
|
print(room.name)
|
|
32
42
|
```
|
|
33
43
|
"""
|
|
34
|
-
if self.bot is None:
|
|
35
|
-
raise RuntimeError("Extension is not loaded")
|
|
36
44
|
return self.bot.get_room(room_id)
|
|
37
45
|
|
|
38
46
|
def load(self, bot: BotLike) -> None:
|
|
39
|
-
self.
|
|
47
|
+
self._bot = bot
|
|
40
48
|
|
|
41
49
|
if self._on_load:
|
|
42
50
|
self._on_load()
|
|
@@ -59,7 +67,7 @@ class Extension(Registry):
|
|
|
59
67
|
return func
|
|
60
68
|
|
|
61
69
|
def unload(self) -> None:
|
|
62
|
-
self.
|
|
70
|
+
self._bot = None
|
|
63
71
|
|
|
64
72
|
if self._on_unload:
|
|
65
73
|
self._on_unload()
|
matrix/group.py
CHANGED
|
@@ -52,13 +52,21 @@ class Group(Command):
|
|
|
52
52
|
The command name defaults to the function name unless
|
|
53
53
|
explicitly provided.
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
## Example
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
@bot.group("math")
|
|
59
|
+
async def math(ctx: Context) -> None:
|
|
60
|
+
await ctx.send_help()
|
|
61
|
+
|
|
62
|
+
@math.command()
|
|
63
|
+
async def add(ctx: Context, a: int, b: int) -> None:
|
|
64
|
+
await ctx.reply(f"{a + b}")
|
|
65
|
+
|
|
66
|
+
@math.command("sub")
|
|
67
|
+
async def subtract(ctx: Context, a: int, b: int) -> None:
|
|
68
|
+
await ctx.reply(f"{a - b}")
|
|
69
|
+
```
|
|
62
70
|
"""
|
|
63
71
|
|
|
64
72
|
def wrapper(func: Callback) -> Command:
|
matrix/help/help_command.py
CHANGED
|
@@ -17,11 +17,7 @@ class HelpCommand(Command, ABC):
|
|
|
17
17
|
DEFAULT_PER_PAGE = 5
|
|
18
18
|
|
|
19
19
|
def __init__(self, prefix: Optional[str] = None, per_page: int = DEFAULT_PER_PAGE):
|
|
20
|
-
"""Initialize the help command.
|
|
21
|
-
|
|
22
|
-
:param prefix: Command prefix override
|
|
23
|
-
:param per_page: Number of commands to display per page
|
|
24
|
-
"""
|
|
20
|
+
"""Initialize the help command."""
|
|
25
21
|
super().__init__(
|
|
26
22
|
self.execute,
|
|
27
23
|
name="help",
|
|
@@ -32,18 +28,48 @@ class HelpCommand(Command, ABC):
|
|
|
32
28
|
|
|
33
29
|
@abstractmethod
|
|
34
30
|
def format_help_page(self, page: Page[Command], title: str = "Commands") -> str:
|
|
31
|
+
"""Format a full page of commands into a displayable string.
|
|
32
|
+
|
|
33
|
+
## Example
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
def format_help_page(self, page, title="Commands") -> str:
|
|
37
|
+
lines = [f"**{title}**"]
|
|
38
|
+
for cmd in page.items:
|
|
39
|
+
lines.append(self.format_command(cmd))
|
|
40
|
+
lines.append(self.format_page_info(page))
|
|
41
|
+
return "\\n".join(lines)
|
|
42
|
+
```
|
|
43
|
+
"""
|
|
35
44
|
pass # pragma: no cover
|
|
36
45
|
|
|
37
46
|
@abstractmethod
|
|
38
47
|
def format_subcommand_page(self, page: Page[Command], group_name: str) -> str:
|
|
48
|
+
"""Format a full page of subcommands for a group into a displayable string.
|
|
49
|
+
|
|
50
|
+
## Example
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
def format_subcommand_page(self, page, group_name) -> str:
|
|
54
|
+
lines = [f"**{group_name} subcommands**"]
|
|
55
|
+
for cmd in page.items:
|
|
56
|
+
lines.append(self.format_subcommand(cmd))
|
|
57
|
+
lines.append(self.format_page_info(page))
|
|
58
|
+
return "\\n".join(lines)
|
|
59
|
+
```
|
|
60
|
+
"""
|
|
39
61
|
pass # pragma: no cover
|
|
40
62
|
|
|
41
63
|
@abstractmethod
|
|
42
64
|
def format_command(self, cmd: Command) -> str:
|
|
43
65
|
"""Format a single command for display.
|
|
44
66
|
|
|
45
|
-
|
|
46
|
-
|
|
67
|
+
## Example
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
def format_command(self, cmd) -> str:
|
|
71
|
+
return f"**{cmd.name}** — {cmd.description}"
|
|
72
|
+
```
|
|
47
73
|
"""
|
|
48
74
|
pass # pragma: no cover
|
|
49
75
|
|
|
@@ -51,8 +77,12 @@ class HelpCommand(Command, ABC):
|
|
|
51
77
|
def format_group(self, group: Group) -> str: # pragma: no cover
|
|
52
78
|
"""Format a group command for display.
|
|
53
79
|
|
|
54
|
-
|
|
55
|
-
|
|
80
|
+
## Example
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
def format_group(self, group) -> str:
|
|
84
|
+
return f"**{group.name}** [group] — {group.description}"
|
|
85
|
+
```
|
|
56
86
|
"""
|
|
57
87
|
pass
|
|
58
88
|
|
|
@@ -60,8 +90,12 @@ class HelpCommand(Command, ABC):
|
|
|
60
90
|
def format_subcommand(self, subcommand: Command) -> str:
|
|
61
91
|
"""Format a subcommand for display.
|
|
62
92
|
|
|
63
|
-
|
|
64
|
-
|
|
93
|
+
## Example
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
def format_subcommand(self, subcommand) -> str:
|
|
97
|
+
return f" **{subcommand.name}** — {subcommand.description}"
|
|
98
|
+
```
|
|
65
99
|
"""
|
|
66
100
|
pass # pragma: no cover
|
|
67
101
|
|
|
@@ -69,8 +103,12 @@ class HelpCommand(Command, ABC):
|
|
|
69
103
|
def format_page_info(self, page: Page[Command]) -> str:
|
|
70
104
|
"""Format the page information display.
|
|
71
105
|
|
|
72
|
-
|
|
73
|
-
|
|
106
|
+
## Example
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
def format_page_info(self, page) -> str:
|
|
110
|
+
return f"Page {page.page_number}/{page.total_pages}"
|
|
111
|
+
```
|
|
74
112
|
"""
|
|
75
113
|
pass # pragma: no cover
|
|
76
114
|
|
|
@@ -98,43 +136,25 @@ class HelpCommand(Command, ABC):
|
|
|
98
136
|
pass # pragma: no cover
|
|
99
137
|
|
|
100
138
|
def get_commands_paginator(self, ctx: Context) -> Paginator[Command]:
|
|
101
|
-
"""Get a paginator for all commands.
|
|
102
|
-
|
|
103
|
-
:param ctx: Command context
|
|
104
|
-
:return: Paginator configured with all commands
|
|
105
|
-
"""
|
|
139
|
+
"""Get a paginator for all commands."""
|
|
106
140
|
all_commands = list(ctx.bot.commands.values())
|
|
107
141
|
sorted_commands = sorted(all_commands, key=lambda c: c.name.lower())
|
|
108
142
|
|
|
109
143
|
return Paginator(sorted_commands, self.per_page)
|
|
110
144
|
|
|
111
145
|
def get_subcommands_paginator(self, group: Group) -> Paginator[Command]:
|
|
112
|
-
"""Get a paginator for all subcommands in a group.
|
|
113
|
-
|
|
114
|
-
:param group: The group to get subcommands from
|
|
115
|
-
:return: Paginator configured with all subcommands
|
|
116
|
-
"""
|
|
146
|
+
"""Get a paginator for all subcommands in a group."""
|
|
117
147
|
subcommands = list(getattr(group, "commands", {}).values())
|
|
118
148
|
sorted_subcommands = sorted(subcommands, key=lambda c: c.name.lower())
|
|
119
149
|
|
|
120
150
|
return Paginator(sorted_subcommands, self.per_page)
|
|
121
151
|
|
|
122
152
|
def find_command(self, ctx: Context, command_name: str) -> Optional[Command]:
|
|
123
|
-
"""Find a command by name.
|
|
124
|
-
|
|
125
|
-
:param ctx: Command context
|
|
126
|
-
:param command_name: Name of the command to find
|
|
127
|
-
:return: Command if found, None otherwise
|
|
128
|
-
"""
|
|
153
|
+
"""Find a command by name."""
|
|
129
154
|
return ctx.bot.commands.get(command_name)
|
|
130
155
|
|
|
131
156
|
def find_subcommand(self, group: Group, subcommand_name: str) -> Optional[Command]:
|
|
132
|
-
"""Find a subcommand within a group.
|
|
133
|
-
|
|
134
|
-
:param group: The group to search in
|
|
135
|
-
:param subcommand_name: Name of the subcommand to find
|
|
136
|
-
:return: Subcommand if found, None otherwise
|
|
137
|
-
"""
|
|
157
|
+
"""Find a subcommand within a group."""
|
|
138
158
|
group_commands = getattr(group, "commands", {})
|
|
139
159
|
return group_commands.get(subcommand_name)
|
|
140
160
|
|
|
@@ -175,11 +195,7 @@ class HelpCommand(Command, ABC):
|
|
|
175
195
|
await self.on_empty_page(ctx)
|
|
176
196
|
|
|
177
197
|
async def show_help_page(self, ctx: Context, page_number: int = 1) -> None:
|
|
178
|
-
"""Show a paginated help page for all commands.
|
|
179
|
-
|
|
180
|
-
:param ctx: Command context
|
|
181
|
-
:param page_number: Page number to display
|
|
182
|
-
"""
|
|
198
|
+
"""Show a paginated help page for all commands."""
|
|
183
199
|
paginator = self.get_commands_paginator(ctx)
|
|
184
200
|
page = paginator.get_page(page_number)
|
|
185
201
|
help_message = self.format_help_page(page)
|
|
@@ -271,12 +287,7 @@ class DefaultHelpCommand(HelpCommand):
|
|
|
271
287
|
"""
|
|
272
288
|
|
|
273
289
|
def format_help_page(self, page: Page[Command], title: str = "Commands") -> str:
|
|
274
|
-
"""Format a complete help page.
|
|
275
|
-
|
|
276
|
-
:param page: Page object containing commands and pagination info
|
|
277
|
-
:param title: Title for the help page
|
|
278
|
-
:return: Complete formatted help page
|
|
279
|
-
"""
|
|
290
|
+
"""Format a complete help page."""
|
|
280
291
|
help_entries = []
|
|
281
292
|
|
|
282
293
|
if not page.items:
|
|
@@ -294,12 +305,7 @@ class DefaultHelpCommand(HelpCommand):
|
|
|
294
305
|
return f"**{title}**\n\n{help_text}\n\n{page_info}"
|
|
295
306
|
|
|
296
307
|
def format_subcommand_page(self, page: Page[Command], group_name: str) -> str:
|
|
297
|
-
"""Format a complete subcommand help page.
|
|
298
|
-
|
|
299
|
-
:param page: Page object containing subcommands and pagination info
|
|
300
|
-
:param group_name: Name of the parent group
|
|
301
|
-
:return: Complete formatted subcommand help page
|
|
302
|
-
"""
|
|
308
|
+
"""Format a complete subcommand help page."""
|
|
303
309
|
help_entries = []
|
|
304
310
|
|
|
305
311
|
if not page.items:
|
|
@@ -314,11 +320,7 @@ class DefaultHelpCommand(HelpCommand):
|
|
|
314
320
|
return f"**{group_name} Subcommands**\n\n{help_text}\n\n{page_info}"
|
|
315
321
|
|
|
316
322
|
def format_command(self, cmd: Command) -> str:
|
|
317
|
-
"""Format a single command for display.
|
|
318
|
-
|
|
319
|
-
:param cmd: The command to format
|
|
320
|
-
:return: Formatted string representation of the command
|
|
321
|
-
"""
|
|
323
|
+
"""Format a single command for display."""
|
|
322
324
|
return (
|
|
323
325
|
f"**{cmd.name}**\n"
|
|
324
326
|
f"Usage: `{cmd.usage}`\n"
|
|
@@ -326,11 +328,7 @@ class DefaultHelpCommand(HelpCommand):
|
|
|
326
328
|
)
|
|
327
329
|
|
|
328
330
|
def format_group(self, group: Group) -> str:
|
|
329
|
-
"""Format a group command for display.
|
|
330
|
-
|
|
331
|
-
:param group: The group to format
|
|
332
|
-
:return: Formatted string representation of the group
|
|
333
|
-
"""
|
|
331
|
+
"""Format a group command for display."""
|
|
334
332
|
subcommands_text = ""
|
|
335
333
|
subcommand_count = len(getattr(group, "commands", {}))
|
|
336
334
|
|
|
@@ -344,11 +342,7 @@ class DefaultHelpCommand(HelpCommand):
|
|
|
344
342
|
)
|
|
345
343
|
|
|
346
344
|
def format_subcommand(self, subcommand: Command) -> str:
|
|
347
|
-
"""Format a subcommand for display.
|
|
348
|
-
|
|
349
|
-
:param subcommand: The subcommand to format
|
|
350
|
-
:return: Formatted string representation of the subcommand
|
|
351
|
-
"""
|
|
345
|
+
"""Format a subcommand for display."""
|
|
352
346
|
return (
|
|
353
347
|
f"**{subcommand.name}**\n"
|
|
354
348
|
f"Usage: `{subcommand.usage}`\n"
|
|
@@ -356,11 +350,7 @@ class DefaultHelpCommand(HelpCommand):
|
|
|
356
350
|
)
|
|
357
351
|
|
|
358
352
|
def format_page_info(self, page: Page[Command]) -> str:
|
|
359
|
-
"""Format the page information display.
|
|
360
|
-
|
|
361
|
-
:param page: Page object containing pagination info
|
|
362
|
-
:return: Formatted page information string
|
|
363
|
-
"""
|
|
353
|
+
"""Format the page information display."""
|
|
364
354
|
return f"**Page {page.page_number}/{page.total_pages}**"
|
|
365
355
|
|
|
366
356
|
async def on_command_not_found(self, ctx: Context, command_name: str) -> None:
|
matrix/help/pagination.py
CHANGED
|
@@ -7,22 +7,14 @@ class Paginator(Generic[T]):
|
|
|
7
7
|
"""A generic paginator for any list of items."""
|
|
8
8
|
|
|
9
9
|
def __init__(self, items: List[T], per_page: int = 5):
|
|
10
|
-
"""Initialize the paginator.
|
|
11
|
-
|
|
12
|
-
:param items: List of items to paginate
|
|
13
|
-
:param per_page: Number of items per page
|
|
14
|
-
"""
|
|
10
|
+
"""Initialize the paginator."""
|
|
15
11
|
self.items = items
|
|
16
12
|
self.per_page = per_page
|
|
17
13
|
self.total_items = len(items)
|
|
18
14
|
self.total_pages = max(1, -(-self.total_items // self.per_page))
|
|
19
15
|
|
|
20
16
|
def get_page(self, page_number: int) -> "Page[T]":
|
|
21
|
-
"""Get a specific page of items.
|
|
22
|
-
|
|
23
|
-
:param page_number: Page number to retrieve (1-indexed)
|
|
24
|
-
:return: Page object containing items and metadata
|
|
25
|
-
"""
|
|
17
|
+
"""Get a specific page of items."""
|
|
26
18
|
# Clamp page number to valid range
|
|
27
19
|
page_number = max(1, min(page_number, self.total_pages))
|
|
28
20
|
|
|
@@ -38,10 +30,7 @@ class Paginator(Generic[T]):
|
|
|
38
30
|
)
|
|
39
31
|
|
|
40
32
|
def get_pages(self) -> List["Page[T]"]:
|
|
41
|
-
"""Get all pages.
|
|
42
|
-
|
|
43
|
-
:return: List of all pages
|
|
44
|
-
"""
|
|
33
|
+
"""Get all pages."""
|
|
45
34
|
return [self.get_page(i) for i in range(1, self.total_pages + 1)]
|
|
46
35
|
|
|
47
36
|
|
|
@@ -56,14 +45,7 @@ class Page(Generic[T]):
|
|
|
56
45
|
per_page: int,
|
|
57
46
|
total_items: int,
|
|
58
47
|
):
|
|
59
|
-
"""Initialize a page.
|
|
60
|
-
|
|
61
|
-
:param items: Items on this page
|
|
62
|
-
:param page_number: Current page number
|
|
63
|
-
:param total_pages: Total number of pages
|
|
64
|
-
:param per_page: Items per page
|
|
65
|
-
:param total_items: Total number of items across all pages
|
|
66
|
-
"""
|
|
48
|
+
"""Initialize a page."""
|
|
67
49
|
self.items = items
|
|
68
50
|
self.page_number = page_number
|
|
69
51
|
self.total_pages = total_pages
|
matrix/protocols.py
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
from typing import Protocol
|
|
2
2
|
|
|
3
|
+
from matrix.config import Config
|
|
3
4
|
from matrix.room import Room
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
class BotLike(Protocol):
|
|
7
8
|
prefix: str | None
|
|
8
9
|
|
|
10
|
+
@property
|
|
11
|
+
def config(self) -> Config: ...
|
|
12
|
+
|
|
9
13
|
def get_room(self, room_id: str) -> Room | None: ...
|
matrix/registry.py
CHANGED
|
@@ -2,7 +2,20 @@ import inspect
|
|
|
2
2
|
import logging
|
|
3
3
|
|
|
4
4
|
from collections import defaultdict
|
|
5
|
-
from typing import
|
|
5
|
+
from typing import (
|
|
6
|
+
TypeVar,
|
|
7
|
+
Any,
|
|
8
|
+
Callable,
|
|
9
|
+
Coroutine,
|
|
10
|
+
Literal,
|
|
11
|
+
Optional,
|
|
12
|
+
Type,
|
|
13
|
+
Union,
|
|
14
|
+
Dict,
|
|
15
|
+
List,
|
|
16
|
+
cast,
|
|
17
|
+
overload,
|
|
18
|
+
)
|
|
6
19
|
|
|
7
20
|
from nio import (
|
|
8
21
|
Event,
|
|
@@ -25,6 +38,8 @@ GroupCallable = Callable[[Callable[..., Coroutine[Any, Any, Any]]], Group]
|
|
|
25
38
|
ErrorCallback = Callable[[Exception], Coroutine]
|
|
26
39
|
CommandErrorCallback = Callable[[Context, Exception], Coroutine[Any, Any, Any]]
|
|
27
40
|
|
|
41
|
+
F = TypeVar("F", ErrorCallback, CommandErrorCallback)
|
|
42
|
+
|
|
28
43
|
|
|
29
44
|
class Registry:
|
|
30
45
|
"""
|
|
@@ -355,43 +370,91 @@ class Registry:
|
|
|
355
370
|
|
|
356
371
|
return wrapper
|
|
357
372
|
|
|
373
|
+
@overload
|
|
358
374
|
def error(
|
|
359
|
-
self,
|
|
360
|
-
|
|
375
|
+
self,
|
|
376
|
+
exception: Optional[type[Exception]] = None,
|
|
377
|
+
*,
|
|
378
|
+
context: Literal[True],
|
|
379
|
+
) -> Callable[[CommandErrorCallback], CommandErrorCallback]: ...
|
|
380
|
+
|
|
381
|
+
@overload
|
|
382
|
+
def error(
|
|
383
|
+
self,
|
|
384
|
+
exception: Optional[type[Exception]] = None,
|
|
385
|
+
*,
|
|
386
|
+
context: Literal[False] = ...,
|
|
387
|
+
) -> Callable[[ErrorCallback], ErrorCallback]: ...
|
|
388
|
+
|
|
389
|
+
def error(
|
|
390
|
+
self,
|
|
391
|
+
exception: Optional[type[Exception]] = None,
|
|
392
|
+
*,
|
|
393
|
+
context: bool = False,
|
|
394
|
+
) -> Union[
|
|
395
|
+
Callable[[ErrorCallback], ErrorCallback],
|
|
396
|
+
Callable[[CommandErrorCallback], CommandErrorCallback],
|
|
397
|
+
]:
|
|
361
398
|
"""Decorator to register an error handler.
|
|
362
399
|
|
|
363
400
|
If an exception type is provided, the handler is only invoked for
|
|
364
401
|
that specific exception. If omitted, the handler acts as a generic
|
|
365
402
|
fallback for any unhandled error.
|
|
366
403
|
|
|
404
|
+
Set ``context=True`` to receive the command context alongside the error,
|
|
405
|
+
useful for command-specific errors where you want to reply to the user.
|
|
406
|
+
|
|
367
407
|
## Example
|
|
368
408
|
|
|
369
409
|
```python
|
|
370
410
|
@bot.error(ValueError)
|
|
371
411
|
async def on_value_error(error):
|
|
372
|
-
|
|
412
|
+
pass
|
|
373
413
|
|
|
374
414
|
@bot.error()
|
|
375
415
|
async def on_any_error(error):
|
|
376
|
-
|
|
416
|
+
pass
|
|
417
|
+
|
|
418
|
+
@bot.error(CommandNotFoundError, context=True)
|
|
419
|
+
async def on_command_not_found(ctx, error):
|
|
420
|
+
await ctx.reply("Command not found!")
|
|
377
421
|
```
|
|
378
422
|
"""
|
|
379
423
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
def wrapper(func: ErrorCallback) -> ErrorCallback:
|
|
424
|
+
def wrapper(
|
|
425
|
+
func: F,
|
|
426
|
+
) -> F:
|
|
384
427
|
if not inspect.iscoroutinefunction(func):
|
|
385
428
|
raise TypeError("Error handlers must be coroutines")
|
|
386
429
|
|
|
387
|
-
|
|
430
|
+
if context:
|
|
431
|
+
self._register_command_error(
|
|
432
|
+
cast(CommandErrorCallback, func), exception
|
|
433
|
+
)
|
|
434
|
+
else:
|
|
435
|
+
self._register_error(cast(ErrorCallback, func), exception)
|
|
388
436
|
|
|
389
437
|
logger.debug(
|
|
390
438
|
"registered error handler '%s' on %s",
|
|
391
439
|
func.__name__,
|
|
392
440
|
type(self).__name__,
|
|
393
441
|
)
|
|
394
|
-
|
|
395
442
|
return func
|
|
396
443
|
|
|
397
444
|
return wrapper
|
|
445
|
+
|
|
446
|
+
def _register_error(
|
|
447
|
+
self, func: ErrorCallback, exception: Optional[type[Exception]] = None
|
|
448
|
+
) -> None:
|
|
449
|
+
if not exception:
|
|
450
|
+
exception = Exception
|
|
451
|
+
self._error_handlers[exception] = func
|
|
452
|
+
|
|
453
|
+
def _register_command_error(
|
|
454
|
+
self,
|
|
455
|
+
func: CommandErrorCallback,
|
|
456
|
+
exception: Optional[type[Exception]] = None,
|
|
457
|
+
) -> None:
|
|
458
|
+
if not exception:
|
|
459
|
+
exception = Exception
|
|
460
|
+
self._command_error_handlers[exception] = func
|
matrix/scheduler.py
CHANGED
|
@@ -21,11 +21,6 @@ class Scheduler:
|
|
|
21
21
|
def _parse_cron(self, cron: str) -> dict:
|
|
22
22
|
"""
|
|
23
23
|
Parse a cron string into a dictionary suitable for CronTrigger.
|
|
24
|
-
|
|
25
|
-
:param cron: The cron string to parse.
|
|
26
|
-
:type cron: str
|
|
27
|
-
:return: A dictionary with cron fields.
|
|
28
|
-
:rtype: dict
|
|
29
24
|
"""
|
|
30
25
|
fields = cron.split()
|
|
31
26
|
if len(fields) != 5:
|
|
@@ -42,10 +37,13 @@ class Scheduler:
|
|
|
42
37
|
"""
|
|
43
38
|
Schedule a coroutine function to be run at specified intervals.
|
|
44
39
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
40
|
+
## Example
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
@bot.schedule("0 9 * * 1-5")
|
|
44
|
+
async def morning_update() -> None:
|
|
45
|
+
await room.send("Good morning!")
|
|
46
|
+
```
|
|
49
47
|
"""
|
|
50
48
|
cron_trigger = CronTrigger(**self._parse_cron(cron))
|
|
51
49
|
self.scheduler.add_job(func, trigger=cron_trigger, name=func.__name__)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: matrix-python
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.10a0
|
|
4
4
|
Summary: An easy-to-use Matrix bot framework designed for quick development and minimal setup
|
|
5
5
|
Author: Simon Roy, Chris Dedman Rollet
|
|
6
6
|
Maintainer-email: Code Society Lab <admin@codesociety.xyz>
|
|
@@ -40,57 +40,72 @@ Provides-Extra: dev
|
|
|
40
40
|
Requires-Dist: pytest==9.0.3; extra == "dev"
|
|
41
41
|
Requires-Dist: pytest-asyncio==1.3.0; extra == "dev"
|
|
42
42
|
Requires-Dist: black==26.3.1; extra == "dev"
|
|
43
|
-
Requires-Dist: mypy==1.20.
|
|
43
|
+
Requires-Dist: mypy==1.20.1; extra == "dev"
|
|
44
44
|
Requires-Dist: types-PyYAML==6.0.12.20260408; extra == "dev"
|
|
45
45
|
Requires-Dist: types-Markdown==3.10.2.20260408; extra == "dev"
|
|
46
|
+
Provides-Extra: doc
|
|
47
|
+
Requires-Dist: mkdocs==1.6.1; extra == "doc"
|
|
48
|
+
Requires-Dist: mkdocs-material==9.7.6; extra == "doc"
|
|
49
|
+
Requires-Dist: mkdocstrings[python]==1.0.4; extra == "doc"
|
|
46
50
|
|
|
47
51
|
<div align="center">
|
|
48
52
|
<em>A simple, developer-friendly library to create powerful <a href="https://matrix.org">Matrix</a> bots.</em>
|
|
49
53
|
</div>
|
|
50
54
|
|
|
51
|
-
<
|
|
55
|
+
<div align="center">
|
|
56
|
+
<img alt="matrix.py" src="https://github.com/user-attachments/assets/d9140a9e-27fa-44e4-a5ca-87ee7bbf868f" />
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
<div align="center">
|
|
52
60
|
|
|
53
|
-
<
|
|
61
|
+
[<img src="https://img.shields.io/badge/Get%20Started-black?style=for-the-badge" />](https://matrixpy.code-society.xyz/guides/introduction/)
|
|
62
|
+
[<img src="https://img.shields.io/badge/Reference-555555?style=for-the-badge" />](https://matrixpy.code-society.xyz/reference/bot/)
|
|
63
|
+
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
<div align="center">
|
|
54
67
|
|
|
55
|
-
[](https://github.com/Code-Society-Lab/matrixpy/wiki)
|
|
56
68
|
[](https://discord.gg/code-society-823178343943897088)
|
|
57
|
-
[](https://matrix.to/#/%23codesociety:matrix.org
|
|
69
|
+
[](https://matrix.to/#/%23codesociety:matrix.org)
|
|
58
70
|
[](https://github.com/Code-Society-Lab/matrixpy/actions/workflows/tests.yml)
|
|
59
71
|
[](https://github.com/Code-Society-Lab/matrixpy/actions/workflows/codeql.yml)
|
|
60
72
|
[](https://securityscorecards.dev/viewer/?uri=github.com/Code-Society-Lab/matrixpy)
|
|
61
73
|
|
|
62
|
-
|
|
63
|
-
the [Matrix protocol](https://matrix.org). It provides a clean,
|
|
64
|
-
decorator-based API similar to popular event-driven frameworks, allowing
|
|
65
|
-
developers to focus on behavior rather than boilerplate.
|
|
74
|
+
</div>
|
|
66
75
|
|
|
67
|
-
|
|
76
|
+
---
|
|
68
77
|
|
|
69
|
-
|
|
70
|
-
-
|
|
71
|
-
|
|
72
|
-
- Automatic event handler registration
|
|
73
|
-
- Built on [matrix-nio](https://github.com/matrix-nio/matrix-nio)
|
|
78
|
+
Matrix.py is a lightweight and intuitive Python library to build bots on the [Matrix protocol](https://matrix.org). It
|
|
79
|
+
provides a clean, decorator-based API similar to popular event-driven frameworks, allowing developers to focus on
|
|
80
|
+
behavior rather than boilerplate.
|
|
74
81
|
|
|
75
|
-
|
|
82
|
+
- **Minimal setup** — install and have a working bot running in minutes
|
|
83
|
+
- **Event-driven** — async/await API reacting to any Matrix room event
|
|
84
|
+
- **Command system** — decorator-based commands with automatic argument parsing
|
|
85
|
+
- **Extensions** — split your bot into modules as it grows
|
|
76
86
|
|
|
77
|
-
|
|
87
|
+
## Quickstart
|
|
78
88
|
|
|
79
|
-
|
|
89
|
+
**Requirements:** Python 3.10+
|
|
80
90
|
|
|
81
|
-
```
|
|
91
|
+
```bash
|
|
82
92
|
pip install matrix-python
|
|
83
93
|
```
|
|
84
94
|
|
|
85
|
-
|
|
95
|
+
Using a virtual environment is strongly recommended:
|
|
86
96
|
|
|
87
|
-
```
|
|
88
|
-
|
|
97
|
+
```bash
|
|
98
|
+
python -m venv venv
|
|
99
|
+
source venv/bin/activate # Windows: venv\Scripts\activate
|
|
100
|
+
pip install matrix-python
|
|
89
101
|
```
|
|
90
102
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
103
|
+
Create a `config.yml`:
|
|
104
|
+
|
|
105
|
+
```yaml
|
|
106
|
+
USERNAME: "@yourbot:matrix.org"
|
|
107
|
+
PASSWORD: "your_password"
|
|
108
|
+
```
|
|
94
109
|
|
|
95
110
|
```python
|
|
96
111
|
from matrix import Bot, Context
|
|
@@ -106,23 +121,29 @@ async def ping(ctx: Context):
|
|
|
106
121
|
bot.start(config="config.yml")
|
|
107
122
|
```
|
|
108
123
|
|
|
109
|
-
|
|
124
|
+
Send `!ping` in any room the bot is in, it will reply `Pong!`.
|
|
125
|
+
|
|
126
|
+
## Where to go next
|
|
110
127
|
|
|
111
|
-
|
|
128
|
+
- [**Guides**](https://matrixpy.codesociety.xyz/guides/introduction/) — step-by-step tutorials covering commands,
|
|
129
|
+
events, checks, extensions, and more
|
|
130
|
+
- [**Reference**](https://matrixpy.codesociety.xyz/reference/bot/) — complete API documentation for every class and
|
|
131
|
+
function
|
|
132
|
+
- [**Examples**](https://matrixpy.codesociety.xyz/examples/) — ready-to-run example bots
|
|
133
|
+
demonstrating common patterns
|
|
112
134
|
|
|
113
|
-
|
|
135
|
+
## Contributing
|
|
114
136
|
|
|
115
|
-
Whether it's fixing bugs, suggesting features, or improving the docs
|
|
137
|
+
We welcome everyone to contribute! Whether it's fixing bugs, suggesting features, or improving the docs. Every bit
|
|
138
|
+
helps.
|
|
116
139
|
|
|
117
|
-
- Submit an issue
|
|
118
|
-
- Open a pull request
|
|
119
|
-
-
|
|
120
|
-
or [Discord](https://discord.gg/code-society-823178343943897088)
|
|
140
|
+
- [Submit an issue](https://github.com/Code-Society-Lab/matrixpy/issues)
|
|
141
|
+
- [Open a pull request](https://github.com/Code-Society-Lab/matrixpy/blob/main/CONTRIBUTING.md)
|
|
142
|
+
- Hop into our [Matrix](https://matrix.to/#/%23codesociety:matrix.org)
|
|
143
|
+
or [Discord](https://discord.gg/code-society-823178343943897088) and say hi!
|
|
121
144
|
|
|
122
|
-
|
|
123
|
-
contributor** is expected to follow the [code of conduct](./CODE_OF_CONDUCT.md).
|
|
145
|
+
Please read the [CONTRIBUTING.md](./CONTRIBUTING.md) and follow the [code of conduct](./CODE_OF_CONDUCT.md).
|
|
124
146
|
|
|
125
|
-
|
|
147
|
+
## License
|
|
126
148
|
|
|
127
|
-
|
|
128
|
-
of [MIT license](https://github.com/Code-Society-Lab/matrixpy/blob/main/LICENSE).
|
|
149
|
+
Released under the [MIT License](https://github.com/Code-Society-Lab/matrixpy/blob/main/LICENSE).
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
matrix/__init__.py,sha256=g8yEFjELnnwlvOKns-Ug6LgOezkjAFZ-Opt7esbBHKg,728
|
|
2
|
+
matrix/_version.py,sha256=mIVsMSXZUY9bR5xv4sLyWvbSaMCfZOJSgUtWBegbo6Q,530
|
|
3
|
+
matrix/bot.py,sha256=tbcn1Ra025I9plM-gf0NpzPKSTBlYe0_L8_RLO8w9GM,11984
|
|
4
|
+
matrix/checks.py,sha256=8geXrN8dEIR8HMbc2DQz4XFxLnBvjeqLUUqO9w1JPnA,678
|
|
5
|
+
matrix/command.py,sha256=I5sb9tTnhEd2RRfWRfGcJy3Xj0pA856KnHPm6JKPY7A,9942
|
|
6
|
+
matrix/config.py,sha256=JW_BBs-msIhtv1AGebZumLsx4td-Gp-NZaNYPJxRsEo,3680
|
|
7
|
+
matrix/content.py,sha256=z5_E2rTvHsODE52OiDkhDHNQAryx5NLhyHjBb65Xe-U,3853
|
|
8
|
+
matrix/context.py,sha256=tmtgzv3mtw4yNBw5ZUuDTr8fes1zWlaFZp7oU-WzAmk,3965
|
|
9
|
+
matrix/errors.py,sha256=HKGb5NUeFuZvieXgpLlVSmUxK4jpA0ODuiPQqQlbQTE,1676
|
|
10
|
+
matrix/extension.py,sha256=5f6pW_6D8wwN5qKhnQRkCWWDkkQw9t47j5XRNZNsyGQ,2399
|
|
11
|
+
matrix/group.py,sha256=P4NWNczfUpl0693lWswqafpEnYfzNXH_gz3swIlaxaE,3734
|
|
12
|
+
matrix/message.py,sha256=w6pu86goylxdrX5fgXPUMB_tW0bOFIk6tKy6qkXTjl4,5136
|
|
13
|
+
matrix/protocols.py,sha256=pIkHL4yuenvxh-gFhRPudCHJcfMBRxq2lUL5S5sPxpM,250
|
|
14
|
+
matrix/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
+
matrix/registry.py,sha256=OiEWaO66k4QOnOPCaXL5Ys-_TnVioI4q5ulyRP_fGS4,14202
|
|
16
|
+
matrix/room.py,sha256=PBuMWQo8mKy2d2XIeMbBlVBTnnqZjOPPGpKLp4K1AVM,14038
|
|
17
|
+
matrix/scheduler.py,sha256=8GDzxJhuDh32HRz3DyVw0SKXAQ9Az3t3jsDersSoB70,1597
|
|
18
|
+
matrix/types.py,sha256=UFjC7p8RAf7piEPvp2X3NuWdqBwkM9Yc3He7KWb9icc,384
|
|
19
|
+
matrix/help/__init__.py,sha256=1u7V7T_-VgYDeQCTXsc4y8Fo-8gJhOqYJq2U3cUjMWg,168
|
|
20
|
+
matrix/help/help_command.py,sha256=DEhOpMGx0-43m--sVqQjq-w71r6yKsrxSPDMFsr4oE4,12277
|
|
21
|
+
matrix/help/pagination.py,sha256=tmqgz_msP0qWefCiMDzDcGMP830z89VgQHxptj8ogzc,2175
|
|
22
|
+
matrix_python-1.4.10a0.dist-info/METADATA,sha256=YFYoLz8OIUYp28jtwVVyluQ5A6QwRRtMehpJzbwOnwk,6209
|
|
23
|
+
matrix_python-1.4.10a0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
24
|
+
matrix_python-1.4.10a0.dist-info/top_level.txt,sha256=BvHVM9c7-5SLzg-1OCRpHKgqAubWhRN1e38e6coHs-g,7
|
|
25
|
+
matrix_python-1.4.10a0.dist-info/RECORD,,
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
matrix/__init__.py,sha256=g8yEFjELnnwlvOKns-Ug6LgOezkjAFZ-Opt7esbBHKg,728
|
|
2
|
-
matrix/_version.py,sha256=Sp0Aavn8Gz-jkQehzIA2xsa-Il-CUVey1i9m5oSJ344,528
|
|
3
|
-
matrix/bot.py,sha256=tbcn1Ra025I9plM-gf0NpzPKSTBlYe0_L8_RLO8w9GM,11984
|
|
4
|
-
matrix/checks.py,sha256=F_7432_OcFO-im4fRAj62MUsyv1mXywT4OsGC_7xbBQ,486
|
|
5
|
-
matrix/command.py,sha256=GrP3WsT07sKehGX7PHfnT7gRX22d99877VPd0X2ViEw,10514
|
|
6
|
-
matrix/config.py,sha256=JW_BBs-msIhtv1AGebZumLsx4td-Gp-NZaNYPJxRsEo,3680
|
|
7
|
-
matrix/content.py,sha256=z5_E2rTvHsODE52OiDkhDHNQAryx5NLhyHjBb65Xe-U,3853
|
|
8
|
-
matrix/context.py,sha256=-CbxY-LtK9-jgHERhvJH73B3SpO-Uk5ty0j1TMKfzuI,4032
|
|
9
|
-
matrix/errors.py,sha256=HKGb5NUeFuZvieXgpLlVSmUxK4jpA0ODuiPQqQlbQTE,1676
|
|
10
|
-
matrix/extension.py,sha256=RbCx58CdRXF8kGUgS-ec1aZdd-K5hQedhCCQ0-YR4Vg,2272
|
|
11
|
-
matrix/group.py,sha256=TRIX7PE3lcB2ZWu3xY2W2OAmE_a8-i2zHNBYnX5uj28,3691
|
|
12
|
-
matrix/message.py,sha256=w6pu86goylxdrX5fgXPUMB_tW0bOFIk6tKy6qkXTjl4,5136
|
|
13
|
-
matrix/protocols.py,sha256=nFb4tLanwtrKWoIhZ96xMwXPjD3RF5ITca_yXtakXC4,166
|
|
14
|
-
matrix/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
-
matrix/registry.py,sha256=PgdmbBADS-yqdFdj9x3QSsVfefx8Li848CU_UBbqCLQ,12646
|
|
16
|
-
matrix/room.py,sha256=PBuMWQo8mKy2d2XIeMbBlVBTnnqZjOPPGpKLp4K1AVM,14038
|
|
17
|
-
matrix/scheduler.py,sha256=EXsL9i8IDXhcpdW8lti0BR5XcIgkmud4iwOPaqcE9Gw,1727
|
|
18
|
-
matrix/types.py,sha256=UFjC7p8RAf7piEPvp2X3NuWdqBwkM9Yc3He7KWb9icc,384
|
|
19
|
-
matrix/help/__init__.py,sha256=1u7V7T_-VgYDeQCTXsc4y8Fo-8gJhOqYJq2U3cUjMWg,168
|
|
20
|
-
matrix/help/help_command.py,sha256=xCLmKklw74LEMjbUfgQR9eaPMFvi3sPtDw2n2pnAnVQ,12800
|
|
21
|
-
matrix/help/pagination.py,sha256=sJk0wC46sFHf7xl7WsGRAUc4FC7b9hPqmwQDmvcjwgM,2717
|
|
22
|
-
matrix_python-1.4.8a0.dist-info/METADATA,sha256=Cw_QAKOVIvymFvEELdhYf72O0UkQOSk21KMpc01KAOY,5421
|
|
23
|
-
matrix_python-1.4.8a0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
24
|
-
matrix_python-1.4.8a0.dist-info/top_level.txt,sha256=BvHVM9c7-5SLzg-1OCRpHKgqAubWhRN1e38e6coHs-g,7
|
|
25
|
-
matrix_python-1.4.8a0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|