< home

Python Modules Tutorial

Any set of objects with an OpenExposition interface (i.e., descendants of class Exposer) can be accessed via Python in two ways.

The embedded Python interpreter (used in ExpositionSystemFLTK and ExpositionSystemCocoa) can be used in combination with GUI manifesters to interface with exposed elements. Also, the objects can be built into a Python module, and then used in other Python environments.

Building a Python module out of an exposer is easy. For example, the class Test discussed in the OpenExposition Introduction can become a part of a Python module like this:

#include <expo/ExpositionSystemPython.h>
#include "Test.h"

using namespace expo;

PyMODINIT_FUNC 
initexpo(void)
{
    ExpositionSystemPython *ES = new ExpositionSystemPython();
    ES->AddExposerFactory("Test", new TemplateExposerFactory<TestExposer>());
    ES->Run();
} 

The main part is specifying the classes to be encapsulated into the MAX external (in this case, TestExposer).

Using a suitable Python script and distutils, the self-contained module can be built. The setup.py script used for the above example looks like this:

from distutils.core import setup, Extension

expo = Extension('expo', sources = ['examples/test/TestPython.cpp', \
    'src/ExpositionSystemPython.cpp', 'src/Exposition.cpp', 'src/ExpositionSystem.cpp', \
    'src/PythonExposition.cpp'])

setup (name = 'Expo',
    version = '1.0',
    description = 'This is an OpenExposition package',
    ext_modules = [expo])

Executing something like python examples/test/setup.py build build_ext -Iinclude:/usr/local/include from the root OpenExposition folder will build the module and place it in the build/lib* folder. The TestPython example project does this - you can then switch to the build/lib* folder, execute Python, and import the built module (expo).

Interfacing with the Python module

Currently, the exposed objects are accessed through the expo module in Python. This module is automatically imported in the embedded interpreter, but has to be manually imported (import expo) when using a built OpenExposition module in some other Python envoronment. All objects that have been exposed through the ExpositionSystem (Calculator1 and Calculator2 in the Test example) can be accessed through appropriate objects in the expo module. For example, you can use things like print expo.Calculator1.call("sum"), or expo.Calculator2.set("a", 2), to interface with instances of TestExposer given as:

class TestExposer : public Test, public Exposer
{
public:
    // Whenever an Exposer constructor is called, the instance is pushed on a stack
    // as the current exposer instance.  All instantiated expositions are automatically
    // assigned to the current exposer.
    TestExposer(string const &name="Test") : Exposer(name)
    {
        // this provides access to a method, which we mark as the "final" action of the exposer
        *new MethodExpo<double,Test>(*this, &Test::sum, "sum")
            << new Property(Property::final);
        // this provides direct access to the flag variable
        *new VariableExpo<bool>(flag, "flag")
            << new InfluencesProperty(GetExpo("sum"));
        // this provides direct access to the a variable
        *new VariableExpo<int>(a, "a")
            << new InfluencesProperty(GetExpo("sum"));
        // this provides access to a variable through a set of get/set methods
        *new PropertyExpo<double, Test>(*this, &Test::GetB, &Test::SetB, "b")
            << new InfluencesProperty(GetExpo("sum"));
        
        // the following call will mark the end of construction for this exposer
        DoneConstructing();
    }
}; // end class TestExposer

In self-contained modules, instances of an exposed class have to be instantiated, for example you can do something like x = expo.spawn("Test") and then print x.call("sum"). If you do this in the embedded Python interpreter, it should also bring up the other manifesters (graphical and sound) for the new object.

In the future, the interface should be a lot more "natural" to Python, i.e. allowing statements such as x.sum() and x.a = 2.

Building your own Python modules

To build your own module, I suggest duplicating the target/project for the TestPython example in the OpenExposition distribution. Make sure you read the Installation Information for instructions on downloading and set-up for building and using the OpenExposition library.

Then, in your copy of TestPython.cpp (or whatever you rename it to) target/project, instead of "Test.h" include your own file that defines an OpenExposition interface through a class that is derived from class Exposer, and substitute the name of your class for the one occurence of TestExposer inside TestPython.cpp. Currently, your Exposer class MUST have a default constructor (see the examples above) in order for this to work.

 

Documentation generated on 14 Jun 2006 for OpenExposition by  doxygen 1.4.6>
Development hosted by SourceForge.net Logo