Decorators

Learn how to use OpenHTF decorators to enhance your test phases with measurements, hardware plugins, and execution configuration.

Last updated · Verified with OpenHTF 1.6.1

Learn how to use OpenHTF decorators to enhance your test phases.

Decorators stack on a phase function. PhaseOptions configures execution, measures declares the measurements the phase records, and plug injects the hardware plug the phase receives as an argument.

  • @htf.PhaseOptions(timeout_s=30)execution: 30 s timeout
  • @htf.measures(Measurement("voltage"))
  • @htf.plug(dmm=MultimeterPlug)
  • def phase_voltage(test, dmm)

Python decorators modify function behavior without changing their code. In OpenHTF, decorators add functionality to test phases like declaring measurements, injecting hardware plugins, and configuring execution. They're applied using the @ symbol before function definitions:

@decorator_function
def my_function():
    pass

Key decorators

OpenHTF provides several essential decorators that make test writing more powerful and organized:

1. Declaring measurements

The @htf.measures decorator is used to declare what measurements a phase will capture and validate:

@htf.measures(
    htf.Measurement("temperature")
    .in_range(0, 100)
    .with_units(units.DEGREE_CELSIUS)
    .with_precision(1)
)
def measure_temperature(test):
    test.measurements.temperature = 25.5

2. Hardware plugin injection

The @htf.plug decorator injects hardware or software plugins into your test phases:

@htf.plug(multimeter=MultimeterPlug)
def test_voltage(test, multimeter):
    voltage = multimeter.measure_voltage()
    test.measurements.voltage = voltage

3. Phase configuration

The @htf.PhaseOptions decorator configures how a phase should execute:

@htf.PhaseOptions(timeout_s=10, repeat_limit=3)
def retry_phase(test):
    # Phase will timeout after 10 seconds and can retry up to 3 times
    return htf.PhaseResult.CONTINUE

Combining

OpenHTF decorators can be combined to create powerful test phases:

@htf.measures(
    htf.Measurement("firmware_version").equals("1.2.4"),
    htf.Measurement("connection_status").equals(True)
)
@htf.plug(device=DeviceConnection)
@htf.PhaseOptions(timeout_s=30)
def verify_device_connection(test, device):
    test.measurements.connection_status = device.is_connected()
    test.measurements.firmware_version = device.get_firmware_version()

Enhanced example

Let's enhance our first test to demonstrate decorator usage:

main.py
import openhtf as htf

@htf.measures(
    htf.Measurement("greeting_message").with_validator(
        lambda msg: "Hello" in msg
    )
)
@htf.PhaseOptions(timeout_s=5)
def hello_world_with_measurement(test):
    message = "Hello world!"
    print(message)
    test.measurements.greeting_message = message

def main():
    test = htf.Test(hello_world_with_measurement)
    test.execute(lambda: "SN1234")

if __name__ == '__main__':
    main()

This enhanced version demonstrates:

  • Measurement validation using @htf.measures
  • Phase timeout using @htf.PhaseOptions
  • Custom validation with lambda functions

Understanding these decorators is crucial for building robust OpenHTF tests that can validate measurements, interact with hardware, and handle various execution scenarios.

Dynamic configuration

Python decorators are callables, which means you can apply them at runtime instead of with the @ syntax: htf.measures(m)(phase) returns the decorated phase. This is how you build phases whose limits come from a config file, a product database or operator input.

main.py
import openhtf as htf

def phase_resistance_test(test):
    test.measurements.resistance = 10.5

def main():
    limits = {"min": 5, "max": 17}   # e.g. loaded from YAML per part number

    measurement = htf.Measurement("resistance").in_range(limits["min"], limits["max"])
    configured_phase = htf.PhaseOptions(timeout_s=10)(
        htf.measures(measurement)(phase_resistance_test)
    )

    test = htf.Test(configured_phase)
    test.execute(lambda: "SN1234")

if __name__ == "__main__":
    main()

The same works for @htf.plug. A worked measurement example is under Callable decorators.

Other decorators

Beyond the three above, OpenHTF exposes:

@htf.diagnose(*diagnosers)

Attach phase diagnosers that classify the phase's results.

@htf.monitors(name, func, units=, poll_interval_ms=)

Sample a value in a background thread while the phase runs — see Monitors.

@CONF.save_and_restore(**overrides)

Temporarily override configuration values for one phase.

@CONF.inject_positional_args

Fill a plug's __init__ arguments from configuration keys of the same name.

phase.with_args(**kwargs) / phase.with_plugs(**plugs)

Not decorators but the same idea: return a copy of a phase with template arguments or plug placeholders filled in. Used in the with_plugs example.

On this page

First-pass yield
0%4.1
Track with TofuPilot