From 72e3c1e78ba43e55d1fd9514773d0e1605026339 Mon Sep 17 00:00:00 2001 From: abhishekmadan30 Date: Thu, 14 May 2026 17:28:07 -0400 Subject: [PATCH] fix: skip external task references when rebuilding edges in from_json --- src/taskgraph/taskgraph.py | 3 ++- test/test_taskgraph.py | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/taskgraph/taskgraph.py b/src/taskgraph/taskgraph.py index 8a5c38ce8..2da916c86 100644 --- a/src/taskgraph/taskgraph.py +++ b/src/taskgraph/taskgraph.py @@ -63,6 +63,7 @@ def from_json(cls, tasks_dict): if "task_id" in value: tasks[key].task_id = value["task_id"] for depname, dep in value["dependencies"].items(): - edges.add((key, dep, depname)) + if dep in tasks_dict: + edges.add((key, dep, depname)) task_graph = cls(tasks, Graph(frozenset(tasks), edges)) return tasks, task_graph diff --git a/test/test_taskgraph.py b/test/test_taskgraph.py index d7966efd8..d1b4f8fff 100644 --- a/test/test_taskgraph.py +++ b/test/test_taskgraph.py @@ -90,6 +90,42 @@ def test_round_trip(self): tasks, new_graph = TaskGraph.from_json(graph.to_json()) self.assertEqual(graph, new_graph) + def test_from_json_skips_external_dep_references(self): + # Optimized/morphed graphs may carry Task.dependencies entries + # pointing at taskIds of replaced or cached tasks that aren't part + # of the graph itself. from_json must keep those references on the + # Task while excluding them from the Graph's edge set. + tasks_dict = { + "a": { + "kind": "fancy", + "label": "a", + "attributes": {}, + "task": {"task": "def"}, + "dependencies": {"prereq": "b", "external": "EXT_TASKID"}, + "soft_dependencies": [], + "if_dependencies": [], + "optimization": None, + "description": "", + }, + "b": { + "kind": "pre", + "label": "b", + "attributes": {}, + "task": {"task": "def2"}, + "dependencies": {}, + "soft_dependencies": [], + "if_dependencies": [], + "optimization": None, + "description": "", + }, + } + tasks, new_graph = TaskGraph.from_json(tasks_dict) + self.assertEqual(new_graph.graph.nodes, frozenset({"a", "b"})) + self.assertEqual(new_graph.graph.edges, {("a", "b", "prereq")}) + self.assertEqual( + tasks["a"].dependencies, {"prereq": "b", "external": "EXT_TASKID"} + ) + simple_graph = TaskGraph( tasks={ "a": Task(