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)
|