]> SALOME platform Git repositories - modules/gui.git/commitdiff
Salome HOME
Imp PAL7743 (output flush is not possible in python console)
authorvsr <vsr@opencascade.com>
Wed, 26 Sep 2007 10:54:16 +0000 (10:54 +0000)
committervsr <vsr@opencascade.com>
Wed, 26 Sep 2007 10:54:16 +0000 (10:54 +0000)
src/PyInterp/PyInterp_base.cxx
src/PyInterp/PyInterp_base.h
src/PythonConsole/PythonConsole_PyEditor.cxx
src/PythonConsole/PythonConsole_PyInterp.cxx

index 7225855fe7172ec0946ef4ca317731543ae3f3f0..d2a855767b80850b97a94a406dadac7ead705721 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "PyInterp_base.h" // this include must be first (see PyInterp_base.h)!
 #include <cStringIO.h>
+#include <structmember.h>
 
 using namespace std;
 
@@ -72,6 +73,108 @@ PyLockWrapper PyInterp_base::GetLockWrapper(){
   return _tstate;
 }
 
+static void
+PyStdOut_dealloc(PyStdOut *self)
+{
+  PyObject_Del(self);
+}
+
+static PyObject *
+PyStdOut_write(PyStdOut *self, PyObject *args)
+{
+  char *c;
+  int l;
+  if (!PyArg_ParseTuple(args, "t#:write",&c, &l))
+    return NULL;
+  if(self->_cb==NULL) {
+    if ( self->_iscerr )
+      std::cerr << c ;
+    else
+      std::cout << c ;
+  }
+  else {
+    self->_cb(self->_data,c);
+  }
+  Py_INCREF(Py_None);
+  return Py_None;
+}
+
+static PyMethodDef PyStdOut_methods[] = {
+  {"write",  (PyCFunction)PyStdOut_write,  METH_VARARGS,
+    PyDoc_STR("write(string) -> None")},
+  {NULL,    NULL}   /* sentinel */
+};
+
+static PyMemberDef PyStdOut_memberlist[] = {
+  {"softspace", T_INT,  offsetof(PyStdOut, softspace), 0,
+   "flag indicating that a space needs to be printed; used by print"},
+  {NULL} /* Sentinel */
+};
+
+
+
+static PyTypeObject PyStdOut_Type = {
+  /* The ob_type field must be initialized in the module init function
+   * to be portable to Windows without using C++. */
+  PyObject_HEAD_INIT(NULL)
+  0,      /*ob_size*/
+  "PyOut",   /*tp_name*/
+  sizeof(PyStdOut),  /*tp_basicsize*/
+  0,      /*tp_itemsize*/
+  /* methods */
+  (destructor)PyStdOut_dealloc, /*tp_dealloc*/
+  0,      /*tp_print*/
+  0, /*tp_getattr*/
+  0, /*tp_setattr*/
+  0,      /*tp_compare*/
+  0,      /*tp_repr*/
+  0,      /*tp_as_number*/
+  0,      /*tp_as_sequence*/
+  0,      /*tp_as_mapping*/
+  0,      /*tp_hash*/
+        0,                      /*tp_call*/
+        0,                      /*tp_str*/
+        PyObject_GenericGetAttr,                      /*tp_getattro*/
+        /* softspace is writable:  we must supply tp_setattro */
+        PyObject_GenericSetAttr,    /* tp_setattro */
+        0,                      /*tp_as_buffer*/
+        Py_TPFLAGS_DEFAULT,     /*tp_flags*/
+        0,                      /*tp_doc*/
+        0,                      /*tp_traverse*/
+        0,                      /*tp_clear*/
+        0,                      /*tp_richcompare*/
+        0,                      /*tp_weaklistoffset*/
+        0,                      /*tp_iter*/
+        0,                      /*tp_iternext*/
+        PyStdOut_methods,                      /*tp_methods*/
+        PyStdOut_memberlist,                      /*tp_members*/
+        0,                      /*tp_getset*/
+        0,                      /*tp_base*/
+        0,                      /*tp_dict*/
+        0,                      /*tp_descr_get*/
+        0,                      /*tp_descr_set*/
+        0,                      /*tp_dictoffset*/
+        0,                      /*tp_init*/
+        0,                      /*tp_alloc*/
+        0,                      /*tp_new*/
+        0,                      /*tp_free*/
+        0,                      /*tp_is_gc*/
+};
+
+
+#define PyStdOut_Check(v)  ((v)->ob_type == &PyStdOut_Type)
+
+static PyStdOut * newPyStdOut( bool iscerr )
+{
+  PyStdOut *self;
+  self = PyObject_New(PyStdOut, &PyStdOut_Type);
+  if (self == NULL)
+    return NULL;
+  self->softspace = 0;
+  self->_cb = NULL;
+  self->_iscerr = iscerr;
+  return self;
+}
 
 // main python interpreter (static attributes)
 
