FX::FXPythonInterp Class Reference
[Python Support]

#include <FXPython.h>

List of all members.


Detailed Description

An instance of the python interpreter.

Embedding Python into your TnFOX application is extremely easy - simply create an instance of the Python interpreter by creating an FXPythonInterp. Thereafter, make calls to Boost.Python passing whatever parameters you like after setting which interpreter you want them to use by setContext(). Full support is provided for multithreaded code, nesting calls to multiple interpreters and the python Global Interpreter Lock (GIL) is correctly maintained.

One issue is what happens when you are embedding python into TnFOX code which is itself embedded in python code? In this situation, you want one of two things: (i) to create a new virgin python environment or (ii) to link into the python environment in which you reside. The former is easy, simply create a new FXPythonInterp. The latter is even easier, simply inspect FXPythonInterp::current() which returns a pointer to the FXPythonInterp responsible for executing the caller (thus if python code calls C++ code, it is set - but if no python is higher up the call stack, it is zero).

Furthermore, nesting of interpreters is possible eg; interpreter A calls C++ code which calls python code in interpreter B which calls some more C++ code. At each stage, current() returns the correct value for the current context. You should note that python treats interpreters and threads running inside an interpreter very similarly and thus a FXPythonInterp exists for each running thread in each interpreter plus an instance for each interpreter you create.

Note:
The current version of python (v2.3) has issues regarding usage of multiple interpreters, particularly with regard to certain extension modules which were not written to allow it.

Usage:

When creating a new interpreter which is the first "touch" of python in the process, the current python program name and arguments will set from FX::FXApp if one of those has been initialised. Otherwise, you must set it yourself (see FX::FXPython). TnFOX.pyd is loaded into your new python environment so you can use it immediately.

The setContext() and unsetContext() methods are used to select the current interpreter that calls to Boost.Python will use. It is very important that for every setContext() there is an equivalent unsetContext() and you must ensure a context is set before calling any python code at all (failing to do this results in an immediate crash and process exit). Furthermore you should be aware that python currently requires mutual exclusion between its interpreters and also between threads running within each of its interpreters so therefore while a setContext() is in place, you are also holding a mutex preventing all other threads in python or going through python from running. Needless to say, you don't want to hold it for too long - and don't rely on this behaviour, as it may change (especially different interpreters being able to run concurrently).

Calls to setContext() and unsetContext() can be nested. When python calls you, the context is released (by the patch applied to boost.python) but when you call python, you must ensure the context is set (our patched pyste ensures all generated bindings for virtual calls do this). You may find FX::FXPython_CtxHold of use which doubly ensures exception safety. Be especially cautious of the fact that setContext() is recursive ie; if a context is set on entry to setContext(), it is restored on unsetContext() and so deadlock is extremely likely.

You must not create threads using python's threading module or any other method - or if you do, these threads must never call TnFOX code. TnFOX relies on QThread creating all the threads as associated state is created with each thread which would be unset otherwise. Besides, currently python's threads behave a bit oddly. v0.5 now permits any QThread calling python for the first time to automatically set up a python thread state so you no longer need worry about it. Note that any threads started before the python DLL is loaded will assume they reference code in the primary interpreter - this contrasts against threads normally inheriting the interpreter in force when the start() method was called for that QThread.

The Boost.Python Library:

You will almost certainly make great use of Boost.Python's "python like" C++ objects which make interacting between the two environments a real boon. While BPL's documentation isn't great, its reference manual outlines what the following objects can do: dict, list, long, numeric, object, str, tuple. In particular, you want to read object and then read it a second time - and remember that BPL reminds you that python isn't C++ by forcing you to do a lot of explicit copy construction. Instead of throwing a error_already_set exception, TnFOX's customised BPL throws a FX::FXPythonException.

Finally, while it has been intended with the facilities provided here to cover all common usage without having to resort to the Python C API, obviously there are limits. If you want to do specialist things, you will need to dive into the direct API from time to time - remember to maintain reference counts (look into handle<> in BPL). However, I think that more often than not you will be too quick to "go direct" when in fact BPL does actually provide an easier solution. Ask on the C++-SIG mailing list on python.org.

See also:
FX::FXPython

Example:

using namespace FX;
using namespace boost::python;
{
    FXPythonCtxHold ctxhold;
    py("def printNum(no): print no");
    object printNum(pyeval("printNum"));
    long_ bignum((FXulong)-1);
    fxmessage("\nThe biggest number C++ can handle: "); printNum(bignum);
    bignum*=bignum;
    fxmessage("That number multiplied by itself: "); printNum(bignum);
}
See the source for the TestEmbedPython test for a lot more of this kind of code.

Public Member Functions

 FXPythonInterp (int argc=0, char **argv=0, const char *name=0)
const char * name () const throw ()
void setContext ()
void unsetContext ()

Static Public Member Functions

static FXPythonInterpcurrent ()
static void int_enterCPP ()
static void int_exitCPP ()

Friends

struct FXPythonInterpPrivate
class FXPython

Constructor & Destructor Documentation

FX::FXPythonInterp::FXPythonInterp ( int  argc = 0,
char **  argv = 0,
const char *  name = 0 
)

Creates an instance of the python interpreter optionally with the specified arguments and name. If python previously was not initialised, this initialises python and returns the default interpreter. In all other cases, creates a new interpreter. Note that if this initialises python, when the last is destroyed it will deinitialise python too.

Note:
On return, current context is set to the new interpreter.


Member Function Documentation

const char* FX::FXPythonInterp::name (  )  const throw ()

Returns the name of this python interpreter.

static FXPythonInterp* FX::FXPythonInterp::current (  )  [static]

Returns the python interpreter executing the calling code or 0 if there is none.

void FX::FXPythonInterp::setContext (  ) 

Sets the execution context to this interpreter.

void FX::FXPythonInterp::unsetContext (  ) 

Unsets the execution context. This MUST be matched with a corresponding setContext().


The documentation for this class was generated from the following file:

(C) 2002-2008 Niall Douglas. Some parts (C) to assorted authors.
Generated on Fri Jun 13 21:56:41 2008 for TnFOX by doxygen v1.5.6