diff --git a/morioc/pvinfo.py b/morioc/pvinfo.py index e212544..253a971 100644 --- a/morioc/pvinfo.py +++ b/morioc/pvinfo.py @@ -1,3 +1,4 @@ +from collections.abc import Sequence import numpy as np @@ -33,11 +34,15 @@ class PVInfo: -def infer_type(value, parse_string=True): #TODO lists/tuples/...? char vs. strings? +def infer_type(value, parse_string=True): #TODO char vs. strings? + if isinstance(value, Sequence) and not isinstance(value, str): + value = np.array(value) # rely on numpy to figure out a consistent dtype + if isinstance(value, np.ndarray): return infer_type_numpy(value) #TODO: also parse strings for np arrays?! elif isinstance(value, np.generic): # covers all numpy scalars value = value.item() + return infer_type_scalar(value, parse_string=parse_string) @@ -74,8 +79,9 @@ def infer_type_scalar(value, parse_string=True): def infer_type_numpy(arr): + # cannot infer a single type from object arrays, default to string representation if arr.dtype == object: - raise NotImplementedError("cannot infer a single type from object arrays") + return "string", str(arr.tolist()) # bool -> int if arr.dtype == bool: @@ -83,7 +89,7 @@ def infer_type_numpy(arr): # epics only allows 1D, and needs conversion to built-in data types lst = arr.ravel().tolist() - dtype, _ = infer_type_scalar(lst[0]) + dtype, _ = infer_type_scalar(lst[0]) # TODO: is taking the first element safe? object arrays are ruled out above... count = len(lst) return dtype, lst, count diff --git a/morioc/test_infer_type.py b/morioc/test_infer_type.py index 0824b96..51ffd75 100755 --- a/morioc/test_infer_type.py +++ b/morioc/test_infer_type.py @@ -66,11 +66,9 @@ def test_it_None(): assert it(None) == ("string", "None") def test_it_True(): -# assert it(True) == ("string", "True") assert it(True) == ("int", 1) def test_it_False(): -# assert it(False) == ("string", "False") assert it(False) == ("int", 0) def test_it_nan(): @@ -116,11 +114,9 @@ def test_it_np1D_bool(): def test_it_np1D_object(): arr = np.array([None]) # gives dtype=object - with pytest.raises(NotImplementedError): - it(arr) + assert it(arr) == ("string", "[None]") arr = np.array(["test", 123, 1.23], dtype=object) - with pytest.raises(NotImplementedError): - it(arr) + assert it(arr) == ("string", "['test', 123, 1.23]") def test_it_np_scalar_int(): @@ -137,6 +133,20 @@ def test_it_np_scalar_bool(): scalar = np.array(True)[()] ref = scalar.item() assert it(scalar) == ("int", 1) + scalar = np.array(False)[()] + ref = scalar.item() + assert it(scalar) == ("int", 0) + + +def test_it_list(): + dat = [0, 1, 2] + ref = dat + assert it(dat) == ("int", ref, len(ref)) + +def test_it_tuple(): + dat = (0, 1, 2) + ref = list(dat) + assert it(dat) == ("int", ref, len(ref))