From 119fcb51f1980034b8818727e845052d7471a569 Mon Sep 17 00:00:00 2001 From: Mario Ostieri <107915956+mariostieriansys@users.noreply.github.com> Date: Fri, 25 Aug 2023 14:18:46 +0100 Subject: [PATCH] Porting EnSight scripts to PyEnSight documentation (#292) Co-authored-by: Kathy Pippert --- doc/source/object_documentation.rst | 4 +- doc/source/user_guide/cmdlang_native.rst | 118 ++++++++++++++++------- 2 files changed, 86 insertions(+), 36 deletions(-) diff --git a/doc/source/object_documentation.rst b/doc/source/object_documentation.rst index 994e78f83b..6c306b849b 100644 --- a/doc/source/object_documentation.rst +++ b/doc/source/object_documentation.rst @@ -4,10 +4,10 @@ Object API reference ******************** -The :ref:`"Object"` API is a direct interface to the EnSight object structures. +The :ref:`"object"` API is a direct interface to the EnSight object structures. It includes the ability to set/query attributes as well as connect callback function that execute when attribute values change, etc. While it is a more -advanced interface than the :ref:`"Native"` API, there are some +advanced interface than the :ref:`"native"` API, there are some operations that can only be performed via that interface. diff --git a/doc/source/user_guide/cmdlang_native.rst b/doc/source/user_guide/cmdlang_native.rst index b6b2927998..fec32d08b2 100644 --- a/doc/source/user_guide/cmdlang_native.rst +++ b/doc/source/user_guide/cmdlang_native.rst @@ -8,17 +8,18 @@ the *command language*. Every operation in EnSight can be captured in command la Scripts can be generated using this language and played back in the GUI or in batch mode. Furthermore, features like context files (that capture a session state) do so using a command language variant. Command language is not documented, but it roughly follows -the :ref:`EnSight architecture `. The *native* Python API +the :ref:`EnSight architecture `. The :ref: `native Python API ` is a binding to this command language interface. Command language overview ------------------------- A command language call has this general form: :samp:`{class}: {command} [values...]`. -For example, :samp:`view_transf: rotate -4. 24. 0.` rotates the current view and -:samp:`data: replace data.case` loads a dataset into the current case. Commands -may also follow a *begin/end* or *modify begin/end* structure where commands of the -same class are used between the begin and end commands. This form is used to *batch* +For example, :samp:`view_transf: rotate -4. 24. 0.` rotates the current view, and +:samp:`data: replace data.case` loads a dataset into the current case. + +Commands may also follow a *begin/end* or *modify begin/end* structure, where commands +of the same class are used between the begin and end commands. This form is used to *batch* a collection of changes into a single update operation. Finally, there is a *select begin/end* form for expanding values onto multiple lines. @@ -38,16 +39,15 @@ line width and part color:: .. note:: - While most of the command language follows these two command forms, there are a - number of commands that do not follow this form. + While most of the command language follows these two command forms, there are + some commands that do not follow this form. -As noted previously, EnSight maintains a *default* object of every type. Commands -can be used to modify most attributes on the default object. A *create* -command can then be used to create a new object instance. For example, the -following code creates a clip by selecting the default clip object and then setting -up the type and clip position value on the default clip. It then changes the current -part selection to what parts should become the parent of the clip and calls -:samp:`clip: create` to create the clip:: +As noted previously, EnSight maintains a *default* object of every type. You can +use commands to modify most attributes on the default object. For example, you can +use the ``create`` command to create a new object instance. The following code creates +a clip by selecting the default clip object and then setting up the type and clip position +value on the default clip. It then changes the current part selection to what parts should +become the parent of the clip and calls the :samp:`clip: create` command to create the clip:: clip: select_default clip: begin @@ -65,8 +65,8 @@ part selection to what parts should become the parent of the clip and calls PyEnSight command language binding ---------------------------------- -The *native* Python API binding is a simple syntax conversion from command language -into Python syntax. The command class is a module in Python under the ``session.ensight`` +The native Python API binding is a simple syntax conversion from command language +into Python syntax. The ``command`` class is a module in Python under the ``session.ensight`` module. All values are passed as native Python parameters. For the *select/begin/end* command form, only the ``begin`` command is used. All of the value lines can be specified as Python parameters or a list. The previous example becomes this Python script: @@ -99,18 +99,17 @@ Native API debugging Every command also returns an error code, which is ``0`` on success. For example, :samp:`err = session.ensight.part.colorby_rgb([0.0,0.0,"sad"])` sets ``err`` to ``-1``. -The :func:`attrtree` -method can be used to enable Python exception handling instead of -returning an error code. It is recommended that this be used when debugging -native API scripts. +You can use the :func:`attrtree` +method to enable Python exception handling instead of returning an error code. You should +use the :func:`attrtree` +method when debugging native API scripts. .. note:: - The exception setting is global and care should be taken to reset the error + Because the exception setting is global, care should be taken to reset the error handling status on an error to ensure proper EnSight operation. -This example shows how one can arrange to have error return values converted -into exceptions: +This example shows how you can convert error return values into exceptions: .. code-block:: python @@ -138,8 +137,8 @@ you can use the right-mouse button menu to select and copy lines of command lang Next, select the text in the editor and use the **Edit** menu to select either the **Convert selection to sendmesg()** or **Convert selection to native Python** option. In general, the native Python conversion results in much more readable Python code -that is far easier to edit than the **Convert selection to sendmesg()** option. The -**Convert selection to native Python** option should be used for all but legacy development. +that is far easier to edit than the **Convert selection to sendmesg()** option. You should +use the **Convert selection to native Python** option 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** option causes the file contents to be executed in the global @@ -152,7 +151,7 @@ Special cases ------------- There are a number of commands in the EnSight command language that are not valid -Python names. A few examples include:: +Python names. Here are a few examples:: function: #_of_levels 5 annotation: 3d_label_size 10.0 @@ -190,14 +189,16 @@ The previous examples are transformed as follows: Selection and the object API ---------------------------- -The native API maintains a notion of a "current selection" with a collection -of commands to manipulate it, for example ``ensight.part.select_begin()``. The object API -reflects the EnSight GUI via SELECTED attributes and selection ENS_GROUP objects. +The native API maintains a notion of a *current selection* with a collection +of commands to manipulate it, such as :func: `select_begin()`. +The object API reflects the EnSight GUI via SELECTED attributes and selection ``ENS_GROUP`` objects. Due to the implicit nature of the native API, until it is used, the native selection -is not reflected in ensight objects. When using both APIs in a single script, it can +is not reflected in EnSight objects. When using both APIs in a single script, it can become necessary to synchronize the two notions of selection. This is done with the -the ``ensight.part.get_mainpartlist_select()`` command. This command sets the -native selection to match the object selection. It can be used like this: +the :func:`get_mainpartlist_select()` +command. This command sets the native selection to match the object selection. For example, this +code allows the object selection mechanisms to be used to set up the part selection for +subsequent native commands: .. code-block:: python @@ -209,6 +210,55 @@ native selection to match the object selection. It can be used like this: session.ensight.part.modify_end() -Which allows the object selection mechanisms to be used to set up the part selection -for subsequent native commands. +.. _ensight_to_pyensight: + +Convert existing EnSight scripts to PyEnSight +--------------------------------------------- + +PyEnSight has been designed to be fully compatible with the existing EnSight Python language, +supporting both the *native* Python API and the *object* API. Indeed, the ``ensight`` attribute +of a PyEnSight ``session`` object is a *clone* of the ``ensight`` module generated via +introspection. This means that any attribute, object, instance, variable, and more +available in the ``ensight`` module is also available in PyEnSight, which manages the +communication with EnSight and the conversion of a command to its corresponding EnSight counterpart. +However, you must make a few adjustments to port an existing EnSight script into +PyEnSight. Here is a list of operations to perform to make the conversion: + +* All the calls to the ``ensight`` module and its attributes must be pre-fixed + with the current session instance. For example: + +.. code-block:: python + + # Old syntax + # ensight.objs.core.PARTS + # New syntax + session.ensight.objs.core.PARTS + +* The ``ensight`` module cannot be imported anymore because it is an attribute of the PyEnSight ``session`` object. + However, you can use the ``scoped_name`` utility to mimic the syntax that you would obtain importing a module + or a submodule: + +.. code-block:: python + + # Remove previous imports + # import ensight + # from ensight.objs import * + # from ensight.objs import core + + # Create a ``scoped_name`` instance + sn = session.ensight.utils.support.scoped_name + + # Create a context manager with the ``scoped_name`` instance, where you can + # use the old syntax + + with sn(session.ensight) as ensight, sn(session.ensight.objs.core) as core: + core.PARTS[0].DESCRIPTION + ensight.view.bounds("ON") + +* The main advantage of using the ``scoped_Name`` instance is that the new syntax is also + supported directly in EnSight. This greatly simplifies the porting of a PyEnSight script + into EnSight. + + +