With Plugs Example
The upstream with_plugs.py example — write one phase against a plug placeholder, then generate several phases with phase.with_plugs() and with_args(), each with its own name and measurement.
Last updated · Verified with OpenHTF 1.6.1
One phase, three instances. When the same check must run against several interfaces (four NICs, three power rails, two radios), write the phase once against a placeholder plug and stamp out concrete phases with with_plugs(). Based on examples/with_plugs.py.
import subprocess
import time
import openhtf as htf
from openhtf.core import base_plugs
class PingPlug(base_plugs.BasePlug):
"""Pings self.host. Only subclasses set host, so only subclasses are usable."""
host = None
def __init__(self):
assert self.host is not None
def _get_command(self, count):
return ['ping', '-c', str(count), self.host]
def run(self, count):
command = self._get_command(count)
print('running: %s' % ' '.join(command))
return subprocess.call(command)
class PingGoogle(PingPlug):
host = 'google.com'
class PingDnsA(PingPlug):
host = '8.8.8.8'
class PingDnsB(PingPlug):
host = '8.8.4.4'
# Phase name and measurement name are templates filled from the plug and args.
@htf.PhaseOptions(name='Ping-{pinger.host}-{count}')
@htf.plug(pinger=PingPlug.placeholder)
@htf.measures('total_time_{pinger.host}_{count}',
htf.Measurement('retcode').equals('{expected_retcode}', type=str))
def test_ping(test, pinger, count, expected_retcode):
del expected_retcode # Only the measurement uses it.
start = time.time()
retcode = pinger.run(count)
elapsed = time.time() - start
test.measurements['total_time_%s_%s' % (pinger.host, count)] = elapsed
test.measurements.retcode = retcode
def main():
ping_plugs = [PingGoogle, PingDnsA, PingDnsB]
phases = [
test_ping.with_plugs(pinger=plug).with_args(count=2, expected_retcode=0)
for plug in ping_plugs
]
test = htf.Test(*phases)
test.execute(test_start=lambda: 'MyDutId')
if __name__ == '__main__':
main()$ python with_plugs.py
running: ping -c 2 google.com
...
running: ping -c 2 8.8.8.8
...
running: ping -c 2 8.8.4.4
...
======================= test: openhtf_test outcome: PASS ======================The record contains three phases — Ping-google.com-2, Ping-8.8.8.8-2, Ping-8.8.4.4-2 — each with its own total_time_<host>_2 and retcode measurements. On Windows replace -c with -n.
What it shows
PingPlug.placeholderEvery BasePlug subclass has a .placeholder attribute. Decorating with a placeholder makes the phase abstract: it cannot run until with_plugs() substitutes a concrete subclass.
phase.with_plugs(pinger=PingGoogle)Returns a copy of the phase with the placeholder replaced. The substitute must be a subclass of the placeholder's class.
phase.with_args(count=2, expected_retcode=0)Fills extra positional parameters of the phase function and any {count}-style templates in the phase name, measurement names and validator arguments. Dynamic naming →
'{pinger.host}' in namesTemplates can reach into plug attributes, so each generated phase and measurement is uniquely named in the record.
.equals('{expected_retcode}', type=str)A templated validator argument. type=str tells the validator how to cast the substituted string.
When to use it
- Per-channel tests:
with_plugs(rail=Rail3V3),with_plugs(rail=Rail5V), ... over onemeasure_railphase. - The same DUT test across several fixtures or instruments, selecting the plug subclass from configuration.
- Table-driven test plans: build the
phaseslist from a CSV of (channel, limit) rows.
For plug instances that differ only by constructor arguments (two multimeters on two COM ports), configuration.bind_init_args is the lighter tool — see Multiple plug configuration.
Next
Measurements
The upstream measurements.py example explained — string and numeric measurements, inline kwargs declaration, validators, units, a multi-dimensional power time series converted to a pandas DataFrame, and marginal limits.
Phase groups
The upstream phase_groups.py example — six runs showing exactly when OpenHTF executes teardown phases after setup errors, main errors, nested groups and errors inside nested groups.