From 84b4e49c6aaf231580a9ba43e780a879591a7c0a Mon Sep 17 00:00:00 2001 From: Slipstream Date: Tue, 10 Jun 2025 15:37:33 -0600 Subject: [PATCH] Add extension reload helper (#9) * Add reload_extension helper * Removes unused message reaction event handling Eliminates dead code for message reaction events that were not being processed or utilized by the application. Cleans up the event dispatcher by removing the unused parser method and event mappings for reaction add/remove events. --- disagreement/event_dispatcher.py | 6 ------ disagreement/ext/loader.py | 13 ++++++++++++- docs/extension_loader.md | 15 +++++++++++++++ tests/test_extension_loader.py | 33 ++++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 docs/extension_loader.md diff --git a/disagreement/event_dispatcher.py b/disagreement/event_dispatcher.py index 7cd6c85..1a5dce6 100644 --- a/disagreement/event_dispatcher.py +++ b/disagreement/event_dispatcher.py @@ -56,8 +56,6 @@ class EventDispatcher: "CHANNEL_CREATE": self._parse_channel_create, "PRESENCE_UPDATE": self._parse_presence_update, "TYPING_START": self._parse_typing_start, - "MESSAGE_REACTION_ADD": self._parse_message_reaction, - "MESSAGE_REACTION_REMOVE": self._parse_message_reaction, } def _parse_message_create(self, data: Dict[str, Any]) -> Message: @@ -75,10 +73,6 @@ class EventDispatcher: self._client._messages.pop(message_id, None) return data - def _parse_message_reaction(self, data: Dict[str, Any]) -> Dict[str, Any]: - """Returns the raw reaction payload.""" - return data - def _parse_interaction_create(self, data: Dict[str, Any]) -> "Interaction": """Parses raw INTERACTION_CREATE data into an Interaction object.""" from .interactions import Interaction diff --git a/disagreement/ext/loader.py b/disagreement/ext/loader.py index 8e8d790..0f14402 100644 --- a/disagreement/ext/loader.py +++ b/disagreement/ext/loader.py @@ -5,7 +5,7 @@ import sys from types import ModuleType from typing import Dict -__all__ = ["load_extension", "unload_extension"] +__all__ = ["load_extension", "unload_extension", "reload_extension"] _loaded_extensions: Dict[str, ModuleType] = {} @@ -41,3 +41,14 @@ def unload_extension(name: str) -> None: module.teardown() sys.modules.pop(name, None) + + +def reload_extension(name: str) -> ModuleType: + """Reload an extension by name. + + This is a convenience wrapper around :func:`unload_extension` followed by + :func:`load_extension`. + """ + + unload_extension(name) + return load_extension(name) diff --git a/docs/extension_loader.md b/docs/extension_loader.md new file mode 100644 index 0000000..115aff9 --- /dev/null +++ b/docs/extension_loader.md @@ -0,0 +1,15 @@ +# Extension Loader + +The `disagreement.ext.loader` module provides simple helpers to manage optional +extensions. Extensions are regular Python modules that expose a `setup` function +called when the extension is loaded. + +```python +from disagreement.ext import loader +``` + +- `loader.load_extension(name)` – Import and initialize an extension. +- `loader.unload_extension(name)` – Tear down and remove a previously loaded + extension. +- `loader.reload_extension(name)` – Convenience wrapper that unloads then loads + the extension again. diff --git a/tests/test_extension_loader.py b/tests/test_extension_loader.py index 37f45f6..7531af1 100644 --- a/tests/test_extension_loader.py +++ b/tests/test_extension_loader.py @@ -42,3 +42,36 @@ def test_load_extension_twice_raises(): loader.load_extension("repeat_ext") loader.unload_extension("repeat_ext") assert called["teardown"] is True + + +def test_reload_extension(monkeypatch): + called_first = create_dummy_module("reload_ext") + loader.load_extension("reload_ext") + + called_second = {"setup": False, "teardown": False} + module_second = types.ModuleType("reload_ext") + + def setup_second(): + called_second["setup"] = True + + def teardown_second(): + called_second["teardown"] = True + + module_second.setup = setup_second + module_second.teardown = teardown_second + + def import_stub(name): + assert name == "reload_ext" + sys.modules[name] = module_second + return module_second + + monkeypatch.setattr(loader, "import_module", import_stub) + + loader.reload_extension("reload_ext") + + assert called_first["teardown"] is True + assert called_second["setup"] is True + assert loader._loaded_extensions["reload_ext"] is module_second + + loader.unload_extension("reload_ext") + assert called_second["teardown"] is True