* clearly separate global and local contexts for execution (not sure this brings something though ...)
* some Py_INCREF were missing
* cleaner compilation units
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)
{
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();
// 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"
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
*/
{
}
-/*!
- \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;
-}
// 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
public:
PyConsole_Interp();
~PyConsole_Interp();
-
-protected:
- virtual bool initContext();
};
#endif // PYCONSOLE_INTERP_H
PyInterp_Event.h
PyInterp_Interp.h
PyInterp_Request.h
+ PyInterp_Utils.h
)
# header files / to install
PyInterp_Event.cxx
PyInterp_Interp.cxx
PyInterp_Request.cxx
+ PyInterp_Utils.cxx
)
# sources / to compile
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 )
#include "PyInterp_Event.h"
#include "PyInterp_Request.h"
+PyInterp_Event::~PyInterp_Event()
+{
+ PyInterp_Request::Destroy( myRequest );
+ myRequest = 0;
+}
+
void PyInterp_ExecuteEvent::Execute()
{
myRequest->execute();
//
// 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.
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.
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)
{
}
*/
PyInterp_Interp::~PyInterp_Interp()
{
+ destroy();
}
/*!
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
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,
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();
\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;
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]")
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);
}
}
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);
//
// 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),
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;
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
// 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();
+ //}
+}
friend class PyInterp_Dispatcher;
friend class PyInterp_ExecuteEvent;
+private:
PyInterp_Request();
PyInterp_Request( const PyInterp_Request& );
// 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* );
{
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 )
{}
--- /dev/null
+// 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);
+}
+
--- /dev/null
+// 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
+
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()
{
/*
* 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;
}
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){
SALOME_PYQT_PyInterp();
~SALOME_PYQT_PyInterp();
- int run(const char *command);
+ virtual int run(const char *command);
protected:
virtual void initPython();
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 )
{}
// 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"