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

Functions

list tracked_markdown ()
 Markdown files the current commit carries.
 
bool in_code_block (list lines, int index)
 Whether a line sits inside a fenced code block.
 
int main ()
 Fail when narrative prose hardcodes a run-relative path.
 

Variables

 REPO_ROOT = Path(__file__).resolve().parents[2]
 
str TOPOLOGY = REPO_ROOT / "tests" / "tooling" / "artifact_topology.json"
 
dict SKIP_DIRS = {".git", "docs_build", "obj", "bin", "stubs", "runs", "studies", "__pycache__", ".pytest_cache"}
 
dict HISTORICAL = {"docs/CHANGELOG.md"}
 
str RUN_OWNED = "config|logs|output|scheduler|visualization|checkpoints"
 
 MANAGED
 
 PLACEHOLDER_ROOT
 
 BARE_PREFIX
 
 REPO_OWNED = re.compile(r"<repo>/[A-Za-z0-9_][A-Za-z0-9_./*<>-]*")
 
 WORKSPACE_OWNED = re.compile(r"<workspace>/[A-Za-z0-9_][A-Za-z0-9_./*<>-]*")
 
tuple REPO_CONFIG_SUBDIRS
 
 NOT_RUN_OWNED_PREFIXES
 
tuple ALLOWED_CONTEXTS
 

Detailed Description

Reject unmanaged run-path literals so a layout change cannot leave prose stale.

Function Documentation

◆ tracked_markdown()

list audit_path_literals.tracked_markdown ( )

Markdown files the current commit carries.

Returns
Sorted Markdown paths.

Definition at line 85 of file audit_path_literals.py.

85def tracked_markdown() -> list:
86 """!
87 @brief Markdown files the current commit carries.
88 @return Sorted Markdown paths.
89 """
90 found = enumerate_repository_files(REPO_ROOT, ".md", frozenset(SKIP_DIRS))
91 if found is None:
92 return sorted(path for path in REPO_ROOT.rglob("*.md") if path.is_file())
93 return found
94
95
Here is the caller graph for this function:

◆ in_code_block()

bool audit_path_literals.in_code_block ( list  lines,
int  index 
)

Whether a line sits inside a fenced code block.

Parameters
[in]linesAll lines of the file.
[in]indexZero-based line index.
Returns
True when the line is inside a fence.

Definition at line 96 of file audit_path_literals.py.

96def in_code_block(lines: list, index: int) -> bool:
97 """!
98 @brief Whether a line sits inside a fenced code block.
99 @param[in] lines All lines of the file.
100 @param[in] index Zero-based line index.
101 @return True when the line is inside a fence.
102 """
103 fences = sum(1 for line in lines[:index] if line.lstrip().startswith("```"))
104 return fences % 2 == 1
105
106
Here is the caller graph for this function:

◆ main()

int audit_path_literals.main ( )

Fail when narrative prose hardcodes a run-relative path.

Returns
Process status code.

Definition at line 107 of file audit_path_literals.py.

107def main() -> int:
108 """!
109 @brief Fail when narrative prose hardcodes a run-relative path.
110 @return Process status code.
111 """
112 contract = json.loads(TOPOLOGY.read_text(encoding="utf-8"))
113 identities = [a["id"] for a in contract["artifacts"]]
114 violations: list = []
115 scanned = 0
116 for path in tracked_markdown():
117 if str(path.relative_to(REPO_ROOT)) in HISTORICAL:
118 continue
119 text = path.read_text(encoding="utf-8", errors="replace")
120 lines = text.splitlines()
121 scanned += 1
122 for number, line in enumerate(lines):
123 if in_code_block(lines, number) or any(token in line for token in ALLOWED_CONTEXTS):
124 continue
125 probe = NOT_RUN_OWNED_PREFIXES.sub("", line)
126 # `<repo>/logs/...` is the repository's own build and test log directory,
127 # which no run configuration moves. Remove the whole reference before
128 # looking for bare prefixes, so the distinct notation actually buys the
129 # author something rather than leaving a bare `logs/` behind.
130 probe = REPO_OWNED.sub("", probe)
131 probe = WORKSPACE_OWNED.sub("", probe)
132 if MANAGED.search(line):
133 found, advice = "unmanaged run-path literal", (
134 "Use logical notation such as `<run.config>`, or move the concrete "
135 "path into a runnable command block.")
136 elif PLACEHOLDER_ROOT.search(line):
137 found, advice = "run-owned directory named under an unresolved run root", (
138 "`<run_dir>/logs/...` names a subdirectory without naming the "
139 "contract that fixes it. Use the logical identity - "
140 "`<run.runtime_logs>/...` - which artifact_topology.json maps.")
141 elif BARE_PREFIX.search(probe):
142 match = BARE_PREFIX.search(probe)
143 found, advice = f"bare run-owned prefix `{match.group(0)}`", (
144 "A bare `logs/...` or `config/...` does not say which owner is "
145 "meant. Use the run's logical identity - `<run.runtime_logs>/...`, "
146 "`<run.solver_output>/...` - or name the other owner explicitly "
147 "with `<repo>/logs/...` or `<workspace>/config/...`.")
148 else:
149 continue
150 violations.append(
151 f"{path.relative_to(REPO_ROOT)}:{number + 1}: {found}\n"
152 f" {line.strip()[:96]}\n"
153 f" {advice}"
154 )
155 if violations:
156 print("Unmanaged run-path literals in narrative prose:", file=sys.stderr)
157 for violation in violations:
158 print(f" {violation}", file=sys.stderr)
159 print(
160 f"\nLogical identities are declared in tests/tooling/artifact_topology.json "
161 f"({len(identities)} identities). Narrative pages should refer to those, so a layout "
162 f"change is a contract change rather than a prose hunt.",
163 file=sys.stderr,
164 )
165 return 1
166 print(f"Path-literal audit passed: {scanned} Markdown files, no unmanaged run-path literals in prose.")
167 return 0
168
169
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_path_literals.REPO_ROOT = Path(__file__).resolve().parents[2]

