Salome HOME
Revamped Python interpreter logic in GUI.
authorAdrien Bruneton <adrien.bruneton@cea.fr>
Thu, 13 Feb 2014 09:53:44 +0000 (10:53 +0100)
committerAdrien Bruneton <adrien.bruneton@cea.fr>
Thu, 13 Feb 2014 10:03:19 +0000 (11:03 +0100)
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

26 files changed:
src/LightApp/LightApp_PyInterp.cxx
src/LightApp/LightApp_PyInterp.h
src/PyConsole/PyConsole_EnhInterp.cxx
src/PyConsole/PyConsole_Interp.cxx
src/PyConsole/PyConsole_Interp.h
src/PyInterp/PyInterp_Dispatcher.cxx
src/PyInterp/PyInterp_Interp.cxx
src/PyInterp/PyInterp_Interp.h
src/PyInterp/PyInterp_Request.h
src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.cxx
src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.cxx
src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.h
src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyInterp.cxx
src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyInterp.h
src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyModule.cxx
src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyModule.h
src/SUITApp/SUITApp.cxx
src/SUITApp/SUITApp_init_python.cxx
src/SUITApp/SUITApp_init_python.hxx
src/SalomeApp/SalomeApp_Application.cxx
src/SalomeApp/SalomeApp_DoubleSpinBox.cxx
src/SalomeApp/SalomeApp_IntSpinBox.cxx
src/SalomeApp/SalomeApp_NoteBook.cxx
src/SalomeApp/SalomeApp_PyInterp.cxx
src/SalomeApp/SalomeApp_PyInterp.h
src/Session/SALOME_Session_Server.cxx

index 5bc90b951807659edf253527aeb71eab865a73c1..9f88b966f80873981dc5fec5b0a10621186b69c6 100644 (file)
 //
 #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()
 {
@@ -44,59 +37,16 @@ LightApp_PyInterp::~LightApp_PyInterp()
 }
  
 /*!\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;
 }
index d13d6bd85ccc04c0410510f74d66347e9b243692..9d605d3985603ba68b4f50225a8a81dc5de9ac3a 100644 (file)
@@ -33,7 +33,6 @@ public:
   
 protected:
   virtual void initPython();
-  virtual bool initContext();
 };
 
 #endif //_LIGHTAPP_PYINTERP_H_
index c648086228c7e9a8eab5bc791428081900908b68..0465d08c1f47d6eab3542a919ca28a4a559bd530 100644 (file)
@@ -73,7 +73,7 @@ int PyConsole_EnhInterp::runDirCommand(const QString & dirArgument, const QStrin
       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)
@@ -104,7 +104,7 @@ int PyConsole_EnhInterp::runDirAndExtract(const QString& dirArgument,
 {
   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();
index 6682d4a02f815d9c2af756d5295e6f2aafcfc673..9d3d996caa3976c73a4ed41a16c7d6cbd83e12d9 100644 (file)
   \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.
 */
 
 /*!
@@ -83,42 +61,6 @@ PyConsole_Interp::~PyConsole_Interp()
 {
 }
  
-/*!
-  \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.
 
@@ -135,10 +77,6 @@ bool PyConsole_Interp::initContext()
     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;
 }
index 4bd15ba9e0bf415ce370babcce42015cfdb12d97..2e3aee9504c439a18990b325e2391ca1ed3209fe 100644 (file)
@@ -39,7 +39,6 @@ public:
   ~PyConsole_Interp();
 
 protected:
-  virtual bool initState();
   virtual bool initContext();  
 };
 
index 95938f67c3d11cb482c73ce40abfe83be8e479a8..73d14db8621585cbd58c9e8a0f3cd9197c58e626 100755 (executable)
@@ -96,11 +96,11 @@ void PyInterp_Request::setListener( QObject* o )
 
 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()
index c2dcd254a5995972675410c15115ff6f3d8b3bfc..0ee1e017317d64418c976f8f005799f94b4c2e71 100644 (file)
@@ -39,9 +39,6 @@
 #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.
@@ -49,16 +46,10 @@ std::map<long,PyThreadState*> currentThreadMap;
 
 /*!
   \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();
 }
 
 /*!
@@ -66,51 +57,15 @@ PyLockWrapper::PyLockWrapper(PyThreadState* theThreadState):
 */
 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);
 }
 
 /*
@@ -232,9 +187,9 @@ static PyStdOut* newPyStdOut( bool iscerr )
 
 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.
@@ -243,10 +198,12 @@ PyInterpreterState* PyInterp_Interp::_interp       = NULL;
   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.
 */
