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
|
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):
|
if isinstance(value, np.ndarray):
|
||||||
return infer_type_numpy(value) #TODO: also parse strings for np arrays?!
|
return infer_type_numpy(value) #TODO: also parse strings for np arrays?!
|
||||||
elif isinstance(value, np.generic): # covers all numpy scalars
|
elif isinstance(value, np.generic): # covers all numpy scalars
|
||||||
value = value.item()
|
value = value.item()
|
||||||
|
|
||||||
return infer_type_scalar(value, parse_string=parse_string)
|
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):
|
def infer_type_numpy(arr):
|
||||||
|
# cannot infer a single type from object arrays, default to string representation
|
||||||
if arr.dtype == object:
|
if arr.dtype == object:
|
||||||
raise NotImplementedError("cannot infer a single type from object arrays")
|
return "string", str(arr.tolist())
|
||||||
|
|
||||||
# bool -> int
|
# bool -> int
|
||||||
if arr.dtype == bool:
|
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
|
# epics only allows 1D, and needs conversion to built-in data types
|
||||||
lst = arr.ravel().tolist()
|
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)
|
count = len(lst)
|
||||||
|
|
||||||
return dtype, lst, count
|
return dtype, lst, count
|
||||||
|
@ -66,11 +66,9 @@ def test_it_None():
|
|||||||
assert it(None) == ("string", "None")
|
assert it(None) == ("string", "None")
|
||||||
|
|
||||||
def test_it_True():
|
def test_it_True():
|
||||||
# assert it(True) == ("string", "True")
|
|
||||||
assert it(True) == ("int", 1)
|
assert it(True) == ("int", 1)
|
||||||
|
|
||||||
def test_it_False():
|
def test_it_False():
|
||||||
# assert it(False) == ("string", "False")
|
|
||||||
assert it(False) == ("int", 0)
|
assert it(False) == ("int", 0)
|
||||||
|
|
||||||
def test_it_nan():
|
def test_it_nan():
|
||||||
@ -116,11 +114,9 @@ def test_it_np1D_bool():
|
|||||||
|
|
||||||
def test_it_np1D_object():
|
def test_it_np1D_object():
|
||||||
arr = np.array([None]) # gives dtype=object
|
arr = np.array([None]) # gives dtype=object
|
||||||
with pytest.raises(NotImplementedError):
|
assert it(arr) == ("string", "[None]")
|
||||||
it(arr)
|
|
||||||
arr = np.array(["test", 123, 1.23], dtype=object)
|
arr = np.array(["test", 123, 1.23], dtype=object)
|
||||||
with pytest.raises(NotImplementedError):
|
assert it(arr) == ("string", "['test', 123, 1.23]")
|
||||||
it(arr)
|
|
||||||
|
|
||||||
|
|
||||||
def test_it_np_scalar_int():
|
def test_it_np_scalar_int():
|
||||||
@ -137,6 +133,20 @@ def test_it_np_scalar_bool():
|
|||||||
scalar = np.array(True)[()]
|
scalar = np.array(True)[()]
|
||||||
ref = scalar.item()
|
ref = scalar.item()
|
||||||
assert it(scalar) == ("int", 1)
|
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