Skip to content

callbacks.OutputToFile always silently fails #1242

Description

@Sporarum

When callbacks.OutputToFile is used as a callback, the test passes with no warning, but the output file is not written to.

We can learn more by looking at the log_records object which does log the error: TypeError: a bytes-like object is required, not 'int'.

Example:

import openhtf
from openhtf.output import callbacks

import logging
logger = logging.getLogger(__name__)

line_break = "\n"

test = openhtf.Test()

test.add_output_callbacks(
  callbacks.OutputToFile("./test.pickle"),
  lambda tr: logger.warning(f"{ line_break.join(list(map(lambda lr: lr.message,tr.log_records)))}")
)

test.execute()

Output:

> python main.py
Tearing down all plugs.
Finishing test execution normally with outcome PASS.
Thread finished: TestExecutorThread
DUT ID is still not set; using default.
Test completed for openhtf_test, outputting now.
Output callback <openhtf.output.callbacks.OutputToFile object at 0x103b39a90> raised:
Traceback (most recent call last):
  File "/Users/<user>/Projects/python-tmp/.venv/lib/python3.13/site-packages/openhtf/core/test_descriptor.py", line 355, in execute
    output_cb(final_state.test_record)
    ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/<user>/Projects/python-tmp/.venv/lib/python3.13/site-packages/openhtf/output/callbacks/__init__.py", line 138, in __call__
    outfile.write(chunk.encode() if isinstance(chunk, str) else chunk)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/<user>/Projects/python-tmp/.venv/lib/python3.13/site-packages/openhtf/output/callbacks/__init__.py", line 48, in write
    return self.temp.write(write_data)
           ~~~~~~~~~~~~~~~^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/python@3.13/3.13.4/Frameworks/Python.framework/Versions/3.13/lib/python3.13/tempfile.py", line 499, in func_wrapper
    return func(*args, **kwargs)
TypeError: a bytes-like object is required, not 'int'

Continuing anyway...

======================= test: openhtf_test  outcome: PASS ======================

This is caused by the following code in openhtf/output/callbacks/__init__.py:

  def __call__(self, test_rec: test_record.TestRecord) -> None:
    with self.open_output_file(test_rec) as outfile:
      serialized_record = self.serialize_test_record(test_rec)
      if isinstance(serialized_record, str):
        outfile.write(serialized_record.encode())
      elif isinstance(serialized_record, Iterable):
        for chunk in serialized_record:
          outfile.write(chunk.encode() if isinstance(chunk, str) else chunk)
      else:
        raise TypeError('Expected string or iterable but got {}.'.format(
            type(serialized_record)))

serialize_record is a bytes (so an Iterables), but this implies chunk is an int, whereas write expects a bytes

Here is one possible fix:

  def __call__(self, test_rec: test_record.TestRecord) -> None:
    with self.open_output_file(test_rec) as outfile:
      serialized_record = self.serialize_test_record(test_rec)
      if isinstance(serialized_record, str):
        outfile.write(serialized_record.encode())
+     elif isinstance(serialized_record, bytes):
+       outfile.write(serialized_record)
      elif isinstance(serialized_record, Iterable):
        for chunk in serialized_record:
          outfile.write(chunk.encode() if isinstance(chunk, str) else chunk)
      else:
        raise TypeError('Expected string or iterable but got {}.'.format(
            type(serialized_record)))

Which seems to work

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions