Add HelpTopic dataclass and TOML loader
This commit is contained in:
parent
5eb205e7bf
commit
b69c2e83d9
2 changed files with 119 additions and 0 deletions
|
|
@ -3,6 +3,7 @@
|
||||||
import importlib
|
import importlib
|
||||||
import logging
|
import logging
|
||||||
import tomllib
|
import tomllib
|
||||||
|
from dataclasses import dataclass
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import cast
|
from typing import cast
|
||||||
|
|
||||||
|
|
@ -139,3 +140,42 @@ def load_commands(directory: Path) -> list[CommandDefinition]:
|
||||||
log.warning("failed to load command from %s: %s", path, e)
|
log.warning("failed to load command from %s: %s", path, e)
|
||||||
|
|
||||||
return commands
|
return commands
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class HelpTopic:
|
||||||
|
"""A help topic loaded from a TOML file."""
|
||||||
|
|
||||||
|
name: str
|
||||||
|
body: str
|
||||||
|
title: str = ""
|
||||||
|
admin: bool = False
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
if not self.title:
|
||||||
|
self.title = self.name
|
||||||
|
|
||||||
|
|
||||||
|
def load_help_topic(path: Path) -> HelpTopic:
|
||||||
|
"""Load a single help topic from a TOML file."""
|
||||||
|
with open(path, "rb") as f:
|
||||||
|
data = tomllib.load(f)
|
||||||
|
|
||||||
|
return HelpTopic(
|
||||||
|
name=data["name"],
|
||||||
|
body=data["body"].strip(),
|
||||||
|
title=data.get("title", ""),
|
||||||
|
admin=data.get("admin", False),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def load_help_topics(directory: Path) -> dict[str, HelpTopic]:
|
||||||
|
"""Load all help topics from a directory of TOML files."""
|
||||||
|
topics: dict[str, HelpTopic] = {}
|
||||||
|
for path in directory.glob("*.toml"):
|
||||||
|
try:
|
||||||
|
topic = load_help_topic(path)
|
||||||
|
topics[topic.name] = topic
|
||||||
|
except Exception as e:
|
||||||
|
log.warning("failed to load help topic from %s: %s", path, e)
|
||||||
|
return topics
|
||||||
|
|
|
||||||
79
tests/test_help_topics.py
Normal file
79
tests/test_help_topics.py
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
"""Tests for TOML help topic loading."""
|
||||||
|
|
||||||
|
import textwrap
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from mudlib.content import load_help_topics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def help_dir(tmp_path):
|
||||||
|
"""Create a temp directory with sample help TOML files."""
|
||||||
|
topic = tmp_path / "combat.toml"
|
||||||
|
topic.write_text(
|
||||||
|
textwrap.dedent("""\
|
||||||
|
name = "combat"
|
||||||
|
title = "combat primer"
|
||||||
|
body = \"\"\"
|
||||||
|
combat is initiated when you attack another entity.
|
||||||
|
use skills to learn your available moves.
|
||||||
|
\"\"\"
|
||||||
|
""")
|
||||||
|
)
|
||||||
|
|
||||||
|
admin_topic = tmp_path / "building.toml"
|
||||||
|
admin_topic.write_text(
|
||||||
|
textwrap.dedent("""\
|
||||||
|
name = "building"
|
||||||
|
title = "builder's guide"
|
||||||
|
admin = true
|
||||||
|
body = \"\"\"
|
||||||
|
use @dig to create zones and @paint to edit terrain.
|
||||||
|
\"\"\"
|
||||||
|
""")
|
||||||
|
)
|
||||||
|
return tmp_path
|
||||||
|
|
||||||
|
|
||||||
|
def test_load_help_topics(help_dir):
|
||||||
|
topics = load_help_topics(help_dir)
|
||||||
|
assert "combat" in topics
|
||||||
|
assert "building" in topics
|
||||||
|
|
||||||
|
|
||||||
|
def test_help_topic_fields(help_dir):
|
||||||
|
topics = load_help_topics(help_dir)
|
||||||
|
combat = topics["combat"]
|
||||||
|
assert combat.name == "combat"
|
||||||
|
assert combat.title == "combat primer"
|
||||||
|
assert combat.admin is False
|
||||||
|
assert "combat is initiated" in combat.body
|
||||||
|
|
||||||
|
|
||||||
|
def test_help_topic_admin_flag(help_dir):
|
||||||
|
topics = load_help_topics(help_dir)
|
||||||
|
building = topics["building"]
|
||||||
|
assert building.admin is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_help_topic_title_defaults_to_name(tmp_path):
|
||||||
|
topic = tmp_path / "simple.toml"
|
||||||
|
topic.write_text('name = "simple"\nbody = "just a test"\n')
|
||||||
|
topics = load_help_topics(tmp_path)
|
||||||
|
assert topics["simple"].title == "simple"
|
||||||
|
|
||||||
|
|
||||||
|
def test_load_help_topics_empty_dir(tmp_path):
|
||||||
|
topics = load_help_topics(tmp_path)
|
||||||
|
assert topics == {}
|
||||||
|
|
||||||
|
|
||||||
|
def test_load_help_topics_skips_bad_files(tmp_path):
|
||||||
|
bad = tmp_path / "broken.toml"
|
||||||
|
bad.write_text("not valid toml [[[")
|
||||||
|
good = tmp_path / "good.toml"
|
||||||
|
good.write_text('name = "good"\nbody = "works"\n')
|
||||||
|
topics = load_help_topics(tmp_path)
|
||||||
|
assert "good" in topics
|
||||||
|
assert "broken" not in topics
|
||||||
Loading…
Reference in a new issue