Source code for psc_sim.user_presets
"""Named user-defined parameter presets persisted beside settings.json."""
from __future__ import annotations
import json
import re
import uuid
from dataclasses import dataclass
from pathlib import Path
from psc_sim.parameters import CellParameters
from psc_sim.settings import settings_path
from psc_sim.validation import params_from_dict, params_to_dict
[docs]
@dataclass
class UserPreset:
id: str
label: str
params: CellParameters
note: str = ""
def user_presets_path() -> Path:
return settings_path().parent / "user_presets.json"
def _slug_id(label: str) -> str:
base = re.sub(r"[^a-z0-9]+", "_", label.strip().lower()).strip("_")
return base or f"preset_{uuid.uuid4().hex[:8]}"
def load_user_presets() -> list[UserPreset]:
path = user_presets_path()
if not path.is_file():
return []
try:
raw = json.loads(path.read_text(encoding="utf-8"))
except (json.JSONDecodeError, OSError):
return []
if not isinstance(raw, list):
return []
out: list[UserPreset] = []
for item in raw:
if not isinstance(item, dict):
continue
pid = str(item.get("id", "")).strip()
label = str(item.get("label", "")).strip()
if not pid or not label:
continue
try:
params = params_from_dict(item["params"])
except (KeyError, TypeError, ValueError):
continue
note = str(item.get("note", ""))
out.append(UserPreset(id=pid, label=label, params=params, note=note))
return out
def save_user_presets(presets: list[UserPreset]) -> None:
path = user_presets_path()
path.parent.mkdir(parents=True, exist_ok=True)
payload = [
{
"id": p.id,
"label": p.label,
"note": p.note,
"params": params_to_dict(p.params),
}
for p in presets
]
path.write_text(json.dumps(payload, indent=2), encoding="utf-8")
def add_user_preset(
label: str,
params: CellParameters,
*,
note: str = "",
preset_id: str | None = None,
) -> UserPreset:
presets = load_user_presets()
pid = preset_id or _slug_id(label)
existing = {p.id for p in presets}
if pid in existing:
pid = f"{pid}_{uuid.uuid4().hex[:6]}"
entry = UserPreset(id=pid, label=label.strip(), params=params, note=note)
presets.append(entry)
save_user_presets(presets)
return entry
def rename_user_preset(preset_id: str, new_label: str) -> bool:
presets = load_user_presets()
label = new_label.strip()
if not label:
return False
for p in presets:
if p.id == preset_id:
p.label = label
save_user_presets(presets)
return True
return False
def delete_user_preset(preset_id: str) -> bool:
presets = load_user_presets()
new_list = [p for p in presets if p.id != preset_id]
if len(new_list) == len(presets):
return False
save_user_presets(new_list)
return True
def user_preset_by_id(preset_id: str) -> UserPreset:
for p in load_user_presets():
if p.id == preset_id:
return p
raise KeyError(preset_id)
def user_preset_item_data(preset_id: str) -> str:
return f"user:{preset_id}"