Product/Package Extensions

Parent Previous Next

EnSight Product Extensions

To simplify the distribution and installation of extensions and full GUI replacements without the need to install files into the CEI file tree, the "product" extension was introduced. Product extensions are located in subdirectories of $CEI_HOME (e.g. $CEI_HOME/*/product.xml) and in the user's preferences directory in the extensions subdirectory (e.g. ~/.ensight232/extensions/*/product.xml' under linux and {PREFERENCESDIR}/extensions/*/product.xml in general). The search path can be extended using the ENSIGHT10_PRODUCT_PATH environmental variable as well (the variable can be a ':' separated list of directories under Linux/Mac or ';' separated list under Windows).

Specifically, to get the user's preferences path in Python, use code like this:


import os, os.path
dir = os.path.join(ensight.query(ensight.PREFERENCESPATH),"extensions")

and to get a list of user-specific product extension files:

import os, os.path, glob
wild = os.path.join(ensight.query(ensight.PREFERENCESPATH),"extensions","*","product.xml")

xmlfiles = glob.glob(wild)


This allows for user-specific product extensions and can be a useful tool in the development of a product extension.

A complete list of product extensions, including both user-specific, environmental variable specified and site-deployed might be obtained with this code snippet:


import os, os.path, glob
files = []
wild = os.path.join(ensight.query(ensight.PREFERENCESPATH),"extensions","*","product.xml")
files += glob.glob(wild)
for p in os.environ.get("ENSIGHT10_PRODUCT_PATH","").split(';'):
    wild = glob.glob(os.path.join(p,'*','product.xml'))
    files += glob.glob(wild)
wild = os.path.join(ensight.version()[3],"*","product.xml")
files += glob.glob(wild)


An example product.xml would look like:


<?xml version="1.0" encoding="UTF-8"?>
<product>
  <ensight_extension>
    <loader>EnSightCFDGUI.py</loader>
    <requires>
      <ensight_core>
        <minimum>9.1.0.0</minimum>
        <maximum>9.2.0.-1</maximum>
      </ensight_core>
    </requires>
  </ensight_extension>
  <ensight_extension>
    <loader>another_extension.py</loader>
    <translation>path/*.qm</translation>
    <sessiondir license="standard" append="1">path/*</sessiondir>
    <documentation langid="">path/docs</documentation>
    <documentation langid="is">path/docs/iceland</documentation>
    <requires>
      <ensight_core>
        <minimum>9.1.0.0</minimum>
        <maximum>9.2.0.-1</maximum>
      </ensight_core>
    </requires>
  </ensight_extension>
</product>


This file defines two extensions to ensight (<ensight_extension>).  The location of the Direct Load bootstrap Python file is specificed by <loader> and must be a subdirectory of the directory where the product.xml file is located.  This particular extension has a single dependency (<requires>) on the EnSight core Python interface (<ensight_core>).  The allowed versions of the EnSight core are specified by the <minimum> and <maximum> tags respectively.  In the example, this extension is allowed to load for all versions of EnSight number 9.1.  Note that numbers are substituted for the '(x)' version tags on EnSight (e.g. 9.1.0(c) corresponds to 9.1.0.2).  All version comparisons are fieldwise numeric and matching the limits enables the extension.  The second extension includes a pair of Qt .qm translation files that go along with the extension.  Note: an extension block (<ensight_extension>) may have any number of <loader> and <translation> tags and multiple <requires> blocks that apply to all of the <loader> and <translation> tags in the block.  Also, the <loader> and <translation> tags can include "glob" wildcards to specify multiple translation and Python loader files.

The <documentation> tag is new in EnSight 10.0.  This tag allows the product XML file to specify a directory where EnSight will look for it's documentation PDF files before it looks for them under $CEI_HOME/ensight*/docs.  The tag also supports the langid="" attribute. This qualifies the path to a specific language.  That path will only be used if EnSight is currently using the specified language.  In the above example, path/docs will always be considered because the language id is "", but if the current EnSight language is set to Icelandic ("is"), the path/docs/iceland will be searched first.  In all cases, the core EnSight docs directories will be searched, having failed all other matches.

The <sessiondir> tag. This tag allows the product XML file to specify a wildcard specification used by the "Welcome" dialog to find the list of example session files.  The 'license' attribute allows the path to be qualified to a specific EnSight license.  For example, <sessiondir license="gold">foo/*</sessiondir> will cause the welcome screen to consider all of the files in the 'foo' subdirectory of this product for use when the license is 'gold' instead of the default directory. By default, the path specified will replace the standard search path for session files.  The 'append' attribute can be used to add to the standard path.  For example, <sessiondir license="standard" append="1">mydir/*</sessiondir> will cause the .ens files in the mydir subdir to be added to the default list of file when using a 'standard' license token.  append="1" will prepend the files to the list and append="2" will add them to the end of the list.  

For the <sessiondir>, <documentation> and <translation> tags, it is also legal to include the 'arch' attribute.  This acts as a filter for the tag.  If specified, the 'arch' must match the currently running CEI_ARCH.  For example, <translation arch="win64">machines/win64/en/*.qm</translation> specifies that 'win64/en/*.qm' will be read only when running a 64bit Windows executable.

There is a simple example wrappered extension attached to this page. Extract this archive into the directory $CEI_HOME/MyCorporation.  This will create a site-specific extension tool hierarchy  that supports versions and language translation and does not require any files to be installed into the ensight core folders (so they will be preserved over install/uninstall cycles).

A more complex example is also attached to this page.  Extract this archive to $CEI_HOME/cei_complex_extension_example.  This example demonstrates a number of different organizational schemes for collected a number of extension subclasses into a single product.xml package.  It includes subdirectories, different loading schemes and a method for finding a common parent extension, so extensions can share a common tree.  It includes both menu and tool extensions.  When loaded, it adds several entries to the user-defined tools panel and a new context sensitive popup menu. They look like this:

EnSight Package Extensions

An EnSight Package is a special case of an EnSight Product extension.  It follows the same rules as a product and uses the same product.xml file to describe it's contents.  A Package adds the <package> tag to the product.xml file as a direct child of the <product> tag.  Extending the example above to make the product.xml become a Package:


<?xml version="1.0" encoding="UTF-8"?>
<product>

  <package>

     <name>An Example Product</name>

     <version>2.0</version>

     <date>8/19/2013</date>

     <publisher>CEI</publisher>

     <info_url>http://www.ceisoftware.com</info_url>

  </package>

  <ensight_extension>
    <loader>EnSightCFDGUI.py</loader>
    <requires>
      <ensight_core>
        <minimum>9.1.0.0</minimum>
        <maximum>9.2.0.-1</maximum>
      </ensight_core>
    </requires>
  </ensight_extension>
  <ensight_extension>
    <loader>another_extension.py</loader>
    <translation>path/*.qm</translation>
    <sessiondir license="standard" append="1">path/*</sessiondir>
    <documentation langid="">path/docs</documentation>
    <documentation langid="is">path/docs/iceland</documentation>
    <requires>
      <ensight_core>
        <minimum>9.1.0.0</minimum>
        <maximum>9.2.0.-1</maximum>
      </ensight_core>
    </requires>
  </ensight_extension>
</product>


The <package> tag specifies a formal name, version, publisher and release date for the package.  The optional <info_url> allows the package to specify a website where the specifics of the package can be documented (most Package GUIs will include the ability to open a webbrowser pointed at that URL).  

The advantages of a Package is that metadata that describes the entire directory structure (possibly including multiple EnSight extensions, documentation, etc) for the product is included.  This allows a GUI to succinctly display information about the package and to do things like compare versions, etc. A Package can stored in a single file (a .epz file) or pushed into a network-based repository using the package manager. The .epz file is a ZIP format file that includes the entire hierarchy of files rooted at (and including) the directory that contains the product.xml file.  The filename extension is simply changed from .zip to .epz.

Loading an EnSight Extension

The product and package extensions provide and <loader> section that defines the name of a Python (.py) file that should be loaded.  These files need to provide a single Python method that the system will call to instantiate all of the extension object instances. A block of this form:


#ENSIGHT_USER_DEFINED_BEGIN
#FACTORY=function_name
#ENSIGHT_USER_DEFINED_END

def function_name(parent):
    return []


is placed at the top of a .py file. In this case, the file will be imported and the function ‘function_name()’ will be invoked with a single ‘parent’ parameter. This function should create all of the instances of the extension class objects one needs and returns them as a Python list. Note that function_name() should also do any parent adding for the objects it wants before returning them. The calling system will register the objects in the returned list and insert them into the ensight.core.extension dictionary.

When this file is imported, the directory it is in will have been added to the sys.path variable. Thus, if the file in question were not an actual extension definition, but a traditional Python module, adding the previous lines to the file and placing the file in the extension search path will cause the directory containing the module to be added to sys.path, simplifying importing of the file by name.