@@ -271,20 +228,21 @@ void PyInterp_Interp::initialize()
   _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;
   }
 
@@ -294,17 +252,16 @@ void PyInterp_Interp::initialize()
 
   // 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()
 {
@@ -313,30 +270,22 @@ 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;
 }
 
@@ -350,24 +299,13 @@ std::string PyInterp_Interp::getbanner()
 */
 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)
@@ -396,12 +334,7 @@ static int run_command(const char *command, PyObject *context)
     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();
@@ -433,7 +366,7 @@ void replaceAll(std::string& str, const std::string& from, const std::string& to
   \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;
@@ -466,7 +399,8 @@ static int compile_command(const char *command,PyObject *context)
 }
 
 /*!
-  \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
 */
@@ -476,8 +410,17 @@ int PyInterp_Interp::run(const char *command)
   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
@@ -489,19 +432,22 @@ int PyInterp_Interp::simpleRun(const char *command, const bool addToHistory)
     _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;
 }
index 77ac9486bda4682757d3c1081450370c2fcdea6b..55c2c70050b8c8e07dcd33a076ac750da208ef20 100644 (file)
 #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();
@@ -60,33 +76,41 @@ public:
 
   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;
index 9a4291b36a5dbb84519cc47089b8b2d2236c0e59..2c09a335c1cd3043f11d61e658ead835b5c6ce18 100644 (file)
@@ -88,7 +88,7 @@ class PYINTERP_EXPORT PyInterp_LockRequest : public PyInterp_Request
 {
 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 )
   {}
 
index b1e1683f0e192df70e99a30ad02fab2313456961..31439aedad097c5c37b067e1789cdfc06765bd69 100644 (file)
@@ -67,10 +67,8 @@ extern "C" {
     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;
     }
 
index 88602237702edce212cf379776796a6e31c87001..7b94636dbe4771bbd69aebc4e15ed76d2eb081bf 100644 (file)
 // 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.
@@ -83,21 +83,8 @@ extern "C"
 
     // 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;
     }
 
index dff9b5963c9b04fd5676f493b0ca41220948b20f..1e07b433225e6615e7d9b5f55bfb1675ea3cf1ce 100644 (file)
@@ -71,9 +71,9 @@ public:
   // 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;
