Inconsistency in encoding between PyTango.LatestDeviceImpl.get_attribute_config_3 and set_attribute_config_3 on the unit field
We need to change the unit of certain parameters during runtime. To do this, we use the following code:
config = self.get_attribute_config_3([name])[0]
config.unit = newUnit
self.set_attribute_config_3([config])
In cases where the unit uses non-latin-1 characters such as "°C" or "m²", the behavior of get_attribute_config_3 and set_attribute_config_3 becomes complex.
If the variable ORBnativeCharCodeSet is not set, get_attribute_config_3 raises an exception when the previous unit contains non-latin-1 characters. If the variable ORBnativeCharCodeSet is set to "UTF-8", get_attribute_config_3 works, and the unit is encoded in UTF-8, directly usable. However, the set_attribute_config_3 method raises an encoding exception, so the unit must be encoded even if it is not changed.
Here is an example of a server device highlighting the issue. It is a device that exposes an attribute, "anAttr," which is initially set to "°C" and changes to "m²" at startup. The device also exposes a command that allows switching the unit between "°C" and "m²."
Example
from tango import Database, DbDevInfo
from tango.server import Device, attribute, command
from tango.server import class_property, device_property
class Dummy(Device):
@attribute(unit='°C')
def anAttr(self):
return 10.0
@command
def change_unit(self):
self.changeUnit("anAttr")
def init_device(self):
"""
Tango init_device method. Default implementation calls
:meth:`get_device_properties`"""
self.unit_index = 0
self.tab_unit = ['m²', '°C']
self.get_device_properties()
self.changeUnit("anAttr")
def changeUnit(self, name):
newUnit = self.tab_unit[self.unit_index]
self.unit_index = (self.unit_index + 1) % len(self.tab_unit)
config = self.get_attribute_config_3([name])[0]
print(f"unit of {name} {config.unit}")
try :
config.unit = newUnit
print(f"new unit of AnAttr {config.unit}")
self.set_attribute_config_3([config])
except Exception as e:
print(e)
config.unit = newUnit.encode()
print(f"new unit of {name} {config.unit}")
self.set_attribute_config_3([config])
def addDevice(nameClass, server, name):
""" add a device"""
print("add Device : ",name)
db = Database()
try :
dev_info = db.get_device_info(name)
except :
device = DbDevInfo()
device._class = nameClass
device.server = server
device.name = name
db.add_device(device)
print("Device", name, "have been added into Database")
if __name__ == "__main__":
import sys
import tango
import os
print(f"ORBnativeCharCodeSet={os.getenv('ORBnativeCharCodeSet')}")
print(tango.utils.info())
addDevice("Dummy", "Dummy/dummy", "tango/Dummy/dummy")
sys.argv.append("dummy")
sys.argv.append("-v3")
Dummy.run_server()
Environment:
PyTango 9.4.1 (9, 4, 1) PyTango compiled with: Python: 3.8.10 Numpy: PYTANGO_NUMPY_VERSION Tango: 9.4.1 Boost: 1.73.0 PyTango runtime is:
Python: 3.8.10 Numpy: 1.24.4 Tango: 9.4.1 PyTango running on: uname_result(system='Windows', node='WDSFM157H', release='10', version='10.0.19045', machine='AMD64', processor='Intel64 Family 6 Model 140 Stepping 1, GenuineIntel')