Definition at line 16 of file audit_path_literals.py.

◆ TOPOLOGY

str audit_path_literals.TOPOLOGY = REPO_ROOT / "tests" / "tooling" / "artifact_topology.json"

Definition at line 17 of file audit_path_literals.py.

◆ SKIP_DIRS

dict audit_path_literals.SKIP_DIRS = {".git", "docs_build", "obj", "bin", "stubs", "runs", "studies", "__pycache__", ".pytest_cache"}

Definition at line 18 of file audit_path_literals.py.

◆ HISTORICAL

dict audit_path_literals.HISTORICAL = {"docs/CHANGELOG.md"}

Definition at line 21 of file audit_path_literals.py.

◆ RUN_OWNED

str audit_path_literals.RUN_OWNED = "config|logs|output|scheduler|visualization|checkpoints"

Definition at line 31 of file audit_path_literals.py.

◆ MANAGED

audit_path_literals.MANAGED
Initial value:
1= re.compile(
2 r"(?<![\w./<])runs/(?:<[^>]+>|\$\{[^}]+\}|[A-Za-z0-9_.*-]+)/(" + RUN_OWNED + r")\b")

Definition at line 34 of file audit_path_literals.py.

◆ PLACEHOLDER_ROOT

audit_path_literals.PLACEHOLDER_ROOT
Initial value:
1= re.compile(
2 r"<(?:run_dir|run|RUN_DIR)>/(" + RUN_OWNED + r")\b")

Definition at line 40 of file audit_path_literals.py.

◆ BARE_PREFIX

audit_path_literals.BARE_PREFIX
Initial value:
1= re.compile(
2 r"(?<![\w./<>-])(" + RUN_OWNED + r")/(?![A-Za-z0-9_./*-]*[<>])[A-Za-z0-9_./*-]*")

Definition at line 51 of file audit_path_literals.py.

◆ REPO_OWNED

audit_path_literals.REPO_OWNED = re.compile(r"<repo>/[A-Za-z0-9_][A-Za-z0-9_./*<>-]*")

Definition at line 58 of file audit_path_literals.py.

◆ WORKSPACE_OWNED

audit_path_literals.WORKSPACE_OWNED = re.compile(r"<workspace>/[A-Za-z0-9_][A-Za-z0-9_./*<>-]*")

Definition at line 64 of file audit_path_literals.py.

◆ REPO_CONFIG_SUBDIRS

tuple audit_path_literals.REPO_CONFIG_SUBDIRS
Initial value:
1= ("guide.md", "build", "grids", "initial_conditions", "monitors",
2 "postprocessors", "profiles", "runtime", "schedulers", "solvers",
3 "studies")

Definition at line 70 of file audit_path_literals.py.

◆ NOT_RUN_OWNED_PREFIXES

audit_path_literals.NOT_RUN_OWNED_PREFIXES
Initial value:
1= re.compile(
2 r"(?<![\w./<>-])config/(?:" + "|".join(
3 name.replace(".", r"\.") for name in REPO_CONFIG_SUBDIRS) + r")\b")

Definition at line 73 of file audit_path_literals.py.

◆ ALLOWED_CONTEXTS

tuple audit_path_literals.ALLOWED_CONTEXTS
Initial value:
1= (
2 "```", # runnable command examples
3 "@verbinclude", # embedded executable templates
4 "@code",
5)

Definition at line 78 of file audit_path_literals.py.