PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
 
Loading...
Searching...
No Matches
Functions | Variables
audit_starter_content Namespace Reference

Functions

subprocess.CompletedProcess[str] run_cli (list[str] args, Path cwd=REPO_ROOT)
 Run one CLI command used to validate a shipped starter artifact.
 
None fail (str context, subprocess.CompletedProcess[str] result)
 Raise a compact error that preserves the relevant CLI output.
 
None validate_bundle (dict[str, str] bundle, str label)
 Validate one declared case/solver/monitor/post or cluster/study composition.
 
Optional[str] _yaml_role (Path path)
 Classify a starter YAML by the same stable top-level shapes used by init.
 
None audit_template_copy (str template_name, Path temporary_root)
 Initialize one declared template and verify canonical relocation preserves its content.
 
int main ()
 Run the starter-content inventory, composition, and initializer audit.
 

Variables

 REPO_ROOT = Path(__file__).resolve().parents[2]
 
str CONTRACT_PATH = REPO_ROOT / "tests" / "tooling" / "starter_content_contract.json"
 
str PICURV = REPO_ROOT / "picurv_cli" / "picurv"
 
str RUNTIME_EXECUTION_EXAMPLE = "execution.example.yml"
 
 file
 

Detailed Description

Certify that shipped starter templates and reusable configuration profiles stay usable.

Function Documentation

◆ run_cli()

subprocess.CompletedProcess[str] audit_starter_content.run_cli ( list[str]  args,
Path   cwd = REPO_ROOT 
)

Run one CLI command used to validate a shipped starter artifact.

Parameters
[in]argsCLI argument list.
[in]cwdWorking directory for the command.
Returns
Completed CLI process.

Definition at line 22 of file audit_starter_content.py.

22def run_cli(args: list[str], cwd: Path = REPO_ROOT) -> subprocess.CompletedProcess[str]:
23 """!
24 @brief Run one CLI command used to validate a shipped starter artifact.
25 @param[in] args CLI argument list.
26 @param[in] cwd Working directory for the command.
27 @return Completed CLI process.
28 """
29 return subprocess.run(
30 [sys.executable, str(PICURV), *args], cwd=cwd, text=True, capture_output=True, timeout=90, check=False
31 )
32
33
Here is the caller graph for this function:

◆ fail()

None audit_starter_content.fail ( str  context,
subprocess.CompletedProcess[str]  result 
)

Raise a compact error that preserves the relevant CLI output.

Parameters
[in]contextHuman-readable operation description.
[in]resultCompleted failing CLI process.
Returns
None.

Definition at line 34 of file audit_starter_content.py.

34def fail(context: str, result: subprocess.CompletedProcess[str]) -> None:
35 """!
36 @brief Raise a compact error that preserves the relevant CLI output.
37 @param[in] context Human-readable operation description.
38 @param[in] result Completed failing CLI process.
39 @return None.
40 """
41 raise RuntimeError(f"{context} failed:\n{result.stdout}\n{result.stderr}")
42
43
Here is the caller graph for this function:

◆ validate_bundle()

None audit_starter_content.validate_bundle ( dict[str, str]  bundle,
str  label 
)

Validate one declared case/solver/monitor/post or cluster/study composition.

Parameters
[in]bundleDeclared role-to-path mapping.
[in]labelHuman-readable bundle description.
Returns
None.

Definition at line 44 of file audit_starter_content.py.

44def validate_bundle(bundle: dict[str, str], label: str) -> None:
45 """!
46 @brief Validate one declared case/solver/monitor/post or cluster/study composition.
47 @param[in] bundle Declared role-to-path mapping.
48 @param[in] label Human-readable bundle description.
49 @return None.
50 """
51 args = ["validate"]
52 for role, path in bundle.items():
53 args.extend([f"--{role}", str(REPO_ROOT / path)])
54 result = run_cli(args)
55 if result.returncode:
56 fail(label, result)
57
58
Here is the call graph for this function:
Here is the caller graph for this function:

◆ _yaml_role()

