DevEnum spectrum and image attributes don't work with high-level client API
Using a DeviceProxy
to access spectrum and image attributes of type DevEnum fails.
For example, using the TangoTest device (version 3.6), we get a `TypeError`.
>>> dp = tango.DeviceProxy("tango://localhost:8090/sys/tg_test/18#dbase=no")
>>> dp.enum_scalar
<enum_scalar.LABEL0: 0>
>>> dp.enum_spectrum
Traceback (most recent call last):
File "/opt/my/env/lib/python3.10/enum.py", line 688, in __new__
return cls._value2member_map_[value]
TypeError: unhashable type: 'numpy.ndarray'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/user/pytango/tango/device_proxy.py", line 326, in __DeviceProxy__getattr
return __get_attribute_value(self, attr_info, name)
File "/home/user/pytango/tango/device_proxy.py", line 289, in __get_attribute_value
return enum_class(attr_value)
File "/opt/my/env/lib/python3.10/enum.py", line 385, in __call__
return cls.__new__(cls, value)
File "/opt/my/env/lib/python3.10/enum.py", line 695, in __new__
if member._value_ == value:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> dp.enum_image
Traceback (most recent call last):
File "/opt/my/env/lib/python3.10/enum.py", line 688, in __new__
return cls._value2member_map_[value]
TypeError: unhashable type: 'numpy.ndarray'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/user/pytango/tango/device_proxy.py", line 326, in __DeviceProxy__getattr
return __get_attribute_value(self, attr_info, name)
File "/home/user/pytango/tango/device_proxy.py", line 289, in __get_attribute_value
return enum_class(attr_value)
File "/opt/my/env/lib/python3.10/enum.py", line 385, in __call__
return cls.__new__(cls, value)
File "/opt/my/env/lib/python3.10/enum.py", line 695, in __new__
if member._value_ == value:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>>
The low-level API works fine.
>>> dp.read_attribute("enum_spectrum")
DeviceAttribute(data_format = tango._tango.AttrDataFormat.SPECTRUM, dim_x = 256, dim_y = 0, has_failed = False, is_empty = False, name = 'enum_spectrum', nb_read = 256, nb_written = 1, quality = tango._tango.AttrQuality.ATTR_VALID, r_dimension = AttributeDimension(dim_x = 256, dim_y = 0), time = TimeVal(tv_nsec = 0, tv_sec = 1667469524, tv_usec = 792644), type = tango._tango.CmdArgType.DevEnum, value = array([0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1,
0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0,
0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0,
0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1,
0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1,
0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1,
1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0,
0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1,
0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0], dtype=int16), w_dim_x = 1, w_dim_y = 0, w_dimension = AttributeDimension(dim_x = 1, dim_y = 0), w_value = array([0], dtype=int16))
>>> dp.read_attribute("enum_image")
DeviceAttribute(data_format = tango._tango.AttrDataFormat.IMAGE, dim_x = 251, dim_y = 251, has_failed = False, is_empty = False, name = 'enum_image', nb_read = 63001, nb_written = 1, quality = tango._tango.AttrQuality.ATTR_VALID, r_dimension = AttributeDimension(dim_x = 251, dim_y = 251), time = TimeVal(tv_nsec = 0, tv_sec = 1667469534, tv_usec = 864271), type = tango._tango.CmdArgType.DevEnum, value = array([[1, 1, 1, ..., 1, 0, 0],
[0, 0, 0, ..., 0, 1, 0],
[1, 0, 1, ..., 0, 1, 1],
...,
[0, 1, 0, ..., 0, 0, 1],
[1, 0, 0, ..., 1, 0, 1],
[0, 1, 0, ..., 1, 0, 1]], dtype=int16), w_dim_x = 1, w_dim_y = 0, w_dimension = AttributeDimension(dim_x = 1, dim_y = 0), w_value = array([], shape=(0, 1), dtype=int16))
The problem is likely in __get_attribute_value
. When getting the attribute value, we should be creating an array of enums.
When setting value, __set_attribute_value
, I'm not sure what options we should support. I guess arrays of enums, and arrays of strings would be convenient.
The unit tests in test_client.py
must be extend to test this (at least for Synchronous device proxy). E.g., for a reading, add a new test that does getattr(tango_test, readable_attribute)
instead of tango_test.read_attribute(readable_attribute, wait=True)
. Test for writing are needed too.