Fuse a set of tasks into a single task. The tasks are fused into a single task that will execute the tasks in a subgraph. The internal tasks are no longer accessible from the outside. All provided tasks must form a valid subgraph that will reduce to a single key. If
(*tasks: GraphNode, key: KeyType | None = None)
| 438 | |
| 439 | @staticmethod |
| 440 | def fuse(*tasks: GraphNode, key: KeyType | None = None) -> GraphNode: |
| 441 | """Fuse a set of tasks into a single task. |
| 442 | |
| 443 | The tasks are fused into a single task that will execute the tasks in a |
| 444 | subgraph. The internal tasks are no longer accessible from the outside. |
| 445 | |
| 446 | All provided tasks must form a valid subgraph that will reduce to a |
| 447 | single key. If multiple outputs are possible with the provided tasks, an |
| 448 | exception will be raised. |
| 449 | |
| 450 | The tasks will not be rewritten but instead a new Task will be created |
| 451 | that will merely reference the old task objects. This way, Task objects |
| 452 | may be reused in multiple fused tasks. |
| 453 | |
| 454 | Parameters |
| 455 | ---------- |
| 456 | key : KeyType | None, optional |
| 457 | The key of the new Task object. If None provided, the key of the |
| 458 | final task will be used. |
| 459 | |
| 460 | See also |
| 461 | -------- |
| 462 | GraphNode.substitute : Easier substitution of dependencies |
| 463 | """ |
| 464 | if any(t.key is None for t in tasks): |
| 465 | raise ValueError("Cannot fuse tasks with missing keys") |
| 466 | if len(tasks) == 1: |
| 467 | return tasks[0].substitute({}, key=key) |
| 468 | all_keys = set() |
| 469 | all_deps: set[KeyType] = set() |
| 470 | for t in tasks: |
| 471 | all_deps.update(t.dependencies) |
| 472 | all_keys.add(t.key) |
| 473 | external_deps = tuple(sorted(all_deps - all_keys, key=hash)) |
| 474 | leafs = all_keys - all_deps |
| 475 | if len(leafs) > 1: |
| 476 | raise ValueError(f"Cannot fuse tasks with multiple outputs {leafs}") |
| 477 | |
| 478 | outkey = leafs.pop() |
| 479 | return Task( |
| 480 | key or outkey, |
| 481 | _execute_subgraph, |
| 482 | {t.key: t for t in tasks}, |
| 483 | outkey, |
| 484 | external_deps, |
| 485 | *(TaskRef(k) for k in external_deps), |
| 486 | _data_producer=any(t.data_producer for t in tasks), |
| 487 | ) |
| 488 | |
| 489 | @classmethod |
| 490 | @lru_cache |
no test coverage detected