Optional[str] audit_starter_content._yaml_role ( Path  path)
protected

Classify a starter YAML by the same stable top-level shapes used by init.

Parameters
[in]pathSource YAML path.
Returns
Canonical configuration role, or None for unclassified YAML.

Definition at line 59 of file audit_starter_content.py.

59def _yaml_role(path: Path) -> Optional[str]:
60 """!
61 @brief Classify a starter YAML by the same stable top-level shapes used by init.
62 @param[in] path Source YAML path.
63 @return Canonical configuration role, or None for unclassified YAML.
64 """
65 payload = yaml.safe_load(path.read_text(encoding="utf-8")) or {}
66 if not isinstance(payload, dict):
67 return None
68 keys = set(payload)
69 if {"grid", "properties", "run_control"} <= keys:
70 return "case"
71 if "base_configs" in keys and ("study_type" in keys or "parameters" in keys or "parameter_sets" in keys):
72 return "study"
73 if "scheduler" in keys and "resources" in keys:
74 return "cluster"
75 if "source_data" in keys or "eulerian_pipeline" in keys or "lagrangian_pipeline" in keys:
76 return "post"
77 if "io" in keys and ("logging" in keys or "profiling" in keys or "diagnostics" in keys):
78 return "monitor"
79 if "momentum_solver" in keys or "poisson_solver" in keys or "operation_mode" in keys:
80 return "solver"
81 return None
82
83
Here is the caller graph for this function:

◆ audit_template_copy()

None audit_starter_content.audit_template_copy ( str  template_name,
Path  temporary_root 
)

Initialize one declared template and verify canonical relocation preserves its content.

Parameters
[in]template_nameTop-level example directory name.
[in]temporary_rootTemporary parent directory for initialized cases.
Returns
None.

Definition at line 84 of file audit_starter_content.py.

84def audit_template_copy(template_name: str, temporary_root: Path) -> None:
85 """!
86 @brief Initialize one declared template and verify canonical relocation preserves its content.
87 @param[in] template_name Top-level example directory name.
88 @param[in] temporary_root Temporary parent directory for initialized cases.
89 @return None.
90 """
91 source = REPO_ROOT / "examples" / template_name
92 destination = temporary_root / template_name
93 result = run_cli(["init", template_name, "--dest", str(destination)])
94 if result.returncode:
95 fail(f"picurv init {template_name}", result)
96 required_dirs = (
97 "config", "config/studies", "inputs", "assets/objects", "assets/sets", "runs", "studies"
98 )
99 for relative in required_dirs:
100 if not (destination / relative).is_dir():
101 raise RuntimeError(f"picurv init {template_name} omitted workspace directory {relative}")
102 if not (destination / ".picurv-workspace.yml").is_file():
103 raise RuntimeError(f"picurv init {template_name} omitted .picurv-workspace.yml")
104
105 source_yamls = [path for path in source.rglob("*.yml") if path.name != RUNTIME_EXECUTION_EXAMPLE]
106 initialized_yamls = list((destination / "config").rglob("*.yml"))
107 if len(initialized_yamls) < len(source_yamls):
108 raise RuntimeError(f"picurv init {template_name} lost one or more YAML configurations")
109
110 for source_path in source.rglob("*"):
111 if not source_path.is_file():
112 continue
113 relative = source_path.relative_to(source)
114 if relative.as_posix() == RUNTIME_EXECUTION_EXAMPLE:
115 continue
116 if source_path.suffix.lower() in {".yml", ".yaml"}:
117 role = _yaml_role(source_path)
118 stem = source_path.stem
119 candidates = [
120 destination / "config" / source_path.name,
121 destination / "config" / f"{role}.yml" if role else destination / source_path.name,
122 destination / "config" / f"{role}-{stem}{source_path.suffix}" if role else destination / source_path.name,
123 destination / "config" / "studies" / source_path.name,
124 ]
125 if not any(candidate.is_file() for candidate in candidates):
126 raise RuntimeError(f"picurv init {template_name} did not relocate YAML {relative}")
127 continue
128 matches = [path for path in destination.rglob(source_path.name) if path.is_file()]
129 if not any(path.read_bytes() == source_path.read_bytes() for path in matches):
130 raise RuntimeError(f"picurv init {template_name} did not preserve {relative}")
131 if (destination / RUNTIME_EXECUTION_EXAMPLE).exists():
132 raise RuntimeError(f"picurv init {template_name} copied site-specific {RUNTIME_EXECUTION_EXAMPLE}")
133
134
Head of a generic C-style linked list.
Definition variables.h:475
Here is the call graph for this function:
Here is the caller graph for this function:

