matrix-python 1.4.3a0__tar.gz → 1.4.5a0__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.
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/PKG-INFO +11 -11
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/matrix/_version.py +3 -3
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/matrix/bot.py +45 -8
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/matrix/errors.py +4 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/matrix/extension.py +14 -1
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/matrix/protocols.py +1 -1
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/matrix_python.egg-info/PKG-INFO +11 -11
- matrix_python-1.4.5a0/matrix_python.egg-info/requires.txt +13 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/pyproject.toml +14 -14
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/tests/test_bot.py +110 -4
- matrix_python-1.4.3a0/matrix_python.egg-info/requires.txt +0 -13
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/.github/dependabot.yml +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/.github/workflows/CODEOWNERS +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/.github/workflows/codeql.yml +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/.github/workflows/publish.yml +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/.github/workflows/scorecard.yml +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/.github/workflows/tests.yml +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/.gitignore +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/CODE_OF_CONDUCT.md +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/CONTRIBUTING.md +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/LICENSE +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/README.md +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/examples/README.md +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/examples/checks.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/examples/config.yaml +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/examples/cooldown.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/examples/error_handling.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/examples/extension.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/examples/ping.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/examples/reaction.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/examples/scheduler.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/matrix/__init__.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/matrix/checks.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/matrix/command.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/matrix/config.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/matrix/content.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/matrix/context.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/matrix/group.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/matrix/help/__init__.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/matrix/help/help_command.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/matrix/help/pagination.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/matrix/message.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/matrix/registry.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/matrix/room.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/matrix/scheduler.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/matrix/types.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/matrix_python.egg-info/SOURCES.txt +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/matrix_python.egg-info/dependency_links.txt +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/matrix_python.egg-info/top_level.txt +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/mypy.ini +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/setup.cfg +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/tests/config_fixture.yaml +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/tests/config_fixture_token.yaml +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/tests/help/test_default_help_command.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/tests/help/test_help_command.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/tests/help/test_pagination.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/tests/test_command.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/tests/test_config.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/tests/test_context.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/tests/test_extension.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/tests/test_group.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/tests/test_message.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/tests/test_registry.py +0 -0
- {matrix_python-1.4.3a0 → matrix_python-1.4.5a0}/tests/test_room.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: matrix-python
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.5a0
|
|
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>
|
|
@@ -684,18 +684,18 @@ Project-URL: Source, https://github.com/Code-Society-Lab/matrixpy
|
|
|
684
684
|
Project-URL: Issues, https://github.com/Code-Society-Lab/matrixpy/issues
|
|
685
685
|
Requires-Python: >=3.10
|
|
686
686
|
Description-Content-Type: text/markdown
|
|
687
|
-
Requires-Dist: matrix-nio
|
|
687
|
+
Requires-Dist: matrix-nio==0.25.2
|
|
688
688
|
Requires-Dist: logger
|
|
689
|
-
Requires-Dist: PyYAML
|
|
690
|
-
Requires-Dist: markdown
|
|
691
|
-
Requires-Dist: APScheduler
|
|
689
|
+
Requires-Dist: PyYAML==6.0.3
|
|
690
|
+
Requires-Dist: markdown==3.10.2
|
|
691
|
+
Requires-Dist: APScheduler==3.11.2
|
|
692
692
|
Provides-Extra: dev
|
|
693
|
-
Requires-Dist: pytest; extra == "dev"
|
|
694
|
-
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
695
|
-
Requires-Dist: black; extra == "dev"
|
|
696
|
-
Requires-Dist: mypy; extra == "dev"
|
|
697
|
-
Requires-Dist: types-PyYAML; extra == "dev"
|
|
698
|
-
Requires-Dist: types-Markdown; extra == "dev"
|
|
693
|
+
Requires-Dist: pytest==9.0.3; extra == "dev"
|
|
694
|
+
Requires-Dist: pytest-asyncio==1.3.0; extra == "dev"
|
|
695
|
+
Requires-Dist: black==26.3.1; extra == "dev"
|
|
696
|
+
Requires-Dist: mypy==1.20.0; extra == "dev"
|
|
697
|
+
Requires-Dist: types-PyYAML==6.0.12.20260408; extra == "dev"
|
|
698
|
+
Requires-Dist: types-Markdown==3.10.2.20260408; extra == "dev"
|
|
699
699
|
|
|
700
700
|
<div align="center">
|
|
701
701
|
<em>A simple, developer-friendly library to create powerful <a href="https://matrix.org">Matrix</a> bots.</em>
|
|
@@ -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.5a0'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 4, 5, 'a0')
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g1174e983d'
|
|
@@ -3,7 +3,7 @@ import inspect
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import logging
|
|
5
5
|
|
|
6
|
-
from typing import
|
|
6
|
+
from typing import Optional, Any
|
|
7
7
|
|
|
8
8
|
from nio import AsyncClient, Event, MatrixRoom
|
|
9
9
|
|
|
@@ -15,7 +15,12 @@ from .extension import Extension
|
|
|
15
15
|
from .registry import Registry
|
|
16
16
|
from .help import HelpCommand, DefaultHelpCommand
|
|
17
17
|
from .scheduler import Scheduler
|
|
18
|
-
from .errors import
|
|
18
|
+
from .errors import (
|
|
19
|
+
AlreadyRegisteredError,
|
|
20
|
+
CommandNotFoundError,
|
|
21
|
+
CheckError,
|
|
22
|
+
RoomNotFoundError,
|
|
23
|
+
)
|
|
19
24
|
|
|
20
25
|
|
|
21
26
|
class Bot(Registry):
|
|
@@ -36,7 +41,9 @@ class Bot(Registry):
|
|
|
36
41
|
|
|
37
42
|
self._config: Config | None = None
|
|
38
43
|
self._client: AsyncClient | None = None
|
|
44
|
+
self._synced: asyncio.Event = asyncio.Event()
|
|
39
45
|
self._help: HelpCommand | None = help_
|
|
46
|
+
|
|
40
47
|
self.extensions: dict[str, Extension] = {}
|
|
41
48
|
self.scheduler: Scheduler = Scheduler()
|
|
42
49
|
self.log: logging.Logger = logging.getLogger(__name__)
|
|
@@ -75,10 +82,23 @@ class Bot(Registry):
|
|
|
75
82
|
except ValueError:
|
|
76
83
|
continue
|
|
77
84
|
|
|
78
|
-
def get_room(self, room_id: str) -> Room:
|
|
79
|
-
"""Retrieve a Room instance
|
|
80
|
-
|
|
81
|
-
|
|
85
|
+
def get_room(self, room_id: str) -> Room | None:
|
|
86
|
+
"""Retrieve a `Room` instance by its Matrix room ID.
|
|
87
|
+
|
|
88
|
+
Returns the `Room` object corresponding to `room_id` if it exists in
|
|
89
|
+
the client's known rooms. Returns `None` if the room cannot be found.
|
|
90
|
+
|
|
91
|
+
## Example
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
room = bot.get_room("!abc123:matrix.org")
|
|
95
|
+
if room:
|
|
96
|
+
print(room.name)
|
|
97
|
+
```
|
|
98
|
+
"""
|
|
99
|
+
if matrix_room := self.client.rooms.get(room_id):
|
|
100
|
+
return Room(matrix_room=matrix_room, client=self.client)
|
|
101
|
+
return None
|
|
82
102
|
|
|
83
103
|
def load_extension(self, extension: Extension) -> None:
|
|
84
104
|
self.log.debug(f"Loading extension: '{extension.name}'")
|
|
@@ -255,10 +275,16 @@ class Bot(Registry):
|
|
|
255
275
|
login_resp = await self.client.login(self.config.password)
|
|
256
276
|
self.log.info("logged in: %s", login_resp)
|
|
257
277
|
|
|
258
|
-
self.
|
|
278
|
+
sync_task = asyncio.create_task(self.client.sync_forever(timeout=30_000))
|
|
259
279
|
|
|
280
|
+
await self._wait_until_synced()
|
|
260
281
|
await self._on_ready()
|
|
261
|
-
|
|
282
|
+
|
|
283
|
+
self.scheduler.start()
|
|
284
|
+
await sync_task
|
|
285
|
+
|
|
286
|
+
async def _wait_until_synced(self) -> None:
|
|
287
|
+
await self._synced.wait()
|
|
262
288
|
|
|
263
289
|
# MATRIX EVENTS
|
|
264
290
|
|
|
@@ -266,6 +292,9 @@ class Bot(Registry):
|
|
|
266
292
|
await self._process_commands(room, event)
|
|
267
293
|
|
|
268
294
|
async def _on_matrix_event(self, matrix_room: MatrixRoom, event: Event) -> None:
|
|
295
|
+
if not self._synced.is_set():
|
|
296
|
+
self._synced.set()
|
|
297
|
+
|
|
269
298
|
# ignore bot events
|
|
270
299
|
if event.sender == self.client.user:
|
|
271
300
|
return
|
|
@@ -276,6 +305,10 @@ class Bot(Registry):
|
|
|
276
305
|
|
|
277
306
|
try:
|
|
278
307
|
room = self.get_room(matrix_room.room_id)
|
|
308
|
+
|
|
309
|
+
if not room:
|
|
310
|
+
raise RoomNotFoundError(f"Room '{matrix_room.room_id}' not found.")
|
|
311
|
+
|
|
279
312
|
await self._dispatch_matrix_event(room, event)
|
|
280
313
|
except Exception as error:
|
|
281
314
|
await self._on_error(error)
|
|
@@ -306,6 +339,10 @@ class Bot(Registry):
|
|
|
306
339
|
|
|
307
340
|
async def _build_context(self, matrix_room: Room, event: Event) -> Context:
|
|
308
341
|
room = self.get_room(matrix_room.room_id)
|
|
342
|
+
|
|
343
|
+
if not room:
|
|
344
|
+
raise RoomNotFoundError(f"Room '{matrix_room.room_id}' not found.")
|
|
345
|
+
|
|
309
346
|
ctx = Context(bot=self, room=room, event=event)
|
|
310
347
|
prefix = self.prefix or self.config.prefix
|
|
311
348
|
|
|
@@ -17,7 +17,20 @@ class Extension(Registry):
|
|
|
17
17
|
self._on_load: Optional[Callable] = None
|
|
18
18
|
self._on_unload: Optional[Callable] = None
|
|
19
19
|
|
|
20
|
-
def get_room(self, room_id: str) -> Room:
|
|
20
|
+
def get_room(self, room_id: str) -> Room | None:
|
|
21
|
+
"""Retrieve a `Room` instance by its Matrix room ID.
|
|
22
|
+
|
|
23
|
+
Returns the `Room` object corresponding to `room_id` if it exists in
|
|
24
|
+
the client's known rooms. Returns `None` if the room cannot be found.
|
|
25
|
+
|
|
26
|
+
## Example
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
room = extension.get_room("!abc123:matrix.org")
|
|
30
|
+
if room:
|
|
31
|
+
print(room.name)
|
|
32
|
+
```
|
|
33
|
+
"""
|
|
21
34
|
if self.bot is None:
|
|
22
35
|
raise RuntimeError("Extension is not loaded")
|
|
23
36
|
return self.bot.get_room(room_id)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: matrix-python
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.5a0
|
|
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>
|
|
@@ -684,18 +684,18 @@ Project-URL: Source, https://github.com/Code-Society-Lab/matrixpy
|
|
|
684
684
|
Project-URL: Issues, https://github.com/Code-Society-Lab/matrixpy/issues
|
|
685
685
|
Requires-Python: >=3.10
|
|
686
686
|
Description-Content-Type: text/markdown
|
|
687
|
-
Requires-Dist: matrix-nio
|
|
687
|
+
Requires-Dist: matrix-nio==0.25.2
|
|
688
688
|
Requires-Dist: logger
|
|
689
|
-
Requires-Dist: PyYAML
|
|
690
|
-
Requires-Dist: markdown
|
|
691
|
-
Requires-Dist: APScheduler
|
|
689
|
+
Requires-Dist: PyYAML==6.0.3
|
|
690
|
+
Requires-Dist: markdown==3.10.2
|
|
691
|
+
Requires-Dist: APScheduler==3.11.2
|
|
692
692
|
Provides-Extra: dev
|
|
693
|
-
Requires-Dist: pytest; extra == "dev"
|
|
694
|
-
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
695
|
-
Requires-Dist: black; extra == "dev"
|
|
696
|
-
Requires-Dist: mypy; extra == "dev"
|
|
697
|
-
Requires-Dist: types-PyYAML; extra == "dev"
|
|
698
|
-
Requires-Dist: types-Markdown; extra == "dev"
|
|
693
|
+
Requires-Dist: pytest==9.0.3; extra == "dev"
|
|
694
|
+
Requires-Dist: pytest-asyncio==1.3.0; extra == "dev"
|
|
695
|
+
Requires-Dist: black==26.3.1; extra == "dev"
|
|
696
|
+
Requires-Dist: mypy==1.20.0; extra == "dev"
|
|
697
|
+
Requires-Dist: types-PyYAML==6.0.12.20260408; extra == "dev"
|
|
698
|
+
Requires-Dist: types-Markdown==3.10.2.20260408; extra == "dev"
|
|
699
699
|
|
|
700
700
|
<div align="center">
|
|
701
701
|
<em>A simple, developer-friendly library to create powerful <a href="https://matrix.org">Matrix</a> bots.</em>
|
|
@@ -5,33 +5,33 @@ requires = ["setuptools>=64", "setuptools_scm>=8"]
|
|
|
5
5
|
name = "matrix-python"
|
|
6
6
|
dynamic = ["version"]
|
|
7
7
|
authors = [
|
|
8
|
-
{ name="Simon Roy" },
|
|
9
|
-
{ name=" Chris Dedman Rollet " }
|
|
8
|
+
{ name = "Simon Roy" },
|
|
9
|
+
{ name = " Chris Dedman Rollet " }
|
|
10
10
|
]
|
|
11
11
|
maintainers = [
|
|
12
|
-
{ name="Code Society Lab", email="admin@codesociety.xyz" }
|
|
12
|
+
{ name = "Code Society Lab", email = "admin@codesociety.xyz" }
|
|
13
13
|
]
|
|
14
14
|
description = "An easy-to-use Matrix bot framework designed for quick development and minimal setup"
|
|
15
15
|
readme = "README.md"
|
|
16
|
-
license = { file="LICENSE" }
|
|
16
|
+
license = { file = "LICENSE" }
|
|
17
17
|
requires-python = ">=3.10"
|
|
18
18
|
|
|
19
19
|
dependencies = [
|
|
20
|
-
"matrix-nio",
|
|
20
|
+
"matrix-nio==0.25.2",
|
|
21
21
|
"logger",
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
"PyYAML==6.0.3",
|
|
23
|
+
"markdown==3.10.2",
|
|
24
|
+
"APScheduler==3.11.2",
|
|
25
25
|
]
|
|
26
26
|
|
|
27
27
|
[project.optional-dependencies]
|
|
28
28
|
dev = [
|
|
29
|
-
"pytest",
|
|
30
|
-
"pytest-asyncio",
|
|
31
|
-
"black",
|
|
32
|
-
"mypy",
|
|
33
|
-
"types-PyYAML",
|
|
34
|
-
|
|
29
|
+
"pytest==9.0.3",
|
|
30
|
+
"pytest-asyncio==1.3.0",
|
|
31
|
+
"black==26.3.1",
|
|
32
|
+
"mypy==1.20.0",
|
|
33
|
+
"types-PyYAML==6.0.12.20260408",
|
|
34
|
+
"types-Markdown==3.10.2.20260408",
|
|
35
35
|
]
|
|
36
36
|
|
|
37
37
|
[project.urls]
|
|
@@ -313,6 +313,30 @@ async def test_command_executes(bot):
|
|
|
313
313
|
assert called, "Expected command handler to be called"
|
|
314
314
|
|
|
315
315
|
|
|
316
|
+
@pytest.mark.asyncio
|
|
317
|
+
async def test_command_not_processed_without_prefix(bot, room):
|
|
318
|
+
called = False
|
|
319
|
+
|
|
320
|
+
@bot.command()
|
|
321
|
+
async def greet(ctx):
|
|
322
|
+
nonlocal called
|
|
323
|
+
called = True
|
|
324
|
+
|
|
325
|
+
event = RoomMessageText.from_dict(
|
|
326
|
+
{
|
|
327
|
+
"content": {"body": "greet", "msgtype": "m.text"},
|
|
328
|
+
"event_id": "$id",
|
|
329
|
+
"origin_server_ts": 123456,
|
|
330
|
+
"sender": "@user:matrix.org",
|
|
331
|
+
"type": "m.room.message",
|
|
332
|
+
}
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
await bot._process_commands(room, event)
|
|
336
|
+
|
|
337
|
+
assert not called
|
|
338
|
+
|
|
339
|
+
|
|
316
340
|
@pytest.mark.asyncio
|
|
317
341
|
async def test_error_decorator_requires_coroutine(bot):
|
|
318
342
|
with pytest.raises(TypeError):
|
|
@@ -376,18 +400,37 @@ def test_command_duplicate_raises(bot):
|
|
|
376
400
|
pass
|
|
377
401
|
|
|
378
402
|
|
|
403
|
+
import asyncio
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
async def start_and_stop(coro):
|
|
407
|
+
task = asyncio.create_task(coro)
|
|
408
|
+
await asyncio.sleep(0) # allow startup
|
|
409
|
+
task.cancel()
|
|
410
|
+
await asyncio.gather(task, return_exceptions=True)
|
|
411
|
+
|
|
412
|
+
|
|
379
413
|
@pytest.mark.asyncio
|
|
380
414
|
async def test_run_uses_token():
|
|
381
415
|
bot = Bot()
|
|
382
416
|
bot._load_config("tests/config_fixture_token.yaml")
|
|
383
417
|
|
|
384
418
|
bot._client.sync_forever = AsyncMock()
|
|
385
|
-
bot.
|
|
419
|
+
bot._on_ready = AsyncMock()
|
|
420
|
+
|
|
421
|
+
# unblock readiness
|
|
422
|
+
bot._synced.set()
|
|
423
|
+
|
|
424
|
+
task = asyncio.create_task(bot.run())
|
|
425
|
+
|
|
426
|
+
await asyncio.sleep(0)
|
|
427
|
+
await asyncio.sleep(0)
|
|
386
428
|
|
|
387
|
-
|
|
429
|
+
task.cancel()
|
|
430
|
+
await asyncio.gather(task, return_exceptions=True)
|
|
388
431
|
|
|
389
432
|
assert bot._client.access_token == "abc123"
|
|
390
|
-
bot.
|
|
433
|
+
bot._on_ready.assert_awaited_once()
|
|
391
434
|
bot._client.sync_forever.assert_awaited_once()
|
|
392
435
|
|
|
393
436
|
|
|
@@ -397,7 +440,15 @@ async def test_run_with_username_and_password(bot):
|
|
|
397
440
|
bot._client.sync_forever = AsyncMock()
|
|
398
441
|
bot._on_ready = AsyncMock()
|
|
399
442
|
|
|
400
|
-
|
|
443
|
+
bot._synced.set()
|
|
444
|
+
|
|
445
|
+
task = asyncio.create_task(bot.run())
|
|
446
|
+
|
|
447
|
+
await asyncio.sleep(0)
|
|
448
|
+
await asyncio.sleep(0)
|
|
449
|
+
|
|
450
|
+
task.cancel()
|
|
451
|
+
await asyncio.gather(task, return_exceptions=True)
|
|
401
452
|
|
|
402
453
|
bot._client.login.assert_awaited_once_with("grace1234")
|
|
403
454
|
bot._on_ready.assert_awaited_once()
|
|
@@ -418,6 +469,39 @@ def test_start_handles_keyboard_interrupt(caplog):
|
|
|
418
469
|
bot._client.close.assert_awaited_once()
|
|
419
470
|
|
|
420
471
|
|
|
472
|
+
@pytest.mark.asyncio
|
|
473
|
+
async def test_on_ready_called_only_once(bot):
|
|
474
|
+
# Prepare
|
|
475
|
+
bot._synced.set()
|
|
476
|
+
bot._on_ready = AsyncMock()
|
|
477
|
+
|
|
478
|
+
# Simulate run
|
|
479
|
+
await bot._wait_until_synced()
|
|
480
|
+
await bot._on_ready()
|
|
481
|
+
|
|
482
|
+
bot._on_ready.assert_awaited_once()
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
@pytest.mark.asyncio
|
|
486
|
+
async def test_scheduler_starts_after_ready(bot):
|
|
487
|
+
bot._synced.set()
|
|
488
|
+
|
|
489
|
+
order = []
|
|
490
|
+
|
|
491
|
+
async def ready():
|
|
492
|
+
order.append("ready")
|
|
493
|
+
|
|
494
|
+
bot._on_ready = AsyncMock(side_effect=ready)
|
|
495
|
+
bot.scheduler.start = MagicMock(side_effect=lambda: order.append("scheduler"))
|
|
496
|
+
|
|
497
|
+
# Simulate run
|
|
498
|
+
await bot._wait_until_synced()
|
|
499
|
+
await bot._on_ready()
|
|
500
|
+
bot.scheduler.start()
|
|
501
|
+
|
|
502
|
+
assert order == ["ready", "scheduler"]
|
|
503
|
+
|
|
504
|
+
|
|
421
505
|
@pytest.mark.asyncio
|
|
422
506
|
async def test_scheduled_task_in_scheduler(bot):
|
|
423
507
|
@bot.schedule("* * * * *")
|
|
@@ -743,3 +827,25 @@ def test_unload_extension_logs_unloading(bot: Bot, loaded_extension: Extension):
|
|
|
743
827
|
bot.unload_extension(loaded_extension.name)
|
|
744
828
|
|
|
745
829
|
bot.log.debug.assert_any_call("unloaded extension '%s'", loaded_extension.name)
|
|
830
|
+
|
|
831
|
+
|
|
832
|
+
def test_unload_extension_removes_only_its_jobs(bot: Bot):
|
|
833
|
+
ext_a = Extension(name="a")
|
|
834
|
+
ext_b = Extension(name="b")
|
|
835
|
+
|
|
836
|
+
@ext_a.schedule("* * * * *")
|
|
837
|
+
async def task():
|
|
838
|
+
pass
|
|
839
|
+
|
|
840
|
+
@ext_b.schedule("* * * * *")
|
|
841
|
+
async def task():
|
|
842
|
+
pass
|
|
843
|
+
|
|
844
|
+
bot.load_extension(ext_a)
|
|
845
|
+
bot.load_extension(ext_b)
|
|
846
|
+
|
|
847
|
+
bot.unload_extension("a")
|
|
848
|
+
|
|
849
|
+
job_names = [j.name for j in bot.scheduler.jobs]
|
|
850
|
+
|
|
851
|
+
assert "task" in job_names
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|