handle Sequence subclasses (list/tuple/...); convert object arrays to strings (like the default for non-array types); convert built-in bools to ints (like numpy boolean arrays)
This commit is contained in:
@ -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
|
||||
|
@ -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))
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user