◆ main()

int audit_starter_content.main ( )

Run the starter-content inventory, composition, and initializer audit.

Returns
Process status code.

Definition at line 135 of file audit_starter_content.py.

135def main() -> int:
136 """!
137 @brief Run the starter-content inventory, composition, and initializer audit.
138 @return Process status code.
139 """
140 contract = json.loads(CONTRACT_PATH.read_text(encoding="utf-8"))
141 actual_templates = sorted(path.name for path in (REPO_ROOT / "examples").iterdir() if path.is_dir())
142 if actual_templates != sorted(contract["template_directories"]):
143 raise RuntimeError(f"Template inventory differs from contract: actual={actual_templates}")
144 unknown_reference_templates = set(contract["reference_only_templates"]) - set(actual_templates)
145 if unknown_reference_templates:
146 raise RuntimeError(f"Reference-only templates are not in the template inventory: {sorted(unknown_reference_templates)}")
147
148 actual_config_assets = sorted(str(path.relative_to(REPO_ROOT)) for path in (REPO_ROOT / "config").rglob("*") if path.is_file())
149 if actual_config_assets != sorted(contract["config_assets"]):
150 raise RuntimeError("Configuration asset inventory differs from the starter-content contract.")
151
152 declared_example_yamls = set(contract["auxiliary_example_yamls"])
153 for bundle in contract["case_bundles"] + contract["study_bundles"]:
154 declared_example_yamls.update(path for path in bundle.values() if path.startswith("examples/"))
155 actual_example_yamls = {str(path.relative_to(REPO_ROOT)) for path in (REPO_ROOT / "examples").rglob("*.yml")}
156 if actual_example_yamls != declared_example_yamls:
157 raise RuntimeError("Example YAML inventory differs from the declared runnable/reference compositions.")
158
159 for bundle in contract["case_bundles"]:
160 validate_bundle(bundle, f"case bundle {bundle['case']}")
161 for bundle in contract["config_role_bundles"]:
162 validate_bundle(bundle, f"config role bundle {bundle['solver']}")
163 for bundle in contract["study_bundles"]:
164 validate_bundle(bundle, f"study bundle {bundle['study']}")
165
166 with tempfile.TemporaryDirectory(prefix="picurv-starter-content-") as temporary_directory:
167 temporary_root = Path(temporary_directory)
168 for template_name in contract["template_directories"]:
169 audit_template_copy(template_name, temporary_root)
170
171 print("Starter template, example, and configuration audit passed.")
172 return 0
173
174
int main(int argc, char **argv)
Entry point for the postprocessor executable.
Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ REPO_ROOT

audit_starter_content.REPO_ROOT = Path(__file__).resolve().parents[2]

Definition at line 16 of file audit_starter_content.py.

◆ CONTRACT_PATH

str audit_starter_content.CONTRACT_PATH = REPO_ROOT / "tests" / "tooling" / "starter_content_contract.json"

Definition at line 17 of file audit_starter_content.py.

◆ PICURV

str audit_starter_content.PICURV = REPO_ROOT / "picurv_cli" / "picurv"

Definition at line 18 of file audit_starter_content.py.

◆ RUNTIME_EXECUTION_EXAMPLE

str audit_starter_content.RUNTIME_EXECUTION_EXAMPLE = "execution.example.yml"

Definition at line 19 of file audit_starter_content.py.

◆ file

audit_starter_content.file

Definition at line 179 of file audit_starter_content.py.