product: maestro audience: test-developer authority: normative
Local Debugging with a Python Runner Script
The recommended pattern for local Python debugging is a run_local.py script at the
package root that simulates the Maestro execution model — setup → steps → teardown in
order, evaluates measurements, and respects terminate-on-fail and run_on_abort.
pytest IS NOT used because it does not model Maestro execution concepts (no
terminate-on-fail semantics, no run_on_abort guarantee, no measurement evaluation).
Anatomy of run_local.py
Place it at the package root alongside package.json. It imports the test module
directly via sys.path:
import sys
sys.path.insert(0, "python_modules")
import esh10000121_tests as tests
Local settings — values Maestro normally injects, declared as defaults overridable via CLI arguments:
_DEFAULTS = {
"host": "http://agent64.local:5000", # cfg.AGENT_HOST
"product_id": "ESH10000121", # exec.tag.ProductId
"product_revision": "1", # exec.tag.ProductRevision
"serial_number": "DEV-001", # exec.serial_number
}
Step helper — models the key YAML execution control flags:
aborted = False
def step(name, fn, *, args=None, meas_specs=None,
terminate_on_fail=False, run_on_abort=False,
retries=0, retry_delay_s=0.0):
global aborted
if aborted and not run_on_abort:
print(f" - [SKIP ] {name} (aborted)")
return
# invoke fn, evaluate meas_specs, print result, set aborted on fail
Test sequence mirrors the YAML:
# SETUP
step("Connect to Agent", tests.connect, args={"host": host},
retries=2, retry_delay_s=1.0, terminate_on_fail=True)
step("Load Forwarder", tests.load_forwarder, terminate_on_fail=True)
# STEPS
step("Scan I2C", tests.scan_i2c, meas_specs=_I2C_MEASUREMENTS,
terminate_on_fail=True)
step("Test Interconnect", tests.test_interconnect, meas_specs=_MPIO_MEASUREMENTS)
# TEARDOWN
step("Disconnect", tests.disconnect, run_on_abort=True)
Measurement specs can be generated programmatically:
_I2C_MEASUREMENTS = [
(f"I2C_ADDR_0x{a.upper()}", f"i2c_addr_0x{a.upper()}", "true")
for a in ["10", "11", "20", "50", "51"]
]
CLI usage:
python run_local.py
python run_local.py --host http://agent72.local:5000 --serial SN-12345
Exit code 0 = PASS, 1 = FAIL.
What the script does NOT model
| YAML feature | Not modelled because |
|---|---|
timeout_ms: per step |
Thread-safe per-call timeout adds complexity |
force: pass/fail/skip |
Development override — not needed locally |
precondition: expressions |
Write a separate branch in the step function |
repeat: loops |
Write a loop in the step function |
MES routing / exec.tag.* |
Simulated by CLI arguments |