def load_config(course_dir: Path) -> MograderConfig:
"""Load ``mograder.toml`` from *course_dir*. Returns defaults if missing."""
config_path = course_dir / "mograder.toml"
if not config_path.is_file():
return DEFAULT_CONFIG
with open(config_path, "rb") as f:
data = tomllib.load(f)
moodle = data.get("moodle", {})
https = data.get("https", {})
defaults = data.get("defaults", {})
dirs = data.get("dirs", {})
gradebook = data.get("gradebook", {})
rlimits = data.get("rlimits", {})
sync = data.get("sync", {})
edit_links_data = data.get("edit_links", {})
penalties = data.get("penalties", {})
hub = data.get("hub", {})
# [[assignments]] with fallback to [[moodle.assignments]]
top_assignments = tuple(data.get("assignments", []))
moodle_assignments = tuple(moodle.get("assignments", []))
assignments = top_assignments if top_assignments else moodle_assignments
return MograderConfig(
title=data.get("title"),
transport=data.get("transport", "moodle"),
config_url=data.get("config_url"),
assignments=assignments,
moodle_csv=moodle.get("csv"),
moodle_match_column=moodle.get("match_column", "Username"),
moodle_name_column=moodle.get("name_column", "Full name"),
moodle_url=moodle.get("url"),
moodle_course_id=moodle.get("course_id"),
moodle_assignments=moodle_assignments,
https_url=https.get("url"),
https_token=https.get("token"),
jobs=defaults.get("jobs", 4),
timeout=defaults.get("timeout", 300),
no_edit=defaults.get("no_edit", False),
no_actions=defaults.get("no_actions", False),
headless_edit=defaults.get("headless_edit", False),
rlimit_cpu=rlimits.get("cpu", 600),
rlimit_nproc=rlimits.get("nproc", 512),
rlimit_nofile=rlimits.get("nofile", 256),
rlimit_as=rlimits.get("as", 1 << 30),
use_bubblewrap=data.get("security", {}).get("use_bubblewrap", False),
source_dir=dirs.get("source", "source"),
release_dir=dirs.get("release", "release"),
submitted_dir=dirs.get("submitted", "submitted"),
autograded_dir=dirs.get("autograded", "autograded"),
feedback_dir=dirs.get("feedback", "feedback"),
import_dir=dirs.get("import", "import"),
gradebook=gradebook.get("path", "gradebook.db"),
sync_remote=sync.get("remote"),
sync_remote_course_dir=sync.get("remote_course_dir"),
sync_remote_venv_dir=sync.get("remote_venv_dir"),
penalty_enabled=penalties.get("enabled", False),
penalty_grace_minutes=penalties.get("grace_minutes", 5),
penalty_per_day=penalties.get("per_day", 5.0),
penalty_max=penalties.get("max", 100.0),
edit_links=tuple((k, v) for k, v in edit_links_data.items()),
hub_port=hub.get("port", 8080),
hub_notebooks_dir=hub.get("notebooks_dir", "hub-notebooks"),
hub_release_dir=hub.get("release_dir", "hub-release"),
hub_session_ttl=hub.get("session_ttl", 3600),
hub_trusted_header=hub.get("trusted_header", "X-Remote-User"),
hub_uv_cache_dir=hub.get("uv_cache_dir", ""),
)