We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Attaching binary file using test.attach raises UnicodeDecodeError
If I attach a png or avi I see the following in OutputTestRecord

Python2.7/site-packages/openhtf/**init**.py", line 185, in OutputTestRecord
    output_cb(test_record)
  File "virtualenv/local/lib/python2.7/site-packages/openhtf/**init**.py", line 83, in **call**
    f.write(self.encode(as_dict))
  File "/usr/lib/python2.7/json/encoder.py", line 209, in encode
    chunks = list(chunks)
  File "/usr/lib/python2.7/json/encoder.py", line 434, in _iterencode
    for chunk in _iterencode_dict(o, _current_indent_level):
  File "/usr/lib/python2.7/json/encoder.py", line 408, in _iterencode_dict
    for chunk in chunks:
  File "/usr/lib/python2.7/json/encoder.py", line 332, in _iterencode_list
    for chunk in chunks:
  File "/usr/lib/python2.7/json/encoder.py", line 408, in _iterencode_dict
    for chunk in chunks:
  File "/usr/lib/python2.7/json/encoder.py", line 408, in _iterencode_dict
    for chunk in chunks:
  File "/usr/lib/python2.7/json/encoder.py", line 390, in _iterencode_dict
    yield _encoder(value)
UnicodeDecodeError: 'utf8' codec can't decode byte 0x89 in position 0: invalid start byte


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `openhtf/io/output/json_factory.py`
Content:
```
1 """Module for outputting test record to JSON-formatted files."""
2 
3 from json import JSONEncoder
4 
5 from openhtf import util
6 from openhtf.exe import test_state
7 
8 
9 class OutputToJSON(JSONEncoder):
10   """Return an output callback that writes JSON Test Records.
11 
12   An example filename_pattern might be:
13     '/data/test_records/%(dut_id)s.%(start_time_millis)s'
14 
15   To use this output mechanism:
16     test = openhtf.Test(PhaseOne, PhaseTwo)
17     test.AddOutputCallback(openhtf.OutputToJson(
18         '/data/test_records/%(dut_id)s.%(start_time_millis)s'))
19 
20   Args:
21     filename_pattern: A format string specifying the filename to write to,
22       will be formatted with the Test Record as a dictionary.
23     inline_attachments: Whether attachments should be included inline in the
24       output.  Set to False if you expect to have large binary attachments.
25   """
26 
27   def __init__(self, filename_pattern=None, inline_attachments=True, **kwargs):
28     super(OutputToJSON, self).__init__(**kwargs)
29     self.filename_pattern = filename_pattern
30     self.inline_attachments = inline_attachments
31 
32   def default(self, obj):
33     if isinstance(obj, BaseException):
34       # Just repr exceptions.
35       return repr(obj)
36     return super(OutputToJSON, self).default(obj)
37 
38   # pylint: disable=invalid-name
39   def __call__(self, test_record):
40     assert self.filename_pattern, 'filename_pattern required'
41     if self.inline_attachments:
42       as_dict = util.ConvertToBaseTypes(test_record)
43     else:
44       as_dict = util.ConvertToBaseTypes(test_record, ignore_keys='attachments')
45     with open(self.filename_pattern % as_dict, 'w') as f:
46       f.write(self.encode(as_dict))
47   # pylint: enable=invalid-name
48
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/openhtf/io/output/json_factory.py b/openhtf/io/output/json_factory.py
--- a/openhtf/io/output/json_factory.py
+++ b/openhtf/io/output/json_factory.py
@@ -1,5 +1,6 @@
 """Module for outputting test record to JSON-formatted files."""
 
+import base64
 from json import JSONEncoder
 
 from openhtf import util
@@ -21,7 +22,9 @@
     filename_pattern: A format string specifying the filename to write to,
       will be formatted with the Test Record as a dictionary.
     inline_attachments: Whether attachments should be included inline in the
-      output.  Set to False if you expect to have large binary attachments.
+      output. Set to False if you expect to have large binary attachments. If
+      True (the default), then attachments are base64 encoded to allow for
+      binary data that's not supported by JSON directly.
   """
 
   def __init__(self, filename_pattern=None, inline_attachments=True, **kwargs):
@@ -40,6 +43,9 @@
     assert self.filename_pattern, 'filename_pattern required'
     if self.inline_attachments:
       as_dict = util.ConvertToBaseTypes(test_record)
+      for phase in as_dict['phases']:
+        for value in phase['attachments'].itervalues():
+          value['data'] = base64.standard_b64encode(value['data'])
     else:
       as_dict = util.ConvertToBaseTypes(test_record, ignore_keys='attachments')
     with open(self.filename_pattern % as_dict, 'w') as f:

{"golden_diff": "diff --git a/openhtf/io/output/json_factory.py b/openhtf/io/output/json_factory.py\n--- a/openhtf/io/output/json_factory.py\n+++ b/openhtf/io/output/json_factory.py\n@@ -1,5 +1,6 @@\n \"\"\"Module for outputting test record to JSON-formatted files.\"\"\"\n \n+import base64\n from json import JSONEncoder\n \n from openhtf import util\n@@ -21,7 +22,9 @@\n     filename_pattern: A format string specifying the filename to write to,\n       will be formatted with the Test Record as a dictionary.\n     inline_attachments: Whether attachments should be included inline in the\n-      output.  Set to False if you expect to have large binary attachments.\n+      output. Set to False if you expect to have large binary attachments. If\n+      True (the default), then attachments are base64 encoded to allow for\n+      binary data that's not supported by JSON directly.\n   \"\"\"\n \n   def __init__(self, filename_pattern=None, inline_attachments=True, **kwargs):\n@@ -40,6 +43,9 @@\n     assert self.filename_pattern, 'filename_pattern required'\n     if self.inline_attachments:\n       as_dict = util.ConvertToBaseTypes(test_record)\n+      for phase in as_dict['phases']:\n+        for value in phase['attachments'].itervalues():\n+          value['data'] = base64.standard_b64encode(value['data'])\n     else:\n       as_dict = util.ConvertToBaseTypes(test_record, ignore_keys='attachments')\n     with open(self.filename_pattern % as_dict, 'w') as f:\n", "issue": "Attaching binary file using test.attach raises UnicodeDecodeError\nIf I attach a png or avi I see the following in OutputTestRecord\n\nPython2.7/site-packages/openhtf/**init**.py\", line 185, in OutputTestRecord\n    output_cb(test_record)\n  File \"virtualenv/local/lib/python2.7/site-packages/openhtf/**init**.py\", line 83, in **call**\n    f.write(self.encode(as_dict))\n  File \"/usr/lib/python2.7/json/encoder.py\", line 209, in encode\n    chunks = list(chunks)\n  File \"/usr/lib/python2.7/json/encoder.py\", line 434, in _iterencode\n    for chunk in _iterencode_dict(o, _current_indent_level):\n  File \"/usr/lib/python2.7/json/encoder.py\", line 408, in _iterencode_dict\n    for chunk in chunks:\n  File \"/usr/lib/python2.7/json/encoder.py\", line 332, in _iterencode_list\n    for chunk in chunks:\n  File \"/usr/lib/python2.7/json/encoder.py\", line 408, in _iterencode_dict\n    for chunk in chunks:\n  File \"/usr/lib/python2.7/json/encoder.py\", line 408, in _iterencode_dict\n    for chunk in chunks:\n  File \"/usr/lib/python2.7/json/encoder.py\", line 390, in _iterencode_dict\n    yield _encoder(value)\nUnicodeDecodeError: 'utf8' codec can't decode byte 0x89 in position 0: invalid start byte\n\n", "before_files": [{"content": "\"\"\"Module for outputting test record to JSON-formatted files.\"\"\"\n\nfrom json import JSONEncoder\n\nfrom openhtf import util\nfrom openhtf.exe import test_state\n\n\nclass OutputToJSON(JSONEncoder):\n  \"\"\"Return an output callback that writes JSON Test Records.\n\n  An example filename_pattern might be:\n    '/data/test_records/%(dut_id)s.%(start_time_millis)s'\n\n  To use this output mechanism:\n    test = openhtf.Test(PhaseOne, PhaseTwo)\n    test.AddOutputCallback(openhtf.OutputToJson(\n        '/data/test_records/%(dut_id)s.%(start_time_millis)s'))\n\n  Args:\n    filename_pattern: A format string specifying the filename to write to,\n      will be formatted with the Test Record as a dictionary.\n    inline_attachments: Whether attachments should be included inline in the\n      output.  Set to False if you expect to have large binary attachments.\n  \"\"\"\n\n  def __init__(self, filename_pattern=None, inline_attachments=True, **kwargs):\n    super(OutputToJSON, self).__init__(**kwargs)\n    self.filename_pattern = filename_pattern\n    self.inline_attachments = inline_attachments\n\n  def default(self, obj):\n    if isinstance(obj, BaseException):\n      # Just repr exceptions.\n      return repr(obj)\n    return super(OutputToJSON, self).default(obj)\n\n  # pylint: disable=invalid-name\n  def __call__(self, test_record):\n    assert self.filename_pattern, 'filename_pattern required'\n    if self.inline_attachments:\n      as_dict = util.ConvertToBaseTypes(test_record)\n    else:\n      as_dict = util.ConvertToBaseTypes(test_record, ignore_keys='attachments')\n    with open(self.filename_pattern % as_dict, 'w') as f:\n      f.write(self.encode(as_dict))\n  # pylint: enable=invalid-name\n", "path": "openhtf/io/output/json_factory.py"}], "after_files": [{"content": "\"\"\"Module for outputting test record to JSON-formatted files.\"\"\"\n\nimport base64\nfrom json import JSONEncoder\n\nfrom openhtf import util\nfrom openhtf.exe import test_state\n\n\nclass OutputToJSON(JSONEncoder):\n  \"\"\"Return an output callback that writes JSON Test Records.\n\n  An example filename_pattern might be:\n    '/data/test_records/%(dut_id)s.%(start_time_millis)s'\n\n  To use this output mechanism:\n    test = openhtf.Test(PhaseOne, PhaseTwo)\n    test.AddOutputCallback(openhtf.OutputToJson(\n        '/data/test_records/%(dut_id)s.%(start_time_millis)s'))\n\n  Args:\n    filename_pattern: A format string specifying the filename to write to,\n      will be formatted with the Test Record as a dictionary.\n    inline_attachments: Whether attachments should be included inline in the\n      output. Set to False if you expect to have large binary attachments. If\n      True (the default), then attachments are base64 encoded to allow for\n      binary data that's not supported by JSON directly.\n  \"\"\"\n\n  def __init__(self, filename_pattern=None, inline_attachments=True, **kwargs):\n    super(OutputToJSON, self).__init__(**kwargs)\n    self.filename_pattern = filename_pattern\n    self.inline_attachments = inline_attachments\n\n  def default(self, obj):\n    if isinstance(obj, BaseException):\n      # Just repr exceptions.\n      return repr(obj)\n    return super(OutputToJSON, self).default(obj)\n\n  # pylint: disable=invalid-name\n  def __call__(self, test_record):\n    assert self.filename_pattern, 'filename_pattern required'\n    if self.inline_attachments:\n      as_dict = util.ConvertToBaseTypes(test_record)\n      for phase in as_dict['phases']:\n        for value in phase['attachments'].itervalues():\n          value['data'] = base64.standard_b64encode(value['data'])\n    else:\n      as_dict = util.ConvertToBaseTypes(test_record, ignore_keys='attachments')\n    with open(self.filename_pattern % as_dict, 'w') as f:\n      f.write(self.encode(as_dict))\n  # pylint: enable=invalid-name\n", "path": "openhtf/io/output/json_factory.py"}]}