Workflow Contexts¶
Workflow contexts are the APIs that coordinate multi-step pipelines.
When to use workflow contexts¶
- Use
Tracker.scenario(...)orconsist.scenario(...)to group related steps under one scenario header run. - Use
ScenarioContext.run(...)for cache-aware function-shaped steps. - Use
ScenarioContext.map_runs(...)for independent parameter sweeps where each row should become one child run under the scenario. - Use
ScenarioContext.trace(...)when the inline block must execute every time (including cache hits). - Use
RunContextinsideinject_context=Trueruns for managed output paths and run-aware logging helpers.
Relationship to consist.run and Tracker.run¶
| API | Execution shape | Cache-hit behavior |
|---|---|---|
consist.run / Tracker.run |
Single function call | Skips function execution and reuses cached outputs |
ScenarioContext.run |
Function step inside scenario | Same cache behavior as Tracker.run |
ScenarioContext.map_runs |
Many independent function runs inside scenario | Executes one child run per row and records a batch result |
ScenarioContext.trace / Tracker.trace |
Inline with block |
Block executes each time; cache state is still recorded |
Scenario step identity kwargs¶
Tracker.scenario(...) creates the header context. Identity kwargs are passed on
step surfaces (ScenarioContext.run(...) / ScenarioContext.trace(...)):
with tracker.scenario("baseline") as sc:
step = sc.run(
fn=prepare,
name="prepare",
adapter=activitysim_adapter,
identity_inputs=[("asim_config", asim_config_dir)],
outputs=["prepared"],
)
with sc.trace(
"analyze",
adapter=activitysim_adapter,
identity_inputs=[("asim_config", asim_config_dir)],
):
analyze_inline(step.outputs["prepared"])
config_plan and hash_inputs are not accepted on scenario step run/trace
surfaces. Use adapter and identity_inputs.
Tracker.scenario(...) and consist.scenario(...) also accept
step_tags=[...] and step_facet={...} to apply default tags/facets to every
child step in the scenario. These defaults apply to run(...) and trace(...)
children only, not to the scenario header itself, and per-step values take
precedence on conflicts.
BindingResult execution envelopes¶
ScenarioContext.run(...) also accepts binding=BindingResult(...) for
orchestrator-facing code that has already resolved a step's explicit inputs,
required coupler keys, and optional coupler keys. Keep using primitive
inputs/input_keys/optional_input_keys kwargs for direct workflow code; the
binding envelope is the preferred path when the binding decision already
lives outside Consist.
binding is execution-only and mutually exclusive with the primitive input
kwargs. It does not change ScenarioContext.trace(...).
from pathlib import Path
import consist
from consist import BindingResult, ExecutionOptions, Tracker
tracker = Tracker(run_dir="./runs", db_path="./provenance.duckdb")
def prepare(raw: Path) -> dict[str, Path]:
out = consist.output_path("prepared", ext="parquet")
out.write_text("prepared\n")
return {"prepared": out}
def analyze(prepared: Path) -> dict[str, Path]:
out = consist.output_path("analysis", ext="parquet")
out.write_text(prepared.read_text())
return {"analysis": out}
with tracker.scenario("baseline") as sc:
prep = sc.run(
fn=prepare,
inputs={"raw": Path("raw.csv")},
execution_options=ExecutionOptions(input_binding="paths"),
outputs=["prepared"],
)
sc.run(
fn=analyze,
binding=BindingResult(
inputs={"prepared": consist.ref(prep, key="prepared")},
input_keys=["prepared"],
),
execution_options=ExecutionOptions(input_binding="loaded"),
outputs=["analysis"],
)
For direct step-to-step workflow code, consist.ref(...) and consist.refs(...)
remain the recommended default. Reach for BindingResult when a planner or
external orchestrator has already compiled the binding decision.
Immutable resolved bindings (advanced)¶
ResolvedBinding is a stricter, opt-in contract for an external planner that
must replay one already-admitted artifact choice exactly. It is not the normal
Coupler workflow: use inputs=, consist.ref(...), and BindingResult for
ordinary scenario composition.
A ResolvedBinding contains typed artifact identities, tracked-artifact
locators, the callable's step-contract identity, and optional admission
evidence. ScenarioContext.run(...) accepts it only with
ExecutionOptions(input_binding="paths"). Before invoking the callable,
Consist verifies the artifact identity and stages a fresh, run-owned copy at
each declared destination; it refuses an unsafe destination or a mismatched
callable. Every strict invocation is written to the run_binding_invocation
ledger. Cache hits keep their producer run immutable and record that producer
as cache_source_run_id on the new invocation record.
Build these bindings in orchestration code with ResolvedBindingBuilder; do
not construct them from unverified paths or use them to replace the normal
Coupler-based workflow.
When a planner must construct a binding before run(...), ask the Scenario for
the final identity rather than reproducing decorator or scenario naming rules:
execution = ExecutionOptions(input_binding="paths", runtime_kwargs=runtime)
identity = scenario.resolve_step_identity(
run_beam,
year=year,
iteration=iteration,
phase="warmstart",
execution_options=execution,
)
binding = (
consist.ResolvedBindingBuilder(
step_name=identity.name,
step_contract_identity=identity.step_contract_identity,
)
.bind_tracked_artifact(
parameter="linkstats_warmstart",
artifact=admitted_linkstats,
destination=Path("inputs/linkstats.parquet"),
source="external_admitted",
)
.freeze()
)
scenario.run(
run_beam,
binding=binding,
step_identity=identity,
execution_options=execution,
)
StepIdentity is an opaque, Scenario-owned preflight result. run(...)
reuses it without re-evaluating dynamic name/model metadata and rejects a
different callable, Scenario, dynamic context, or runtime kwargs. Do not pass
name= or model= again when supplying step_identity=.
For an artifact already admitted through Consist, use the tracked-artifact bridge rather than reconstructing an identity or locator in downstream code:
binding = (
consist.ResolvedBindingBuilder(
step_name="beam",
step_contract_identity=step_contract_identity(run_beam, "beam"),
)
.bind_tracked_artifact(
parameter="linkstats_warmstart",
artifact=admitted_linkstats,
destination=Path("inputs/linkstats.parquet"),
source="external_admitted",
)
.with_diagnostics({"selection": {"reason": "approved warm start"}})
.freeze()
)
The strict contract has two serializations. identity_json() contains the
step contract plus each parameter's typed identity and destination; its digest
partitions cache reuse. evidence_json() adds tracked locators, selection
details, metadata, admission evidence, and diagnostics. The latter is written
to run_binding_invocation, so explaining why a fallback was selected never
changes cache reuse.
For Python ResolvedBinding runs only, immutable typed bound inputs use
content-addressed cache identity. Ordinary BindingResult, primitive
inputs=, Coupler values, and legacy directories keep their normal
provenance-Merkle identity. This is not a container image-cache contract:
native executor="container" strict bindings are rejected.
Inspect run.identity_summary["input_identity"] to see the strict/ordinary
input split. Inspect
tracker.db.get_binding_invocations(requested_run_id=...) for the selected
artifact, producer, and immutable audit evidence on each hit or miss.
Snapshot and callable-path invariant¶
For input_binding="paths", a strict input parameter receives the fresh
run-owned snapshot under .resolved-bindings/<run-id>/<destination>, not the
original admitted path. A model that reads a workspace path or a
container-mapped path must be configured so that its final visible path resolves
to those snapshot bytes. A separately staged workspace copy is not equivalent
merely because it has the same intended filename; it must resolve to the strict
snapshot (or be independently verified against its typed identity).
V1 scope limitation¶
Every V1 strict input must correspond to a named callable parameter. Consist
does not yet model a strict staged_artifact that participates in identity and
staging while being accessed only through a workspace destination or
RunContext. Do not hide dynamic artifacts behind fake parameters or omit them
from strict identity; keep those restart closures on the ordinary workflow path
until that explicit artifact mode exists.
Parallel sweep runs¶
ScenarioContext.map_runs(...) is the scenario-level fan-out helper for
embarrassingly parallel sweeps. It builds one BatchRunSpec per input row,
executes each spec in a worker process, and returns a BatchResult summary.
Use it when:
- Every row can run independently.
- The worker function is importable as
"module:function". - The parent scenario should group all child runs for later queries.
- You want retry metadata for failed rows.
rows = [
{"case_id": 0, "seed": 10, "elasticity": -0.2},
{"case_id": 1, "seed": 11, "elasticity": -0.4},
]
with tracker.scenario("elasticity_sweep") as sc:
batch = sc.map_runs(
rows=rows,
fn="project.steps:run_elasticity_case",
name_template="case_{case_id}",
model="demand_model",
config_from=lambda row: {
"seed": row["seed"],
"elasticity": row["elasticity"],
},
facet_from=lambda row: {
"case_id": row["case_id"],
"elasticity": row["elasticity"],
},
expected_outputs=["summary"],
)
The returned BatchResult separates correlation metadata from persisted run
metadata:
BatchResult.resultscontainsRunSpecResultobjects for observed outcomes.RunSpecResult.run_idis the requested child run ID for the spec.RunSpecResult.persisted_run_idis set only when a run record exists.BatchResult.child_run_idsincludes only persisted child run IDs.BatchResult.failed_specscontainsBatchRunSpecobjects that can be retried.
The current backend is backend="processes". It requires an importable callable
reference and does not support direct callables, lambdas, or notebook-local
functions. cancel_pending_on_failure=True makes a best-effort attempt to
cancel work that has not started after the first observed failure; running
workers may still complete.
Minimal runnable scenario example¶
from pathlib import Path
import consist
from consist import Tracker
tracker = Tracker(run_dir="./runs", db_path="./provenance.duckdb")
def prepare() -> Path:
out = consist.output_path("prepared", ext="txt")
out.write_text("prepared\n")
return out
def analyze(prepared_artifact) -> Path:
out = consist.output_path("analysis", ext="txt")
out.write_text(prepared_artifact.path.read_text())
return out
with tracker.scenario("baseline") as sc:
prep = sc.run(fn=prepare, name="prepare", outputs=["prepared"])
analysis = sc.run(
fn=analyze,
name="analyze",
inputs={"prepared_artifact": consist.ref(prep, key="prepared")},
outputs=["analysis"],
)
Scenario Context¶
A context manager for grouping multiple steps into a single "scenario".
A scenario creates a parent run (the "header") that aggregates the
results, metadata, and lineage of all steps executed within its block.
It provides a coupler to pass artifacts between steps, making it
ideal for multi-stage simulation workflows.
Attributes:
| Name | Type | Description |
|---|---|---|
coupler |
Coupler
|
Scenario-local artifact registry for passing outputs between steps. Supports runtime-declared output validation. |
Examples:
with tracker.scenario("base_case") as sc:
# Step 1: Pre-process
sc.run(preprocess_fn, inputs={"raw": "data.csv"}, outputs=["clean"])
# Step 2: Model (reads "clean" from the coupler automatically)
sc.run(model_fn, input_keys=["clean"], outputs=["results"])
run_id
property
¶
Run ID of the scenario header.
Returns:
| Type | Description |
|---|---|
str
|
The run ID for the scenario header (or the scenario name if the header has not been created yet). |
config
property
¶
Read-only view of the scenario configuration.
Returns:
| Type | Description |
|---|---|
MappingProxyType
|
Immutable mapping of configuration values for the scenario. Updates are applied by changing inputs to the scenario, not by mutating this mapping. |
inputs
property
¶
Read-only view of registered exogenous inputs.
Returns:
| Type | Description |
|---|---|
MappingProxyType
|
Immutable mapping of input keys to artifacts added via |
add_input(path, key, **kwargs)
¶
Log an external input artifact to the scenario header run.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
ArtifactRef
|
Path (or prebuilt |
required |
key
|
str
|
Semantic key for the artifact. |
required |
**kwargs
|
Any
|
Additional metadata forwarded to |
{}
|
Returns:
| Type | Description |
|---|---|
Artifact
|
Logged artifact associated with the scenario. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If a step has already started or the scenario context is inactive. |
declare_outputs(*names, required=False, warn_undefined=False, description=None)
¶
Declare outputs that should be present in the scenario coupler.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*names
|
str
|
Output keys to declare. |
()
|
required
|
bool | Mapping[str, bool]
|
Whether declared outputs are required. A mapping allows per-key overrides. |
False
|
warn_undefined
|
bool
|
If True, warn when outputs are logged that were not declared. |
False
|
description
|
Optional[Mapping[str, str]]
|
Human-readable descriptions for declared outputs. |
None
|
require_outputs(*names, required=True, warn_undefined=False, description=None)
¶
Declare required outputs that must be present at scenario exit.
This is a convenience wrapper around declare_outputs that defaults
required=True.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*names
|
str
|
Output keys to require. |
()
|
required
|
bool | Mapping[str, bool]
|
Whether required outputs are enforced. A mapping allows per-key overrides. |
True
|
warn_undefined
|
bool
|
If True, warn when outputs are logged that were not declared. |
False
|
description
|
Optional[Mapping[str, str]]
|
Human-readable descriptions for required outputs. |
None
|
collect_by_keys(artifacts, *keys, prefix='')
¶
Collect explicit artifacts into the scenario coupler by key.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
artifacts
|
Mapping[str, Artifact]
|
Source artifacts mapping (usually outputs from a step). |
required |
*keys
|
str
|
Keys to collect from the mapping. |
()
|
prefix
|
str
|
Optional prefix to apply to collected keys in the coupler. |
""
|
Returns:
| Type | Description |
|---|---|
Dict[str, Artifact]
|
The collected artifacts keyed by their (possibly prefixed) names. |
run(fn=None, name=None, *, run_id=None, model=None, step_identity=None, description=None, config=None, adapter=None, config_plan_ingest=True, config_plan_profile_schema=False, inputs=None, input_keys=None, optional_input_keys=None, binding=None, depends_on=None, tags=None, facet=None, facet_from=None, facet_schema_version=None, facet_index=None, identity_inputs=None, year=None, iteration=None, phase=None, stage=None, parent_run_id=None, outputs=None, output_paths=None, output_sets=None, profile_file_schema=None, capture_dir=None, capture_pattern='*', cache_options=None, output_policy=None, execution_options=None)
¶
Execute a cached scenario step and update the Coupler with outputs.
This method wraps Tracker.run while ensuring the scenario header
is updated with step metadata and artifacts.
Decorator metadata is resolved once by the scenario before it delegates
the fully resolved invocation to Tracker.run. In particular,
decorated input_keys and optional_input_keys are compatibility
metadata and do not cause a deprecation warning solely because of this
internal handoff.
Use execution_options.runtime_kwargs for runtime-only inputs and
consist.require_runtime_kwargs to validate required keys.
For direct workflow code, prefer primitive inputs= kwargs and, when
needed, the direct input_keys= / optional_input_keys= compatibility
surfaces. For complex or externally orchestrated workflows that already
resolved the binding plan, pass binding=BindingResult(...) instead;
binding is an execution envelope and is mutually exclusive with the
primitive input kwargs.
Pass policy controls via cache_options, output_policy,
and execution_options.
adapter and identity_inputs are the public identity-related
kwargs.
profile_file_schema is the scenario-step equivalent of
Tracker.run(..., profile_file_schema=...): it profiles named
tabular inputs and declared tabular outputs logged during this step.
Examples:
Direct workflow code:
sc.run(
fn=step,
inputs={"raw": raw_path},
execution_options=ExecutionOptions(input_binding="paths"),
)
sc.run(
fn=step,
inputs={"raw": consist.ref(previous_result, key="raw")},
execution_options=ExecutionOptions(input_binding="loaded"),
)
Orchestrator-facing execution envelope:
sc.run(
fn=step,
binding=BindingResult(
inputs={"raw": raw_path},
input_keys=["data"],
optional_input_keys=["maybe"],
),
execution_options=ExecutionOptions(input_binding="paths"),
)
binding cannot be combined with primitive inputs, input_keys, or
optional_input_keys.
map_runs(rows, fn, name_template=None, model=None, config_from=None, facet_from=None, max_workers=None, backend='processes', cancel_pending_on_failure=False, expected_outputs=None)
¶
Fan out parameter sweep runs in parallel under the parent scenario.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
rows
|
Iterable[Dict[str, Any]]
|
Rows of inputs/parameter combinations to sweep. |
required |
fn
|
str
|
Importable module-path string reference (e.g. "my_module:run_case"). Direct callables are not supported for the process backend. |
required |
name_template
|
Optional[str]
|
Optional string template to format run names (e.g. "case-{case_id}"). |
None
|
model
|
Optional[str]
|
The model name for categorizing child runs. Defaults to function name. |
None
|
config_from
|
Optional[Callable[[Dict[str, Any]], Dict[str, Any]]]
|
Optional function to transform a row into a run configuration dict. |
None
|
facet_from
|
Optional[Callable[[Dict[str, Any]], Dict[str, Any]]]
|
Optional function to extract facets from a row. |
None
|
max_workers
|
Optional[int]
|
The maximum number of parallel workers. Defaults to executor default. |
None
|
backend
|
str
|
The backend executor: "processes" (ProcessPoolExecutor) or "threads" (ThreadPoolExecutor). |
"processes"
|
cancel_pending_on_failure
|
bool
|
If True, make a best-effort attempt to cancel futures that have not started after the first observed failure. Already-running workers may still complete. |
False
|
Returns:
| Type | Description |
|---|---|
BatchResult
|
The aggregated results of the parallel run execution. |
trace(name, *, run_id=None, model=None, description=None, config=None, adapter=None, config_plan_ingest=True, config_plan_profile_schema=False, inputs=None, input_keys=None, optional_input_keys=None, depends_on=None, tags=None, facet=None, facet_from=None, facet_schema_version=None, facet_index=None, identity_inputs=None, year=None, iteration=None, parent_run_id=None, outputs=None, output_paths=None, capture_dir=None, capture_pattern='*', cache_mode='reuse', cache_hydration=None, cache_version=None, cache_epoch=None, validate_cached_outputs='lazy', code_identity=None, code_identity_extra_deps=None, output_mismatch='warn', output_missing='warn')
¶
Manual tracing context manager for scenario steps.
This wraps Tracker.trace to log a step while allowing inline code
blocks. Use ScenarioContext.run when you want function execution
to be skipped on cache hits.
adapter and identity_inputs are the public identity-related
kwargs.
Run Context¶
Provide run-aware helpers to a Python callable.
Consist injects this object when inject_context is enabled. It exposes
output locations, artifact logging helpers, and canonicalization facts
without requiring application code to access a global tracker.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tracker
|
Tracker
|
Active tracker for the executing run. |
required |
canonicalization
|
CanonicalizationSnapshot
|
Immutable observations from the applied config plan. These are canonicalization-time facts, not final staged or container paths. |
None
|
Notes
Cache hits and native container executions do not invoke the Python callable, so they do not receive this context.
Examples:
>>> def my_step(ctx: RunContext):
... output_path = ctx.run_dir / "results.csv"
... ctx.log_artifact(output_path, "results")
run_dir
property
¶
Run-specific output directory for the active step.
Returns:
| Type | Description |
|---|---|
Path
|
The directory where this step should write outputs by default. This value is derived from the active run and respects any per-run artifact directory overrides. |
inputs
property
¶
output_dir(namespace=None)
¶
Resolve the managed output directory for the active run.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
namespace
|
Optional[str]
|
Optional relative subdirectory under the managed run output directory. |
None
|
Returns:
| Type | Description |
|---|---|
Path
|
Absolute directory path for managed outputs. The directory is created if it does not exist. |
output_path(key, ext='parquet')
¶
Resolve a deterministic managed output path for the active run.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
Artifact key used as the output filename stem. Relative path segments are allowed to organize outputs into subdirectories. |
required |
ext
|
str
|
File extension to append. Leading dots are ignored and the extension is normalized to lowercase. |
"parquet"
|
Returns:
| Type | Description |
|---|---|
Path
|
Absolute managed output path. Parent directories are created if needed. |
load(key_or_artifact)
¶
log_artifact(*args, **kwargs)
¶
Log an artifact within the active run.
This is a thin wrapper around Tracker.log_artifact.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*args
|
Any
|
Positional arguments forwarded to |
()
|
**kwargs
|
Any
|
Keyword arguments forwarded to |
{}
|
Returns:
| Type | Description |
|---|---|
Artifact
|
The logged artifact. |
log_artifacts(*args, **kwargs)
¶
Log multiple artifacts within the active run.
This is a thin wrapper around Tracker.log_artifacts.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*args
|
Any
|
Positional arguments forwarded to |
()
|
**kwargs
|
Any
|
Keyword arguments forwarded to |
{}
|
Returns:
| Type | Description |
|---|---|
Dict[str, Artifact]
|
Mapping of artifact keys to logged artifacts. |
log_input(*args, **kwargs)
¶
Log an input artifact within the active run.
This is a thin wrapper around Tracker.log_input.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*args
|
Any
|
Positional arguments forwarded to |
()
|
**kwargs
|
Any
|
Keyword arguments forwarded to |
{}
|
Returns:
| Type | Description |
|---|---|
Artifact
|
The logged input artifact. |
log_output(*args, **kwargs)
¶
Log an output artifact within the active run.
This is a thin wrapper around Tracker.log_output.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*args
|
Any
|
Positional arguments forwarded to |
()
|
**kwargs
|
Any
|
Keyword arguments forwarded to |
{}
|
Returns:
| Type | Description |
|---|---|
Artifact
|
The logged output artifact. |
log_meta(**kwargs)
¶
Update metadata for the active run.
This is a thin wrapper around Tracker.log_meta.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs
|
Any
|
Metadata key/value pairs to merge into the run record. |
{}
|
capture_outputs(directory, pattern='*')
¶
Capture files written under directory and log them as outputs on exit.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
directory
|
Path
|
Directory to monitor for new or modified files. |
required |
pattern
|
str
|
Glob pattern for files to capture. |
"*"
|
Yields:
| Type | Description |
|---|---|
OutputCapture
|
Container listing artifacts that were logged during the context. |
Coupler¶
Bases: CouplerMapMixin[Artifact, DeclaredOutput]
Scenario-local helper to thread named artifacts between steps.
Coupler is intentionally small: - It stores the "latest Artifact for a semantic key" in-memory.
It does not log artifacts, infer inputs/outputs, or mutate Artifacts as a side effect of reads. Keep provenance operations on the Tracker.
set(key, artifact)
¶
Store an artifact under a validated key.
set_from_artifact(key, value)
¶
Set an artifact, accepting both Artifact objects and artifact-like values.
This method is useful when integrating with optional dependencies (like noop mode) where you may receive either: - A real Artifact (when tracking is enabled) - An artifact-like object with .path and .container_uri properties (noop mode) - A Path or string (fallback)
All three forms are stored in the coupler and can be retrieved with get() or require().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
The coupler key (e.g., "persons", "skims"). Must follow artifact-key rules. |
required |
value
|
Artifact or artifact - like or Path or str
|
The value to store. Can be a real Artifact, artifact-like object with .path/.container_uri properties, a Path, or a string path. |
required |
Returns:
| Type | Description |
|---|---|
Any
|
The value that was stored. |
Examples:
Using with optional Consist dependency:
# Works whether log_output returns Artifact or NoopArtifact
artifact = tracker.log_output(path, key="persons")
coupler.set_from_artifact("persons", artifact)
Mixed real and fallback artifacts:
update(artifacts=None, /, **kwargs)
¶
Bulk-store artifacts from a mapping and/or keyword arguments.
view(namespace)
¶
Return a namespace-scoped coupler view.
The returned view writes keys as <namespace>/<key> into this coupler
while allowing reads and writes using namespace-local key names.
get(key)
¶
Return artifact for key or None if unset.
require(key)
¶
Return artifact for key or raise a helpful KeyError.
keys()
¶
items()
¶
values()
¶
path(key, *, required=True)
¶
Resolve an artifact's URI to an absolute host path.
This does not mutate the Artifact; it only returns a resolved Path.
declare_outputs(*names, required=False, warn_undefined=False, description=None)
¶
Declare expected output keys and optional metadata.
missing_declared_outputs()
¶
Return required declared outputs that are still unset.
require_outputs(*names, required=True, warn_undefined=False, description=None)
¶
Convenience wrapper for declaring outputs as required.
collect_by_keys(artifacts, *keys, prefix='')
¶
Copy selected artifact keys into this coupler with an optional prefix.
describe_outputs()
¶
Return a copy of declared-output descriptions.