Skip to content

Resolve "Dynamic attribute in 9.3.5 fails"

Closes #465 (closed)

The reason is that _ensure_user_method_executable method, introduced in 9.3.5 is not compatible with the trick in these servers to add non device method to dynamic attribute, when link to the method is added to class __dict__.

To check whether _ensure_user_method_executable is bound we did the following test:

        assert name == user_method.__name__, (
                "Sanity check failed. PyTango bug? The names must match. "
                "{} != {} on {}".format(name, user_method.__name__, obj)
            )
        is_bound = (
            hasattr(user_method, "__self__")
            and getattr(user_method, "__self__") is not None
        )

This code fails in case of external method, added to the __dict__, due to

a) 'name' can be not equal user_method.__name__

b) external method does not have 'self' attribute

E.g. the following code is valid for PyTango, but check fails:

    def read_function_outside_of_any_class(attr):
        attr.set_value(123)

    class TestDevice(Device):
        green_mode = server_green_mode

        def initialize_dynamic_attributes(self):
            # trick to run server with non device method: patch __dict__
            self.__dict__['read_dyn_attr1'] = read_function_outside_of_any_class
            attr = attribute(
                name="dyn_attr1",
                dtype=int,
                access=AttrWriteType.READ,
            )
            self.add_attribute(attr)

I suggest the following:

a) we do not check name matching

b) for the PyTango is crucial, that we patch with __run_in_executor the method, which is in the device's dict, so we can check it with the following comparison:

is_device_method = getattr(obj, name, None) == user_method

It seems, that this code works for all previous cases and for the "hacked" devices.

Edited by Anton Joubert

Merge request reports