Fix unicode encoding issues with records module. (#460)
diff --git a/mobly/records.py b/mobly/records.py
index d9cb555..74dd8f9 100644
--- a/mobly/records.py
+++ b/mobly/records.py
@@ -14,6 +14,8 @@
"""This module has classes for test result collection, and test result output.
"""
+from io import open
+
import collections
import copy
import enum
@@ -115,8 +117,13 @@
new_content['Type'] = entry_type.value
# Both user code and Mobly code can trigger this dump, hence the lock.
with self._lock:
- # Use safe_dump here to avoid language-specific tags in final output.
- with open(self._path, 'a') as f:
+ # For Python3, setting the encoding on yaml.safe_dump does not work
+ # because Python3 file descriptors set an encoding by default, which
+ # PyYAML uses instead of the encoding on yaml.safe_dump. So, the
+ # encoding has to be set on the open call instead.
+ with open(self._path, 'a', encoding='utf-8') as f:
+ # Use safe_dump here to avoid language-specific tags in final
+ # output.
yaml.safe_dump(
new_content,
f,
diff --git a/tests/mobly/records_test.py b/tests/mobly/records_test.py
index 9c795aa..fbbc4f4 100755
--- a/tests/mobly/records_test.py
+++ b/tests/mobly/records_test.py
@@ -13,6 +13,7 @@
# limitations under the License.
from builtins import str
+from io import open
import copy
import mock
@@ -355,10 +356,33 @@
dump_path = os.path.join(self.tmp_path, 'ha.yaml')
writer = records.TestSummaryWriter(dump_path)
writer.dump(record1.to_dict(), records.TestSummaryEntryType.RECORD)
- with open(dump_path, 'r') as f:
+ with open(dump_path, 'r', encoding='utf-8') as f:
content = yaml.load(f)
self.assertEqual(content['Type'],
records.TestSummaryEntryType.RECORD.value)
+ self.assertEqual(content[records.TestResultEnums.RECORD_DETAILS],
+ self.details)
+ self.assertEqual(content[records.TestResultEnums.RECORD_EXTRAS],
+ self.float_extra)
+
+ def test_summary_write_dump_with_unicode(self):
+ unicode_details = u'\u901a' # utf-8 -> b'\xe9\x80\x9a'
+ unicode_extras = u'\u8fc7' # utf-8 -> b'\xe8\xbf\x87'
+ s = signals.TestFailure(unicode_details, unicode_extras)
+ record1 = records.TestResultRecord(self.tn)
+ record1.test_begin()
+ record1.test_fail(s)
+ dump_path = os.path.join(self.tmp_path, 'ha.yaml')
+ writer = records.TestSummaryWriter(dump_path)
+ writer.dump(record1.to_dict(), records.TestSummaryEntryType.RECORD)
+ with open(dump_path, 'r', encoding='utf-8') as f:
+ content = yaml.load(f)
+ self.assertEqual(content['Type'],
+ records.TestSummaryEntryType.RECORD.value)
+ self.assertEqual(content[records.TestResultEnums.RECORD_DETAILS],
+ unicode_details)
+ self.assertEqual(content[records.TestResultEnums.RECORD_EXTRAS],
+ unicode_extras)
def test_summary_user_data(self):
user_data1 = {'a': 1}
@@ -368,7 +392,7 @@
writer = records.TestSummaryWriter(dump_path)
for data in user_data:
writer.dump(data, records.TestSummaryEntryType.USER_DATA)
- with open(dump_path, 'r') as f:
+ with open(dump_path, 'r', encoding='utf-8') as f:
contents = []
for c in yaml.load_all(f):
contents.append(c)