Repository: microsoft/Qcodes

Issue:
add handling of unknown types to JSON stream
@alexcjohnson @giulioungaretti 





Discussion:

Resolving patch:
diff --git a/qcodes/utils/helpers.py b/qcodes/utils/helpers.py
--- a/qcodes/utils/helpers.py
+++ b/qcodes/utils/helpers.py
@@ -18,6 +18,7 @@ class NumpyJSONEncoder(json.JSONEncoder):
     """Return numpy types as standard types."""
     # http://stackoverflow.com/questions/27050108/convert-numpy-type-to-python
     # http://stackoverflow.com/questions/9452775/converting-numpy-dtypes-to-native-python-types/11389998#11389998
+
     def default(self, obj):
         if isinstance(obj, np.integer):
             return int(obj)
@@ -33,7 +34,12 @@ def default(self, obj):
                 'im': float(obj.imag)
             }
         else:
-            return super(NumpyJSONEncoder, self).default(obj)
+            try:
+                s = super(NumpyJSONEncoder, self).default(obj)
+            except TypeError:
+                # we cannot convert the object to JSON, just take a string
+                s = str(obj)
+            return s
 
 
 def tprint(string, dt=1, tag='default'):
diff --git a/qcodes/utils/validators.py b/qcodes/utils/validators.py
--- a/qcodes/utils/validators.py
+++ b/qcodes/utils/validators.py
@@ -364,7 +364,7 @@ def validate(self, value, context=''):
             if (np.shape(value) != self._shape):
                 raise ValueError(
                     '{} does not have expected shape {}; {}'.format(
-                            repr(value), self._shape, context))
+                        repr(value), self._shape, context))
 
         # Only check if max is not inf as it can be expensive for large arrays
         if self._max_value != (float("inf")):


Test patch:
diff --git a/qcodes/tests/test_helpers.py b/qcodes/tests/test_helpers.py
--- a/qcodes/tests/test_helpers.py
+++ b/qcodes/tests/test_helpers.py
@@ -1,15 +1,19 @@
-from unittest import TestCase
-import time
-from datetime import datetime
 import asyncio
 import json
+import time
+
+from collections import OrderedDict
+from datetime import datetime
+from unittest import TestCase
+
+
 import numpy as np
 
 from qcodes.utils.helpers import (is_sequence, permissive_range, wait_secs,
                                   make_unique, DelegateAttributes,
                                   LogCapture, strip_attrs, full_class,
                                   named_repr, make_sweep, is_sequence_of,
-                                  compare_dictionaries)
+                                  compare_dictionaries, NumpyJSONEncoder)
 from qcodes.utils.deferred_operations import is_function
 
 
@@ -550,6 +554,38 @@ def test_depth(self):
             with self.subTest(args=args):
                 self.assertFalse(is_sequence_of(*args))
 
+# tests related to JSON encoding
+class TestJSONencoder(TestCase):
+
+        def testNumpyJSONEncoder(self):
+            e = NumpyJSONEncoder()
+
+            # test basic python types
+            od = OrderedDict()
+            od['a'] = 0
+            od['b'] = 1
+            testinput=[10, float(10.), 'hello', od]
+            testoutput=['10', '10.0', '"hello"',  '{"a": 0, "b": 1}']
+            # int
+            for d, r in zip(testinput, testoutput):
+                v=e.encode(d)
+                if type(d) == dict:
+                    self.assertDictEqual(v, r)
+                else:
+                    self.assertEqual(v, r)
+
+
+            # test numpy array
+            x=np.array([1,0,0])
+            v=e.encode(x)
+            self.assertEqual(v, '[1, 0, 0]')
+
+            # test class
+            class dummy(object):
+                pass
+            # test that does not raise, do not care about
+            # return value
+            e.encode(dummy())
 
 class TestCompareDictionaries(TestCase):
     def test_same(self):