ESO Recipe Execution Tool
3.13
|
Functions | |
cpl_error_code | er_python_load_modules (er_stringarray_t *paths) |
Loads relevant information for Python modules that contain plugins. More... | |
cpl_error_code | er_python_select_module (const char *module_name) |
Selects a specific Python module to use for execution. More... | |
int | er_python_get_plugin_list (cpl_pluginlist *list) |
Fills a list with all available plugins for a selected Python module. More... | |
void | er_python_cleanup (void) |
Resets loaded Python module information. More... | |
This module provides functions needed to interface with a Python interpreter running as an external process that will execute a Python based plugin. The CPL plugin API is preserved as much as possible, both on the EsoRex side and within the Python plugin code. Thus, the EsoRex core code will invoke the Python based plugin through the usual calls to the cpl_plugin
class (more specifically, derived classes such as cpl_recipe
). This module provides the mechanism to load Python modules, identify the Python based plugins, select the desired module, and then actually perform the necessary communication with the Python interpreter to execute the plugin.
The exported functions of this interface deal with the differences in loading Python module plugins versus C/C++ based shared library plugins. Only the loading and unloading needs special treatment from EsoRex, since the actual invocation of the plugin is through the usual cpl_plugin
API. Thus, starting/stopping the Python interpreter and the communication protocol is all hidden behind the interface from EsoRex's point of view inside the private functions of this module.
Loading of a Python module involves starting the Python interpreter, loading the named Python module file and finding all Python classes that derive from a class called CplPlugin
. This is accomplished with the function er_python_load_modules(). All such classes are registered and can be subsequently selected with er_python_select_module(). Selecting the desired module is necessary, so that er_python_get_plugin_list() knows for which Python module to return the list of available plugins. The function er_python_get_plugin_list() can be considered as the equivalent of the cpl_plugin_get_info()
entry point function that must be implemented by a C/C++ based shared library plugin. Once er_python_get_plugin_list() has successfully returned a list of CPL plugin objects, there is no difference in the invocation procedure to execute the plugin between a Python module or shared library based plugin. Once the invocation of the plugin is complete, one must cleanup by calling the er_python_cleanup() function. A simple code example for the call sequence to invoke a Python based plugin will look as follows (error handling is ignored for simplicity):
Under the hood, communication with the Python interpreter is handled by the execute
function, which is registered with the cpl_plugin
objects returned by er_python_get_plugin_list(). The communication protocol uses JSON as the exchange format that is sent over Unix pipes. The execute
function is a stub that will implement the following steps:
python
shell command and give it the initial Python stub code to execute. cpl_plugin
structure as JSON format. cpl_plugin
structure and update the cpl_plugin
argument of the execute
function. The other end of the protocol is implemented in the initial Python stub code passed to the Python interpreter to execute. The steps it will perform are:
CplPlugin
). execute
method, passing the decoded Python object as the method's argument. execute
method completes, the updated argument and return value are encoded as JSON again. Note that the JSON is not send over the stdin and stdout pipes, but rather two new dedicated pipes are created to handle the interprocess communication. This allows the stdin and stdout pipes to behave as one would normally expect. For example, they will be attached to the same terminal or file as the parent process (i.e. EsoRex) was attached to. This means that print statements in the Python code will write the output to the same location as one would expect if the Python code was executed manually in the Python interpreter. Separation of the EsoRex to Python communication protocol from stdin/stdout avoids unexpected interference or having stdin/stdout redirected in an unexpected manner.
Developers of Python based plugins must implement a plugin class that has the following requirements:
CplPlugin
or it must itself be called CplPlugin
. __init__
constructor must take no arguments or all arguments must have defaults. __init__
function: basestring
, optional) int
) basestring
, optional) basestring
, optional) basestring
, optional) basestring
, optional) basestring
, optional) list
, optional). This must be a list of dictionaries with the following keys: 'value'
, 'range'
or 'enum'
. (type basestring
) basestring
) bool
, int
, float
or basestring
) 'range'
. (type int
or float
, but default must have the same matching type) 'range'
. (type int
or float
, but default must have the same matching type) 'enum'
. The individual elements in the list can be one of int
, float
or basestring
; but must all have the same type and must match the type used for default. (type list
) basestring
, optional) basestring
, optional) basestring
, optional) bool
, optional) basestring
, optional) bool
, optional) basestring
, optional) bool
, optional) basestring
, optional) list
, optional). This must be a list of dictionaries with the following keys: basestring
) int
) int
) list
). This must be a list of dictionaries with the following keys: basestring
) int
) int
) list
of basestring
elements) Must have a method called execute
defined as follows:
def execute(self, plugin):
It will take a single dictionary argument plugin and return an integer return code. 0
will indicate success and any other value will indicate an error. If an error does occur, the execute
method should assign an appropriate string message to the attribute self.error_message
.
Input parameters can be accessed as plugin
['parameters']. Input frames are accessed as plugin
['frames']. Any new output frames must be appended to the plugin
['frames'] list.
The following is a simple example of a Python class that implements the required interface:
void er_python_cleanup | ( | void | ) |
Resets loaded Python module information.
This function should be called when one no longer needs to deal with any Python based plugins.
int er_python_get_plugin_list | ( | cpl_pluginlist * | list | ) |
Fills a list with all available plugins for a selected Python module.
This function is the equivalent of the cpl_plugin_get_info()
function found in a compiled plugin library. It will fill a list of CPL plugin objects for all plugins found in the currently selected Python module. er_python_select_module() must be called before this function is invoked.
list | The plugin list that will be filled with CPL plugin objects. |
0
is returned on success and an appropriate CPL error code otherwise. cpl_error_code er_python_load_modules | ( | er_stringarray_t * | paths | ) |
Loads relevant information for Python modules that contain plugins.
This function will go through a list of module paths that point to Python code files and attempt to load these. If the module can be loaded successfully and it contains any classes that derive from a base class called CplPlugin
(including CplPlugin
itself) then these are recorded, such that er_python_select_module() can then be used to select a particular Python module to run. Only classes directly within the Python module's namespace are considered, i.e. secondary imported modules will not have their classes added unless they are imported into the namespace with a "from ... import ...
" Python statement.
[in,out] | paths | The list of module paths that need to be checked if they can be loaded. Any paths that do not contain loadable plugins will be removed from the list by this function. |
CPL_ERROR_NONE
on success and an appropriate error code if a severe error occurred.cpl_error_code er_python_select_module | ( | const char * | module_name | ) |
Selects a specific Python module to use for execution.
This function is used to select the Python module that will be used when the er_python_get_plugin_list() function is invoked and attempts to load all available plugin classes.
module_name | The full path name of the python module to use. |
CPL_ERROR_NONE
on success or an appropriate error code if a severe error occurs.