Now only uses execution contexts, no more sub interpreter.
+ reviewed PyInterp_Interp class and Python initialization
+ removed GetLockWrapper() method from PyInterp_Interp class.
+ interpreter member is no more requested in PyLock_Request (can be set to NULL)
+ reviewed PyLockWrapper class design to forbid copy ctor and assignment
+ more sophisticated stdout/stderr redirection for Python command: restore what was previously used after Python command execution.
+ get rid of "shared_modules" logic - no more necessary with a single interpreter
//
#include "LightApp_PyInterp.h"
-#include <SUITApp_init_python.hxx>
-#include <PyConsole_Interp.h>
-
-#include <pthread.h>
-
/*!
- * constructor : multi Python interpreter, one per SALOME study.
- * calls initialize method defined in base class, which calls virtual methods
- * initstate & initcontext redefined here.
+ * constructor : Python interpreter.
*/
LightApp_PyInterp::LightApp_PyInterp(): PyConsole_EnhInterp()
{
}
/*!\class LightApp_PyInterp
- * EDF-CCAR
- * When SALOME uses multi Python interpreter feature,
- * Every study has its own interpreter and thread state (_tstate = Py_NewInterpreter())
- * This is fine because every study has its own modules (sys.modules) stdout and stderr
- * BUT some Python modules must be imported only once. In multi interpreter context Python
- * modules (*.py) are imported several times.
- * The pyqt module must be imported only once because it registers classes in a C module.
- * It's quite the same with omniorb modules (internals and generated with omniidl)
- * This problem is handled with "shared modules" defined in salome_shared_modules.py
- * These "shared modules" are imported only once and only copied in all the other interpreters
- * BUT it's not the only problem. Every interpreter has its own __builtin__ module. That's fine
- * but if we have copied some modules and imported others problems may arise with operations that
- * are not allowed in restricted execution environment. So we must impose that all interpreters
- * have identical __builtin__ module.
- * That's all, for the moment ...
+ * [ABN] : there is now a single Python interpreter for the whole SALOME run.
+ * Different execution environment are provided to emulate independent
+ * "virtual" Python interpreters.
*/
-bool LightApp_PyInterp::initContext()
-{
- /*!
- * The GIL is assumed to be held
- * It is the caller responsability caller to acquire the GIL
- * It will still be held on initContext output
- */
- if ( !PyConsole_Interp::initContext() )
- return false;
-
- //Import special module to change the import mechanism
- PyObjWrapper m1( PyImport_ImportModule( "import_hook" ) );
- if ( !m1 )
- {
- PyErr_Print();
- return false;
- }
-
- // Call init_shared_modules to initialize the shared import mechanism for modules
- //that must not be imported twice
- PyObjWrapper m2( PyObject_CallMethod( m1, (char*)"init_shared_modules", (char*)"O", SUIT_PYTHON::salome_shared_modules_module ) );
- if ( !m2 )
- {
- PyErr_Print();
- return false;
- }
- return true;
-}
-
/*!
Do nothing
- The initialization has been done in main
+ The initialization has been done in main - see SUITApp/SUITApp.cxx - main()
*/
void LightApp_PyInterp::initPython()
{
- _gtstate=SUIT_PYTHON::_gtstate; // initialisation in main
- _interp=SUIT_PYTHON::_interp;
}
protected:
virtual void initPython();
- virtual bool initContext();
};
#endif //_LIGHTAPP_PYINTERP_H_
if (dirArgument.trimmed() != "")
cmd = dirArgument + ".";
cmd += _last_matches[0] + ".__doc__";
- PyObject * str = PyRun_String(cmd.toStdString().c_str(), Py_eval_input, _g, _g);
+ PyObject * str = PyRun_String(cmd.toStdString().c_str(), Py_eval_input, _context, _context);
if (!str || str == Py_None || !PyString_Check(str))
{
if (!str)
{
QRegExp re("^[A-Z].+_[A-Z]+[a-z]+.+$"); // discard SWIG static method, e.g. MEDCouplingUMesh_Blabla
QString command("dir(" + dirArgument + ")");
- PyObject * plst = PyRun_String(command.toStdString().c_str(), Py_eval_input, _g, _g);
+ PyObject * plst = PyRun_String(command.toStdString().c_str(), Py_eval_input, _context, _context);
if(!plst || plst == Py_None) {
if(!plst)
PyErr_Clear();
\class PyConsole_Interp
\brief Python interpreter to be embedded to the SALOME study's GUI.
- Python interpreter is created one per SALOME study.
+ There is only one Python interpreter for the whole SALOME environment.
- Call initialize method defined in the base class PyInterp_Interp,
- to intialize interpreter after instance creation.
+ Call the initialize() method defined in the base class PyInterp_Interp,
+ to initialize the interpreter after instance creation.
The method initialize() calls virtuals methods
- initPython() to initialize global Python interpreter
- - initState() to initialize embedded interpreter state
+ //- initState() to initialize embedded interpreter state (OBSOLETE)
- initContext() to initialize interpreter internal context
- initRun() to prepare interpreter for running commands
-
- /EDF-CCAR/
- When SALOME uses multi Python interpreter feature,
- every study has its own interpreter and thread state (_tstate = Py_NewInterpreter()).
- This is fine because every study has its own modules (sys.modules) stdout and stderr.
-
- <b>But</b> some Python modules must be imported only once. In multi interpreter
- context Python modules (*.py) are imported several times.
- For example, the PyQt module must be imported only once because
- it registers classes in a C module.
-
- It's quite the same with omniorb modules (internals and generated with omniidl).
-
- This problem is handled with "shared modules" defined in salome_shared_modules.py.
- These "shared modules" are imported only once and only copied in all
- the other interpreters.
-
- <b>But</b> it's not the only problem. Every interpreter has its own
- __builtin__ module. That's fine but if we have copied some modules
- and imported others problems may arise with operations that are not allowed
- in restricted execution environment. So we must impose that all interpreters
- have identical __builtin__ module.
*/
/*!
{
}
-/*!
- \brief Initialize internal Python interpreter state.
-
- When calling initState the GIL is not held
- It must not be held on exit
-
- \return \c true on success
-*/
-bool PyConsole_Interp::initState()
-{
- PyEval_AcquireLock();
- _tstate = Py_NewInterpreter(); // create an interpreter and save current state
- PySys_SetArgv(PyInterp_Interp::_argc,PyInterp_Interp::_argv); // initialize sys.argv
-
- if(!builtinmodule) // PAL18041: deepcopy function don't work in Salome
- {
- //builtinmodule is static member of PyInterp class
- //If it is not NULL (initialized to the builtin module of the main interpreter
- //all the sub interpreters will have the same builtin
- //_interp is a static member and is the main interpreter
- //The first time we initialized it to the builtin of main interpreter
- builtinmodule=PyDict_GetItemString(_interp->modules, "__builtin__");
- }
-
- //If builtinmodule has been initialized all the sub interpreters
- // will have the same __builtin__ module
- if(builtinmodule){
- PyObject *m = PyImport_GetModuleDict();
- PyDict_SetItemString(m, "__builtin__", builtinmodule);
- _tstate->interp->builtins = PyModule_GetDict(builtinmodule);
- Py_INCREF(_tstate->interp->builtins);
- }
- PyEval_ReleaseThread(_tstate);
- return true;
-}
-
/*!
\brief Initialize python interpeter context.
PyErr_Print();
return false;
}
- _g = PyModule_GetDict(m); // get interpreter dictionnary context
-
- if(builtinmodule){
- PyDict_SetItemString(_g, "__builtins__", builtinmodule); // assign singleton __builtin__ module
- }
+ _context = PyModule_GetDict(m); // get interpreter dictionnary context
return true;
}
~PyConsole_Interp();
protected:
- virtual bool initState();
virtual bool initContext();
};
void PyInterp_LockRequest::safeExecute()
{
- if ( getInterp() ){
- PyLockWrapper aLock = getInterp()->GetLockWrapper();
+ //if ( getInterp() ){ // No need to have an interpreter now! we can simply run in a empty context
+ PyLockWrapper aLock; // Acquire GIL
//ProcessVoidEvent( new PyInterp_ExecuteEvent( this ) );
execute();
- }
+ //}
}
PyInterp_Event::~PyInterp_Event()
#define TOP_HISTORY_PY "--- top of history ---"
#define BEGIN_HISTORY_PY "--- begin of history ---"
-// a map to store python thread states that have been created for a given system thread (key=thread id,value=thread state)
-std::map<long,PyThreadState*> currentThreadMap;
-
/*!
\class PyLockWrapper
\brief Python GIL wrapper.
/*!
\brief Constructor. Automatically acquires GIL.
- \param theThreadState python thread state
*/
-PyLockWrapper::PyLockWrapper(PyThreadState* theThreadState):
- myThreadState(theThreadState),
- mySaveThreadState(0)
+PyLockWrapper::PyLockWrapper()
{
- if (myThreadState->interp == PyInterp_Interp::_interp)
- _savestate = PyGILState_Ensure();
- else
- PyEval_AcquireThread(myThreadState);
+ _gil_state = PyGILState_Ensure();
}
/*!
*/
PyLockWrapper::~PyLockWrapper()
{
- if (myThreadState->interp == PyInterp_Interp::_interp)
- PyGILState_Release(_savestate);
- else
- PyEval_ReleaseThread(myThreadState);
-}
-
-/*!
- \brief Get Python GIL wrapper.
- \return GIL lock wrapper (GIL is automatically acquired here)
-*/
-PyLockWrapper PyInterp_Interp::GetLockWrapper()
-{
- if (_tstate->interp == PyInterp_Interp::_interp)
- return _tstate;
-
- // If we are here, we have a secondary python interpreter. Try to get a thread state synchronized with the system thread
- long currentThreadid=PyThread_get_thread_ident(); // the system thread id
- PyThreadState* theThreadState;
- if(currentThreadMap.count(currentThreadid) != 0)
- {
- //a thread state exists for this thread id
- PyThreadState* oldThreadState=currentThreadMap[currentThreadid];
- if(_tstate->interp ==oldThreadState->interp)
- {
- //The old thread state has the same python interpreter as this one : reuse the threadstate
- theThreadState=oldThreadState;
- }
- else
- {
- //The old thread state has not the same python interpreter as this one : delete the old threadstate and create a new one
- PyEval_AcquireLock();
- PyThreadState_Clear(oldThreadState);
- PyThreadState_Delete(oldThreadState);
- PyEval_ReleaseLock();
- theThreadState=PyThreadState_New(_tstate->interp);
- currentThreadMap[currentThreadid]=theThreadState;
- }
- }
- else
- {
- // no old thread state for this thread id : create a new one
- theThreadState=PyThreadState_New(_tstate->interp);
- currentThreadMap[currentThreadid]=theThreadState;
- }
- return theThreadState;
+// if (myThreadState->interp == PyInterp_Interp::_interp)
+// PyGILState_Release(_savestate);
+// else
+// PyEval_ReleaseThread(myThreadState);
+
+ /* The destructor can never be called concurrently by two threads since it is called
+ * when the GIL is held - the below test should never run concurrently in two threads.
+ */
+ PyGILState_Release(_gil_state);
}
/*
int PyInterp_Interp::_argc = 1;
char* PyInterp_Interp::_argv[] = {(char*)""};
-PyObject* PyInterp_Interp::builtinmodule = NULL;
-PyThreadState* PyInterp_Interp::_gtstate = NULL;
-PyInterpreterState* PyInterp_Interp::_interp = NULL;
+//PyObject* PyInterp_Interp::builtinmodule = NULL;
+//PyThreadState* PyInterp_Interp::_gtstate = NULL;
+//PyInterpreterState* PyInterp_Interp::_interp = NULL;
/*!
\brief Basic constructor.
must call virtual method initalize().
*/
PyInterp_Interp::PyInterp_Interp():
- _tstate(0), _vout(0), _verr(0), _g(0)
+ _vout(0), _verr(0), _context(0)
{
}
+
+
/*!
\brief Destructor.
*/
_history.clear(); // start a new list of user's commands
_ith = _history.begin();
- initPython();
- // Here the global lock is released
+ initPython(); // This also inits the multi-threading for Python (but w/o acquiring GIL)
- initState();
+ //initState(); // [ABN] OBSOLETE
- PyEval_AcquireThread(_tstate);
+ // ---- The rest of the initialisation process is done hodling the GIL
+ PyLockWrapper lck;
initContext();
- // used to interpret & compile commands
+ // used to interpret & compile commands - this is really imported here
+ // and only added again (with PyImport_AddModule) later on
PyObjWrapper m(PyImport_ImportModule("codeop"));
if(!m) {
PyErr_Print();
- PyEval_ReleaseThread(_tstate);
+ PyEval_ReleaseLock();
return;
}
// All the initRun outputs are redirected to the standard output (console)
initRun();
- PyEval_ReleaseThread(_tstate);
}
/*!
\brief Initialize Python interpreter.
- In case if Python is not initialized, it sets program name, initializes the interpreter, sets program arguments,
- initializes threads.
- Otherwise, it just obtains the global interpreter and thread states. This is important for light SALOME configuration,
+ In case if Python is not initialized, it sets program name, initializes the single true Python
+ interpreter, sets program arguments, and initializes threads.
+ Otherwise, does nothing. This is important for light SALOME configuration,
as in full SALOME this is done at SalomeApp level.
- \sa SalomeApp_PyInterp class
+ \sa SalomeApp_PyInterp class and main() in SALOME_Session_Server
*/
void PyInterp_Interp::initPython()
{
Py_SetProgramName(_argv[0]);
Py_Initialize(); // Initialize the interpreter
PySys_SetArgv(_argc, _argv);
- PyEval_InitThreads(); // Create (and acquire) the interpreter lock
- }
- if ( _interp == NULL )
- _interp = PyThreadState_Get()->interp;
- if (PyType_Ready(&PyStdOut_Type) < 0) {
- PyErr_Print();
+ PyEval_InitThreads(); // Create (and acquire) the Python global interpreter lock (GIL)
+ PyEval_ReleaseLock();
}
- if ( _gtstate == NULL )
- _gtstate = PyEval_SaveThread(); // Release global thread state
}
/*!
\brief Get embedded Python interpreter banner.
\return banner string
*/
-std::string PyInterp_Interp::getbanner()
+std::string PyInterp_Interp::getbanner() const
{
- // Should we take the lock ?
- // PyEval_RestoreThread(_tstate);
+ PyLockWrapper lck;
std::string aBanner("Python ");
aBanner = aBanner + Py_GetVersion() + " on " + Py_GetPlatform() ;
aBanner = aBanner + "\ntype help to get general information on environment\n";
- //PyEval_SaveThread();
return aBanner;
}
*/
bool PyInterp_Interp::initRun()
{
- //
- // probably all below code isn't required
- //
- /*
- PySys_SetObject("stderr",_verr);
- PySys_SetObject("stdout",_vout);
-
- //PyObject *m = PyImport_GetModuleDict();
-
- PySys_SetObject("stdout",PySys_GetObject("__stdout__"));
- PySys_SetObject("stderr",PySys_GetObject("__stderr__"));
- */
return true;
}
/*!
\brief Compile Python command and evaluate it in the
- python dictionary context if possible.
+ python dictionary context if possible. This is not thread-safe.
+ This is the caller's responsability to make this thread-safe.
\internal
\param command Python command string
\param context Python context (dictionary)
return 1;
}
else {
- // Complete and correct text. We evaluate it.
- //#if PY_VERSION_HEX < 0x02040000 // python version earlier than 2.4.0
- // PyObjWrapper r(PyEval_EvalCode(v,context,context));
- //#else
PyObjWrapper r(PyEval_EvalCode((PyCodeObject *)(void *)v,context,context));
- //#endif
if(!r) {
// Execution error. We return -1
PyErr_Print();
\return -1 on fatal error, 1 if command is incomplete and 0
if command is executed successfully
*/
-static int compile_command(const char *command,PyObject *context)
+static int compile_command(const char *command, PyObject *context)
{
// First guess if command is execution of a script with args, or a simple Python command
std::string singleCommand = command;
}
/*!
- \brief Run Python command.
+ \brief Run Python command - the command has to fit on a single line (no \n!).
+ Use ';' if you need multiple statements evaluated at once.
\param command Python command
\return command status
*/
return simpleRun(command);
}
+/**
+ * Called before a command is run (when calling run() method). Not thread-safe. Caller's responsability
+ * to acquire GIL if needed.
+ */
+int PyInterp_Interp::beforeRun()
+{
+ return 0;
+}
+
/*!
- \brief Run Python command (used internally).
+ \brief Run Python command (used internally). Not thread-safe. GIL acquisition is caller's responsability.
\param command Python command
\param addToHistory if \c true (default), the command is added to the commands history
\return command status
_ith = _history.end();
}
- // We come from C++ to enter Python world
- // We need to acquire the Python global lock
- //PyLockWrapper aLock(_tstate); // san - lock is centralized now
+ // Current stdout and stderr are saved
+ PyObject * oldOut = PySys_GetObject((char*)"stdout");
+ PyObject * oldErr = PySys_GetObject((char*)"stderr");
+ // Keep them alive (PySys_GetObject returned a *borrowed* ref!)
+ Py_INCREF(oldOut);
+ Py_INCREF(oldErr);
- // Reset redirected outputs before treatment
+ // Redirect outputs to SALOME Python console before treatment
PySys_SetObject((char*)"stderr",_verr);
PySys_SetObject((char*)"stdout",_vout);
- int ier = compile_command(command,_g);
+ int ier = compile_command(command,_context);
- // Outputs are redirected on standards outputs (console)
- PySys_SetObject((char*)"stdout",PySys_GetObject((char*)"__stdout__"));
- PySys_SetObject((char*)"stderr",PySys_GetObject((char*)"__stderr__"));
+ // Outputs are redirected to what they were before
+ PySys_SetObject((char*)"stdout",oldOut);
+ PySys_SetObject((char*)"stderr",oldErr);
return ier;
}
#include <list>
#include <string>
+/**
+ * Utility class wrappin the Python GIL acquisition. This makes use of the high level
+ * API (PyGILState_Ensure and PyGILState_Release), and is hence compatible with only
+ * one running Python interpreter (no call to Py_NewInterpreter()).
+ * When the class is instanciated the lock is acquired. It is released at destruction time.
+ * Copy construction (and hence assignation) is forbidden.
+ */
class PYINTERP_EXPORT PyLockWrapper
{
- PyThreadState* myThreadState;
- PyThreadState* mySaveThreadState;
- PyGILState_STATE _savestate;
+ PyGILState_STATE _gil_state;
public:
- PyLockWrapper(PyThreadState* theThreadState);
+ PyLockWrapper();
~PyLockWrapper();
+
+private:
+ // "Rule of 3" - Forbid usage of copy operator and copy-constructor
+ PyLockWrapper(const PyLockWrapper & another);
+ const PyLockWrapper & operator=(const PyLockWrapper & another);
};
typedef void PyOutChanged(void* data,char * c);
+/**
+ * Main class representing a *virtual* Python interpreter. There is really only one true
+ * Python interpreter in the whole application (no call to Py_NewInterpreter),
+ * but the use of different execution contexts allow
+ * to split the execution lines, and hence to emulate (relatively) independent interpreters.
+ * This has some consequences: modules imported in one context are not re-imported in another context
+ * (only there namespace is made available when importing in another context).
+ * See also class PyConsole_Interp.
+ */
class PYINTERP_EXPORT PyInterp_Interp
{
public:
static int _argc;
static char* _argv[];
- static PyObject *builtinmodule;
- static PyThreadState *_gtstate;
- static PyInterpreterState *_interp;
PyInterp_Interp();
virtual ~PyInterp_Interp();
virtual int run(const char *command);
- PyLockWrapper GetLockWrapper();
+ // [ABN] - the PyLockWrapper is no more attached to the interpreter
+ // PyLockWrapper GetLockWrapper() const;
- std::string getbanner();
+ std::string getbanner() const;
void setverrcb(PyOutChanged*,void*);
void setvoutcb(PyOutChanged*,void*);
const char * getPrevious();
- const char * getNext();
+ const char * getNext();
protected:
- PyThreadState * _tstate;
+ /** Redirection of stdout and stderr */
PyObject * _vout;
PyObject * _verr;
- PyObject * _g;
+ /** Execution context (local and global variables) */
+ PyObject * _context;
PyObject * _codeop;
std::list<std::string> _history;
std::list<std::string>::iterator _ith;
- virtual int beforeRun() { return 0; }
+ virtual int beforeRun();
int simpleRun(const char* command, const bool addToHistory = true);
- virtual bool initRun();
virtual void initPython();
- virtual bool initState() = 0;
- virtual bool initContext() = 0;
+ /** OBSOLETE - should'nt be called anymore */
+ //virtual bool initState() = 0;
+
+ /** Initialize execution context. Must set the member _context, and return True on success. */
+ virtual bool initContext() = 0;
+ virtual bool initRun();
};
+/**
+ * Utility class to properly handle the reference counting required on Python objects.
+ */
class PYINTERP_EXPORT PyObjWrapper
{
PyObject* myObject;
{
public:
- PyInterp_LockRequest( PyInterp_Interp* interp, QObject* listener = 0, bool sync = false )
+ PyInterp_LockRequest( PyInterp_Interp* interp, QObject* listener=0, bool sync=false )
: PyInterp_Request( listener, sync ), myInterp( interp )
{}
static bool alreadyInitialized = false;
if ( !alreadyInitialized ) {
- // call only once (see comment above) !
- PyEval_RestoreThread( KERNEL_PYTHON::_gtstate);
+ PyLockWrapper lck; // GIL acquisition
INIT_FUNCTION();
- PyEval_ReleaseThread( KERNEL_PYTHON::_gtstate);
alreadyInitialized = !alreadyInitialized;
}
// Py_ssize_t for old Pythons
// This code is as recommended by"
// http://www.python.org/dev/peps/pep-0353/#conversion-guidelines
-#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
-typedef int Py_ssize_t;
-# define PY_SSIZE_T_MAX INT_MAX
-# define PY_SSIZE_T_MIN INT_MIN
-#endif
+//#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
+//typedef int Py_ssize_t;
+//# define PY_SSIZE_T_MAX INT_MAX
+//# define PY_SSIZE_T_MIN INT_MIN
+//#endif
//
// NB: Python requests.
// make initialization only once (see comment above) !
if ( !alreadyInitialized ) {
- static PyThreadState* gtstate = 0;
-#ifndef GUI_DISABLE_CORBA
- if ( SUIT_PYTHON::initialized )
- gtstate = SUIT_PYTHON::_gtstate;
- else
- gtstate = KERNEL_PYTHON::_gtstate;
-#else
- gtstate = SUIT_PYTHON::_gtstate;
-#endif
- PyEval_RestoreThread( gtstate );
-
+ PyLockWrapper lck; // GIL acquisition
INIT_FUNCTION();
-
- PyEval_ReleaseThread( gtstate );
-
alreadyInitialized = !alreadyInitialized;
}
// data model management
QString createObject( const QString& );
QString createObject( const QString&,
- const QString&,
- const QString&,
- const QString& );
+ const QString&,
+ const QString&,
+ const QString& );
void setName( const QString&, const QString& );
QString getName( const QString& ) const;
* Do nothing
* The initialization has been done in main
*/
- MESSAGE("SALOME_PYQT_PyInterp::initPython");
-#ifndef GUI_DISABLE_CORBA
- if(SUIT_PYTHON::initialized) {
- ASSERT(SUIT_PYTHON::_gtstate); // initialisation in main
- SCRUTE(SUIT_PYTHON::_gtstate);
- _tstate = SUIT_PYTHON::_gtstate;
- }
- else {
- ASSERT(KERNEL_PYTHON::_gtstate); // initialisation in main
- SCRUTE(KERNEL_PYTHON::_gtstate);
- _tstate = KERNEL_PYTHON::_gtstate;
- }
-#else
- SCRUTE(SUIT_PYTHON::_gtstate);
- _tstate = SUIT_PYTHON::_gtstate;
-#endif
-}
-
-bool SALOME_PYQT_PyInterp::initState()
-{
- /*
- * The GIL is assumed to not be held on the call
- * The GIL is acquired in initState and will be held on initState exit
- * It is the caller responsability to release the lock on exit if needed
- */
- PyEval_AcquireThread(_tstate);
- SCRUTE(_tstate);
- PyEval_ReleaseThread(_tstate);
- return true;
+ MESSAGE("SALOME_PYQT_PyInterp::initPython - does nothing");
}
-
bool SALOME_PYQT_PyInterp::initContext()
{
/*
* It is the caller responsability to acquire the GIL before calling initContext
* It will still be held on initContext exit
*/
- _g = PyDict_New(); // create interpreter dictionnary context
- PyObject *bimod = PyImport_ImportModule("__builtin__");
- PyDict_SetItemString(_g, "__builtins__", bimod);
- Py_DECREF(bimod);
+ _context = PyDict_New(); // create interpreter dictionnary context
return true;
}
MESSAGE("compile");
PyObject *code = Py_CompileString((char *)command,"PyGUI",Py_file_input);
if(!code){
- // Une erreur s est produite en general SyntaxError
+ // An error occured - normally here a SyntaxError
PyErr_Print();
return -1;
}
- //#if PY_VERSION_HEX < 0x02040000 // python version earlier than 2.4.0
- // PyObject *r = PyEval_EvalCode(code,_g,_g);
- //#else
- PyObject *r = PyEval_EvalCode((PyCodeObject *)code,_g,_g);
- //#endif
+ PyObject *r = PyEval_EvalCode((PyCodeObject *)code,_context,_context);
+
Py_DECREF(code);
if(!r){
- // Une erreur s est produite a l execution
+ // An error occured at execution
PyErr_Print();
return -1 ;
}
protected:
virtual void initPython();
- virtual bool initState();
virtual bool initContext();
};
XmlHandler( PyModuleHelper* helper, const QString& fileName );
void createActions();
void createPopup( QMenu* menu,
- const QString& context,
- const QString& parent,
- const QString& object );
+ const QString& context,
+ const QString& parent,
+ const QString& object );
void activateMenus( bool );
private:
QIcon loadIcon( const QString& fileName );
void createMenu( QDomNode& parentNode,
- const int parentMenuId = -1,
- QMenu* parentPopup = 0 );
+ const int parentMenuId = -1,
+ QMenu* parentPopup = 0 );
void createToolBar( QDomNode& parentNode );
void insertPopupItems( QDomNode& parentNode,
- QMenu* menu );
+ QMenu* menu );
private:
PyModuleHelper* myHelper;
\param fileName path to the XML menu description file
*/
PyModuleHelper::XmlHandler::XmlHandler( PyModuleHelper* helper,
- const QString& fileName )
+ const QString& fileName )
: myHelper( helper )
{
if ( !fileName.isEmpty() ) {
\param context popup menu object name
*/
void PyModuleHelper::XmlHandler::createPopup( QMenu* menu,
- const QString& context,
- const QString& parent,
- const QString& object )
+ const QString& context,
+ const QString& parent,
+ const QString& object )
{
// get document element
QDomElement aDocElem = myDoc.documentElement();
if ( module() && !fileName.isEmpty() ) {
SUIT_ResourceMgr* resMgr = module()->getApp()->resourceMgr();
QPixmap pixmap = resMgr->loadPixmap( module()->name(),
- QApplication::translate( module()->name().toLatin1().data(),
- fileName.toLatin1().data() ) );
- if ( !pixmap.isNull() )
- icon = QIcon( pixmap );
+ QApplication::translate( module()->name().toLatin1().data(),
+ fileName.toLatin1().data() ) );
+ if ( !pixmap.isNull() )
+ icon = QIcon( pixmap );
}
return icon;
\param parentPopup parent popup menu (0 for top-level menu)
*/
void PyModuleHelper::XmlHandler::createMenu( QDomNode& parentNode,
- const int parentMenuId,
- QMenu* parentPopup )
+ const int parentMenuId,
+ QMenu* parentPopup )
{
if ( !module() || parentNode.isNull() )
return;
if ( id != -1 ) {
// create menu action
QAction* action = module()->createAction( id, // ID
- tooltip, // tooltip
- icon, // icon
- label, // menu text
- tooltip, // status-bar text
- QKeySequence( accel ), // keyboard accelerator
- module(), // action owner
- toggle ); // toogled action
- myHelper->connectAction( action );
+ tooltip, // tooltip
+ icon, // icon
+ label, // menu text
+ tooltip, // status-bar text
+ QKeySequence( accel ), // keyboard accelerator
+ module(), // action owner
+ toggle ); // toogled action
+ myHelper->connectAction( action );
module()->createMenu( action, // action
menuId, // parent menu ID
id, // ID (same as for createAction())
// -1 action ID is not allowed : it means that <item-id> attribute is missed in the XML file!
// also check if the action with given ID is already created
if ( id != -1 ) {
- // create toolbar action
- QAction* action = module()->createAction( id, // ID
- tooltip, // tooltip
- icon, // icon
- label, // menu text
- tooltip, // status-bar text
- QKeySequence( accel ), // keyboard accelerator
- module(), // action owner
- toggle ); // toogled action
- myHelper->connectAction( action );
- module()->createTool( action, tbId, -1, pos );
+ // create toolbar action
+ QAction* action = module()->createAction( id, // ID
+ tooltip, // tooltip
+ icon, // icon
+ label, // menu text
+ tooltip, // status-bar text
+ QKeySequence( accel ), // keyboard accelerator
+ module(), // action owner
+ toggle ); // toogled action
+ myHelper->connectAction( action );
+ module()->createTool( action, tbId, -1, pos );
}
}
else if ( aTagName == "separatorTB" || aTagName == "separator" ) {
// -1 action ID is not allowed : it means that <item-id> attribute is missed in the XML file!
// also check if the action with given ID is already created
if ( id != -1 ) {
- QAction* action = module()->createAction( id, // ID
- tooltip, // tooltip
- icon, // icon
- label, // menu text
- tooltip, // status-bar text
- QKeySequence( accel ), // keyboard accelerator
- module(), // action owner
- toggle ); // toogled action
- myHelper->connectAction( action );
+ QAction* action = module()->createAction( id, // ID
+ tooltip, // tooltip
+ icon, // icon
+ label, // menu text
+ tooltip, // status-bar text
+ QKeySequence( accel ), // keyboard accelerator
+ module(), // action owner
+ toggle ); // toogled action
+ myHelper->connectAction( action );
QAction* before = ( pos >= 0 && pos < actions.count() ) ? actions[ pos ] : 0;
menu->insertAction( before, action );
}
{
delete myXmlHandler;
if ( myInterp && myPyModule ) {
- PyLockWrapper aLock = myInterp->GetLockWrapper();
+ PyLockWrapper aLock; // Acquire GIL
Py_XDECREF( myPyModule );
}
}
{
if ( myModule && a )
QObject::connect( a, SIGNAL( triggered( bool ) ),
- this, SLOT( actionActivated() ),
- Qt::UniqueConnection );
+ this, SLOT( actionActivated() ),
+ Qt::UniqueConnection );
}
/*!
\brief Initialization of the Python-based SALOME module.
This method can be used for creation of the menus, toolbars and
- other such staff.
+ other such stuff.
There are two ways to do this:
- 1) for obsolete modules implementatino this method first tries to read
- <module>_<language>.xml resource file which contains a menu,
+ 1) for obsolete modules, the implementation of this method first tries to read
+ the <module>_<language>.xml resource file which contains a menu,
toolbars and popup menus description;
2) new modules can create menus by direct calling of the
corresponding methods of SalomePyQt Python API in the Python
\note SALOME supports two modes of modules loading:
- immediate (all the modules are created and initialized
- immediately when the application object is created;
+ immediately when the application object is created);
- postponed modules loading (used currently); in this mode
the module is loaded only by explicit request.
If postponed modules loading is not used, the active
{
public:
InitializeReq( PyModuleHelper* _helper,
- CAM_Application* _app )
+ CAM_Application* _app )
: PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true)
myHelper( _helper ),
- myApp( _app )
+ myApp( _app )
{}
protected:
virtual void execute()
{
public:
ActivateReq( PyModuleHelper* _helper,
- SUIT_Study* _study,
- bool _customize )
- : PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true)
- myHelper( _helper ),
- myStudy ( _study ),
- myCustomize( _customize )
- {}
+ SUIT_Study* _study,
+ bool _customize )
+ : PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true)
+ myHelper( _helper ),
+ myStudy ( _study ),
+ myCustomize( _customize )
+ {}
protected:
virtual void execute()
- {
- if ( !myCustomize )
- myHelper->internalActivate( myStudy ); // first activation stage
- else
- myHelper->internalCustomize( myStudy ); // second activation stage
- }
+ {
+ if ( !myCustomize )
+ myHelper->internalActivate( myStudy ); // first activation stage
+ else
+ myHelper->internalCustomize( myStudy ); // second activation stage
+ }
private:
PyModuleHelper* myHelper;
SUIT_Study* myStudy;
if ( myLastActivateStatus ) {
// connect preferences changing signal
connect( myModule->getApp(), SIGNAL( preferenceChanged( const QString&, const QString&, const QString& ) ),
- this, SLOT( preferenceChanged( const QString&, const QString&, const QString& ) ) );
+ this, SLOT( preferenceChanged( const QString&, const QString&, const QString& ) ) );
// connect active view change signal
SUIT_Desktop* d = study->application()->desktop();
connect( d, SIGNAL( windowActivated( SUIT_ViewWindow* ) ),
- this, SLOT( activeViewChanged( SUIT_ViewWindow* ) ) );
+ this, SLOT( activeViewChanged( SUIT_ViewWindow* ) ) );
// if active window exists, call activeViewChanged() function;
// temporary solution: if a getActiveView() in SalomePyQt available
// we no longer need this
{
public:
DeactivateReq( PyInterp_Interp* _py_interp,
- PyModuleHelper* _helper,
+ PyModuleHelper* _helper,
SUIT_Study* _study )
: PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true)
myHelper( _helper ),
- myStudy ( _study )
+ myStudy ( _study )
{}
protected:
virtual void execute()
// disconnect the SUIT_Desktop signal windowActivated()
SUIT_Desktop* d = study->application()->desktop();
disconnect( d, SIGNAL( windowActivated( SUIT_ViewWindow* ) ),
- this, SLOT( activeViewChanged( SUIT_ViewWindow* ) ) );
+ this, SLOT( activeViewChanged( SUIT_ViewWindow* ) ) );
// deactivate menus, toolbars, etc
if ( myXmlHandler ) myXmlHandler->activateMenus( false );
\param parameter preference resources parameter name
*/
void PyModuleHelper::preferencesChanged( const QString& section,
- const QString& parameter )
+ const QString& parameter )
{
FuncMsg fmsg( "PyModuleHelper::preferencesChanged()" );
{
public:
PrefChangeReq( PyInterp_Interp* _py_interp,
- PyModuleHelper* _helper,
- const QString& _section,
- const QString& _parameter )
+ PyModuleHelper* _helper,
+ const QString& _section,
+ const QString& _parameter )
: PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true)
myHelper ( _helper ),
mySection( _section ),
\param parameter preference resources parameter name
*/
void PyModuleHelper::preferenceChanged( const QString& module,
- const QString& section,
- const QString& parameter )
+ const QString& section,
+ const QString& parameter )
{
FuncMsg fmsg( "PyModuleHelper::preferenceChanged()" );
{
public:
StudyChangedReq( PyModuleHelper* _helper,
- SUIT_Study* _study )
+ SUIT_Study* _study )
: PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true)
myHelper( _helper ),
- myStudy ( _study )
+ myStudy ( _study )
{}
protected:
virtual void execute()
{
public:
ActionReq( PyInterp_Interp* _py_interp,
- PyModuleHelper* _helper,
- int _id )
+ PyModuleHelper* _helper,
+ int _id )
: PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true)
myHelper( _helper ),
myId ( _id )
const QString& _context,
QMenu* _menu )
: PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true)
- myHelper ( _helper ),
+ myHelper ( _helper ),
myContext( _context ),
myMenu ( _menu )
{}
{
public:
CreatePrefReq( PyInterp_Interp* _py_interp,
- PyModuleHelper* _helper )
+ PyModuleHelper* _helper )
: PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true)
myHelper( _helper )
{}
{
public:
ActiveViewChangeReq( PyInterp_Interp* _py_interp,
- PyModuleHelper* _helper,
- SUIT_ViewWindow* _view )
+ PyModuleHelper* _helper,
+ SUIT_ViewWindow* _view )
: PyInterp_LockRequest( _py_interp, 0, true ),
myHelper( _helper ),
- myView( _view )
+ myView( _view )
{}
protected:
virtual void execute()
{
public:
TryCloseViewReq( PyInterp_Interp* _py_interp,
- PyModuleHelper* _helper,
- SUIT_ViewWindow* _view )
+ PyModuleHelper* _helper,
+ SUIT_ViewWindow* _view )
: PyInterp_LockRequest( _py_interp, 0, true ),
myHelper( _helper ),
- myView( _view )
+ myView( _view )
{}
protected:
virtual void execute()
{
public:
CloseViewReq( PyInterp_Interp* _py_interp,
- PyModuleHelper* _helper,
- SUIT_ViewWindow* _view )
+ PyModuleHelper* _helper,
+ SUIT_ViewWindow* _view )
: PyInterp_LockRequest( _py_interp, 0, true ),
myHelper( _helper ),
myView( _view )
{
public:
CloneViewReq( PyInterp_Interp* _py_interp,
- PyModuleHelper* _helper,
- SUIT_ViewWindow* _view )
+ PyModuleHelper* _helper,
+ SUIT_ViewWindow* _view )
: PyInterp_LockRequest( _py_interp, 0, true ),
myHelper( _helper ),
- myView( _view )
+ myView( _view )
{}
protected:
virtual void execute()
{
public:
SaveReq( PyInterp_Interp* _py_interp,
- PyModuleHelper* _helper,
- QStringList& _files )
+ PyModuleHelper* _helper,
+ QStringList& _files )
: PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true)
myHelper( _helper ) ,
myFiles( _files )
{
public:
LoadReq( PyInterp_Interp* _py_interp,
- PyModuleHelper* _helper,
- QStringList _files,
- bool& _loaded )
+ PyModuleHelper* _helper,
+ QStringList _files,
+ bool& _loaded )
: PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true)
myHelper( _helper ) ,
myFiles( _files ),
{
public:
DumpPythonReq( PyInterp_Interp* _py_interp,
- PyModuleHelper* _helper,
- QStringList& _files )
+ PyModuleHelper* _helper,
+ QStringList& _files )
: PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true)
myHelper( _helper ) ,
myFiles( _files )
{
public:
IsDraggableReq( PyInterp_Interp* _py_interp,
- PyModuleHelper* _helper,
- LightApp_DataObject* _data_object,
- bool& _is_draggable )
+ PyModuleHelper* _helper,
+ LightApp_DataObject* _data_object,
+ bool& _is_draggable )
: PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true)
myHelper( _helper ) ,
myDataObject( _data_object ),
// Executing the request synchronously
if ( !PyInterp_Dispatcher::Get()->IsBusy() )
PyInterp_Dispatcher::Get()->Exec( new IsDraggableReq( myInterp,
- const_cast<PyModuleHelper*>( this ),
- const_cast<LightApp_DataObject*>( data_object ),
- draggable ) );
+ const_cast<PyModuleHelper*>( this ),
+ const_cast<LightApp_DataObject*>( data_object ),
+ draggable ) );
}
return draggable;
{
public:
IsDropAcceptedReq( PyInterp_Interp* _py_interp,
- PyModuleHelper* _helper,
- LightApp_DataObject* _data_object,
- bool& _is_drop_accepted )
+ PyModuleHelper* _helper,
+ LightApp_DataObject* _data_object,
+ bool& _is_drop_accepted )
: PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true)
myHelper( _helper ) ,
myDataObject( _data_object ),
// Executing the request synchronously
if ( !PyInterp_Dispatcher::Get()->IsBusy() )
PyInterp_Dispatcher::Get()->Exec( new IsDropAcceptedReq( myInterp,
- const_cast<PyModuleHelper*>( this ),
- const_cast<LightApp_DataObject*>( data_object ),
- dropAccepted ) );
+ const_cast<PyModuleHelper*>( this ),
+ const_cast<LightApp_DataObject*>( data_object ),
+ dropAccepted ) );
}
return dropAccepted;
\param action current drop action (copy or move)
*/
void PyModuleHelper::dropObjects( const DataObjectList& what, SUIT_DataObject* where,
- const int row, Qt::DropAction action )
+ const int row, Qt::DropAction action )
{
FuncMsg fmsg( "PyModuleHelper::dropObjects()" );
{
public:
DropObjectsReq( PyInterp_Interp* _py_interp,
- PyModuleHelper* _helper,
- const DataObjectList& _what,
- SUIT_DataObject* _where,
- const int _row,
- Qt::DropAction _action )
+ PyModuleHelper* _helper,
+ const DataObjectList& _what,
+ SUIT_DataObject* _where,
+ const int _row,
+ Qt::DropAction _action )
: PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true)
myHelper( _helper ) ,
myWhat( _what ),
- myWhere( _where ),
- myRow( _row ),
- myAction ( _action )
+ myWhere( _where ),
+ myRow( _row ),
+ myAction ( _action )
{}
protected:
virtual void execute()
public:
EngineIORReq( PyInterp_Interp* _py_interp,
PyModuleHelper* _helper,
- QString& _ior )
+ QString& _ior )
: PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true)
myHelper( _helper ),
- myIOR( _ior )
+ myIOR( _ior )
{}
protected:
virtual void execute()
if ( anIOR.isEmpty() ) {
// post request
PyInterp_Dispatcher::Get()->Exec( new EngineIORReq( myInterp,
- const_cast<PyModuleHelper*>( this ),
- anIOR ) );
+ const_cast<PyModuleHelper*>( this ),
+ anIOR ) );
}
return anIOR;
// import 'salome' module and call 'salome_init' method;
// do it only once on interpreter creation
// ... first get python lock
- PyLockWrapper aLock = myInterp->GetLockWrapper();
+ PyLockWrapper aLock; // Acquire GIL
// ... then import a module
PyObjWrapper aMod = PyImport_ImportModule( "salome" );
if ( !aMod ) {
\brief Import Python GUI module and store reference to the module.
\internal
- Attention! initInterp() should be called first!!!
+ Warning! initInterp() should be called first!!!
*/
void PyModuleHelper::importModule()
{
// import Python GUI module and put it in <myPyModule> attribute
// ... first get python lock
- PyLockWrapper aLock = myInterp->GetLockWrapper();
+ PyLockWrapper aLock; // Acquire GIL
// ... then import a module
QString aMod = QString( "%1GUI" ).arg( myModule->name() );
try {
// call setWorkSpace() method
// ... first get python lock
- PyLockWrapper aLock = myInterp->GetLockWrapper();
+ PyLockWrapper aLock; // Acquire GIL
// ... then try to import SalomePyQt module. If it's not possible don't go on.
PyObjWrapper aQtModule( PyImport_ImportModule( "SalomePyQt" ) );
// then call Python module's initialize() method
// ... first get python lock
- PyLockWrapper aLock = myInterp->GetLockWrapper();
+ PyLockWrapper aLock; // Acquire GIL
// ... (the Python module is already imported)
// ... finally call Python module's initialize() method
}
// get python lock
- PyLockWrapper aLock = myInterp->GetLockWrapper();
+ PyLockWrapper aLock; // Acquire GIL
// call Python module's activate() method (for the new modules)
if ( PyObject_HasAttrString( myPyModule , (char*)"activate" ) ) {
setWorkSpace();
// get python lock
- PyLockWrapper aLock = myInterp->GetLockWrapper();
+ PyLockWrapper aLock; // Acquire GIL
if ( IsCallOldMethods ) {
// call Python module's setSettings() method (obsolete)
setWorkSpace();
// get python lock
- PyLockWrapper aLock = myInterp->GetLockWrapper();
+ PyLockWrapper aLock; // Acquire GIL
// call Python module's activeStudyChanged() method
if ( PyObject_HasAttrString( myPyModule, (char*)"activeStudyChanged" ) ) {
if ( PyObject_HasAttrString(myPyModule , (char*)"isDraggable") ) {
PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"isDraggable",
- (char*)"s", what->entry().toLatin1().constData() ) );
+ (char*)"s", what->entry().toLatin1().constData() ) );
if( !res || !PyBool_Check( res )) {
PyErr_Print();
draggable = false;
if ( PyObject_HasAttrString(myPyModule , (char*)"isDropAccepted") ) {
PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"isDropAccepted",
- (char*)"s", where->entry().toLatin1().constData() ) );
+ (char*)"s", where->entry().toLatin1().constData() ) );
if( !res || !PyBool_Check( res )) {
PyErr_Print();
dropAccepted = false;
\param action current drop action (copy or move)
*/
void PyModuleHelper::internalDropObjects( const DataObjectList& what, SUIT_DataObject* where,
- const int row, Qt::DropAction action )
+ const int row, Qt::DropAction action )
{
FuncMsg fmsg( "--- PyModuleHelper::internalDropObjects()" );
PyObjWrapper sipList( sipBuildResult( 0, "D", theList, sipType_QStringList, NULL) );
#endif
if ( PyObject_HasAttrString(myPyModule, (char*)"dropObjects") ) {
- PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"dropObjects", (char*)"Osii",
- sipList.get(),
- whereObject->entry().toLatin1().constData(),
- row, action ) );
+ PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"dropObjects", (char*)"Osii",
+ sipList.get(),
+ whereObject->entry().toLatin1().constData(),
+ row, action ) );
if( !res ) {
PyErr_Print();
if ( PyObject_HasAttrString( myPyModule , "engineIOR" ) ) {
PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"engineIOR", (char*)"" ) );
if ( !res ) {
- PyErr_Print();
+ PyErr_Print();
}
else {
- // parse the return value, result chould be string
- if ( PyString_Check( res ) ) {
- ior = PyString_AsString( res );
- }
+ // parse the return value, result chould be string
+ if ( PyString_Check( res ) ) {
+ ior = PyString_AsString( res );
+ }
}
}
}
// Connect tryCloseView() and deleteView() signals
if ( viewMgr ) {
connect( viewMgr, SIGNAL( tryCloseView( SUIT_ViewWindow* ) ),
- this, SLOT( tryCloseView( SUIT_ViewWindow* ) ),
- Qt::UniqueConnection );
+ this, SLOT( tryCloseView( SUIT_ViewWindow* ) ),
+ Qt::UniqueConnection );
connect( viewMgr, SIGNAL( deleteView( SUIT_ViewWindow* ) ),
this, SLOT( closeView( SUIT_ViewWindow* ) ),
- Qt::UniqueConnection );
+ Qt::UniqueConnection );
}
// Connect cloneView() signal of an OCC View
if ( view->inherits( "OCCViewer_ViewWindow" ) ) {
connect( view, SIGNAL( viewCloned( SUIT_ViewWindow* ) ),
this, SLOT( cloneView( SUIT_ViewWindow* ) ),
- Qt::UniqueConnection );
+ Qt::UniqueConnection );
}
// Connect cloneView() signal of Plot2d View
else if ( viewModel && viewModel->inherits( "Plot2d_Viewer" ) ) {
connect( viewModel, SIGNAL( viewCloned( SUIT_ViewWindow* ) ),
this, SLOT( cloneView( SUIT_ViewWindow* ) ),
- Qt::UniqueConnection );
+ Qt::UniqueConnection );
}
}
bool isDraggable( const SUIT_DataObject* ) const;
bool isDropAccepted( const SUIT_DataObject* ) const;
void dropObjects( const DataObjectList&, SUIT_DataObject*,
- const int, Qt::DropAction );
+ const int, Qt::DropAction );
QString engineIOR() const;
private:
bool internalIsDraggable( LightApp_DataObject* );
bool internalIsDropAccepted( LightApp_DataObject* );
void internalDropObjects( const DataObjectList&, SUIT_DataObject*,
- const int, Qt::DropAction );
+ const int, Qt::DropAction );
QString internalEngineIOR() const;
void connectView( SUIT_ViewWindow* );
int _argc = 1;
char* _argv[] = {(char*)""};
SUIT_PYTHON::init_python(_argc,_argv);
-
- PyEval_RestoreThread( SUIT_PYTHON::_gtstate );
-
- if ( !SUIT_PYTHON::salome_shared_modules_module ) // import only once
- SUIT_PYTHON::salome_shared_modules_module = PyImport_ImportModule( (char*)"salome_shared_modules" );
- if ( !SUIT_PYTHON::salome_shared_modules_module )
- PyErr_Print();
-
- PyEval_ReleaseThread( SUIT_PYTHON::_gtstate );
-
+ PyEval_ReleaseLock();
#endif
SUIT_Application* theApp = aSession->startApplication( argList.first() );
//
#include "SUITApp_init_python.hxx"
-
-PyThreadState* SUIT_PYTHON::_gtstate = NULL;
-PyObject *SUIT_PYTHON::salome_shared_modules_module = NULL;
-PyInterpreterState* SUIT_PYTHON::_interp = NULL;
bool SUIT_PYTHON::initialized = false;
void SUIT_PYTHON::init_python(int argc, char **argv)
Py_SetProgramName(argv[0]);
Py_Initialize(); // Initialize the interpreter
PySys_SetArgv(argc, argv);
- SUIT_PYTHON::_interp = PyThreadState_Get()->interp;
- PyEval_InitThreads(); // Create (and acquire) the interpreter lock
- SUIT_PYTHON::_gtstate = PyEval_SaveThread(); // Release global thread state
- SUIT_PYTHON::initialized = true;
+ PyEval_InitThreads(); // Create (and acquire) the interpreter lock - can be called many times
}
struct SUITAPP_EXPORT SUIT_PYTHON
{
- static PyThreadState *_gtstate;
- static PyInterpreterState *_interp;
- static PyObject *salome_shared_modules_module;
static bool initialized;
static void init_python(int argc, char **argv);
-
};
#endif // _SUITAPP_INIT_PYTHON_
createExtraActions();
// import Python module that manages SALOME plugins
- PyGILState_STATE gstate = PyGILState_Ensure();
- PyObjWrapper pluginsmanager = PyImport_ImportModule((char*)"salome_pluginsmanager");
- PyObjWrapper res = PyObject_CallMethod( pluginsmanager, (char*)"initialize", (char*)"isss",0,"salome",tr("MEN_DESK_PLUGINS_TOOLS").toStdString().c_str(),tr("MEN_DESK_PLUGINS").toStdString().c_str());
- if ( !res )
- PyErr_Print();
- PyGILState_Release(gstate);
+ {
+ PyLockWrapper lck; // acquire GIL
+ PyObjWrapper pluginsmanager = PyImport_ImportModule((char*)"salome_pluginsmanager");
+ PyObjWrapper res = PyObject_CallMethod( pluginsmanager, (char*)"initialize", (char*)"isss",0,"salome",tr("MEN_DESK_PLUGINS_TOOLS").toStdString().c_str(),tr("MEN_DESK_PLUGINS").toStdString().c_str());
+ if ( !res )
+ PyErr_Print();
+ }
// end of SALOME plugins loading
}
{
PyConsole_Console* pyConsole = app->pythonConsole();
PyConsole_Interp* pyInterp = pyConsole->getInterp();
- PyLockWrapper aLock = pyInterp->GetLockWrapper();
+ PyLockWrapper aLock; // Acquire GIL
std::string command;
command = "import salome_notebook ; ";
command += "salome_notebook.notebook.setAsReal(\"";
{
PyConsole_Console* pyConsole = app->pythonConsole();
PyConsole_Interp* pyInterp = pyConsole->getInterp();
- PyLockWrapper aLock = pyInterp->GetLockWrapper();
+ PyLockWrapper aLock; // Acquire GIL
std::string command;
command = "import salome_notebook ; ";
command += "salome_notebook.notebook.setAsInteger(\"";
SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
PyConsole_Console* pyConsole = app->pythonConsole();
PyConsole_Interp* pyInterp = pyConsole->getInterp();
- PyLockWrapper aLock = pyInterp->GetLockWrapper();
+ PyLockWrapper aLock; // Acquire GIL
std::string command = "import salome_notebook ; ";
command += "salome_notebook.checkThisNoteBook(";
for( int i = 0, n = aLastRowIsEmpty ? aNumRows - 1 : aNumRows; i < n; i++ ) {
SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
PyConsole_Console* pyConsole = app->pythonConsole();
PyConsole_Interp* pyInterp = pyConsole->getInterp();
- PyLockWrapper aLock = pyInterp->GetLockWrapper();
+ PyLockWrapper aLock; // Acquire GIL
std::string command = "import salome_notebook ; ";
command += "salome_notebook.checkThisNoteBook(";
for( int i = 0, n = aLastRowIsEmpty ? aNumRows - 1 : aNumRows; i < n; i++ )
{
}
-/*!\class SalomeApp_PyInterp
- * EDF-CCAR
- * When SALOME uses multi Python interpreter feature,
- * Every study has its own interpreter and thread state (_tstate = Py_NewInterpreter())
- * This is fine because every study has its own modules (sys.modules) stdout and stderr
- * BUT some Python modules must be imported only once. In multi interpreter context Python
- * modules (*.py) are imported several times.
- * The pyqt module must be imported only once because it registers classes in a C module.
- * It's quite the same with omniorb modules (internals and generated with omniidl)
- * This problem is handled with "shared modules" defined in salome_shared_modules.py
- * These "shared modules" are imported only once and only copied in all the other interpreters
- * BUT it's not the only problem. Every interpreter has its own __builtin__ module. That's fine
- * but if we have copied some modules and imported others problems may arise with operations that
- * are not allowed in restricted execution environment. So we must impose that all interpreters
- * have identical __builtin__ module.
- * That's all, for the moment ...
- */
-
-
-bool SalomeApp_PyInterp::initContext()
-{
- /*!
- * The GIL is assumed to be held
- * It is the caller responsability caller to acquire the GIL
- * It will still be held on initContext output
- */
- if ( !PyConsole_Interp::initContext() )
- return false;
-
- // Import special module to change the import mechanism
- PyObjWrapper m1( PyImport_ImportModule( "import_hook" ) );
- if ( !m1 )
- {
- MESSAGE( "initContext: problem with import_hook import" );
- PyErr_Print();
- ASSERT( 0 );
- return false;
- }
-
- // Call init_shared_modules to initialize the shared import mechanism for modules
- //that must not be imported twice
- PyObjWrapper m2( PyObject_CallMethod( m1, (char*)"init_shared_modules", (char*)"O", KERNEL_PYTHON::salome_shared_modules_module ) );
- if ( !m2 )
- {
- MESSAGE( "initContext: problem with init_shared_modules call" );
- PyErr_Print();
- ASSERT( 0 );
- return false;
- }
-
- return true;
-}
-
/*!
- Do nothing
- The initialization has been done in main
+ Do nothing (we could rely on the test done in the implementation of this method in the super
+ class PyInterp_Interp, but in this context we are sure the initialization has been done in main()
+ of SALOME_Session_Server)
*/
void SalomeApp_PyInterp::initPython()
{
- MESSAGE("SalomeApp_PyInterp::initPython");
- ASSERT(KERNEL_PYTHON::_gtstate); // initialisation in main
- SCRUTE(KERNEL_PYTHON::_gtstate);
- _gtstate=KERNEL_PYTHON::_gtstate;
- _interp=KERNEL_PYTHON::_interp;
+ MESSAGE("SalomeApp_PyInterp::initPython - does nothing");
}
/*!
virtual void initPython();
protected:
- virtual bool initContext();
virtual int beforeRun();
private:
QString fname = QFileInfo( _fname ).fileName();
if( exp.exactMatch( fname ) ) {
- QStringList vers = exp.cap( 1 ).split( ".", QString::SkipEmptyParts );
- int major=0, minor=0;
- int release = 0, dev1 = 0, dev2 = 0;
- if ( vers.count() > 0 ) major = vers[0].toInt();
- if ( vers.count() > 1 ) minor = vers[1].toInt();
- if ( vers.count() > 2 ) {
- if ( vers_exp.indexIn( vers[2] ) != -1 ) {
- release = vers_exp.cap( 1 ).toInt();
- QString tag = vers_exp.cap( 2 ).toLower();
- if ( !tag.isEmpty() ) {
- if ( tag == "rc" ) // release candidate
- dev1 = 49; // 'rc'=49
- else // a, b, c, ...
- dev1 = (int)( tag[ 0 ].toLatin1() ) - (int)( QChar('a').toLatin1() ) + 1; // 'a'=1, 'b'=2, ..., 'z'=26
- }
- if ( !vers_exp.cap( 3 ).isEmpty() )
- dev2 = vers_exp.cap( 3 ).toInt();
- }
- }
-
- int dev = dev1*100+dev2;
- id = major;
- id*=100; id+=minor;
- id*=100; id+=release;
- id*=10000;
- if ( dev > 0 ) id-=dev;
+ QStringList vers = exp.cap( 1 ).split( ".", QString::SkipEmptyParts );
+ int major=0, minor=0;
+ int release = 0, dev1 = 0, dev2 = 0;
+ if ( vers.count() > 0 ) major = vers[0].toInt();
+ if ( vers.count() > 1 ) minor = vers[1].toInt();
+ if ( vers.count() > 2 ) {
+ if ( vers_exp.indexIn( vers[2] ) != -1 ) {
+ release = vers_exp.cap( 1 ).toInt();
+ QString tag = vers_exp.cap( 2 ).toLower();
+ if ( !tag.isEmpty() ) {
+ if ( tag == "rc" ) // release candidate
+ dev1 = 49; // 'rc'=49
+ else // a, b, c, ...
+ dev1 = (int)( tag[ 0 ].toLatin1() ) - (int)( QChar('a').toLatin1() ) + 1; // 'a'=1, 'b'=2, ..., 'z'=26
+ }
+ if ( !vers_exp.cap( 3 ).isEmpty() )
+ dev2 = vers_exp.cap( 3 ).toInt();
+ }
+ }
+
+ int dev = dev1*100+dev2;
+ id = major;
+ id*=100; id+=minor;
+ id*=100; id+=release;
+ id*=10000;
+ if ( dev > 0 ) id-=dev;
}
}
return id;
int _argc = 1;
char* _argv[] = {(char*)""};
KERNEL_PYTHON::init_python( _argc,_argv );
- PyEval_RestoreThread( KERNEL_PYTHON::_gtstate );
- if ( !KERNEL_PYTHON::salome_shared_modules_module ) // import only once
- KERNEL_PYTHON::salome_shared_modules_module = PyImport_ImportModule( "salome_shared_modules" );
- if ( !KERNEL_PYTHON::salome_shared_modules_module ) {
- INFOS( "salome_shared_modules_module == NULL" );
- PyErr_Print();
- }
- PyEval_ReleaseThread( KERNEL_PYTHON::_gtstate );
// ...create ORB, get RootPOA object, NamingService, etc.
ORB_INIT &init = *SINGLETON_<ORB_INIT>::Instance();
if ( splash )
splash->finish( aGUIApp->desktop() );
-
+
result = _qappl.exec();
splash = 0;
-
+
if ( result == SUIT_Session::NORMAL ) {
- // desktop is explicitly closed by user from GUI
- // exit flags says if it's necessary to shutdown all servers
- // all session server only
+ // desktop is explicitly closed by user from GUI
+ // exit flags says if it's necessary to shutdown all servers
+ // all session server only
shutdownAll = aGUISession->exitFlags();
- }
- else {
- // desktop might be closed from:
- // - StopSesion() /temporarily/ or
- // - Shutdown() /permanently/
- stat = session->GetStatSession();
- shutdownSession = stat.state == SALOME::shutdown;
- }
- if ( shutdownAll || shutdownSession ) {
- _SessionMutex.lock(); // lock mutex before leaving loop - it will be unlocked later
- break;
- }
+ }
+ else {
+ // desktop might be closed from:
+ // - StopSesion() /temporarily/ or
+ // - Shutdown() /permanently/
+ stat = session->GetStatSession();
+ shutdownSession = stat.state == SALOME::shutdown;
+ }
+ if ( shutdownAll || shutdownSession ) {
+ _SessionMutex.lock(); // lock mutex before leaving loop - it will be unlocked later
+ break;
+ }
}
delete aGUISession;