@@ -124,12 +227,9 @@ void PyInterp_base::initialize()
     return;
   }
 
-  // Create cStringIO to capture stdout and stderr
-  PycString_IMPORT;
-  if (PycStringIO) { // CTH11627 : additional check
-    _vout = PycStringIO->NewOutput(128);
-    _verr = PycStringIO->NewOutput(128);
-  }
+  // Create python objects to capture stdout and stderr
+  _vout=(PyObject*)newPyStdOut( false ); // stdout 
+  _verr=(PyObject*)newPyStdOut( true );  // stderr
 
   // All the initRun outputs are redirected to the standard output (console)
   initRun();
@@ -147,6 +247,10 @@ void PyInterp_base::init_python()
   PySys_SetArgv(_argc, _argv);
   PyEval_InitThreads(); // Create (and acquire) the interpreter lock
   _interp = PyThreadState_Get()->interp;
+  if (PyType_Ready(&PyStdOut_Type) < 0)
+    {
+      PyErr_Print();
+    }
   _gtstate = PyEval_SaveThread(); // Release global thread state
 }
 
@@ -164,17 +268,18 @@ string PyInterp_base::getbanner()
 
 int PyInterp_base::initRun()
 {
+  // 
+  // probably all below code isn't required
+  //
+  /*
   PySys_SetObject("stderr",_verr);
   PySys_SetObject("stdout",_vout);
 
-  PyObjWrapper verr(PyObject_CallMethod(_verr,"reset",""));
-  PyObjWrapper vout(PyObject_CallMethod(_vout,"reset",""));
-
   //PyObject *m = PyImport_GetModuleDict();
   
   PySys_SetObject("stdout",PySys_GetObject("__stdout__"));
   PySys_SetObject("stderr",PySys_GetObject("__stderr__"));
-
+  */
   return 0;
 }
 
@@ -264,9 +369,6 @@ int PyInterp_base::simpleRun(const char *command)
   PySys_SetObject("stderr",_verr);
   PySys_SetObject("stdout",_vout);
 
-  PyObjWrapper verr(PyObject_CallMethod(_verr,"reset",""));
-  PyObjWrapper vout(PyObject_CallMethod(_vout,"reset",""));
-
   int ier = compile_command(command,_g);
 
   // Outputs are redirected on standards outputs (console)
@@ -300,17 +402,15 @@ const char * PyInterp_base::getNext()
 }
 
 