index 849ff2c7d8e48bd3b5284f8c1bab1464f789099c..ab58c83d468cf8bde289bc543e71cb456c5ffa13 100644 (file)
@@ -49,38 +49,9 @@ void SALOME_PYQT_PyInterp::initPython()
   * 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()
 {
   /*
@@ -88,10 +59,7 @@ 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;
 }
 
@@ -100,18 +68,15 @@ int SALOME_PYQT_PyInterp::run(const char *command)
   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 ;
   }
index ebf5c2553102635d3ce85dafec6f28f0c3054b3a..6abdde73fb5fc1416a7b91015817d8891cdb3da1 100644 (file)
@@ -38,7 +38,6 @@ class SALOME_PYQT_LIGHT_EXPORT SALOME_PYQT_PyInterp : public PyInterp_Interp
   
  protected:
   virtual void initPython();
-  virtual bool initState();
   virtual bool initContext();
 };
 
index b4eba060a54045c450310f9da1e166019640ad82..a9d6ad43fcc96f304471a5dc915c8be272ce1c43 100644 (file)
@@ -228,9 +228,9 @@ public:
   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:
@@ -238,11 +238,11 @@ 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;
@@ -258,7 +258,7 @@ private:
   \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() ) { 
@@ -305,9 +305,9 @@ void PyModuleHelper::XmlHandler::createActions()
   \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();
@@ -364,10 +364,10 @@ QIcon PyModuleHelper::XmlHandler::loadIcon( const QString& fileName )
   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;
@@ -381,8 +381,8 @@ QIcon PyModuleHelper::XmlHandler::loadIcon( const QString& fileName )
   \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;
@@ -425,14 +425,14 @@ void PyModuleHelper::XmlHandler::createMenu( QDomNode& parentNode,
             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())
@@ -496,17 +496,17 @@ void PyModuleHelper::XmlHandler::createToolBar( QDomNode& parentNode )
             // -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" ) {
@@ -552,15 +552,15 @@ void PyModuleHelper::XmlHandler::insertPopupItems( QDomNode& parentNode, QMenu*
         // -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 );
         }
@@ -627,7 +627,7 @@ PyModuleHelper::~PyModuleHelper()
 {
   delete myXmlHandler;
   if ( myInterp && myPyModule ) {
-    PyLockWrapper aLock = myInterp->GetLockWrapper();
+    PyLockWrapper aLock; // Acquire GIL
     Py_XDECREF( myPyModule );
   }
 }
@@ -691,8 +691,8 @@ void PyModuleHelper::connectAction( QAction* a )
 {
   if ( myModule && a )
     QObject::connect( a, SIGNAL( triggered( bool ) ), 
-                     this, SLOT( actionActivated() ),
-                     Qt::UniqueConnection );
+                      this, SLOT( actionActivated() ),
+                      Qt::UniqueConnection );
 }
 
 /*!
@@ -747,11 +747,11 @@ QStringList PyModuleHelper::viewManagers() const
   \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
@@ -759,7 +759,7 @@ QStringList PyModuleHelper::viewManagers() const
 
   \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
@@ -798,10 +798,10 @@ void PyModuleHelper::initialize( CAM_Application* app )
   {
   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()
@@ -841,21 +841,21 @@ bool PyModuleHelper::activate( SUIT_Study* study )
   {
   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;
@@ -881,12 +881,12 @@ bool PyModuleHelper::activate( SUIT_Study* study )
     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 
@@ -924,11 +924,11 @@ bool PyModuleHelper::deactivate( SUIT_Study* study )
   {
   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()
@@ -950,7 +950,7 @@ bool PyModuleHelper::deactivate( SUIT_Study* study )
   // 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 );
@@ -1023,7 +1023,7 @@ void PyModuleHelper::modelClosed( SUIT_Study* study )
   \param parameter preference resources parameter name
 */
 void PyModuleHelper::preferencesChanged( const QString& section, 
-                                        const QString& parameter )
+                                         const QString& parameter )
 {
   FuncMsg fmsg( "PyModuleHelper::preferencesChanged()" );
 
@@ -1031,9 +1031,9 @@ void PyModuleHelper::preferencesChanged( const QString& section,
   {
   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 ),
@@ -1065,8 +1065,8 @@ void PyModuleHelper::preferencesChanged( const QString& 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()" );
 
@@ -1094,10 +1094,10 @@ void PyModuleHelper::studyActivated( SUIT_Study* study )
   {
   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()
@@ -1130,8 +1130,8 @@ void PyModuleHelper::actionActivated()
   {
   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  )
@@ -1176,7 +1176,7 @@ void PyModuleHelper::contextMenu( const QString& context, QMenu* menu )
                     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 )
     {}
@@ -1214,7 +1214,7 @@ void PyModuleHelper::createPreferences()
   {
   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 )
     {}
@@ -1249,11 +1249,11 @@ void PyModuleHelper::activeViewChanged( SUIT_ViewWindow* view )
   {
   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()
@@ -1283,11 +1283,11 @@ void PyModuleHelper::tryCloseView( SUIT_ViewWindow* view )
   {
   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()
@@ -1314,8 +1314,8 @@ void PyModuleHelper::closeView( SUIT_ViewWindow* view )
   {
   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 )
@@ -1345,11 +1345,11 @@ void PyModuleHelper::cloneView( SUIT_ViewWindow* 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()
@@ -1383,8 +1383,8 @@ void PyModuleHelper::save( QStringList& files )
   {
   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 )
@@ -1420,9 +1420,9 @@ bool PyModuleHelper::load( const QStringList& 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 ),
@@ -1466,8 +1466,8 @@ void PyModuleHelper::dumpPython( QStringList& 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 )
@@ -1504,9 +1504,9 @@ bool PyModuleHelper::isDraggable( const SUIT_DataObject* what ) const
   {
   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 ),
@@ -1529,9 +1529,9 @@ bool PyModuleHelper::isDraggable( const SUIT_DataObject* what ) const
     // 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;
@@ -1553,9 +1553,9 @@ bool PyModuleHelper::isDropAccepted( const SUIT_DataObject* where ) const
   {
   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 ),
@@ -1578,9 +1578,9 @@ bool PyModuleHelper::isDropAccepted( const SUIT_DataObject* where ) const
     // 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;
@@ -1594,7 +1594,7 @@ bool PyModuleHelper::isDropAccepted( const SUIT_DataObject* where ) const
   \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()" );
 
@@ -1603,17 +1603,17 @@ void PyModuleHelper::dropObjects( const DataObjectList& what, SUIT_DataObject* w
   {
   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()
@@ -1647,10 +1647,10 @@ QString PyModuleHelper::engineIOR() const
   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()
@@ -1667,8 +1667,8 @@ QString PyModuleHelper::engineIOR() const
   if ( anIOR.isEmpty() ) {
     // post request
     PyInterp_Dispatcher::Get()->Exec( new EngineIORReq( myInterp, 
-                                                       const_cast<PyModuleHelper*>( this ),
-                                                       anIOR ) );
+                                      const_cast<PyModuleHelper*>( this ),
+                                      anIOR ) );
   }
 
   return anIOR;
@@ -1708,7 +1708,7 @@ void PyModuleHelper::initInterp( int studyId )
     // 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 ) {
@@ -1732,7 +1732,7 @@ void PyModuleHelper::initInterp( int studyId )
   \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()
 {
@@ -1747,7 +1747,7 @@ 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 {
@@ -1787,7 +1787,7 @@ void PyModuleHelper::setWorkSpace()
 
   // 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" ) );
@@ -1865,7 +1865,7 @@ void PyModuleHelper::internalInitialize( CAM_Application* app )
 
   // 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
@@ -1969,7 +1969,7 @@ void PyModuleHelper::internalActivate( SUIT_Study* study )
   }
 
   // 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" ) ) {
@@ -2024,7 +2024,7 @@ void PyModuleHelper::internalCustomize( SUIT_Study* study )
   setWorkSpace();
 
   // get python lock
-  PyLockWrapper aLock = myInterp->GetLockWrapper();
+  PyLockWrapper aLock; // Acquire GIL
 
   if ( IsCallOldMethods ) {
     // call Python module's setSettings() method (obsolete)
@@ -2166,7 +2166,7 @@ void PyModuleHelper::internalStudyChanged( SUIT_Study* study )
   setWorkSpace();
 
   // get python lock
-  PyLockWrapper aLock = myInterp->GetLockWrapper();
+  PyLockWrapper aLock; // Acquire GIL
 
   // call Python module's activeStudyChanged() method
   if ( PyObject_HasAttrString( myPyModule, (char*)"activeStudyChanged" ) ) {
@@ -2552,7 +2552,7 @@ bool PyModuleHelper::internalIsDraggable( LightApp_DataObject* what )
 
   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;
@@ -2584,7 +2584,7 @@ bool PyModuleHelper::internalIsDropAccepted( LightApp_DataObject* where )
 
   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;
@@ -2606,7 +2606,7 @@ bool PyModuleHelper::internalIsDropAccepted( LightApp_DataObject* where )
   \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()" );
 
@@ -2631,10 +2631,10 @@ void PyModuleHelper::internalDropObjects( const DataObjectList& what, SUIT_DataO
   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();
@@ -2663,13 +2663,13 @@ QString PyModuleHelper::internalEngineIOR() const
     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 );
+        }
       }
     }
   }
@@ -2688,23 +2688,23 @@ void PyModuleHelper::connectView( SUIT_ViewWindow* view )
   // 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 );
   }
 }
index 49c4296325c00077533ef462694c4d6912d80016..4a823bc441ddbafd1cb5613b985055995dd4bcda 100644 (file)
@@ -103,7 +103,7 @@ public slots:
   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:
@@ -131,7 +131,7 @@ 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* );
index 725a53ec176b7ca5596f9e1e36beafae45f067a5..7c5a6a262a7b4e11708322007152340463781772 100644 (file)
@@ -277,16 +277,7 @@ int main( int argc, char* argv[] )
     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() );
index a158de5d2a7376576aad9ae242ebcf65034701b4..8cb014016bbce2e70c2a9358d908a9553e2d02b8 100644 (file)
 //
 #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)
@@ -37,9 +33,6 @@ 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
 }
 
