Dynamic command with no argument raises DevFailed exception

In PyTango 10.0.2, if you have a device that has a dynamic command with no argument (dtype_in=None), then calling the command raises a DevFailed exception.

Here is a device server that demonstrates the problem:

from tango.server import Device, command

class DynamicCommand(Device):

    def init_device(self):
        super().init_device()
        device_level = True
        cmd = command(f=self.command1)
        self.add_command(cmd, device_level)
        cmd = command(f=self.command2, dtype_out=float)
        self.add_command(cmd, device_level)
        cmd = command(f=self.command3, dtype_in=float, dtype_out=float)
        self.add_command(cmd, device_level)

    def command1(self) -> None:
        print("command1 has been called")

    def command2(self) -> float:
        print("command2 has been called")
        return 2.0

    def command3(self, value: float) -> float:
        print("command3 has been called")
        return 2.0 * value

Calling command3 works as expected, but calling command1 or command2 raises DevFailed. The full DevFailed exception is, e.g.

DevFailed[
DevError[
    desc = TypeError: DynamicCommand.command1() missing 1 required positional argument: 'self'

  origin = UNKNOWN: cannot get Python's traceback. Most probably, was a failure in c++ bindings
  reason = PyDs_PythonError
severity = ERR]

DevError[
    desc = Cannot execute command
  origin = virtual CORBA::Any *PyCmd::execute(Tango::DeviceImpl *, const CORBA::Any &) at (/Users/gitlab/builds/tango-controls/pytango/ext/server/command.cpp:311)
  reason = PyDs_UnexpectedFailure
severity = ERR]

DevError[
    desc = Failed to execute command_inout on device foo/bar/baz, command command1
  origin = virtual DeviceData Tango::Connection::command_inout(const std::string &, const DeviceData &) at (/Users/runner/miniforge3/conda-bld/cpptango_1739462625904/work/src/client/devapi_base.cpp:1432)
  reason = API_CommandFailed
severity = ERR]
]

The code works as expected with PyTango 9.5.1.

Assignee Loading
Time tracking Loading