Repository: microsoft/Qcodes

Issue:
numpy types (e.g. int, float) with bit size 8, 16, 32 and 64, etc. not recognized as as non_array_type by data saver
We cannot insert numpy types via the data saver. To reproduce: 

```python
from qcodes import Parameter
from qcodes.dataset.measurements import Measurement
from qcodes.dataset.experiment_container import new_experiment

exp = new_experiment("name", "sample")

x = Parameter("x", set_cmd=None, get_cmd=None)

meas = Measurement()
meas.register_parameter(x)

with meas.run() as datasaver: 
    datasaver.add_result((x, np.float16(1.0)))  # Fails with np.int8, np.int16, etc as well. 
```


Discussion:

Resolving patch:
diff --git a/qcodes/dataset/measurements.py b/qcodes/dataset/measurements.py
--- a/qcodes/dataset/measurements.py
+++ b/qcodes/dataset/measurements.py
@@ -3,7 +3,7 @@
 from time import monotonic
 from collections import OrderedDict
 from typing import (Callable, Union, Dict, Tuple, List, Sequence, cast,
-                    MutableMapping, MutableSequence, Optional)
+                    MutableMapping, MutableSequence, Optional, Any)
 from inspect import signature
 from numbers import Number
 
@@ -19,13 +19,23 @@
 log = logging.getLogger(__name__)
 
 array_like_types = (tuple, list, np.ndarray)
-non_array_like_types = (int, float, str)
 
 
 class ParameterTypeError(Exception):
     pass
 
 
+def is_number(thing: Any) -> bool:
+    """
+    Test if an object can be converted to a number
+    """
+    try:
+        float(thing)
+        return True
+    except (ValueError, TypeError):
+        return False
+
+
 class DataSaver:
     """
     The class used byt the Runner context manager to handle the
@@ -56,7 +66,7 @@ def __init__(self, dataset: DataSet, write_period: float,
 
     def add_result(self,
                    *res_tuple: Tuple[Union[_BaseParameter, str],
-                                     Union[str, int, float, np.ndarray]])-> None:
+                                     Union[str, int, float, np.dtype, np.ndarray]])-> None:
         """
         Add a result to the measurement results. Represents a measurement
         point in the space of measurement parameters, e.g. in an experiment
@@ -114,7 +124,7 @@ def add_result(self,
                                      f'and {array_size}')
                 else:
                     input_size = array_size
-            elif any(isinstance(value, t) for t in non_array_like_types):
+            elif is_number(value) or isinstance(value, str):
                 pass
             else:
                 raise ValueError('Wrong value type received. '


Test patch:
diff --git a/qcodes/tests/dataset/test_datasaver.py b/qcodes/tests/dataset/test_datasaver.py
--- a/qcodes/tests/dataset/test_datasaver.py
+++ b/qcodes/tests/dataset/test_datasaver.py
@@ -1,8 +1,11 @@
 import pytest
 import os
 import tempfile
+import numpy as np
+
 import qcodes as qc
 from qcodes.dataset.measurements import DataSaver
+from qcodes.dataset.param_spec import ParamSpec
 from qcodes.dataset.sqlite_base import connect, init_db
 from qcodes.dataset.database import initialise_database
 
@@ -71,3 +74,42 @@ def test_default_callback(experiment):
         DataSaver.default_callback = None
         if test_set is not None:
             test_set.conn.close()
+
+
+def test_numpy_types(experiment):
+    """
+    Test that we can save numpy types in the data set
+    """
+
+    p = ParamSpec("p", "numeric")
+    test_set = qc.new_data_set("test-dataset")
+    test_set.add_parameter(p)
+
+    data_saver = DataSaver(
+        dataset=test_set, write_period=0, parameters={"p": p})
+
+    dtypes = [np.int8, np.int16, np.int32, np.int64, np.float16, np.float32,
+              np.float64]
+
+    for dtype in dtypes:
+        data_saver.add_result(("p", dtype(2)))
+
+    data_saver.flush_data_to_database()
+    data = test_set.get_data("p")
+    assert data == [[2] for _ in range(len(dtypes))]
+
+
+def test_string(experiment):
+    """
+    Test that we can save text in the data set
+    """
+    p = ParamSpec("p", "text")
+
+    test_set = qc.new_data_set("test-dataset")
+    test_set.add_parameter(p)
+    data_saver = DataSaver(
+        dataset=test_set, write_period=0, parameters={"p": p})
+
+    data_saver.add_result(("p", "some text"))
+    data_saver.flush_data_to_database()
+    assert test_set.get_data("p") == [["some text"]]