From 9707c34d423aee602c21e38f676782e9ae73665d Mon Sep 17 00:00:00 2001 From: Edward Linscott Date: Wed, 26 Aug 2026 18:39:11 +0200 Subject: [PATCH] Remove unread Graph.graph_type attribute Nothing in node-graph or aiida-workgraph ever read self.graph_type; its only observed value was the "NORMAL" default. Drop the constructor argument, the attribute, and its slot in get_metadata()/to_dict(); from_dict() now discards a stored graph_type key instead of round-tripping it, so old serialized graphs still load. Co-Authored-By: Claude Fable 5 --- src/node_graph/graph.py | 14 ++++---------- tests/test_graph.py | 11 +++++++++++ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/node_graph/graph.py b/src/node_graph/graph.py index 57f3b9c..a6e1995 100644 --- a/src/node_graph/graph.py +++ b/src/node_graph/graph.py @@ -68,7 +68,6 @@ class Graph(IOOwnerMixin, WidgetRenderableMixin): Attributes: name (str): The name of the task graph. uuid (str): The UUID of this task graph. - graph_type (str): The type of the task graph. state (str): The state of this task graph. action (str): The action of this task graph. platform (str): The platform used to create this task graph. @@ -102,7 +101,6 @@ def __init__( outputs: Optional[SocketSpec | List[str]] = None, ctx: Optional[SocketSpec | List[str]] = None, uuid: Optional[str] = None, - graph_type: str = "NORMAL", graph: Optional[Graph] = None, parent: Optional[Task] = None, interactive_widget: bool = False, @@ -116,12 +114,10 @@ def __init__( Args: name (str, optional): The name of the task graph. Defaults to "Graph". uuid (str, optional): The UUID of the task graph. Defaults to None. - graph_type (str, optional): The type of the task graph. Defaults to "NORMAL". """ self.name = name self.uuid = uuid or str(uuid1()) - self.graph_type = graph_type self.graph = graph self.parent = parent self.type_mapping = dict(self._REGISTRY.type_mapping) @@ -610,16 +606,14 @@ def to_dict( def get_metadata(self) -> Dict[str, Any]: """Export graph metadata including *live* graph-level IO specs.""" - meta: Dict[str, Any] = { - "graph_type": self.graph_type, - } + meta: Dict[str, Any] = {} # also save the parent class information meta["graph_class"] = { "callable_name": self.__class__.__name__, "module_path": self.__class__.__module__, } for key, value in (self._metadata or {}).items(): - if key in {"graph_type", "graph_class"}: + if key == "graph_class": continue meta[key] = value return meta @@ -748,7 +742,8 @@ def from_dict(cls, ngdata: Dict[str, Any]) -> Graph: """ spec = GraphSpec.from_dict(ngdata.get("spec", {})) raw_meta = ngdata.get("metadata", {}) or {} - base_meta = {k: raw_meta[k] for k in ("graph_type",) if k in raw_meta} + # graph_type is discarded: old serialized graphs may still carry it, + # but nothing constructs or reads it any more. extra_meta = {k: v for k, v in raw_meta.items() if k not in {"graph_type"}} ng = cls( name=ngdata["name"], @@ -756,7 +751,6 @@ def from_dict(cls, ngdata: Dict[str, Any]) -> Graph: inputs=spec.inputs, outputs=spec.outputs, ctx=spec.ctx, - graph_type=base_meta.get("graph_type", "NORMAL"), metadata=extra_meta, ) ng.state = ngdata.get("state", "CREATED") diff --git a/tests/test_graph.py b/tests/test_graph.py index 3a97eb1..abec29f 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -37,6 +37,17 @@ def test_from_dict(ng_decorator): assert ng.to_dict() == ng1.to_dict() +def test_from_dict_discards_stale_graph_type(): + """A stored graph_type key from an old payload loads without error.""" + ng = Graph(name="test_graph") + ngdata = ng.to_dict() + assert "graph_type" not in ngdata["metadata"] + ngdata["metadata"]["graph_type"] = "NORMAL" + restored = Graph.from_dict(ngdata) + assert not hasattr(restored, "graph_type") + assert "graph_type" not in restored.to_dict()["metadata"] + + def test_from_dict_namespace_links(): @task() def make_pair(x: int, y: int) -> namespace(a=int, nested=namespace(x=int, y=int)):