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.