Creating instances of a device with dynamic attributes

Hi,

I am writing a PyTango device which consists of two parts. One is a device class which adds new dynamic attributes with a command, call it 'TheDevice'. The second is a device which creates instances of the previously mentioned dynamic attribute device, call it 'DeviceCreator'. Please see below for a minimal working example.

The setup is behaving mostly as I would like it to, but I have one problem.

Current behaviour
When creating a device with DeviceCreator, it retains all the dynamically created attributes from all instances of TheDevice. For example, I create two instances of TheDevice. I add the attribute 'a' to one and the attribute 'b' to the other. If I now create a new instance of TheDevice using DeviceCreator, this new instance has both attribute 'a' and attribute 'b'.

If I restart the DeviceCreator, the previously remembered attributes are forgotten.

Desired behaviour
I would like every newly created device to have no dynamic attributes after creation.

Possible explanation
According to the documentation for tango.LatestDeviceImpl.add_attribute

Please, note that if you add an attribute to a device at device creation time, this attribute will be added to the device class attribute list. Therefore, all devices belonging to the same class created after this attribute addition will also have this attribute.

It seems like the dynamically added attributes are added to the device class attribute list. This also explains why restarting the DeviceCreator forgets the remembered attributes, since the device class is freshly added to the database.

However, the attributes are not created at the device creation time. They are added with a command, which is always executed after the device has been Init'd.

Minimal working example
I hope this can function as a minimal working example.

TheDevice.py

from tango.server import Device, command
from tango import DevDouble, AttrWriteType

class TheDevice(Device):

@command(dtype_in=str)
def AddAttribute(self, name):
attribute = Attr(name, DevDouble, AttrWriteType.READ)
self.add_attribute(attribute, r_meth=self.read)

def read(self, attribute):
attribute.set_value(10.0) # Example value

def init_device(self):
Device.init_device(self)


DeviceCreator.py

from tango import Util
from tango.server import Device, command
from TheDevice import TheDevice
import sys

class DeviceCreator(Device):

@command(dtype_in=str)
def CreateDevice(self, name):
Util.instance().create_device("TheDevice", name)

def init_device(self):
Device.init_device(self)

def run():
util = Util(sys.argv)
util.add_class(TheDevice.TangoClassClass, TheDevice)

DeviceCreator.run_server()

if __name__ == "__main__":
run()


If anyone knows a solution or work-around for this problem, it would be very much appreciated!
Edited 1 year ago
Hi Rutger

Thanks for the detailed explanation and minimal example. You have found a long-standing issue with cppTango (and PyTango, which is built on top of cppTango). There's an interesting thread about it here: https://gitlab.com/tango-controls/cppTango/-/issues/814

I think the Sardana workaround for the problem is here (but I stand to be corrected): https://gitlab.com/sardana-org/sardana/-/blob/3.3.4/src/sardana/tango/pool/PoolDevice.py#L229

The Sardana code is doing a lot more than your example, but hopefully you can find the bits that apply.

/Anton
Hi again,

I managed to adapt the Sardana workaround to my code. I now immediately delete the attribute from the device class after the dynamic attribute is added. This works exactly as it should. Thanks for your help!
 
Register or login to create to post a reply.