platformdirs config path + tomlkit TOML config store: working versions (tested 2026-10-15)
Resolve a per-user config file with platformdirs, then read and write it with tomlkit while preserving comments, key order and native types.
passed6 passed · 0 failed2026-10-15 18:10 UTC- Status
- passed
- Last passed
- 2026-10-15 18:10 UTC
- Tests
- 6 / 6
- Language
- Python
- Runtime
- Python 3.13.16
pinned versions3
platformdirs@4.13.0tomlkit@0.15.1pytest@9.1.1
run it
uv venv -q .venv && uv pip install -q --python .venv/bin/python -r requirements.txt .venv/bin/python -m pytest -q
test environment
Python 3.13.16 linux 6.17.0-1022-azure x64 runner: github-actions 38783276983
The code
Exactly the files that passed. Your agent can pull them with get_recipe("platformdirs-toml-config-store") (install), or see them on GitHub.
requirements.txt
platformdirs==4.13.0 tomlkit==0.15.1 pytest==9.1.1
config_store.py
from __future__ import annotations
from pathlib import Path
import platformdirs
import tomlkit
class ConfigStore:
"""A TOML config that lives in the platform's per-user config directory."""
def __init__(
self,
appname: str = "provenpin",
filename: str = "config.toml",
path: Path | None = None,
):
self.path = (
Path(path) if path is not None else platformdirs.user_config_path(appname) / filename
)
self.path.parent.mkdir(parents=True, exist_ok=True)
def load(self) -> tomlkit.TOMLDocument:
if not self.path.exists():
return tomlkit.document()
return tomlkit.parse(self.path.read_text(encoding="utf-8"))
def save(self, doc: tomlkit.TOMLDocument) -> None:
# Write to a sibling first so a crash never leaves a half-written config.
tmp = self.path.with_name(f"{self.path.name}.tmp")
tmp.write_text(tomlkit.dumps(doc), encoding="utf-8")
tmp.replace(self.path)
def get(self, key: str, default=None):
node = self.load()
for part in key.split("."):
try:
node = node[part]
except (KeyError, TypeError):
return default
return node
def set(self, key: str, value) -> tomlkit.TOMLDocument:
doc = self.load()
*parents, leaf = key.split(".")
node = doc
for part in parents:
node = node.setdefault(part, tomlkit.table())
node[leaf] = value
self.save(doc)
return doc
tests/test_config_store.py
import sys
import pytest
from config_store import ConfigStore
def test_missing_file_loads_an_empty_document(tmp_path):
store = ConfigStore(path=tmp_path / "config.toml")
doc = store.load()
assert dict(doc) == {}
assert store.get("ui.theme", "system") == "system"
def test_set_then_get_round_trips_through_disk(tmp_path):
store = ConfigStore(path=tmp_path / "config.toml")
store.set("server.host", "localhost")
store.set("server.port", 8080)
reloaded = ConfigStore(path=tmp_path / "config.toml")
assert reloaded.get("server.host") == "localhost"
assert reloaded.get("server.port") == 8080
def test_set_preserves_comments_and_key_order(tmp_path):
path = tmp_path / "config.toml"
path.write_text(
"# hand edited, keep this comment\n[ui]\ntheme = 'light' # was dark\n",
encoding="utf-8",
)
store = ConfigStore(path=path)
store.set("ui.font_size", 13)
out = path.read_text(encoding="utf-8")
assert "# hand edited, keep this comment" in out
assert "theme = 'light' # was dark" in out
assert out.index("theme") < out.index("font_size")
def test_save_creates_missing_parent_directories(tmp_path):
path = tmp_path / "does" / "not" / "exist" / "config.toml"
assert not path.parent.exists()
ConfigStore(path=path).set("first_run", True)
assert path.read_text(encoding="utf-8").strip() == "first_run = true"
def test_non_string_values_round_trip(tmp_path):
store = ConfigStore(path=tmp_path / "config.toml")
store.set("limits.retries", 3)
store.set("limits.ratio", 0.5)
store.set("limits.enabled", True)
store.set("limits.hosts", ["alpha", "beta"])
fresh = ConfigStore(path=tmp_path / "config.toml")
assert fresh.get("limits.retries") == 3
assert fresh.get("limits.ratio") == 0.5
assert fresh.get("limits.enabled") is True
assert fresh.get("limits.hosts") == ["alpha", "beta"]
@pytest.mark.skipif(sys.platform != "linux", reason="XDG is a Linux convention")
def test_xdg_config_home_controls_the_default_location(monkeypatch, tmp_path):
monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path))
store = ConfigStore("provenpin")
assert store.path == tmp_path / "provenpin" / "config.toml"
pytest.ini
[pytest] pythonpath = .
Connect to ProvenPin
Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.
terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp
~/.cursor/mcp.json
{ "mcpServers": { "provenpin": { "url": "https://mcp.provenpin.com/mcp" } } }.vscode/mcp.json
{ "servers": { "provenpin": { "type": "http", "url": "https://mcp.provenpin.com/mcp" } } }~/.codeium/windsurf/mcp_config.json
{ "mcpServers": { "provenpin": { "serverUrl": "https://mcp.provenpin.com/mcp" } } }MCP settings
{ "mcpServers": { "provenpin": { "type": "streamableHttp", "url": "https://mcp.provenpin.com/mcp" } } }Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.