-string PyInterp_base::getverr(){ 
-  //PyLockWrapper aLock(_tstate);
-  PyObjWrapper v(PycStringIO->cgetvalue(_verr));
-  string aRet(PyString_AsString(v));
-  return aRet;
+void PyInterp_base::setvoutcb(PyOutChanged* cb, void* data)
+{  
+  ((PyStdOut*)_vout)->_cb=cb;
+  ((PyStdOut*)_vout)->_data=data;
 }
 
 
-string PyInterp_base::getvout(){  
-  //PyLockWrapper aLock(_tstate);
-  PyObjWrapper v(PycStringIO->cgetvalue(_vout));
-  string aRet(PyString_AsString(v));
-  return aRet;
+void PyInterp_base::setverrcb(PyOutChanged* cb, void* data)
+{  
+  ((PyStdOut*)_verr)->_cb=cb;
+  ((PyStdOut*)_verr)->_data=data;
 }
index 71931655cd30ae6db5061993290e8717ac047784..298b1c5088b2d3f8753017590d173a414f156d0d 100644 (file)
@@ -63,6 +63,8 @@ class PYINTERP_EXPORT PyLockWrapper
   ~PyLockWrapper();
 };
 
+typedef void PyOutChanged(void* data,char * c);
+
 class PYINTERP_EXPORT PyInterp_base{
  public:
   static int _argc;
@@ -85,8 +87,8 @@ class PYINTERP_EXPORT PyInterp_base{
   PyLockWrapper GetLockWrapper();
 
   std::string getbanner(); 
-  std::string getverr();
-  std::string getvout();  
+  void setverrcb(PyOutChanged*,void*);
+  void setvoutcb(PyOutChanged*,void*);
 
   const char * getPrevious();
   const char * getNext();    
@@ -142,4 +144,13 @@ public:
   }
 };
 
+
+typedef struct {
+  PyObject_HEAD
+  int softspace;
+  PyOutChanged* _cb;
+  void* _data;
+  bool _iscerr;
+} PyStdOut;
+
 #endif
index 21e2566f44a09b0fcd40736e90849003c9d27fb2..deecd648f886719e0c25919b31570d6ca16d884b 100755 (executable)
@@ -38,6 +38,7 @@
 #include <qapplication.h>
 #include <qpopupmenu.h>
 #include <qfontmetrics.h>
+#include <iostream>
 
 using namespace std;
 
@@ -59,7 +60,7 @@ static QString DOTS_PROMPT  = "... ";
 class ExecCommand : public PyInterp_LockRequest
 {
 public:
-  ExecCommand(PyInterp_base* theInterp, const char* theCommand,
+  ExecCommand(PyInterp_base* theInterp, const QString& theCommand,
               PythonConsole_PyEditor* theListener, bool sync = false)
     : PyInterp_LockRequest( theInterp, theListener, sync ),
       myCommand( theCommand ), myState( PyInterp_Event::OK )
@@ -67,22 +68,17 @@ public:
 
 protected:
   virtual void execute(){
-    if(myCommand != ""){
+    if( !myCommand.stripWhiteSpace().isEmpty() ) {
 //      if(MYDEBUG) MESSAGE("*** ExecCommand::execute() started");
       SUIT_Session::SetPythonExecuted(true); // disable GUI user actions
       int ret = getInterp()->run( myCommand.latin1() );
       SUIT_Session::SetPythonExecuted(false); // enable GUI user actions
 //      if(MYDEBUG) MESSAGE("ExecCommand::execute() - myInterp = "<<getInterp()<<"; myCommand = '"<<myCommand.latin1()<<"' - "<<ret);
-      if(ret < 0)
+      if( ret < 0 )
        myState = PyInterp_Event::ERROR;
-      else if(ret > 0)
+      else if( ret > 0 )
        myState = PyInterp_Event::INCOMPLETE;
-      myError  = getInterp()->getverr().c_str();
-      myOutput = getInterp()->getvout().c_str();
 //      if(MYDEBUG) MESSAGE("*** ExecCommand::execute() finished");
-    }else{
-      myError = "";
-      myOutput = "";
     }
   }
 
@@ -91,15 +87,26 @@ protected:
     return new PyInterp_Event( myState, (PyInterp_Request*)this );    
   }
 
-public:
-  QString myError;
-  QString myOutput;
-
 private:
   QString myCommand;
   int myState;
 };
 
+#define PRINT_EVENT 65432
+
+class PrintEvent : public QCustomEvent
+{
+public:
+  PrintEvent( const char* c ) : QCustomEvent( PRINT_EVENT ), myText( c ) {}
+  QString text() const { return myText; }
+private:
+  QString myText;
+};
+
+void staticCallback( void* data, char* c )
+{
+  QApplication::postEvent( (PythonConsole_PyEditor*)data, new PrintEvent( c ) ); 
+}
 
 /*!
     Constructor
@@ -116,7 +123,11 @@ PythonConsole_PyEditor::PythonConsole_PyEditor(PyInterp_base* theInterp, QWidget
   setUndoRedoEnabled( false );
 
   _currentPrompt = READY_PROMPT;
-  setWordWrap(NoWrap);
+  setWordWrap( WidgetWidth );
+  setWrapPolicy( Anywhere );
+
+  theInterp->setvoutcb( staticCallback, this );
+  theInterp->setverrcb( staticCallback, this );
 
   connect(this,SIGNAL(returnPressed()),this,SLOT(handleReturn()) );
 
@@ -228,7 +239,7 @@ void PythonConsole_PyEditor::handleReturn()
   
   // Post a request to execute Python command
   // Editor will be informed via a custom event that execution has been completed
-  PyInterp_Dispatcher::Get()->Exec( new ExecCommand( myInterp, _buf.latin1(), this ) );
+  PyInterp_Dispatcher::Get()->Exec( new ExecCommand( myInterp, _buf, this ) );
 }
 
 /*!
@@ -703,22 +714,21 @@ void PythonConsole_PyEditor::keyPressEvent( QKeyEvent* e )
 void PythonConsole_PyEditor::customEvent(QCustomEvent* e)
 {
   switch( e->type() ) {
+  case PRINT_EVENT:
+    {
+      PrintEvent* pe=(PrintEvent*)e;
+      setText( pe->text() );
+      return;
+    }
   case PyInterp_Event::OK:
   case PyInterp_Event::ERROR:
     {
-      PyInterp_Event* pe = dynamic_cast<PyInterp_Event*>( e );
-      if ( pe ){
-       ExecCommand* ec = dynamic_cast<ExecCommand*>( pe->GetRequest() );
-       if ( ec ){
-         // The next line has appeared dangerous in case if
-         // Python command execution has produced very large output.
-         // A more clever approach is needed...
-         setText(ec->myOutput);
-         setText(ec->myError);
-       }
-      }
       _buf.truncate(0);
       _currentPrompt = READY_PROMPT;
+      QString txt = text( paragraphs()-1 );
+      txt.truncate( txt.length()-1 );
+      if ( !txt.isEmpty() )
+       setText("\n");
       setText(_currentPrompt);
       viewport()->unsetCursor();
       if( myIsInLoop )
@@ -729,6 +739,10 @@ void PythonConsole_PyEditor::customEvent(QCustomEvent* e)
     {
       _buf.append("\n");
       _currentPrompt = DOTS_PROMPT;
+      QString txt = text( paragraphs()-1 );
+      txt.truncate( txt.length()-1 );
+      if ( !txt.isEmpty() )
+       setText("\n");
       setText(_currentPrompt);
       viewport()->unsetCursor();
       if( myIsInLoop )
index e061b3677bdd5d6d316b708b254b7bfce8cfafb5..0046f02e34be8f300443280d43b4e3a866ede53b 100755 (executable)
@@ -76,8 +76,7 @@ PythonConsole_PyInterp::~PythonConsole_PyInterp()
 bool PythonConsole_PyInterp::initState()
 {
   /*
-   * The GIL is acquired and will be held on initState output
-   * It is the caller responsability to release the lock if needed
+   * The GIL is acquired on input and released on output
    */
     /*PyEval_AcquireLock();
 #ifdef WNT