Skill Tracer
Skills › Scientific Agent Skills › clinical-reports › generate_report_template.py

generate_report_template.py

115 lines · skills/clinical-reports/scripts/generate_report_template.py at 5f2bc03

1#!/usr/bin/env python3
2"""Copy a fail-closed structured clinical-report template to a local path."""
3
4from __future__ import annotations
5
6import argparse
7import sys
8from pathlib import Path
9
10sys.dont_write_bytecode = True
12from _common import ( # noqa: E402
13 ValidationError,
14 load_json_object,
15 local_input_path,
16 local_output_path,
19TOOL = "generate_report_template"
20TEMPLATES = {
21 "case-report": "case_report_template.json",
22 "radiology-scaffold": "radiology_report_template.json",
23 "pathology-scaffold": "pathology_report_template.json",
24 "lab-scaffold": "lab_report_template.json",
25 "csr": "clinical_trial_csr_template.json",
26 "trial-results": "clinical_trial_results_template.json",
27 "trial-protocol-checklist": "trial_protocol_reporting_checklist.json",
28 "safety-aggregate": "clinical_trial_safety_aggregate_template.json",
29 "adverse-event-csv": "adverse_event_aggregate_input_template.csv",
30 "research-summary": "research_summary_template.json",
31 "deidentification-checklist": "deidentification_process_checklist.json",
32 "quality-review": "quality_review_checklist.json",
33 "provenance": "provenance_manifest_template.json",
34 "terminology": "terminology_manifest_template.json",
35 "consistency": "consistency_manifest_template.json",
39def template_directory() -> Path:
40 """Return the fixed bundled asset directory."""
41 return Path(__file__).resolve().parent.parent / "assets"
44def list_templates() -> str:
45 """Return a stable machine-readable-friendly list."""
46 lines = ["Available fail-closed templates:"]
47 lines.extend(f"- {name}: {TEMPLATES[name]}" for name in sorted(TEMPLATES))
48 return "\n".join(lines) + "\n"
51def generate_template(
52 template_type: str,
53 raw_output: str,
54 *,
55 overwrite: bool = False,
56) -> Path:
57 """Copy one fixed asset without interpolation or clinical content."""
58 if template_type not in TEMPLATES:
59 raise ValidationError(f"unknown template type: {template_type}")
60 source = template_directory() / TEMPLATES[template_type]
61 suffix = source.suffix.lower()
62 validated_source = local_input_path(
63 str(source),
64 suffixes={suffix},
65 max_bytes=1_000_000,
66 )
67 if suffix == ".json":
68 load_json_object(str(validated_source))
69 output = local_output_path(
70 raw_output,
71 suffixes={suffix},
72 overwrite=overwrite,
73 )
74 output.write_bytes(validated_source.read_bytes())
75 return output
78def build_parser() -> argparse.ArgumentParser:
79 parser = argparse.ArgumentParser(
80 description=(
81 "Copy a bundled fail-closed JSON/CSV template. No interpolation, "
82 "network access, clinical inference, signing, filing, or submission."
83 )
84 )
85 mode = parser.add_mutually_exclusive_group(required=True)
86 mode.add_argument("--list", action="store_true", help="List template types")
87 mode.add_argument("--type", choices=sorted(TEMPLATES), help="Template type")
88 parser.add_argument("-o", "--output", help="Required local output when --type is used")
89 parser.add_argument("--overwrite", action="store_true")
90 return parser
93def main(argv: list[str] | None = None) -> int:
94 args = build_parser().parse_args(argv)
95 if args.list:
96 if args.output:
97 print("--output is not used with --list", file=sys.stderr)
98 return 2
99 print(list_templates(), end="")
100 return 0
101 if not args.output:
102 print("--output is required with --type", file=sys.stderr)
103 return 2
104 try:
105 output = generate_template(args.type, args.output, overwrite=args.overwrite)
106 print(f"Created blocked draft template: {output}")
107 print("Qualified review is required; this output is not for clinical use or submission.")
108 return 0
109 except (OSError, ValidationError) as exc:
110 print(f"{TOOL}: BLOCKED: {exc}", file=sys.stderr)
111 return 1
114if __name__ == "__main__":
115 raise SystemExit(main())