feat: paste detailed help via FlaskPaste for !help command
!help <cmd> now pastes the command's docstring and appends the URL. !help <plugin> pastes detail for all plugin commands. !help (no args) pastes a full reference grouped by plugin. Falls back gracefully when flaskpaste is not loaded or paste fails. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,8 @@
|
||||
import asyncio
|
||||
import importlib.util
|
||||
import sys
|
||||
import types
|
||||
from dataclasses import dataclass
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
# -- Load plugin module directly ---------------------------------------------
|
||||
@@ -16,9 +18,22 @@ _spec.loader.exec_module(_mod)
|
||||
# -- Fakes -------------------------------------------------------------------
|
||||
|
||||
|
||||
@dataclass
|
||||
class _FakeHandler:
|
||||
name: str
|
||||
callback: object
|
||||
help: str = ""
|
||||
plugin: str = ""
|
||||
admin: bool = False
|
||||
tier: str = "user"
|
||||
|
||||
|
||||
class _FakeRegistry:
|
||||
def __init__(self):
|
||||
self._bots: dict = {}
|
||||
self.commands: dict = {}
|
||||
self._modules: dict = {}
|
||||
self.events: dict = {}
|
||||
|
||||
|
||||
class _FakeBot:
|
||||
@@ -26,10 +41,14 @@ class _FakeBot:
|
||||
self.replied: list[str] = []
|
||||
self.registry = _FakeRegistry()
|
||||
self.nick = "derp"
|
||||
self.prefix = "!"
|
||||
self._receive_sound = False
|
||||
if mumble:
|
||||
self._mumble = MagicMock()
|
||||
|
||||
def _plugin_allowed(self, plugin: str, channel) -> bool:
|
||||
return True
|
||||
|
||||
async def reply(self, message, text: str) -> None:
|
||||
self.replied.append(text)
|
||||
|
||||
@@ -90,3 +109,121 @@ class TestDeafCommand:
|
||||
msg = _Msg(text="!deaf")
|
||||
asyncio.run(_mod.cmd_deaf(bot, msg))
|
||||
bot._mumble.users.myself.deafen.assert_called_once()
|
||||
|
||||
|
||||
# -- Help command tests ------------------------------------------------------
|
||||
|
||||
|
||||
def _cmd_with_doc():
|
||||
"""Manage widgets.
|
||||
|
||||
Usage:
|
||||
!widget add <name>
|
||||
!widget del <name>
|
||||
|
||||
Examples:
|
||||
!widget add foo
|
||||
"""
|
||||
|
||||
|
||||
def _cmd_no_doc():
|
||||
pass
|
||||
|
||||
|
||||
def _make_fp_module(url="https://paste.example.com/abc/raw"):
|
||||
"""Create a fake flaskpaste module that returns a fixed URL."""
|
||||
mod = types.ModuleType("flaskpaste")
|
||||
mod.create_paste = lambda bot, text: url
|
||||
return mod
|
||||
|
||||
|
||||
class TestHelpCommand:
|
||||
def test_help_cmd_with_paste(self):
|
||||
"""!help <cmd> with docstring pastes detail, appends URL."""
|
||||
bot = _FakeBot()
|
||||
handler = _FakeHandler(
|
||||
name="widget", callback=_cmd_with_doc,
|
||||
help="Manage widgets", plugin="widgets",
|
||||
)
|
||||
bot.registry.commands["widget"] = handler
|
||||
bot.registry._modules["flaskpaste"] = _make_fp_module()
|
||||
msg = _Msg(text="!help widget")
|
||||
asyncio.run(_mod.cmd_help(bot, msg))
|
||||
assert len(bot.replied) == 1
|
||||
assert "!widget -- Manage widgets" in bot.replied[0]
|
||||
assert "https://paste.example.com/abc/raw" in bot.replied[0]
|
||||
|
||||
def test_help_cmd_no_docstring(self):
|
||||
"""!help <cmd> without docstring skips paste."""
|
||||
bot = _FakeBot()
|
||||
handler = _FakeHandler(
|
||||
name="noop", callback=_cmd_no_doc,
|
||||
help="Does nothing", plugin="misc",
|
||||
)
|
||||
bot.registry.commands["noop"] = handler
|
||||
bot.registry._modules["flaskpaste"] = _make_fp_module()
|
||||
msg = _Msg(text="!help noop")
|
||||
asyncio.run(_mod.cmd_help(bot, msg))
|
||||
assert len(bot.replied) == 1
|
||||
assert "!noop -- Does nothing" in bot.replied[0]
|
||||
assert "paste.example.com" not in bot.replied[0]
|
||||
|
||||
def test_help_plugin_with_paste(self):
|
||||
"""!help <plugin> pastes detail for all plugin commands."""
|
||||
bot = _FakeBot()
|
||||
mod = types.ModuleType("widgets")
|
||||
mod.__doc__ = "Widget management plugin."
|
||||
bot.registry._modules["widgets"] = mod
|
||||
bot.registry._modules["flaskpaste"] = _make_fp_module()
|
||||
bot.registry.commands["widget"] = _FakeHandler(
|
||||
name="widget", callback=_cmd_with_doc,
|
||||
help="Manage widgets", plugin="widgets",
|
||||
)
|
||||
bot.registry.commands["wstat"] = _FakeHandler(
|
||||
name="wstat", callback=_cmd_no_doc,
|
||||
help="Widget stats", plugin="widgets",
|
||||
)
|
||||
msg = _Msg(text="!help widgets")
|
||||
asyncio.run(_mod.cmd_help(bot, msg))
|
||||
assert len(bot.replied) == 1
|
||||
reply = bot.replied[0]
|
||||
assert "widgets -- Widget management plugin." in reply
|
||||
assert "!widget, !wstat" in reply
|
||||
# Only widget has a docstring, so paste should still happen
|
||||
assert "https://paste.example.com/abc/raw" in reply
|
||||
|
||||
def test_help_list_with_paste(self):
|
||||
"""!help (no args) pastes full reference."""
|
||||
bot = _FakeBot()
|
||||
bot.registry._modules["flaskpaste"] = _make_fp_module()
|
||||
mod = types.ModuleType("core")
|
||||
mod.__doc__ = "Core plugin."
|
||||
bot.registry._modules["core"] = mod
|
||||
bot.registry.commands["ping"] = _FakeHandler(
|
||||
name="ping", callback=_cmd_with_doc,
|
||||
help="Check alive", plugin="core",
|
||||
)
|
||||
bot.registry.commands["help"] = _FakeHandler(
|
||||
name="help", callback=_cmd_no_doc,
|
||||
help="Show help", plugin="core",
|
||||
)
|
||||
msg = _Msg(text="!help")
|
||||
asyncio.run(_mod.cmd_help(bot, msg))
|
||||
assert len(bot.replied) == 1
|
||||
assert "help, ping" in bot.replied[0]
|
||||
assert "https://paste.example.com/abc/raw" in bot.replied[0]
|
||||
|
||||
def test_help_no_flaskpaste(self):
|
||||
"""Without flaskpaste loaded, help still works (no URL)."""
|
||||
bot = _FakeBot()
|
||||
handler = _FakeHandler(
|
||||
name="widget", callback=_cmd_with_doc,
|
||||
help="Manage widgets", plugin="widgets",
|
||||
)
|
||||
bot.registry.commands["widget"] = handler
|
||||
# No flaskpaste in _modules
|
||||
msg = _Msg(text="!help widget")
|
||||
asyncio.run(_mod.cmd_help(bot, msg))
|
||||
assert len(bot.replied) == 1
|
||||
assert "!widget -- Manage widgets" in bot.replied[0]
|
||||
assert "https://" not in bot.replied[0]
|
||||
|
||||
Reference in New Issue
Block a user