Salome HOME
Python console, various improvements:
authorabn <adrien.bruneton@cea.fr>
Fri, 19 Sep 2014 13:31:32 +0000 (15:31 +0200)
committerabn <adrien.bruneton@cea.fr>
Fri, 19 Sep 2014 13:31:32 +0000 (15:31 +0200)
* clearly separate global and local contexts for execution (not sure this brings something though ...)
* some Py_INCREF were missing
* cleaner compilation units

16 files changed:
src/PyConsole/PyConsole_EnhInterp.cxx
src/PyConsole/PyConsole_Interp.cxx
src/PyConsole/PyConsole_Interp.h
src/PyInterp/CMakeLists.txt
src/PyInterp/PyInterp_Dispatcher.cxx
src/PyInterp/PyInterp_Event.cxx
src/PyInterp/PyInterp_Interp.cxx
src/PyInterp/PyInterp_Interp.h
src/PyInterp/PyInterp_Request.cxx
src/PyInterp/PyInterp_Request.h
src/PyInterp/PyInterp_Utils.cxx [new file with mode: 0644]
src/PyInterp/PyInterp_Utils.h [new file with mode: 0644]
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/SalomeApp/SalomeApp_NoteBook.cxx

index 8915f07656c90eef32e14f840f735a86a2d49e6c..1f5defe0714bde0bcf29d7593ffcae097c4fcab9 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, _context, _context);
+      PyObject * str = PyRun_String(cmd.toStdString().c_str(), Py_eval_input, _global_context, _local_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, _context, _context);
+  PyObject * plst = PyRun_String(command.toStdString().c_str(), Py_eval_input, _global_context, _local_context);
   if(!plst || plst == Py_None) {
     if(!plst)
       PyErr_Clear();
index d230e9b12e1e4af677da1399e84e0d4f65f3e363..c200a85c091d2e94bfa7d73a532fdca2db705c44 100644 (file)
@@ -22,7 +22,7 @@
 
 //  SALOME SALOMEGUI : implementation of desktop and GUI kernel
 //  File   : PyConsole_Interp.cxx
-//  Author : Nicolas REJNERI
+//  Author : Nicolas REJNERI, Adrien BRUNETON
 //  Module : SALOME
 //
 #include "PyConsole_Interp.h"
@@ -38,7 +38,6 @@
 
   The method initialize() calls virtuals methods
   - initPython()  to initialize global Python interpreter
-  //- initState()   to initialize embedded interpreter state (OBSOLETE)
   - initContext() to initialize interpreter internal context
   - initRun()     to prepare interpreter for running commands
 */
@@ -61,22 +60,3 @@ PyConsole_Interp::~PyConsole_Interp()
 {
 }
  
-/*!
-  \brief Initialize python interpeter context.
-
-  The GIL is assumed to be held.
-  It is the caller responsability to acquire the GIL.
-  It must still be held on initContext() exit.
-
-  \return \c true on success
-*/
-bool PyConsole_Interp::initContext()
-{
-  PyObject *m = PyImport_AddModule("__main__");  // interpreter main module (module context)
-  if(!m){
-    PyErr_Print();
-    return false;
-  }  
-  _context = PyModule_GetDict(m);          // get interpreter dictionnary context
-  return true;
-}
index d122db0a6cd307f8130156a48df753938c79db23..0b929332efdcb5a6961a7eee085d29966d528938 100644 (file)
@@ -22,7 +22,7 @@
 
 //  SALOME SALOMEGUI : implementation of desktop and GUI kernel
 //  File   : PyConsole_Interp.h
-//  Author : Nicolas REJNERI
+//  Author : Nicolas REJNERI, Adrien BRUNETON
 //  Module : SALOME
 //
 #ifndef PYCONSOLE_INTERP_H
@@ -37,9 +37,6 @@ class PYCONSOLE_EXPORT PyConsole_Interp : public PyInterp_Interp
 public:
   PyConsole_Interp();
   ~PyConsole_Interp();
-
-protected:
-  virtual bool initContext();  
 };
 
 #endif // PYCONSOLE_INTERP_H
