Source code for cutcutcodec.core.compilation.graph_to_json

"""Help for serialisation of assembly graph."""

import inspect
import pathlib

import networkx

from cutcutcodec.core.classes.node import Node
from cutcutcodec.utils import get_project_root


def _node_cls_to_string(cls: type) -> str:
    """Convert a Node class in str.

    Bijection with ``cutcutcodec.core.compilation.json_to_graph._string_to_node_cls`` function.

    Parameters
    ----------
    cls : type
        The cutcutcodec.core.classes.node.Node subclass.

    Returns
    -------
    str
        The relative import path of the class.

    Examples
    --------
    >>> from cutcutcodec.core.compilation.graph_to_json import _node_cls_to_string
    >>> from cutcutcodec.core.classes.node import Node
    >>> _node_cls_to_string(Node)
    'classes.node.Node'
    >>>

    """
    assert issubclass(cls, Node), cls.__name__
    root_parts = (
        pathlib.Path(inspect.getsourcefile(cls))
        .resolve()
        .relative_to(get_project_root() / "core")
        .with_suffix("")
        .parts
    )
    cls_str = ".".join(root_parts) + "." + cls.__name__
    return cls_str


[docs] def graph_to_json(graph: networkx.MultiDiGraph) -> dict[str]: """Create the complete json serializable dictionary of the assembly graph. Reverse operation with ``cutcutcodec.core.compilation.json_to_graph.json_to_graph`` function. Leave the "cache" of the nodes. Parameters ---------- graph : networkx.MultiDiGraph The assembly graph. Returns ------- dict[str] The equivalent graph (without cache) in the dictionary form. Examples -------- >>> from pprint import pprint >>> from cutcutcodec.core.classes.container import ContainerOutput >>> from cutcutcodec.core.compilation.graph_to_json import graph_to_json >>> from cutcutcodec.core.compilation.tree_to_graph import tree_to_graph >>> from cutcutcodec.core.generation.audio.noise import GeneratorAudioNoise >>> graph = tree_to_graph(ContainerOutput(GeneratorAudioNoise(0).out_streams)) >>> graph.nodes["container_output_1"]["cache"] = None >>> graph.nodes["container_output_1"]["state"]["copy"] = False >>> graph.nodes["container_output_1"]["display"] = {"position": [0, 0]} >>> pprint(graph_to_json(graph)) {'edges': [['generator_audio_noise_1', 'container_output_1', '0->0']], 'nodes': {'container_output_1': {'class': 'classes.container.ContainerOutput', 'display': {'position': [0, 0]}, 'state': {'copy': False}}, 'generator_audio_noise_1': {'class': 'generation.audio.noise.GeneratorAudioNoise', 'state': {'layout': 'stereo', 'seed': 0.0}}}} >>> """ assert isinstance(graph, networkx.MultiDiGraph), graph.__class__.__name__ def get_node_attrs(data: dict) -> dict: """Convert a node into json.""" assert {"class", "state"}.issubset(data), set(data) # issubset(dict) <=> issubset(set) attrs = {"class": _node_cls_to_string(data["class"]), "state": data["state"]} if attrs["state"].get("copy") is True: # remove because it's the default behavour attrs["state"] = {k: v for k, v in data["state"].items() if k != "copy"} for category in data: if category in {"cache", "class", "state"}: continue attrs.update({category: data[category]}) return attrs json_dict = { "edges": sorted(list(e) for e in graph.edges), "nodes": {node: get_node_attrs(data) for node, data in graph.nodes.data()}, } return json_dict