Output Templating¶
When a ProcessingTool produces file outputs, you
declare output path templates with the explicit
Template marker on the Outputs class. The
engine resolves these templates before calling process_row.
Basic templates¶
class Segment(ProcessingTool):
display_name = "Segment"
environment = EnvironmentSpec(name="cellpose", dependencies={})
class Inputs:
image: Annotated[Path, ImageSpec()]
class Outputs:
mask: Annotated[Path, ImageSpec(semantics={"label"})] = Template(
"{image.stem}_mask.tif"
)
The template {image.stem}_mask.tif resolves using the image input path:
Input:
/data/experiment/cell_001.tifOutput:
<assets_dir>/cell_001_mask.tif
Available variables¶
Variable |
Description |
|---|---|
|
Name of the current node |
|
Current row index (string) |
|
Unix timestamp of execution |
|
Stem of an input path (filename without extension) |
|
Full filename of an input path |
|
Extension of an input path (e.g., |
|
All extensions (e.g., |
|
Input value, useful for scalar parameters such as channel indices |
|
Extension from the single path input (shorthand) |
|
Value of a column from the upstream DataFrame |
Path-derived variables¶
Any input annotated with a path type, including
Annotated[Path, ImageSpec(...)], exposes .stem, .name, .ext,
and .exts:
class Outputs:
# Given image = "cells.ome.tif"
result: Annotated[Path, ImageSpec()] = Template(
"{image.stem}_result{image.exts}"
)
# → "cells_result.ome.tif"
Column references¶
Access values from the upstream DataFrame with {column:<name>}:
class Outputs:
report: Path = Template("{column:sample_id}_report.csv")
Row index¶
{row_index} is especially useful for one-to-many (explosion) tools where
a single input row produces multiple outputs:
class TileImage(ProcessingTool):
display_name = "Tile"
# ...
class Outputs:
tile: Annotated[Path, ImageSpec()] = Template(
"{image.stem}_tile_{row_index}.tif"
)
# → "cell_001_tile_0::0.tif", "cell_001_tile_0::1.tif", ...
Resolution order¶
Templates are resolved by the engine before process_row is called. The
resolved path is passed to process_row via the
Arguments object. The tool writes its output to
this path and returns it in the Outputs.
def process_row(self, arguments: Arguments) -> "Segment.Outputs":
# arguments.mask is already a resolved Path
imsave(str(arguments.mask), mask_array)
return self.Outputs(mask=arguments.mask)