Skip to content

egse.command

This module defines a number of classes and helper functions to define and work with commands that operate hardware devices. The goal is to be able to define / create commands transparently from a YAML file without having to write (too much) code.

Definitions

command

a string that is sent to a device over an interface like TCP/IP or USB. This string is generated by the get_cmd_string() method of the Command class.

The string contains format like syntax that looks like an f-string, but is interpreted differently. See further: How to format device command strings.

Command

the base class for commands. This class contains the definition of the command and provides methods to parse and check arguments. The Command can be 'called' or 'executed' in which case a number of actions are performed based on the provided arguments.

CommandExecution

this class contains all the information needed to execute a command, without actually executing it. A CommandExecution contains the command definition and the parameters for the execution. It is mainly served as a communication mechanism to the control servers, i.e. the client side (Proxy) defines a command execution and the server then executes the command.

CommandError

a catch-all exception for unrecoverable errors in this module

InvalidArgumentsError

a CommandError raised when the arguments provided are themselve invalid or if the number of arguments is not matching expectations

The basic interface is:

cmd = Command(name     = <command name>,
              cmd      = <command string>,
              response = <callable to retreive a response>,
              wait     = <callable to wait a specific time/delay>)

where:

  • name: a name for the command, this is just needed for reporting, not used in commanding
  • cmd: the command string to send or execute, see further for details
  • response: send a second command to read or get a response on the 'cmd' sent
  • wait: a function object that will wait for a specific duration, e.g. partial(time.sleep, 10).

Formatting device command strings

The cmd argument is a string that contains placeholders (replacement fields) for future arguments that will be passed when calling the Command. The replacement fields are marked with curly braces and are mandatory. When a name is provided in the curly braces, the argument shall be provided as a keyword argument, otherwise a positional argument is expected. In the current implementation the cmd can only contain either positional arguments or keyword argument, not a mix of both.

The replacement fields may also have a format specifier to specify a precise format for that field.

Examples

moveAbsolute = Command(
    name = "moveAbsolute",
    cmd  = "&2 Q70=0 Q71={tx:.6f} Q72={ty:.6f} Q73={tz:.6f} "
           "Q74={rx:.6f} Q75={ry:.6f} Q76={rz:.6f} Q20=11"
)

response = moveAbsolute(1, 1, 1, 0, 0, 20)
response = moveAbsolute(tx=1, ty=1, tz=1, rx=0, ry=0, rz=20)

Questions

Do we need additional hooks into this commanding?

  • add a meaning to the check, what is it and what is it used for?
  • add a output processor possibility. A callback function that will process the output value before returning it by the call.
  • provide an execute method for the CommandExecution that executes the command with the saved parameters

Classes:

Name Description
ClientServerCommand
Command

A Command is basically a string that is send to a device and for which the

CommandError

A Command Exception as a base class for this module.

CommandExecution

This class contains all the information that is needed to execute a command

InvalidArgumentsError

The arguments provided are invalid

InvalidCommandExecution

A invalid command execution.

Functions:

Name Description
dry_run

This decorator prepares the function to handle a dry run.

get_function

Returns a function (unbound method) from a given class.

get_method

Returns a bound method from a given class instance.

load_commands

Loads the command definitions from the given command_settings and builds an internal

parse_format_string

Parse and decode the format string.

ClientServerCommand

ClientServerCommand(
    name,
    cmd,
    response=None,
    wait=None,
    check=None,
    description=None,
    device_method=None,
)

Bases: Command

Methods:

Name Description
client_call

This method is called at the client side. It is used by the Proxy

server_call

This method is called at the server side. It is used by the CommandProtocol class in the

client_call

client_call(other, *args, **kwargs)

This method is called at the client side. It is used by the Proxy as a generic command to send a command execution to the server.

Parameters:

Name Type Description Default
other

a sub-class of the Proxy class

required
args

arguments that will be passed on to this command when executed

()
kwargs

keyword arguments that will be passed on to this command when executed

{}

Returns:

Type Description

the response that is returned by calling the command (at the server side).

server_call

server_call(other, *args, **kwargs)

This method is called at the server side. It is used by the CommandProtocol class in the execute method.

Parameters:

Name Type Description Default
other

a sub-class of the CommandProtocol

required
args

arguments are passed on to the response method

()
kwargs

keyword arguments are passed on to the response method

{}

Returns:

Type Description

0 on success and -1 on failure.

Command

Command(
    name,
    cmd,
    response=None,
    wait=None,
    check=None,
    description=None,
    device_method=None,
)

A Command is basically a string that is send to a device and for which the device returns a response.

The command string can contain placeholders that will be filled when the command is 'called'.

The arguments that are given will be filled into the formatted string. Arguments can be positional or keyword arguments, not both.

CommandError

Bases: Error

A Command Exception as a base class for this module.

CommandExecution

CommandExecution(cmd, *args, **kwargs)

This class contains all the information that is needed to execute a command with a set of parameters/arguments. The command is however not executed automatically. That is the responsibility of the caller to actually execute the command with the given parameters.

Developer info

you can see this as a partial (functools) which defines the command and its arguments, but doesn't execute until explicitly called. You can execute the command by calling the cmd with the given arguments:

ce = CommandExecution(cmd, 20.0)
...
response = ce.run()

InvalidArgumentsError

Bases: CommandError

The arguments provided are invalid

InvalidCommandExecution

InvalidCommandExecution(exc, cmd, *args, **kwargs)

Bases: CommandExecution

A invalid command execution.

Parameters:

Name Type Description Default
exc

the Exception that was raised and describes the problem

required
cmd

the Command object

required
*args

the positional arguments that were given

()
**kwargs

the keyword arguments that were given

{}

dry_run

dry_run(func)

This decorator prepares the function to handle a dry run.

A dry run is used to check the logic of an instrument commanding script without actually executing the instrument commands. The commands are instead added to the command sequence in the global state.

Parameters:

Name Type Description Default
func Callable

the function that needs to be executed

required

Returns:

Type Description
Callable

A wrapper around the given function.

get_function

get_function(parent_class, method_name)

Returns a function (unbound method) from a given class.

Parameters:

Name Type Description Default
parent_class

the class that provides the method

required
method_name str

name of the method that is requested

required

Returns:

Type Description
Callable

the method [type: function].

Note

The function returned is an unbound class instance method and therefore this function expects as its first argument the class instance, i.e. self, when you call it as a function.

get_method

get_method(parent_obj, method_name)

Returns a bound method from a given class instance.

Parameters:

Name Type Description Default
parent_obj

the class instance that provides the method

required
method_name str

name of the method that is requested

required

Returns:

Type Description
Callable

the method [type: method].

Note

The method returned is an bound class instance method and therefore this method does not expects as its first argument the class instance, i.e. self, when you call this as a function.

load_commands

load_commands(
    protocol_class,
    command_settings,
    command_class,
    device_class,
)

Loads the command definitions from the given command_settings and builds an internal dictionary containing the command names as keys and the corresponding Command class objects as values.

The command_settings is usually loaded from a YAML configuration file containing the command definitions for the device.

Parameters:

Name Type Description Default
protocol_class

the CommandProtocol or a sub-class

required
command_settings

a dictionary containing the command definitions for this device

required
command_class

the type of command to create, a subclass of Command

required
device_class

the type of the base device class from which the methods are loaded

required

parse_format_string

parse_format_string(fstring)

Parse and decode the format string.