Coverage for src / graphable / views / json.py: 100%
34 statements
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-16 21:32 +0000
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-16 21:32 +0000
1from dataclasses import dataclass
2from json import dumps
3from logging import getLogger
4from pathlib import Path
5from typing import Any, Callable
7from ..graph import Graph
8from ..graphable import Graphable
9from ..registry import register_view
11logger = getLogger(__name__)
14@dataclass
15class JsonStylingConfig:
16 """
17 Configuration for JSON graph serialization.
19 Attributes:
20 node_data_fnc: Optional function to add extra data to each node's JSON object.
21 reference_fnc: Function to generate the string identifier for each node.
22 indent: JSON indentation level.
23 """
25 node_data_fnc: Callable[[Graphable[Any]], dict[str, Any]] | None = None
26 reference_fnc: Callable[[Graphable[Any]], str] = lambda n: str(n.reference)
27 indent: int | str | None = 2
30def create_topology_json(graph: Graph, config: JsonStylingConfig | None = None) -> str:
31 """
32 Generate a JSON representation of the graph.
34 Args:
35 graph (Graph): The graph to convert.
36 config (JsonStylingConfig | None): Serialization configuration.
38 Returns:
39 str: A JSON string containing 'nodes' and 'edges'.
40 """
41 logger.debug("Creating JSON representation of the graph.")
42 config = config or JsonStylingConfig()
44 nodes = []
45 edges = []
47 for node in graph.topological_order():
48 node_id = config.reference_fnc(node)
49 node_entry = {
50 "id": node_id,
51 "reference": str(node.reference),
52 "tags": list(node.tags),
53 }
54 if config.node_data_fnc:
55 node_entry.update(config.node_data_fnc(node))
56 nodes.append(node_entry)
58 for dependent, _ in graph.internal_dependents(node):
59 edges.append({"source": node_id, "target": config.reference_fnc(dependent)})
61 data = {"nodes": nodes, "edges": edges}
63 return dumps(data, indent=config.indent)
66@register_view(".json", creator_fnc=create_topology_json)
67def export_topology_json(
68 graph: Graph,
69 output: Path,
70 config: JsonStylingConfig | None = None,
71) -> None:
72 """
73 Export the graph to a JSON file.
75 Args:
76 graph (Graph): The graph to export.
77 output (Path): The output file path.
78 config (JSONStylingConfig | None): Serialization configuration.
79 """
80 logger.info(f"Exporting JSON to: {output}")
81 with open(output, "w+") as f:
82 f.write(create_topology_json(graph, config))