index 584eb0f7ddce49f475c996504b13705f1a4976f7..f85d651f28fa03c2c95fd136252499f9fd229553 100755 (executable)
@@ -47,6 +47,7 @@ SET(_other_HEADERS
   PyInterp_Event.h
   PyInterp_Interp.h
   PyInterp_Request.h
+  PyInterp_Utils.h
 )
 
 # header files / to install
@@ -63,6 +64,7 @@ SET(_other_SOURCES
   PyInterp_Event.cxx
   PyInterp_Interp.cxx
   PyInterp_Request.cxx
+  PyInterp_Utils.cxx
 )
 
 # sources / to compile
index 73898b53dfff115b721d53c78be82c60853b8c3f..40b0059e834e6bed488cf10d452fc2ecdd1d4d03 100755 (executable)
 
 PyInterp_Dispatcher* PyInterp_Dispatcher::myInstance = 0;
 
-void PyInterp_Request::process()
-{
-  safeExecute();
-
-  bool isSync = IsSync();
-
-  if ( !isSync )
-    myMutex.lock();
-
-  if ( listener() )
-    processEvent( listener() );
-
-  if ( !isSync )
-    myMutex.unlock();
-}
-
-void PyInterp_Request::safeExecute()
-{
-  //ProcessVoidEvent( new PyInterp_ExecuteEvent( this ) );
-  execute();
-}
-
-void PyInterp_Request::Destroy( PyInterp_Request* request )
-{
-  // Lock and unlock the mutex to avoid errors on its deletion
-  request->myMutex.lock();
-  request->myMutex.unlock();
-  delete request;
-}
-
-QEvent* PyInterp_Request::createEvent()
-{
-  return new PyInterp_Event( PyInterp_Event::ES_NOTIFY, this );
-}
-
-void PyInterp_Request::processEvent( QObject* o )
-{
-  if ( !o )
-    return;
-
-  QEvent* e = createEvent();
-  if ( !e )
-    return;
-
-  if ( !IsSync() )
-    QCoreApplication::postEvent( o, e );
-  else
-  {
-    QCoreApplication::sendEvent( o, e );
-    delete e;
-  }
-}
-
-void PyInterp_Request::setListener( QObject* o )
-{
-  myMutex.lock();
-  myListener = o;
-  myMutex.unlock();
-}
-
-void PyInterp_LockRequest::safeExecute()
-{
-  //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()
-{
-  PyInterp_Request::Destroy( myRequest );
-  myRequest = 0;
-}
-
 PyInterp_Dispatcher* PyInterp_Dispatcher::Get()
 {
   if ( !myInstance )
index 398b73e16a4ccec8a26de5ddc01c926d000ea68f..0bdfddac29e4e4320bb3562ed5bce0f8b821309d 100644 (file)
 #include "PyInterp_Event.h"
 #include "PyInterp_Request.h"
 
+PyInterp_Event::~PyInterp_Event()
+{
+  PyInterp_Request::Destroy( myRequest );
+  myRequest = 0;
+}
+
 void PyInterp_ExecuteEvent::Execute()
 {
   myRequest->execute();
index c4ee5d5f6a399fb0c6245d191e33a9593a82cf41..4664009ef4654096d475ba44d56903535f55d53f 100644 (file)
 //
 
 //  File   : PyInterp_Interp.cxx
-//  Author : Christian CAREMOLI, Paul RASCLE, EDF
+//  Author : Christian CAREMOLI, Paul RASCLE, Adrien BRUNETON
 //  Module : SALOME
 //
 #include "PyInterp_Interp.h"  // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!!
+#include "PyInterp_Utils.h"
 #include <pythread.h>
 
 #include <cStringIO.h>
 #define TOP_HISTORY_PY   "--- top of history ---"
 #define BEGIN_HISTORY_PY "--- begin of history ---"
 
-/*!
-  \class PyLockWrapper
-  \brief Python GIL wrapper.
-*/
-
-/*!
-  \brief Constructor. Automatically acquires GIL.
-*/
-PyLockWrapper::PyLockWrapper()
-{
-  _gil_state = PyGILState_Ensure();
-}
-
-/*!
-  \brief Destructor. Automatically releases GIL.
-*/
-PyLockWrapper::~PyLockWrapper()
-{
-//  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);
-}
-
 /*
   The following functions are used to hook the Python
   interpreter output.
@@ -187,9 +159,6 @@ 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;
 
 /*!
   \brief Basic constructor.
@@ -198,7 +167,7 @@ char* PyInterp_Interp::_argv[] = {(char*)""};
   must call virtual method initalize().
 */
 PyInterp_Interp::PyInterp_Interp():
-  _vout(0), _verr(0), _context(0)
+  _vout(0), _verr(0), _local_context(0), _global_context(0)
 {
 }
 
@@ -209,6 +178,7 @@ PyInterp_Interp::PyInterp_Interp():
 */
 PyInterp_Interp::~PyInterp_Interp()
 {
+  destroy();
 }
 
 /*!
@@ -217,7 +187,6 @@ PyInterp_Interp::~PyInterp_Interp()
   This method shoud be called after construction of the interpreter.
   The method initialize() calls virtuals methods
   - initPython()  to initialize global Python interpreter
-  - initState()   to initialize embedded interpreter state
   - initContext() to initialize interpreter internal context
   - initRun()     to prepare interpreter for running commands
   which should be implemented in the successor classes, according to the
@@ -307,27 +276,49 @@ bool PyInterp_Interp::initRun()
   return true;
 }
 
+/*!
+ * Initialize context dictionaries. GIL is held already.
+ */
+bool PyInterp_Interp::initContext()
+{
+  PyObject *m = PyImport_AddModule("__main__");  // interpreter main module (module context)
+  if(!m){
+    PyErr_Print();
+    return false;
+  }
+  _global_context = PyModule_GetDict(m);          // get interpreter global variable context
+  Py_INCREF(_global_context);
+  _local_context = PyDict_New();
+  return true;
+}
+
+/*!
+ * Destroy context dictionaries. GIL is held already.
+ */
 void PyInterp_Interp::closeContext()
 {
+  Py_XDECREF(_global_context);
+  Py_XDECREF(_local_context);
 }
 
 /*!
   \brief Compile Python command and evaluate it in the
-         python dictionary context if possible. This is not thread-safe.
+         python dictionary contexts 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 on fatal error, 1 if command is incomplete and 0
          if command is executed successfully
  */
-static int run_command(const char *command, PyObject *context)
+static int run_command(const char *command, PyObject * global_ctxt, PyObject * local_ctxt)
 {
   PyObject *m = PyImport_AddModule("codeop");
   if(!m) { // Fatal error. No way to go on.
     PyErr_Print();
     return -1;
   }
+
+//  PyObjWrapper v(Py_CompileString(command, "<salome_input>", Py_file_input));
   PyObjWrapper v(PyObject_CallMethod(m,(char*)"compile_command",(char*)"s",command));
   if(!v) {
     // Error encountered. It should be SyntaxError,
@@ -343,7 +334,7 @@ static int run_command(const char *command, PyObject *context)
     return 1;
   }
   else {
-    PyObjWrapper r(PyEval_EvalCode((PyCodeObject *)(void *)v,context,context));
+    PyObjWrapper r(PyEval_EvalCode((PyCodeObject *)(void *)v,global_ctxt, local_ctxt));
     if(!r) {
       // Execution error. We return -1
       PyErr_Print();
@@ -375,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 * global_ctxt, PyObject * local_ctxt)
 {
   // First guess if command is execution of a script with args, or a simple Python command
   std::string singleCommand = command;
@@ -391,7 +382,7 @@ static int compile_command(const char *command, PyObject *context)
   if (commandArgs.empty()) {
     // process command: expression
     // process command: execfile(r"/absolute/path/to/script.py") (no args)
-    return run_command(singleCommand.c_str(), context);
+    return run_command(singleCommand.c_str(), global_ctxt, local_ctxt);
   }
   else {
     // process command: execfile(r"/absolute/path/to/script.py [args:arg1,...,argn]")
@@ -403,7 +394,7 @@ static int compile_command(const char *command, PyObject *context)
     replaceAll(commandArgs, ",", "\",\"");
     commandArgs = "\""+commandArgs+"\"";
     std::string completeCommand = preCommandBegin+"\""+script+"\","+commandArgs+preCommandEnd+singleCommand+";sys.argv=save_argv";
-    return run_command(completeCommand.c_str(), context);
+    return run_command(completeCommand.c_str(), global_ctxt, local_ctxt);
   }
 }
 
@@ -452,7 +443,7 @@ int PyInterp_Interp::simpleRun(const char *command, const bool addToHistory)
   PySys_SetObject((char*)"stderr",_verr);
   PySys_SetObject((char*)"stdout",_vout);
 
-  int ier = compile_command(command,_context);
+  int ier = compile_command(command, _global_context, _local_context);
 
   // Outputs are redirected to what they were before
   PySys_SetObject((char*)"stdout",oldOut);
index 766f02a5e72ded74c206ecd05e13ac568f71d19d..9b855a4f2903c770bb3ef49dbee5223bc81d94e1 100644 (file)
 //
 
 //  File   : PyInterp_Interp.h
-//  Author : Christian CAREMOLI, Paul RASCLE, EDF
+//  Author : Christian CAREMOLI, Paul RASCLE, Adrien BRUNETON
 //  Module : SALOME
 //
 #ifndef PYINTERP_INTERP_H
 #define PYINTERP_INTERP_H
 
 #include "PyInterp.h"   // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!!
+#include "PyInterp_Utils.h"
 
 #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
-{
-  PyGILState_STATE _gil_state;
-public:
-  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);
 
+typedef struct {
+  PyObject_HEAD
+  int softspace;
+  PyOutChanged* _cb;
+  void* _data;
+  bool _iscerr;
+} PyStdOut;
+
 /**
  * Main class representing a *virtual* Python interpreter. There is really only one true
  * Python interpreter in the whole application (no call to Py_NewInterpreter),
@@ -92,8 +81,9 @@ protected:
   PyObject * _vout;
   PyObject * _verr;
   /** Execution context (local and global variables) */
-  PyObject * _context;
-  PyObject * _codeop;
+  PyObject * _global_context;
+  PyObject * _local_context;
+
   std::list<std::string> _history;
   std::list<std::string>::iterator _ith;
 
@@ -101,46 +91,11 @@ protected:
   int simpleRun(const char* command, const bool addToHistory = true);
 
   virtual void initPython();
-  /** 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;
+  /** Initialize execution context. */
+  virtual bool initContext();
   virtual bool initRun();
   virtual void closeContext();
 };
 
-/**
- * Utility class to properly handle the reference counting required on Python objects.
- */
-class PYINTERP_EXPORT PyObjWrapper
-{
-  PyObject* myObject;
-public:
-  PyObjWrapper(PyObject* theObject) : myObject(theObject) {}
-  PyObjWrapper() : myObject(0) {}
-  virtual ~PyObjWrapper() { Py_XDECREF(myObject); }
-
-  operator PyObject*()    { return myObject;  }
-  PyObject* operator->()  { return myObject;  }
-  PyObject* get()         { return myObject;  }
-  bool operator!()        { return !myObject; }
-  bool operator==(PyObject* theObject) { return myObject == theObject; }
-  PyObject** operator&()  { return &myObject; }
-  PyObjWrapper& operator=(PyObjWrapper* theObjWrapper)
-  {
-    Py_XDECREF(myObject);
-    myObject = theObjWrapper->myObject;
-    return *this;
-  }
-};
-
-typedef struct {
-  PyObject_HEAD
-  int softspace;
-  PyOutChanged* _cb;
-  void* _data;
-  bool _iscerr;
-} PyStdOut;
-
 #endif // PYINTERP_INTERP_H
index eab188f7afb536417de6c6d1046e9bd450f246b9..f541a1a06119abe87cd1d42dd513ee62cf35c7da 100644 (file)
 //  Module : GUI
 
 #include "PyInterp_Request.h"
+#include "PyInterp_Utils.h"
+#include <QCoreApplication>
 
+void PyInterp_Request::process()
+{
+  safeExecute();
+
+  bool isSync = IsSync();
+
+  if ( !isSync )
+    myMutex.lock();
+
+  if ( listener() )
+    processEvent( listener() );
+
+  if ( !isSync )
+    myMutex.unlock();
+}
+
+void PyInterp_Request::safeExecute()
+{
+  //ProcessVoidEvent( new PyInterp_ExecuteEvent( this ) );
+  execute();
+}
+
+void PyInterp_Request::Destroy( PyInterp_Request* request )
+{
+  // Lock and unlock the mutex to avoid errors on its deletion
+  request->myMutex.lock();
+  request->myMutex.unlock();
+  delete request;
+}
+
+QEvent* PyInterp_Request::createEvent()
+{
+  return new PyInterp_Event( PyInterp_Event::ES_NOTIFY, this );
+}
+
+void PyInterp_Request::processEvent( QObject* o )
+{
+  if ( !o )
+    return;
+
+  QEvent* e = createEvent();
+  if ( !e )
+    return;
+
+  if ( !IsSync() )
+    QCoreApplication::postEvent( o, e );
+  else
+  {
+    QCoreApplication::sendEvent( o, e );
+    delete e;
+  }
+}
+
+void PyInterp_Request::setListener( QObject* o )
+{
+  myMutex.lock();
+  myListener = o;
+  myMutex.unlock();
+}
+
+void PyInterp_LockRequest::safeExecute()
+{
+  //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();
+  //}
+}
index 4ceacd3e0160fb7c28c484d4f72c3e33ed697b3f..56046869fe3c0f26eb912999bbcfb80300a4b9df 100644 (file)
@@ -43,6 +43,7 @@ class PYINTERP_EXPORT PyInterp_Request
   friend class PyInterp_Dispatcher;
   friend class PyInterp_ExecuteEvent;
 
+private:
   PyInterp_Request();
   PyInterp_Request( const PyInterp_Request& );
 
@@ -51,7 +52,7 @@ protected:
   // protected destructor - to control deletion of requests
 
 public:
-  PyInterp_Request( QObject* listener, bool sync = false )
+  PyInterp_Request( QObject* listener, bool sync = true )
     : myIsSync( sync ), myListener( listener ) {};
 
   static void     Destroy( PyInterp_Request* );
@@ -88,7 +89,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=true )
     : PyInterp_Request( listener, sync ), myInterp( interp )
   {}
 
diff --git a/src/PyInterp/PyInterp_Utils.cxx b/src/PyInterp/PyInterp_Utils.cxx
new file mode 100644 (file)
index 0000000..4fa3bc2
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright (C) 2007-2014  CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+//  Author : Adrien BRUNETON
+//
+
+#include "PyInterp_Utils.h"
+
+/*!
+  \class PyLockWrapper
+  \brief Python GIL wrapper.
+*/
+
+/*!
+  \brief Constructor. Automatically acquires GIL.
+*/
+PyLockWrapper::PyLockWrapper()
+{
+  _gil_state = PyGILState_Ensure();
+}
+
+/*!
+  \brief Destructor. Automatically releases GIL.
+*/
+PyLockWrapper::~PyLockWrapper()
+{
+  PyGILState_Release(_gil_state);
+}
+
diff --git a/src/PyInterp/PyInterp_Utils.h b/src/PyInterp/PyInterp_Utils.h
new file mode 100644 (file)
index 0000000..c9866ba
--- /dev/null
@@ -0,0 +1,78 @@
+// Copyright (C) 2007-2014  CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+//  Author : Adrien BRUNETON
+//
+
+#ifndef PYINTERP_UTILS_H
+#define PYINTERP_UTILS_H
+
+#include "PyInterp.h"
+#include <Python.h>
+
+/**
+ * Utility class wrapping 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
+{
+  PyGILState_STATE _gil_state;
+public:
+  PyLockWrapper();
+  ~PyLockWrapper();
+
+private:
+  // "Rule of 3" - Forbid usage of copy operator and copy-constructor
+  PyLockWrapper(const PyLockWrapper & another);
+  const PyLockWrapper & operator=(const PyLockWrapper & another);
+};
+
+
+/**
+ * Utility class to properly handle the reference counting required on Python objects.
+ */
+class PYINTERP_EXPORT PyObjWrapper
+{
+  PyObject* myObject;
+public:
+  PyObjWrapper(PyObject* theObject) : myObject(theObject) {}
+  PyObjWrapper() : myObject(0) {}
+  virtual ~PyObjWrapper() { Py_XDECREF(myObject); }
+
+  operator PyObject*()    { return myObject;  }
+  PyObject* operator->()  { return myObject;  }
+  PyObject* get()         { return myObject;  }
+  bool operator!()        { return !myObject; }
+  bool operator==(PyObject* theObject) { return myObject == theObject; }
+  PyObject** operator&()  { return &myObject; }
+  PyObjWrapper& operator=(PyObjWrapper* theObjWrapper)
+  {
+    Py_XDECREF(myObject);
+    myObject = theObjWrapper->myObject;
+    return *this;
+  }
+};
+
+#endif
+
index bb72bb2b65604c85a365f80b8a9b91616f3dbd7d..c473793934549622e6664f5f0f467978a7e28ebf 100644 (file)
@@ -52,6 +52,10 @@ void SALOME_PYQT_PyInterp::initPython()
   MESSAGE("SALOME_PYQT_PyInterp::initPython - does nothing");
 }
 
+/*!
+ * Override. Create a distinct context from the SALOME Python console.
+ * Especially the global context is not connected to __main__ as in PyInterp_Interp
+ */
 bool SALOME_PYQT_PyInterp::initContext()
 {
   /*
@@ -59,7 +63,8 @@ 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
    */
-  _context = PyDict_New();          // create interpreter dictionnary context
+  _local_context = PyDict_New();
+  _global_context = PyDict_New();
   return true;
 }
 
@@ -72,7 +77,7 @@ int SALOME_PYQT_PyInterp::run(const char *command)
     PyErr_Print();
     return -1;
   }
-  PyObject *r = PyEval_EvalCode((PyCodeObject *)code,_context,_context);
+  PyObject *r = PyEval_EvalCode((PyCodeObject *)code,_global_context,_local_context);
 
   Py_DECREF(code);
   if(!r){
index 5857ffe8d81e8b17fd14f55051380bbd64a1a45f..795c0770cedaad464fda914e4866af286bf79d57 100644 (file)
@@ -34,7 +34,7 @@ class SALOME_PYQT_LIGHT_EXPORT SALOME_PYQT_PyInterp : public PyInterp_Interp
   SALOME_PYQT_PyInterp();
   ~SALOME_PYQT_PyInterp();
   
-  int run(const char *command);
+  virtual int run(const char *command);
   
  protected:
   virtual void initPython();
index d8c21b0056b3371d90a6128bbf06377d3a0833a9..30bd9616e86d17ff13836ca5ea8bda47258a939b 100644 (file)
@@ -1096,7 +1096,7 @@ void PyModuleHelper::studyActivated( SUIT_Study* study )
   public:
     StudyChangedReq( PyModuleHelper* _helper,
                      SUIT_Study*     _study )
-      : PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true)
+      : PyInterp_Request(0, true ), // this request should be processed synchronously (sync == true)
         myHelper( _helper ), 
         myStudy ( _study )
     {}
index 45d8dea5bbb5a7bddcd8b49c4461a4ba66410d8b..b5ecb767ad43ae4563cf3331481cb11da9def5fb 100644 (file)
@@ -21,8 +21,8 @@
 // Author : Roman NIKOLAEV, Open CASCADE S.A.S.
 // Module : GUI
 //
-#include <PyConsole_Interp.h> // this include must be first (see PyInterp_base.h)!
-#include <PyConsole_Console.h>
+#include "PyConsole_Interp.h" // this include must be first (see PyInterp_base.h)!
+#include "PyConsole_Console.h"
 
 #include "SalomeApp_NoteBook.h"
 #include "SalomeApp_Application.h"