script
py3r.behaviour.script lets you run and sweep parameterised Python pipeline scripts without modifying them.
Annotate any scalar script variable with Param and any intermediate result with Output. Both are transparent during normal execution — the script runs unchanged on its own. When invoked via run or sensitivity, parameter values are injected into each subprocess and outputs are captured and returned in a ScriptResults container.
Each iteration runs in a fresh subprocess, so process state never leaks between runs. stop_after_outputs=True combined with outputs= terminates the subprocess as soon as the last requested output is captured, allowing you to short-circuit long pipelines when only early-stage results are needed.
Annotation¶
py3r.behaviour.script.param.Param ¶
Param(
default: bool | int | float | str | None = _MISSING,
*,
name: str,
) -> bool | int | float | str
Mark a script variable as a runner parameter.
In normal script execution, returns default. If no default is given,
raises RuntimeError to signal that the script must be run via
:func:run or :func:sensitivity with a value supplied for this parameter.
When run via :func:run or :func:sensitivity, returns the injected value.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
bool | int | float | str | None
|
Value used during normal execution. Omit to mark the parameter as required (no default — must always be supplied by the runner). |
_MISSING
|
|
str
|
Parameter name, matched against keys passed to |
required |
Examples¶
>>> window = Param(5, name="window")
>>> window
5
>>> type(window)
<class 'int'>
py3r.behaviour.script.param.Output ¶
Output(value: object, *, name: str) -> object
Mark a script value as a runner output to capture.
In normal script execution, returns value unchanged. When run via
:func:run or :func:sensitivity, captures the value under name
in the results.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
object
|
The value to capture. Any type is accepted. |
required |
|
str
|
Output name, used to key results in |
required |
Examples¶
>>> import pandas as pd
>>> df = pd.DataFrame({"a": [1, 2]})
>>> result = Output(df, name="summary")
>>> result is df
True
Running and sweeping¶
py3r.behaviour.script.runner.run ¶
run(
script_path: str | Path,
params: dict[str, Any] | None = None,
*,
outputs: list[str] | None = None,
stop_after_outputs: bool = False,
) -> ScriptResults
Run a parameterised script exactly once with the given parameter values.
Unspecified parameters use their script default. Parameters with no default must be provided.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
str | Path
|
Path to a Python script containing |
required |
|
dict[str, Any] | None
|
Parameter values to inject, keyed by name. Unspecified params use their script default. |
None
|
|
list[str] | None
|
Names of |
None
|
|
bool
|
If True, the subprocess is terminated immediately after the last requested output is captured. |
False
|
Returns:
| Type | Description |
|---|---|
ScriptResults
|
Single-entry results container. Access outputs via |
ScriptResults
|
|
Examples¶
from py3r.behaviour.script import run
sr = run("pipeline.py", {"data_path": "/data/session1", "threshold": 0.8})
summary = sr[{"data_path": "/data/session1", "threshold": 0.8}]["summary"]
Capture only an early output and stop the subprocess before downstream stages run:
sr = run("pipeline.py", {"threshold": 0.8}, outputs=["tracking"], stop_after_outputs=True)
py3r.behaviour.script.runner.sensitivity ¶
sensitivity(
script_path: str | Path,
params: dict[str, list],
*,
nominal: dict[str, Any] | None = None,
outputs: list[str] | None = None,
stop_after_outputs: bool = False,
mode: Literal["independent", "grid"] = "independent",
) -> ScriptResults
Run a parameterised script repeatedly, sweeping flagged :func:Param values.
Each iteration runs in a subprocess. :func:Output values are collected and
returned in a :class:ScriptResults container. Failed iterations are recorded
but do not stop the run.
For each swept parameter, its script default is automatically included in the
sweep (deduplicated silently) and used as the nominal value for independent-mode
sweeps. Use nominal to override this.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
str | Path
|
Path to a Python script containing |
required |
|
dict[str, list]
|
Mapping of parameter name to list of values to sweep. |
required |
|
dict[str, Any] | None
|
Nominal (baseline) values for independent-mode sweeps. Overrides script defaults. Required for any swept parameter that has no script default. |
None
|
|
list[str] | None
|
Names of |
None
|
|
bool
|
If True, each subprocess is terminated after the last requested output is captured. Useful when outputs appear early in a long pipeline. |
False
|
|
Literal['independent', 'grid']
|
|
'independent'
|
Returns:
| Type | Description |
|---|---|
ScriptResults
|
Results container keyed by parameter combination. Access individual |
ScriptResults
|
outputs via |
ScriptResults
|
scalar outputs with |
Examples¶
Independent sweep (default mode) — one parameter varies at a time:
from py3r.behaviour.script import sensitivity
sr = sensitivity("pipeline.py", {"smooth_window": [3, 5, 7], "threshold": [0.5, 0.8]})
df = sr.to_dataframe()
Grid sweep — every combination of parameter values:
sr = sensitivity(
"pipeline.py",
{"smooth_window": [3, 5, 7], "threshold": [0.5, 0.8]},
mode="grid",
)
Required parameter not being swept must be supplied via nominal:
sr = sensitivity(
"pipeline.py",
{"smooth_window": [3, 5, 7]},
nominal={"threshold": 0.8},
)
Early termination — stop each subprocess after the first output is captured, skipping downstream pipeline stages:
sr = sensitivity(
"pipeline.py",
{"smooth_window": [3, 5, 7]},
outputs=["tracking"],
stop_after_outputs=True,
)
py3r.behaviour.script.runner.inspect ¶
inspect(script_path: str | Path) -> None
Print a summary of the :func:Param and :func:Output calls in a script.
Useful for quickly checking what parameters a script exposes, which have defaults, and what outputs it produces — without actually running it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
str | Path
|
Path to a Python script containing |
required |
Examples¶
from py3r.behaviour.script import inspect
inspect("pipeline.py")
# Script: pipeline.py
#
# Parameters:
# data_path default='/my/data' type=str
# smooth_window default=5 type=int
# threshold required
#
# Outputs:
# tracking
# summary
Results¶
py3r.behaviour.script.results.ScriptResults ¶
ScriptResults(
param_names: list[str], output_names: list[str]
)
Container for results returned by :func:run and :func:sensitivity.
Keyed by parameter combination; holds captured :func:Output values per
iteration. Access individual outputs by passing a parameter dict:
sr[{"window": 5}]["summary"]
Flatten scalar outputs across all iterations to a DataFrame:
df = sr.to_dataframe()
Attributes¶
errors : list[tuple[dict, str]]
Failed iterations as (param_dict, error_message) pairs.
errors
property
¶
errors: list[tuple[dict, str]]
Failed iterations as a list of (param_dict, error_message) pairs.
to_dataframe ¶
to_dataframe() -> pd.DataFrame
Flatten scalar outputs into a DataFrame (one row per iteration).
Each row contains the parameter values for that iteration plus one
column per captured scalar output. Raises TypeError if any output
is not a scalar — access those directly via indexing instead.
Returns¶
pd.DataFrame One row per completed iteration; columns are parameter names followed by output names.