This document describes the Interactive Research Environment (IRE) provided by the cisstInteractive library. The IRE is a graphical user interface that includes an interpreter (shell) for the Python programming language. It is primarily intended to be embedded in a C++ program that uses the cisst libraries, but it can also be used in standalone mode, where it is started (launched) directly from Python.
The IRE requires that the Python interpreter, and the wxPython package (Version 2.5 or greater), be installed on the system. Note that although wxPython is based on the wxWidgets C++ package, it is not necessary to install wxWidgets - the wxPython installation includes a wrapped version of wxWidgets. For more details, consult the build instructions (ADD LINK HERE).
The IRE provides the following main features:
The cisst examples directory includes pythonEmbeddedIRE, which demonstrates use of the IRE with a C++ program. Note that there is also a pythonEmbedded example that demonstrates sharing of objects between a C++ program and its embedded (text-mode) Python interpreter. Because this document focuses on the IRE, this latter example will not be described in detail.
The cisstInteractive library consists of C++ and Python source code. The C++ code is provided by the file ireFramework.cpp and its associated header files, ireFramework.h and ireExport.h. The Python code consists of several Python source files (*.py) grouped into the irepy module. Note that the irepy is organized as a subdirectory in the cisst source tree:
.../libs/code/cisstInteractive/irepy
During compilation of the cisst source code, a special build command is executed to create ``compiled'' versions (*.pyc) of the irepy module in the build tree; specifically in an irepy subdirectory of the bin directory. Note that .../bin/irepy is used for Windows as well, even though C++ libraries and executables are placed in .../bin/release and .../bin/debug, because the Python files are not dependent on the C++ compiler configuration.
The ireFramework.h file declares the ireFramework class. C++ programs can launch the IRE by invoking the ireFramework::launchIREShell method, as described in Section 5. The ireFramework.cpp file provides the implementation of the ireFramework class. The procedure for launching the IRE depends on whether the new_thread parameter is true or false. (MAYBE MOVE THE DISCUSSION OF THIS HERE).
The ireFramework.cpp file also provides the implementation of the ireLogger module, which provides an interface between the C++ log functions (see cmnLogger.h) and the Logger Output window of the IRE. The ireLogger module provides the following four methods to the Python interpreter:
One interesting feature of the ireLogger callback is that it can bypass the Python interpreter if a callable C function (as determined by PyCFunction_Check) is passed via SetTextOutput. In this case, the ireLogger callback function, PrintLog directly calls the C function via PyCFunction_Call. Besides improving efficiency, this has the added advantage that it does not require multi-threaded access to the Python interpreter, so the overhead of acquiring and releasing the global interpreter lock can be avoided.
The Python wrappers for the ireLogger methods were manually created, rather than being automatically generated by Swig. It may be possible to use Swig and still obtain the unique features of this implementation, such as direct calls to wrapped C functions via PyCFunction_Call, but that was not investigated.
The irepy module includes the following Python files:
Describe the example program.
The IRE can be launched from Python by simply importing the ``irepy'' module and then invoking the ``launch'' method, as follows:
import irepy irepy.launch()
These two commands can be specified on the command line, allowing the user to create convenient ``shortcuts''. For example, an IRE desktop shortcut can be created on Microsoft Windows by specifying the following target:
C:\Python24\python.exe -i -c "import irepy; irepy.launch()"
Note that the Python installation on the Microsoft Windows and Macintosh OS X operating systems includes python and pythonw executables. The pythonw executable must be used on the Macintosh because otherwise OS X will not allow the IRE to access the display. Either executable can be used on Microsoft Windows. The difference between them is that python runs in a terminal window, whereas pythonw does not. Although pythonw is more visually appealing (no terminal window lying in the background), the python executable is recommended for the IRE because output from the IRE Python modules (e.g., error or debug info) is displayed in the terminal window. Note that if pythonw is used, the -i option should not be specified.
The cisstInteractive library has been designed to streamline the launching of the IRE. The C++ program must include the ireFramework.h file, for example as follows:
#include <cisstInteractive/ireFramework.h>
This file defines the ireFramework class, which is a Singleton class (i.e., only one instance can be created). The IRE can be started by the following command:
ireFramework::LaunchIREShell();
This launches the IRE in the current thread and does not return until the IRE is exited. The LaunchIREShell command takes the following optional parameters:
The LaunchIREShell method may throw the std::runtime_error exception, so it is recommended that ireFramework::LaunchIREShell be invoked within a try...catch block.
Finally, the C++ program should call ireFramework::FinalizeShell() when the IRE is exited.
Obviously, the IRE must execute in a separate thread if the user wishes to run the C++ program and the IRE concurrently. There are two options for creating the IRE thread:
The first option is recommended because the IRE thread will be managed in the same manner as any thread created within the C++ program (i.e., multithreading will work as expected). In the second case, the Python thread will not get any execution time unless the C++ program periodically calls the ireFramework::JoinIREShell method with a non-zero timeout parameter.
Note, however, that the first method (starting a thread in C++) is not as portable as the second method (starting a thread in Python), unless an operating system abstraction library, such as cisstOSAbstraction, is used. Because cisstOSAbstraction is not yet available as open source software, the pythonEmbeddedIRE example program uses the second method.
OS X does not generally allow terminal programs, such as pythonEmbeddedIRE, to access the display. Therefore, the pythonEmbeddedIRE example program employs a workaround, where it ``borrows'' the identity of pythonw to get access to the display. This workaround can be used for other terminal programs. For details, see the file pythonEmbeddedIRE.cpp.
The cisstCommon library provides an Object Registry (cmnObjectRegister class) that can allow C++ objects to be made available to Python code. An object can only be added to the Registry if it is derived from the cmnGenericObject base class.
Because the Object Registry is part of the cisstCommon library, it can be used with or without the IRE (cisstInteractive library). The pythonEmbedded example program demonstrates use of the Object Registry with a simple embedded Python shell that is invoked by repeated calls to PyRun_SimpleString. The pythonEmbeddedIRE example program demonstrates use of the Object Registry with the IRE.
In general, the process is as follows:
Obviously, the Object Registry is only useful when the user is working with Python and C++ code. For this reason, it is initially disabled (and the Register Contents window is not displayed) when the IRE is started directly from Python (i.e., in standalone mode). It is automatically enabled when the cisstCommon library (actually, cisstCommonPython) is imported into the IRE. The Register Contents window is not automatically shown, however, and must be selected via the View menu.
Describe all the menu items, windows, etc...
What to do when it doesn't work. Make sure wxPython is installed. Make sure that PYTHONPATH is defined. Make sure that LD_LIBRARY_PATH (or DYLD_LIBRARY_PATH) is defined. And so on...