Chapter 8: EnSight Python Interpreter

Python EnSight Module Interface

EnSight object API

EnSight extension mechanism

Helper modules

Overview

EnSight includes a built-in interpreter for the Python programming language (www.python.org). The system allows Python code to be executed within the EnSight program, not unlike the command language allows. Python is a more fully featured programming language with formal flow control, classes and complex variable types. It is also intrinsically extensible. EnVe is an example of a Python extension. The popularity of the Python language means that there are a large number of available extensions (for example, XML, SQL, COM, etc). The Python built into EnSight includes the core classes and libraries as well as the EnSight, EnVe, numpy and PyQt (Python interface to the PyQt GUI library) modules. The PyQt module allows Python code running inside of EnSight to create cross-platform custom GUIs that can interact with EnSight. The EnSight core itself implements extensions (command language, right mouse button menus, user-defined tools and user-defined GUIs) in Python.

The core interface to the Python interpreter is accessed via the Python tab in the command dialog graphical user interface.

The Cmd: edit field allows the user to interactively type in Python commands. The output of those commands is captured in the pane above the prompt. Normal output from Python is in black text, while error output is displayed as red text. Simple, one-line commands can be entered and executed when the user presses Enter. The command prompt allows for command recall as well. The Up and Down arrow keys walk though the most recently entered commands, facilitating rapid editing and re-issuing of commands. A button is provided to clear the current log text at any time. The Log font... button allows the user to change the font used in the dialog as well as the Python source code editor.

EnSight provides a built-in editor for Python code that includes Python aware syntax highlighting. Buttons are provided to create a new Python script file or edit an existing one. The editor window looks like this:

The line numbers are down the left side and a column is provided to allow the user to hide/show blocks of text. This also makes it easier to see how the block indented structure of Python denotes scope. The menu options allow for many options. In addition to basic file I/O and cut/copy/paste editing, there is a find/replace dialog set and options to indent/unindent and block comment. A menu allows the user to adjust the font used for display. This selection is stored in the user's preferences.

The editor provides a simple auto-completion mechanism that can be enabled from the Edit menu or by typing the Ctrl+Tab key. When enabled, if the . character is typed, the text to the left of the . is scanned for a Python module name match and items in that module are displayed for easy selection. For example, entering ensight. brings up a list of objects in the Python EnSight module. The can be very helpful in getting the proper syntax, especially of seldom used commands.


Note:  The system will work for the EnSight core Python modules as well as any module that has been imported into the global Python interpreter namespace.


Converting Command Language to EnSight Python

There is a built-in mechanism to convert code in command language into Python. To do this, you first paste the command language into the Python editor (lines of command language can be selected and copied using the right mouse button menu in the Execution tab). Next, select the text in the editor and use the Edit menu options for Convert selection to sendmesg() or Convert selection to native Python. In general, the native Python conversion results in much more readable Python code that is far easier to edit than the sendmesg() option. The native option should be used for all but legacy development.

The file menu provides two items to execute the current file text in the EnSight Python interpreter. The Run script item causes the file contents to be executed in the global namespace (for example, like the execfile() function). The Import script as module item first saves the current file to disk and then executes a Python import operation on the file, which executes in a private namespace. Both will check the syntax of the current file and allow for rapid prototyping.

Write and Import Modules for EnSight Python

If you wish to write and import your own python modules and import them into EnSight, then set the environmental variable CEI_PYTHONPATH to point to the location of your module. After you put your new module in place, you may need to start up EnSight once with the -no_prefs option to force a reload of all the modules, then quit and restart EnSight normally to get all your preferences for your session.

ensight -no_prefs

For an example module that you can import and use in your scripts, as well as use as a template for your module, see $CEI/ensight242/site_preferences/extensions/ens_utils.py. Try the following in your python scripts or in the command window.

import ens_utils as eu
dir(eu)

Then pick a module that you are interested in and do a help, for example:

help(eu.get_const_var_names)
help(eu.get_const_val)

General Python Use in EnSight

EnSight will accept Python scripts in most situations where it is expecting a command script. For example, in the Load: prompt in the Command dialog, as the name of a keyboard or HUM macro and on the command line (-p), the user may specify the name of a Python script to be executed. This would allow things like graphical user interfaces to be popped up when keys are pressed, etc. The command language play: filename command will accept a Python filename, allowing the execution of Python code from any command file. EnSight differentiates between command language files and Python files based on filename suffix. Python files are assumed to end in '.py' or '.pyc'. All other files are assumed to contain EnSight command language instructions. Unlike the command language, EnSight Python code is not journaled during execution by default, thus Python commands will not show up in any saved EnSight command stream unless special flags are set.

Simple Python commands can also be embedded directly in EnSight command language. If a line of command language begins with 'ensight.', it is assumed to be Python code and is passed directly to the Python interpreter. This means that the native API, discussed later in this section, can be used directly in .enc files. Also, the command language command: ext: python has been added to command language. This command passes the remainder of the command line to the Python interpreter. Therefore, in EnSight, the following is a legal .enc file:

VERSION 10.2
ensight.view_transf.rotate(0.0,0.0,0.1)
ext: python print("Hello from Python!")

Note:  The printed string will appear in the Python tab in the Command dialog.


How Not to Use EnSight Python

When you want to do something in EnSight, try thinking within the EnSight functionality and only use EnSight Python to control EnSight, or to make it easier using a new custom graphical user interface, or to make it work repetitively.

Do not use Python as a substitute for the EnSight calculator. Python is an interpreted language. Python is serial within EnSight for many operations. For example, EnSight Python query of elements requires a sequential round trip for every element in a serial fashion.

For example, if I wish to count the number of cells in a part inside a box tool, it would be a very, very bad idea to get the box tool attributes in python and then cycle through a EnSight Python query of each of the elements in all the parts to see which ones fell inside the box tool limits. Instead, I would use the EnSight calculator, which has a server with a calculator written in optimized, compiled, threaded code as follows. I could use a inner clip of the box tool and find only those cells with a value inside. I would assign a value of 1.0 to each element using MakeScalElem and a value of 1.0, and then sum up the values all in the EnSight calculator using StatMoment with the sum option.

Using EnSight, I would have even more flexibility: I could even filter by the element type using the EleMetric and the Filter function to filter out the unwanted element types.

Python and the EnSight Command Line

There are a number of situations where it would be helpful for the Python interpreter in EnSight to have access to the EnSight command line. This is done through the 'sys.argv' interface in Python. The EnSight client application supports the command line options '-pyargv' and '-endpyargv'. These options serve to mark a section of the command line used to launch EnSight to be passed to the EnSight Python interpreter. For example:

ensight242_client -c -pyargv example -another_example -endpyargv -X

Will cause EnSight to be launched with the -c and -X options and the value of sys.argv to be set to [ensight,example,-another_example] in Python. The use of -endpyargv is optional and if missing, will cause all the arguments following '-pyargv' to be passed to sys.argv.


Note:  EnSight will prepend the string ensight to the start of sys.argv. If the raw command line is desired, it is available as the 'ensight.argv' list.


In the above example, the output would be something like: ['C:\\Program Files\\CEI\\ensight242\\machines\\win64\\ens242cl.exe', '-hide_console', '-c', '-pyargv', 'example', '-another_example', '-endpyargv', '-X', '-homecwd']

Limitations of the EnSight Python Interface

Python is a complex and broad-ranging programming language. There are a few features of the language that can cause problems if called from within EnSight. The features should not be used by Python code running inside of EnSight.

Re-entrant interfaces to the command language are not allowed. For example, a Python script may use ensight.sendmesg() to play a command language file. If that file in turn tries to execute a Python script, EnSight will fail. The reverse is also true. If a command language script calls a Python script which then calls a command language script, EnSight will fail. In general, avoid nesting play: commands that change interpreters.

Python supports threads and you can use these, except there are two problems. Python threads require the interpreter be running at all times to execute. In EnSight, the interpreter is dormant unless Python code is being executed, so the threads may not always be executed. Second, threads that explicitly or implicitly modify graphical user interface elements can cause issues. In EnSight, it is critical that only the main thread of execution make graphical user interface changes.


Note:  Even simple things like print in EnSight Python cause graphical user interface elements to change (the output is logged to a Qt widget). The best advice is not to use Python threads in EnSight.


The PyQt module provides a socket interface. This interface is based on asynchronous socket calls. While the interface is quite nice, it has the side effect of making all the other socket calls in EnSight under Windows asynchronous. This will cause EnSight's socket communication library to fail. If you need a socket connection in Python, use the provided Python module instead of the PyQt module.

EnSight balances the X11 Motif widgets with those provided by PyQt, allowing both to exist and co-operate. One exception to this rule is the issue of modal widgets. The current event handling system cannot properly handle the case of both widget systems having a modal widget. Therefore, this case must be avoided. The most common situation occurs when a modal PyQt widget is active and a callback function on that widget uses ensight.sendmesg() and the resulting command causes EnSight to pop up a modal X11 dialog. This will cause EnSight to hang. The work-around is to avoid calling sendmesg() when there is a modal PyQt widget.


Note:  Qt popup menus are modal widgets. Always allow the modal operation to complete before making the sendmesg() calls.


In order to provide a more seamless integration between the EnSight core windows and those generated via the Python API, special consideration must be given to the parents of top-level widgets. Two methods, ensight.qtparent() and ensight.reparent(), provide this functionality. Proper use of these methods is to provide ensight.qtparent() as the parent of any top-level Qt widget and to call ensight.reparent() in the widget __init__() method. An example would be:

class example(QWidget):
    def __init__(self, parent=None, flags=Qt.WType_TopLevel):
        QWidget.__init__(self, parent, flags)
        ensight.reparent(self)
        ...
temp = example(ensight.qtparent())
temp.show()

The resulting top-level widget will interact properly with the EnSight graphical user interface windows.