Spaces:
Sleeping
Sleeping
Download src/chokepoint/graph/loader.py from YuraBodnar/ChokePointAI: direct link, hf CLI and curl.
- Browser
- Download file 2.4 kB
-
https://huggingface.co/spaces/YuraBodnar/ChokePointAI/resolve/main/src/chokepoint/graph/loader.py
- Command line
-
hf download hf://spaces/YuraBodnar/ChokePointAI/src/chokepoint/graph/loader.py
-
curl -L -o loader.py https://huggingface.co/spaces/YuraBodnar/ChokePointAI/resolve/main/src/chokepoint/graph/loader.py
2.4 kB
| from __future__ import annotations | |
| from pathlib import Path | |
| from typing import TYPE_CHECKING, Any | |
| import networkx as nx | |
| import yaml | |
| if TYPE_CHECKING: | |
| Graph = nx.DiGraph[str, dict[str, Any], dict[str, Any]] | |
| class GraphValidationError(ValueError): | |
| """Raised when the seed graph fails structural validation.""" | |
| def load_seed_graph(seed_dir: Path) -> Graph: | |
| """Load nodes.yaml and edges.yaml into a validated directed graph.""" | |
| nodes = yaml.safe_load((seed_dir / "nodes.yaml").read_text()) or [] | |
| edges = yaml.safe_load((seed_dir / "edges.yaml").read_text()) or [] | |
| graph: Graph = nx.DiGraph() | |
| for node in nodes: | |
| node_data = dict(node) | |
| node_id = node_data.pop("id") | |
| graph.add_node(node_id, **node_data) | |
| dangling_errors: list[str] = [] | |
| for edge in edges: | |
| edge_data = dict(edge) | |
| source = edge_data.pop("source") | |
| target = edge_data.pop("target") | |
| if source not in graph or target not in graph: | |
| dangling_errors.append(f"dangling edge reference: {source} -> {target}") | |
| continue | |
| graph.add_edge(source, target, **edge_data) | |
| try: | |
| _validate(graph) | |
| except GraphValidationError as error: | |
| dangling_errors.append(str(error)) | |
| if dangling_errors: | |
| raise GraphValidationError("; ".join(dangling_errors)) | |
| return graph | |
| def _validate(graph: Graph) -> None: | |
| """Raise one error containing every structural violation in the graph.""" | |
| errors: list[str] = [] | |
| for source, target, attributes in graph.edges(data=True): | |
| if source not in graph.nodes or target not in graph.nodes: | |
| errors.append(f"dangling edge reference: {source} -> {target}") | |
| if source == target: | |
| errors.append(f"self-loop not allowed: {source} -> {target}") | |
| weight = attributes.get("weight") | |
| if not isinstance(weight, int | float) or not 0.0 <= weight <= 1.0: | |
| errors.append(f"edge weight out of [0,1]: {source} -> {target} = {weight}") | |
| for node_id, attributes in graph.nodes(data=True): | |
| for field in ("criticality", "resilience"): | |
| value: Any = attributes.get(field) | |
| if not isinstance(value, int | float) or not 0.0 <= value <= 1.0: | |
| errors.append(f"node {node_id} missing/invalid {field}") | |
| if errors: | |
| raise GraphValidationError("; ".join(errors)) | |