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

Overview
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 dynamically at runtime instead of using static decorator syntax. This is useful when you need to configure decorators based on runtime conditions.
main.py
import openhtf as htf
def phase_resistance_test(test):
test.measurements.resistance = 10.5
def main():
min_resistance = 5 # Dynamic parameters
max_resistance = 17
measurement = htf.Measurement('resistance').in_range(min_resistance, max_resistance)
configured_phase = htf.measures(measurement)(phase_resistance_test)
test = htf.Test([configured_phase])
test.execute(lambda: "SN1234")
if __name__ == "__main__":
main()
This pattern allows you to:
- Load decorator parameters from configuration files
- Calculate validation limits based on runtime conditions
- Create phases with parameters determined by user input
- Build test sequences dynamically based on device specifications
You can apply the same pattern to other OpenHTF decorators like @htf.plug
and @htf.PhaseOptions
that need runtime configuration. For more comprehensive examples and advanced measurement patterns, see the advanced Measurements use cases in the documentation.