Skip to content

node_schema

node_schema #

A JSON-serializable catalog of every procedure node class.

Builds a JSON-serializable catalog of every procedure node class — names, categories, input ports (with CGType wire forms), settings (with defaults), generic forwarding, and return types. This is a faithful catalog of the installed library: it carries no editor opinions (palette visibility and the like are the management portal's concern), so the catalog can never drift from the library and any front-end derives its own view from it.

Note: capturegraph is imported lazily inside iter_node_classes so that importing this module does not pull in the whole library; the import there loads every node leaf module and so completes NODE_REGISTRY.

build_node_schema() #

The full node catalog as a JSON-serializable dict.

Source code in capturegraph-lib/capturegraph/procedures/procedure/exporting/node_schema.py
def build_node_schema() -> dict[str, Any]:
    """The full node catalog as a JSON-serializable dict."""
    nodes = []
    for kind, cls in sorted(iter_node_classes().items()):
        fields = classify_fields(cls)
        nodes.append(
            {
                "kind": kind,
                "category": _category(cls),
                "doc": _doc_summary(cls),
                "return_type": _type_json(cls._return_type),
                "inputs": fields["inputs"],
                "settings": fields["settings"],
                "substeps": fields["substeps"],
                "generic": _generic_info(cls),
            }
        )

    return {
        "version": SCHEMA_VERSION,
        "nodes": nodes,
    }

classify_fields(cls) #

Split a node class's dataclass fields into inputs/settings/substeps.

Uses the same marker roles the runtime uses ([...type_checking.fields][]).

Source code in capturegraph-lib/capturegraph/procedures/procedure/exporting/node_schema.py
def classify_fields(cls: type) -> dict[str, Any]:
    """Split a node class's dataclass fields into inputs/settings/substeps.

    Uses the same marker roles the runtime uses ([...type_checking.fields][]).
    """
    inputs: list[dict[str, Any]] = []
    settings: list[dict[str, Any]] = []
    has_substeps = False

    for field in dataclass_fields(cls):
        name = field.name
        annotation = field.type
        role = role_of(name, annotation)
        if role is FieldRole.LABEL:
            continue

        has_default = field.default is not MISSING or field.default_factory is not MISSING

        if role is FieldRole.INPUT:
            inputs.append(
                {
                    "name": name,
                    "cgtype": _type_json(annotations.input_value_type(annotation)),
                    "required": not has_default and not annotations.is_optional(annotation),
                }
            )
        elif role is FieldRole.SUBSTEPS:
            has_substeps = True
        else:  # FieldRole.SETTING
            type_string, optional = _setting_type(annotations.setting_value_type(annotation))
            optional = optional or annotations.is_optional(annotation)
            default = None
            if field.default is not MISSING:
                default = _json_default(field.default)
            elif field.default_factory is not MISSING:
                default = _json_default(field.default_factory())
            settings.append(
                {
                    "name": name,
                    "type": type_string,
                    "required": not has_default and not optional,
                    "default": default,
                }
            )

    return {"inputs": inputs, "settings": settings, "substeps": has_substeps}

iter_node_classes() #

All node classes, keyed by class name (= JSON kind).

Each node registers itself in NODE_REGISTRY when its module is imported; importing the capturegraph root loads every node leaf module, so the registry is complete here.

Source code in capturegraph-lib/capturegraph/procedures/procedure/exporting/node_schema.py
def iter_node_classes() -> dict[str, type]:
    """All node classes, keyed by class name (= JSON kind).

    Each node registers itself in ``NODE_REGISTRY`` when its module is imported;
    importing the ``capturegraph`` root loads every node leaf module, so the
    registry is complete here.
    """
    import capturegraph  # noqa: F401  (loads every node leaf module → NODE_REGISTRY)
    from capturegraph.procedures.procedure import NODE_REGISTRY

    return dict(NODE_REGISTRY)