PyTango client: reconnection issue with DevEnum if enum numbers changed
Let's consider the following python device server:
from enum import IntEnum
from tango.server import Device, attribute, command
class FillingModeType(IntEnum):
UNIFORM = 0
FOUR_BUNCHES = 1
SIXTEEN_BUNCHES = 2
class TestEnum(Device):
fill_mode = FillingModeType.UNIFORM
@attribute
def filling_mode(self) -> FillingModeType:
return self.fill_mode
@filling_mode.setter
def filling_mode(self, filli_mode: int):
# note that we receive an integer, not an enum instance,
# so we have to convert that to an instance of our enum.
self.fill_mode = FillingModeType(filli_mode)
if __name__ == "__main__":
TestEnum.run_server()
Now let's consider a client like the following one:
import sys
import tango
if len(sys.argv) != 2:
print("must provide one and only one TestEnum device name")
sys.exit(1)
test_enum = tango.DeviceProxy(sys.argv[1])
try:
filling_mode = test_enum.filling_mode
print("filling_mode at client startup:")
print(filling_mode, filling_mode.name, filling_mode.value)
except Exception as ex:
print("Exception caught at read: ", ex)
while True:
new_filling_mode = input("New Filling Mode? --> ")
print("Setting filling_mode to \"", new_filling_mode, "\"")
try:
test_enum.filling_mode = new_filling_mode
except Exception as ex:
print("Exception caught at write: ", ex)
try:
filling_mode = test_enum.filling_mode
print(filling_mode, filling_mode.name, filling_mode.value)
except Exception as ex:
print("Exception caught at read: ", ex)
This client reads the filling_mode attribute and gives the possibility to set a new value for the filling mode attribute, by passing a string representing the enum value.
If the user provides a string value which does not corresponds to an existing enum value, an exception is thrown on the client side:
New Filling Mode? --> BLABLA
Exception caught at write: Invalid enum value 2 for attribute filling_mode Valid values: ['UNIFORM', 'FOUR_BUNCHES', 'SIXTEEN_BUNCHES']
Now, if we keep the client running and restart the Device server, but with a new version which is the same as the previous server version, except the FillingModeType slightly modified like this:
class FillingModeType(IntEnum):
UNIFORM = 0
FOUR_BUNCHES = 1
EIGHT_BUNCHES = 2
SIXTEEN_BUNCHES = 3
The client will reconnect correctly but we will start to get into trouble when the client will try to set the filling_mode to SIXTEEN_BUNCHES. In the previous version of the server, SIXTEEN_BUNCHES was corresponding to enum value 2 and now it corresponds to enum value 3. What we observe is that the value 2 is sent by the client in this case and the device server filling mode is set to EIGHT_BUNCHES instead of SIXTEEN_BUNCHES requested by the client.
If we try to set the attribute value to 'EIGHT_BUNCHES' from the client (not restarted), then we get this exception:
Exception caught at write: Invalid enum value EIGHT_BUNCHES for attribute filling_mode Valid values: ['UNIFORM', 'FOUR_BUNCHES', 'SIXTEEN_BUNCHES']
Do you think we could find a way to update the client knowledge at device reconnection to ensure that the enum value sent on the wire corresponds to the string of the enum field in this use case?