phenotypic.gui.builder._conversion_dag.to_pipeline_dag#

phenotypic.gui.builder._conversion_dag.to_pipeline_dag(state: _DagBuilderState) ImagePipeline[source]#

Convert a DAG-shaped BuilderState to an ImagePipeline.

Steps (spec §5.4):

  1. Validate the state; raise ValueError on any blocking issue (severity == "error").

  2. Walk image-flow edges from the InputImage block in the root scope to produce a topological order of non-input blocks.

  3. For each block, fold any aux edges targeting it into its params dict — scalar aux at params[port], list-aux at params[port][slot] with empty slots set to None.

  4. Partition the resulting instances by MeasureFeatures / PostMeasurement membership into ops / meas / post lists.

  5. Construct a fresh ImagePipeline with the root scope’s name, desc, nrows, ncols.

Aux-only blocks (those without an outgoing image-flow edge) are never returned as top-level entries — they are folded into the consumer’s params via _block_to_marker() recursion.

Parameters:

state (_DagBuilderState) – The BuilderState to materialise.

Returns:

A fresh ImagePipeline.

Raises:

ValueError – If validate() returns any issue with severity == "error". The message lists each rule kind and the offending block’s label so the GUI toast can surface a deterministic explanation.

Return type:

ImagePipeline

Examples

Build a one-op DAG (Input Image → GaussianBlur) and materialise it as an ImagePipeline. The synth-yeast fixture is loaded only to anchor the example in the project’s microbiology context — the conversion does not touch image data:

>>> from phenotypic.data import load_synth_yeast_plate
>>> from phenotypic.gui.builder._state import (
...     BuilderScope, BuilderState, BlockNode, Edge,
...     _new_block_id,
... )
>>> from phenotypic.gui.builder._conversion_dag import to_pipeline_dag
>>> scope = BuilderScope(name="demo", desc="one-op chain")
>>> input_block = scope.blocks[0]
>>> blur = BlockNode(
...     block_id=_new_block_id(),
...     class_name="GaussianBlur",
...     params={},
...     label="blur",
... )
>>> scope.blocks.append(blur)
>>> scope.edges.append(Edge(
...     edge_id=_new_block_id(),
...     source_block_id=input_block.block_id,
...     target_block_id=blur.block_id,
...     target_port="in",
...     kind="image",
... ))
>>> state = BuilderState(root=scope)
>>> pipeline = to_pipeline_dag(state)
>>> len(pipeline.get_ops())
1
>>> _ = load_synth_yeast_plate()  # microbiology context anchor