index dcd23d28574cf849e4ba5e6833fb54c48169aaf8..62a9a3e7ba3b922d8ae1cabb7596e17fc933e19a 100644 (file)
 
 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_
index c7b16a8ae4bcaf0f84ccd7daf80a9588eb6e35fd..25a7465da2695b8a00e6c6f36cc1c6cfe26a6e32 100644 (file)
@@ -369,12 +369,13 @@ void SalomeApp_Application::createActions()
   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
 
 }
index e3bf34f43ee6ec2cf028ef1c11e71bbc103849f9..d3101ee290d635cf7d89b916b8be5d588009070b 100644 (file)
@@ -436,7 +436,7 @@ SalomeApp_DoubleSpinBox::SearchState SalomeApp_DoubleSpinBox::findVariable( cons
             {
               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(\"";
index 2771f44c5c3002709974b9a30080e376968c7734..cf0bd0c93f48b6965c14d31c1cdb81b78afc9b53 100644 (file)
@@ -384,7 +384,7 @@ SalomeApp_IntSpinBox::SearchState SalomeApp_IntSpinBox::findVariable( const QStr
             {
               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(\"";
index 90a434582c57aeff5726f6703d7c114710b1b541..accca55943395331f2c0a8231ebba8e3a901c0c0 100644 (file)
@@ -286,7 +286,7 @@ bool NoteBook_TableRow::IsValidStringValue(const QString theValue)
   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++ ) {
@@ -460,7 +460,7 @@ bool NoteBook_Table::IsValid() const
   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++ )
index a0301b6ca6b84c81bcfb283b9eaf43691c0f4254..c2e329cc58f89f0564a405293d92893936d5bc68 100755 (executable)
@@ -48,70 +48,14 @@ SalomeApp_PyInterp::~SalomeApp_PyInterp()
 {
 }
  
-/*!\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");
 }
 
 /*!
index d457cf763e88af2d739341e7913cf1b43b5472da..801121239718517f708de1e1b62ac6fe9dee35e7 100755 (executable)
@@ -38,7 +38,6 @@ public:
   virtual void initPython();
 
 protected:
-  virtual bool initContext();
   virtual int  beforeRun();
 
 private:
index 9fbb1542df009b38282b7c589d43b9f7a20b2957..f6ddf9d053fe839d5b1ff3291da2744daba16dc4 100755 (executable)
@@ -234,32 +234,32 @@ protected:
       
       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;
@@ -475,14 +475,6 @@ int main( int argc, char **argv )
     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();
@@ -631,28 +623,28 @@ int main( int argc, char **argv )
 
         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;