Salome HOME
Merge from V6_main 01/04/2013
[modules/yacs.git] / src / runtime / PythonNode.cxx
1 // Copyright (C) 2006-2013  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "RuntimeSALOME.hxx"
21 #include "PythonNode.hxx"
22 #include "PythonPorts.hxx"
23 #include "TypeCode.hxx"
24 #include "Container.hxx"
25 #include "SalomeContainer.hxx"
26 #include "ConversionException.hxx"
27
28 #include "PyStdout.hxx"
29 #include <iostream>
30 #include <sstream>
31 #include <fstream>
32
33 #ifdef WNT
34 #include <process.h>
35 #define getpid _getpid
36 #endif
37
38 #if PY_VERSION_HEX < 0x02050000 
39 typedef int Py_ssize_t;
40 #endif
41
42 //#define _DEVDEBUG_
43 #include "YacsTrace.hxx"
44
45 using namespace YACS::ENGINE;
46 using namespace std;
47
48 const char PythonNode::IMPL_NAME[]="Python";
49 const char PythonNode::KIND[]="Python";
50
51 PythonNode::PythonNode(const PythonNode& other, ComposedNode *father):InlineNode(other,father)
52 {
53   _implementation=IMPL_NAME;
54   PyGILState_STATE gstate=PyGILState_Ensure();
55   _context=PyDict_New();
56   if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
57     {
58       stringstream msg;
59       msg << "Impossible to set builtins" << __FILE__ << ":" << __LINE__;
60       PyGILState_Release(gstate);
61       _errorDetails=msg.str();
62       throw Exception(msg.str());
63     }
64   PyGILState_Release(gstate);
65 }
66
67 PythonNode::PythonNode(const std::string& name):InlineNode(name)
68 {
69   _implementation=IMPL_NAME;
70   PyGILState_STATE gstate = PyGILState_Ensure();
71   _context=PyDict_New();
72   if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
73     {
74       stringstream msg;
75       msg << "Impossible to set builtins" << __FILE__ << ":" << __LINE__;
76       PyGILState_Release(gstate);
77       _errorDetails=msg.str();
78       throw Exception(msg.str());
79     }
80   PyGILState_Release(gstate);
81 }
82
83 PythonNode::~PythonNode()
84 {
85   PyGILState_STATE gstate = PyGILState_Ensure();
86   DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
87   Py_DECREF(_context);
88   PyGILState_Release(gstate);
89 }
90
91 void PythonNode::checkBasicConsistency() const throw(YACS::Exception)
92 {
93   DEBTRACE("checkBasicConsistency");
94   InlineNode::checkBasicConsistency();
95
96   PyGILState_STATE gstate = PyGILState_Ensure();
97   PyObject* res;
98   res=Py_CompileString(_script.c_str(),getName().c_str(),Py_file_input);
99   if(res == NULL)
100     {
101       std::string error="";
102       PyObject* new_stderr = newPyStdOut(error);
103       PySys_SetObject((char*)"stderr", new_stderr);
104       PyErr_Print();
105       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
106       Py_DECREF(new_stderr);
107       PyGILState_Release(gstate);
108       throw Exception(error);
109     }
110   else
111     Py_XDECREF(res);
112   PyGILState_Release(gstate);
113 }
114
115 void PythonNode::load()
116 {
117   DEBTRACE( "---------------PyNode::load function---------------" );
118   if(_mode=="remote")
119     loadRemote();
120   else
121     loadLocal();
122 }
123
124 void PythonNode::loadLocal()
125 {
126   DEBTRACE( "---------------PyNode::loadLocal function---------------" );
127   // do nothing
128 }
129
130 void PythonNode::loadRemote()
131 {
132   DEBTRACE( "---------------PyNode::loadRemote function---------------" );
133   if(_container)
134     {
135       if(!_container->isAlreadyStarted(0))
136         {
137           try
138             {
139               _container->start(0);
140             }
141           catch(Exception& e)
142             {
143               _errorDetails=e.what();
144               throw e;
145             }
146         }
147     }
148   else
149     {
150       std::string what("PyNode::loadRemote : a load operation requested on \"");
151       what+=_name; what+="\" with no container specified.";
152       _errorDetails=what;
153       throw Exception(what);
154     }
155
156   Engines::Container_var objContainer=((SalomeContainer*)_container)->getContainerPtr(0);
157
158   try
159     {
160       _pynode = objContainer->createPyScriptNode(getName().c_str(),getScript().c_str());
161     }
162   catch( const SALOME::SALOME_Exception& ex )
163     {
164       std::string msg="Exception on remote python node creation ";
165       msg += '\n';
166       msg += ex.details.text.in();
167       _errorDetails=msg;
168       throw Exception(msg);
169     }
170
171   PyGILState_STATE gstate = PyGILState_Ensure();
172   const char picklizeScript[]="import cPickle\n"
173                               "def pickleForDistPyth2009(kws):\n"
174                               "  return cPickle.dumps(((),kws),-1)\n"
175                               "\n"
176                               "def unPickleForDistPyth2009(st):\n"
177                               "  args=cPickle.loads(st)\n"
178                               "  return args\n";
179   PyObject *res=PyRun_String(picklizeScript,Py_file_input,_context,_context);
180   if(res == NULL)
181     {
182       _errorDetails="";
183       PyObject* new_stderr = newPyStdOut(_errorDetails);
184       PySys_SetObject((char*)"stderr", new_stderr);
185       PyErr_Print();
186       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
187       Py_DECREF(new_stderr);
188
189       PyGILState_Release(gstate);
190       throw Exception("Error during load");
191     }
192   Py_DECREF(res);
193
194   _pyfuncSer=PyDict_GetItemString(_context,"pickleForDistPyth2009");
195   _pyfuncUnser=PyDict_GetItemString(_context,"unPickleForDistPyth2009");
196   if(_pyfuncSer == NULL)
197     {
198       _errorDetails="";
199       PyObject* new_stderr = newPyStdOut(_errorDetails);
200       PySys_SetObject((char*)"stderr", new_stderr);
201       PyErr_Print();
202       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
203       Py_DECREF(new_stderr);
204
205       PyGILState_Release(gstate);
206       throw Exception("Error during load");
207     }
208   if(_pyfuncUnser == NULL)
209     {
210       _errorDetails="";
211       PyObject* new_stderr = newPyStdOut(_errorDetails);
212       PySys_SetObject((char*)"stderr", new_stderr);
213       PyErr_Print();
214       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
215       Py_DECREF(new_stderr);
216
217       PyGILState_Release(gstate);
218       throw Exception("Error during load");
219     }
220   DEBTRACE( "---------------End PyNode::loadRemote function---------------" );
221   PyGILState_Release(gstate);
222
223 }
224
225 void PythonNode::execute()
226 {
227   if(_mode=="remote")
228     executeRemote();
229   else
230     executeLocal();
231 }
232
233 void PythonNode::executeRemote()
234 {
235   DEBTRACE( "++++++++++++++ PyNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
236   if(!_pyfuncSer)
237     throw Exception("DistributedPythonNode badly loaded");
238   PyGILState_STATE gstate = PyGILState_Ensure();
239
240   //===========================================================================
241   // Get inputs in input ports, build a Python dict and pickle it
242   //===========================================================================
243   PyObject* ob;
244   PyObject* args = PyDict_New();
245   std::list<InputPort *>::iterator iter2;
246   int pos=0;
247   for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); ++iter2)
248     {
249       InputPyPort *p=(InputPyPort *)*iter2;
250       ob=p->getPyObj();
251       PyDict_SetItemString(args,p->getName().c_str(),ob);
252       pos++;
253     }
254 #ifdef _DEVDEBUG_
255   PyObject_Print(args,stderr,Py_PRINT_RAW);
256   std::cerr << endl;
257 #endif
258   PyObject *serializationInput=PyObject_CallFunctionObjArgs(_pyfuncSer,args,NULL);
259   //The pickled string may contain NULL characters so use PyString_AsStringAndSize
260   char* serializationInputC;
261   Py_ssize_t len;
262   if (PyString_AsStringAndSize(serializationInput, &serializationInputC, &len))
263     {
264       PyGILState_Release(gstate);
265       throw Exception("DistributedPythonNode problem in python pickle");
266     }
267   PyGILState_Release(gstate);
268
269   Engines::pickledArgs_var serializationInputCorba=new Engines::pickledArgs;
270   serializationInputCorba->length(len);
271   for(int i=0; i < len ; i++)
272     serializationInputCorba[i]=serializationInputC[i];
273
274   //get the list of output argument names
275   std::list<OutputPort *>::iterator iter;
276   Engines::listofstring myseq;
277   myseq.length(getNumberOfOutputPorts());
278   pos=0;
279   for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); ++iter)
280     {
281       OutputPyPort *p=(OutputPyPort *)*iter;
282       myseq[pos]=p->getName().c_str();
283       DEBTRACE( "port name: " << p->getName() );
284       DEBTRACE( "port kind: " << p->edGetType()->kind() );
285       DEBTRACE( "port pos : " << pos );
286       pos++;
287     }
288   //===========================================================================
289   // Execute in remote Python node
290   //===========================================================================
291   DEBTRACE( "-----------------starting remote python invocation-----------------" );
292   Engines::pickledArgs_var resultCorba;
293   try
294     {
295       //pass outargsname and dict serialized
296       resultCorba=_pynode->execute(myseq,serializationInputCorba);
297     }
298   catch( const SALOME::SALOME_Exception& ex )
299     {
300       std::string msg="Exception on remote python invocation";
301       msg += '\n';
302       msg += ex.details.text.in();
303       _errorDetails=msg;
304       throw Exception(msg);
305     }
306   DEBTRACE( "-----------------end of remote python invocation-----------------" );
307   //===========================================================================
308   // Get results, unpickle and put them in output ports
309   //===========================================================================
310   char *resultCorbaC=new char[resultCorba->length()+1];
311   resultCorbaC[resultCorba->length()]='\0';
312   for(int i=0;i<resultCorba->length();i++)
313     resultCorbaC[i]=resultCorba[i];
314
315   gstate = PyGILState_Ensure();
316
317   PyObject* resultPython=PyString_FromStringAndSize(resultCorbaC,resultCorba->length());
318   delete [] resultCorbaC;
319   args = PyTuple_New(1);
320   PyTuple_SetItem(args,0,resultPython);
321   PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
322   Py_DECREF(args);
323
324   if (finalResult == NULL)
325   {
326     std::stringstream msg;
327     msg << "Conversion with pickle of output ports failed !";
328     msg << " : " << __FILE__ << ":" << __LINE__;
329     PyGILState_Release(gstate);
330     _errorDetails=msg.str();
331     throw YACS::ENGINE::ConversionException(msg.str());
332   }
333
334   DEBTRACE( "-----------------PythonNode::outputs-----------------" );
335   int nres=1;
336   if(finalResult == Py_None)
337     nres=0;
338   else if(PyTuple_Check(finalResult))
339     nres=PyTuple_Size(finalResult);
340
341   if(getNumberOfOutputPorts() != nres)
342     {
343       std::string msg="Number of output arguments : Mismatch between definition and execution";
344       Py_DECREF(finalResult);
345       PyGILState_Release(gstate);
346       _errorDetails=msg;
347       throw Exception(msg);
348     }
349
350   pos=0;
351   try
352     {
353       for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); ++iter)
354         {
355           OutputPyPort *p=(OutputPyPort *)*iter;
356           DEBTRACE( "port name: " << p->getName() );
357           DEBTRACE( "port kind: " << p->edGetType()->kind() );
358           DEBTRACE( "port pos : " << pos );
359           if(PyTuple_Check(finalResult))
360             ob=PyTuple_GetItem(finalResult,pos) ;
361           else
362             ob=finalResult;
363           DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
364           p->put(ob);
365           pos++;
366         }
367       Py_DECREF(finalResult);
368     }
369   catch(ConversionException& ex)
370     {
371       Py_DECREF(finalResult);
372       PyGILState_Release(gstate);
373       _errorDetails=ex.what();
374       throw;
375     }
376
377   PyGILState_Release(gstate);
378
379   DEBTRACE( "++++++++++++++ ENDOF PyNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
380 }
381
382 void PythonNode::executeLocal()
383 {
384   DEBTRACE( "++++++++++++++ PyNode::executeLocal: " << getName() << " ++++++++++++++++++++" );
385   PyGILState_STATE gstate = PyGILState_Ensure();
386
387   DEBTRACE( "---------------PyNode::inputs---------------" );
388   list<InputPort *>::iterator iter2;
389   for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
390     {
391       InputPyPort *p=(InputPyPort *)*iter2;
392       DEBTRACE( "port name: " << p->getName() );
393       DEBTRACE( "port kind: " << p->edGetType()->kind() );
394       PyObject* ob=p->getPyObj();
395       DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
396 #ifdef _DEVDEBUG_
397       PyObject_Print(ob,stderr,Py_PRINT_RAW);
398       cerr << endl;
399 #endif
400       int ier=PyDict_SetItemString(_context,p->getName().c_str(),ob);
401       DEBTRACE( "after PyDict_SetItemString:ob refcnt: " << ob->ob_refcnt );
402     }
403   
404   DEBTRACE( "---------------End PyNode::inputs---------------" );
405   
406   //calculation
407   DEBTRACE( "----------------PyNode::calculation---------------" );
408   DEBTRACE(  _script );
409   DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
410
411   std::ostringstream stream;
412   stream << "/tmp/PythonNode_";
413   stream << getpid();
414
415   PyObject* code=Py_CompileString(_script.c_str(), stream.str().c_str(), Py_file_input);
416   if(code == NULL)
417     {
418       _errorDetails="";
419       PyObject* new_stderr = newPyStdOut(_errorDetails);
420       PySys_SetObject((char*)"stderr", new_stderr);
421       PyErr_Print();
422       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
423       Py_DECREF(new_stderr);
424       PyGILState_Release(gstate);
425       throw Exception("Error during execution");
426     }
427   PyObject *res = PyEval_EvalCode((PyCodeObject *)code, _context, _context);
428   Py_DECREF(code);
429   DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
430   fflush(stdout);
431   fflush(stderr);
432   if(res == NULL)
433     {
434       _errorDetails="";
435       PyObject* new_stderr = newPyStdOut(_errorDetails);
436       PySys_SetObject((char*)"stderr", new_stderr);
437       ofstream errorfile(stream.str().c_str());
438       if (errorfile.is_open())
439         {
440           errorfile << _script;
441           errorfile.close();
442         }
443       PyErr_Print();
444       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
445       Py_DECREF(new_stderr);
446
447       PyGILState_Release(gstate);
448       throw Exception("Error during execution");
449     }
450   Py_DECREF(res);
451   
452   DEBTRACE( "-----------------PyNode::outputs-----------------" );
453   list<OutputPort *>::iterator iter;
454   try
455     {
456       for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
457         {
458           OutputPyPort *p=(OutputPyPort *)*iter;
459           DEBTRACE( "port name: " << p->getName() );
460           DEBTRACE( "port kind: " << p->edGetType()->kind() );
461           PyObject *ob=PyDict_GetItemString(_context,p->getName().c_str());
462           if(ob==NULL){
463              PyGILState_Release(gstate);
464              std::string msg="Error during execution: there is no variable ";
465              msg=msg+p->getName()+" in node context";
466              _errorDetails=msg;
467              throw Exception(msg);
468           }
469           DEBTRACE( "PyNode::outputs::ob refcnt: " << ob->ob_refcnt );
470 #ifdef _DEVDEBUG_
471           PyObject_Print(ob,stderr,Py_PRINT_RAW);
472           cerr << endl;
473 #endif
474           p->put(ob);
475         }
476     }
477   catch(ConversionException& ex)
478     {
479       PyGILState_Release(gstate);
480       _errorDetails=ex.what();
481       throw;
482     }
483
484   DEBTRACE( "-----------------End PyNode::outputs-----------------" );
485   PyGILState_Release(gstate);
486   DEBTRACE( "++++++++++++++ End PyNode::execute: " << getName() << " ++++++++++++++++++++" );
487 }
488
489 std::string PythonNode::getContainerLog()
490 {
491   if(_mode=="local")return "";
492
493   std::string msg;
494   try
495     {
496       Engines::Container_var objContainer=((SalomeContainer*)_container)->getContainerPtr(0);
497       CORBA::String_var logname = objContainer->logfilename();
498       DEBTRACE(logname);
499       msg=logname;
500       std::string::size_type pos = msg.find(":");
501       msg=msg.substr(pos+1);
502     }
503   catch(...)
504     {
505       msg = "Container no longer reachable";
506     }
507   return msg;
508 }
509
510 void PythonNode::shutdown(int level)
511 {
512   DEBTRACE("PythonNode::shutdown " << level);
513   if(_mode=="local")return;
514   if(_container)
515     {
516       if(!CORBA::is_nil(_pynode)) _pynode->UnRegister();
517       _pynode=Engines::PyScriptNode::_nil();
518       _container->shutdown(level);
519     }
520 }
521
522 Node *PythonNode::simpleClone(ComposedNode *father, bool editionOnly) const
523 {
524   return new PythonNode(*this,father);
525 }
526
527 //! Create a new node of same type with a given name
528 PythonNode* PythonNode::cloneNode(const std::string& name)
529 {
530   PythonNode* n=new PythonNode(name);
531   n->setScript(_script);
532   list<InputPort *>::iterator iter;
533   for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
534     {
535       InputPyPort *p=(InputPyPort *)*iter;
536       DEBTRACE( "port name: " << p->getName() );
537       DEBTRACE( "port kind: " << p->edGetType()->kind() );
538       n->edAddInputPort(p->getName(),p->edGetType());
539     }
540   list<OutputPort *>::iterator iter2;
541   for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
542     {
543       OutputPyPort *p=(OutputPyPort *)*iter2;
544       DEBTRACE( "port name: " << p->getName() );
545       DEBTRACE( "port kind: " << p->edGetType()->kind() );
546       n->edAddOutputPort(p->getName(),p->edGetType());
547     }
548   return n;
549 }
550
551 PyFuncNode::PyFuncNode(const PyFuncNode& other, ComposedNode *father):InlineFuncNode(other,father),_pyfunc(0)
552 {
553   _implementation = PythonNode::IMPL_NAME;
554   PyGILState_STATE gstate = PyGILState_Ensure();
555   _context=PyDict_New();
556   DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
557   if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
558     {
559       stringstream msg;
560       msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
561       _errorDetails=msg.str();
562       PyGILState_Release(gstate);
563       throw Exception(msg.str());
564     }
565   PyGILState_Release(gstate);
566 }
567
568 PyFuncNode::PyFuncNode(const std::string& name): InlineFuncNode(name),_pyfunc(0)
569 {
570
571   _implementation = PythonNode::IMPL_NAME;
572   DEBTRACE( "PyFuncNode::PyFuncNode " << name );
573   PyGILState_STATE gstate = PyGILState_Ensure();
574   _context=PyDict_New();
575   DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
576   if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
577     {
578       stringstream msg;
579       msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
580       _errorDetails=msg.str();
581       PyGILState_Release(gstate);
582       throw Exception(msg.str());
583     }
584   PyGILState_Release(gstate);
585 }
586
587 PyFuncNode::~PyFuncNode()
588 {
589   DEBTRACE( getName() );
590   PyGILState_STATE gstate = PyGILState_Ensure();
591   DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
592   if(_pyfunc)DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
593   Py_DECREF(_context);
594   PyGILState_Release(gstate);
595   if(!CORBA::is_nil(_pynode))
596     {
597       _pynode->UnRegister();
598     }
599 }
600
601 void PyFuncNode::checkBasicConsistency() const throw(YACS::Exception)
602 {
603   DEBTRACE("checkBasicConsistency");
604   InlineFuncNode::checkBasicConsistency();
605
606   PyGILState_STATE gstate = PyGILState_Ensure();
607   PyObject* res;
608   res=Py_CompileString(_script.c_str(),getName().c_str(),Py_file_input);
609   if(res == NULL)
610     {
611       std::string error="";
612       PyObject* new_stderr = newPyStdOut(error);
613       PySys_SetObject((char*)"stderr", new_stderr);
614       PyErr_Print();
615       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
616       Py_DECREF(new_stderr);
617       PyGILState_Release(gstate);
618       throw Exception(error);
619     }
620   else
621     Py_XDECREF(res);
622   PyGILState_Release(gstate);
623 }
624
625 void PyFuncNode::load()
626 {
627   DEBTRACE( "---------------PyfuncNode::load function---------------" );
628   if(_mode=="remote")
629     loadRemote();
630   else
631     loadLocal();
632 }
633
634 void PyFuncNode::loadRemote()
635 {
636   DEBTRACE( "---------------PyfuncNode::loadRemote function---------------" );
637   if(_container)
638     {
639       if(!_container->isAlreadyStarted(0))
640         {
641           try
642             {
643               _container->start(0);
644             }
645           catch(Exception& e)
646             {
647               _errorDetails=e.what();
648               throw e;
649             }
650         }
651     }
652   else
653     {
654       std::string what("PyFuncNode::loadRemote : a load operation requested on \"");
655       what+=_name; what+="\" with no container specified.";
656       _errorDetails=what;
657       throw Exception(what);
658     }
659
660   Engines::Container_var objContainer=((SalomeContainer*)_container)->getContainerPtr(0);
661   try
662     {
663       _pynode = objContainer->createPyNode(getName().c_str(),getScript().c_str());
664     }
665   catch( const SALOME::SALOME_Exception& ex )
666     {
667       std::string msg="Exception on remote python node creation ";
668       msg += '\n';
669       msg += ex.details.text.in();
670       _errorDetails=msg;
671       throw Exception(msg);
672     }
673
674   PyGILState_STATE gstate = PyGILState_Ensure();
675   const char picklizeScript[]="import cPickle\n"
676                               "def pickleForDistPyth2009(*args,**kws):\n"
677                               "  return cPickle.dumps((args,kws),-1)\n"
678                               "\n"
679                               "def unPickleForDistPyth2009(st):\n"
680                               "  args=cPickle.loads(st)\n"
681                               "  return args\n";
682   PyObject *res=PyRun_String(picklizeScript,Py_file_input,_context,_context);
683   if(res == NULL)
684     {
685       _errorDetails="";
686       PyObject* new_stderr = newPyStdOut(_errorDetails);
687       PySys_SetObject((char*)"stderr", new_stderr);
688       PyErr_Print();
689       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
690       Py_DECREF(new_stderr);
691
692       PyGILState_Release(gstate);
693       throw Exception("Error during load");
694     }
695   Py_DECREF(res);
696
697   _pyfuncSer=PyDict_GetItemString(_context,"pickleForDistPyth2009");
698   _pyfuncUnser=PyDict_GetItemString(_context,"unPickleForDistPyth2009");
699   if(_pyfuncSer == NULL)
700     {
701       _errorDetails="";
702       PyObject* new_stderr = newPyStdOut(_errorDetails);
703       PySys_SetObject((char*)"stderr", new_stderr);
704       PyErr_Print();
705       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
706       Py_DECREF(new_stderr);
707
708       PyGILState_Release(gstate);
709       throw Exception("Error during load");
710     }
711   if(_pyfuncUnser == NULL)
712     {
713       _errorDetails="";
714       PyObject* new_stderr = newPyStdOut(_errorDetails);
715       PySys_SetObject((char*)"stderr", new_stderr);
716       PyErr_Print();
717       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
718       Py_DECREF(new_stderr);
719
720       PyGILState_Release(gstate);
721       throw Exception("Error during load");
722     }
723   DEBTRACE( "---------------End PyfuncNode::loadRemote function---------------" );
724   PyGILState_Release(gstate);
725 }
726
727 void PyFuncNode::loadLocal()
728 {
729   DEBTRACE( "---------------PyFuncNode::load function " << getName() << " ---------------" );
730   DEBTRACE(  _script );
731
732 #ifdef _DEVDEBUG_
733   list<OutputPort *>::iterator iter;
734   for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
735     {
736       OutputPyPort *p=(OutputPyPort *)*iter;
737       DEBTRACE( "port name: " << p->getName() );
738       DEBTRACE( "port kind: " << p->edGetType()->kind() );
739     }
740 #endif
741
742   PyGILState_STATE gstate = PyGILState_Ensure();
743   DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
744
745   std::ostringstream stream;
746   stream << "/tmp/PythonNode_";
747   stream << getpid();
748
749   PyObject* code=Py_CompileString(_script.c_str(), stream.str().c_str(), Py_file_input);
750   if(code == NULL)
751     {
752       _errorDetails="";
753       PyObject* new_stderr = newPyStdOut(_errorDetails);
754       PySys_SetObject((char*)"stderr", new_stderr);
755       PyErr_Print();
756       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
757       Py_DECREF(new_stderr);
758       PyGILState_Release(gstate);
759       throw Exception("Error during execution");
760     }
761   PyObject *res = PyEval_EvalCode((PyCodeObject *)code, _context, _context);
762   Py_DECREF(code);
763
764   DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
765   if(res == NULL)
766     {
767       _errorDetails="";
768       PyObject* new_stderr = newPyStdOut(_errorDetails);
769       PySys_SetObject((char*)"stderr", new_stderr);
770       ofstream errorfile(stream.str().c_str());
771       if (errorfile.is_open())
772         {
773           errorfile << _script;
774           errorfile.close();
775         }
776       PyErr_Print();
777       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
778       Py_DECREF(new_stderr);
779
780       PyGILState_Release(gstate);
781       throw Exception("Error during execution");
782       return;
783     }
784   Py_DECREF(res);
785   _pyfunc=PyDict_GetItemString(_context,_fname.c_str());
786   DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
787   if(_pyfunc == NULL)
788     {
789       _errorDetails="";
790       PyObject* new_stderr = newPyStdOut(_errorDetails);
791       PySys_SetObject((char*)"stderr", new_stderr);
792       PyErr_Print();
793       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
794       Py_DECREF(new_stderr);
795
796       PyGILState_Release(gstate);
797       throw Exception("Error during execution");
798     }
799   DEBTRACE( "---------------End PyFuncNode::load function---------------" );
800   PyGILState_Release(gstate);
801 }
802
803 void PyFuncNode::execute()
804 {
805   if(_mode=="remote")
806     executeRemote();
807   else
808     executeLocal();
809 }
810
811 void PyFuncNode::executeRemote()
812 {
813   DEBTRACE( "++++++++++++++ PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
814   if(!_pyfuncSer)
815     throw Exception("DistributedPythonNode badly loaded");
816   PyGILState_STATE gstate = PyGILState_Ensure();
817
818   //===========================================================================
819   // Get inputs in input ports, build a Python tuple and pickle it
820   //===========================================================================
821   PyObject* ob;
822   PyObject* args = PyTuple_New(getNumberOfInputPorts());
823   std::list<InputPort *>::iterator iter2;
824   int pos=0;
825   for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); ++iter2)
826     {
827       InputPyPort *p=(InputPyPort *)*iter2;
828       ob=p->getPyObj();
829       Py_INCREF(ob);
830       PyTuple_SetItem(args,pos,ob);
831       pos++;
832     }
833 #ifdef _DEVDEBUG_
834   PyObject_Print(args,stderr,Py_PRINT_RAW);
835   std::cerr << endl;
836 #endif
837   PyObject *serializationInput=PyObject_CallObject(_pyfuncSer,args);
838   //The pickled string may contain NULL characters so use PyString_AsStringAndSize
839   char* serializationInputC;
840   Py_ssize_t len;
841   if (PyString_AsStringAndSize(serializationInput, &serializationInputC, &len))
842     {
843       PyGILState_Release(gstate);
844       throw Exception("DistributedPythonNode problem in python pickle");
845     }
846   PyGILState_Release(gstate);
847
848   Engines::pickledArgs_var serializationInputCorba=new Engines::pickledArgs;
849   serializationInputCorba->length(len);
850   for(int i=0; i < len ; i++)
851     serializationInputCorba[i]=serializationInputC[i];
852
853   //===========================================================================
854   // Execute in remote Python node
855   //===========================================================================
856   DEBTRACE( "-----------------starting remote python invocation-----------------" );
857   Engines::pickledArgs_var resultCorba;
858   try
859     {
860       resultCorba=_pynode->execute(getFname().c_str(),serializationInputCorba);
861     }
862   catch( const SALOME::SALOME_Exception& ex )
863     {
864       std::string msg="Exception on remote python invocation";
865       msg += '\n';
866       msg += ex.details.text.in();
867       _errorDetails=msg;
868       throw Exception(msg);
869     }
870   DEBTRACE( "-----------------end of remote python invocation-----------------" );
871   //===========================================================================
872   // Get results, unpickle and put them in output ports
873   //===========================================================================
874   char *resultCorbaC=new char[resultCorba->length()+1];
875   resultCorbaC[resultCorba->length()]='\0';
876   for(int i=0;i<resultCorba->length();i++)
877     resultCorbaC[i]=resultCorba[i];
878
879   gstate = PyGILState_Ensure();
880
881   PyObject* resultPython=PyString_FromStringAndSize(resultCorbaC,resultCorba->length());
882   delete [] resultCorbaC;
883   args = PyTuple_New(1);
884   PyTuple_SetItem(args,0,resultPython);
885   PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
886   Py_DECREF(args);
887
888   DEBTRACE( "-----------------PythonNode::outputs-----------------" );
889   int nres=1;
890   if(finalResult == Py_None)
891     nres=0;
892   else if(PyTuple_Check(finalResult))
893     nres=PyTuple_Size(finalResult);
894
895   if(getNumberOfOutputPorts() != nres)
896     {
897       std::string msg="Number of output arguments : Mismatch between definition and execution";
898       Py_DECREF(finalResult);
899       PyGILState_Release(gstate);
900       _errorDetails=msg;
901       throw Exception(msg);
902     }
903
904   pos=0;
905   std::list<OutputPort *>::iterator iter;
906   try
907     {
908       for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); ++iter)
909         {
910           OutputPyPort *p=(OutputPyPort *)*iter;
911           DEBTRACE( "port name: " << p->getName() );
912           DEBTRACE( "port kind: " << p->edGetType()->kind() );
913           DEBTRACE( "port pos : " << pos );
914           if(PyTuple_Check(finalResult))
915             ob=PyTuple_GetItem(finalResult,pos) ;
916           else 
917             ob=finalResult;
918           DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
919           p->put(ob);
920           pos++;
921         }
922       Py_DECREF(finalResult);
923     }
924   catch(ConversionException& ex)
925     {
926       Py_DECREF(finalResult);
927       PyGILState_Release(gstate);
928       _errorDetails=ex.what();
929       throw;
930     }
931
932   PyGILState_Release(gstate);
933
934   DEBTRACE( "++++++++++++++ ENDOF PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
935 }
936
937 void PyFuncNode::executeLocal()
938 {
939   DEBTRACE( "++++++++++++++ PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
940
941   int pos=0;
942   PyObject* ob;
943   if(!_pyfunc)throw Exception("PyFuncNode badly loaded");
944   PyGILState_STATE gstate = PyGILState_Ensure();
945
946   DEBTRACE( "---------------PyFuncNode::inputs---------------" );
947   PyObject* args = PyTuple_New(getNumberOfInputPorts()) ;
948   list<InputPort *>::iterator iter2;
949   for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
950     {
951       InputPyPort *p=(InputPyPort *)*iter2;
952       DEBTRACE( "port name: " << p->getName() );
953       DEBTRACE( "port kind: " << p->edGetType()->kind() );
954       ob=p->getPyObj();
955 #ifdef _DEVDEBUG_
956       PyObject_Print(ob,stderr,Py_PRINT_RAW);
957       cerr << endl;
958 #endif
959       DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
960       Py_INCREF(ob);
961       PyTuple_SetItem(args,pos,ob);
962       DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
963       pos++;
964     }
965   DEBTRACE( "---------------End PyFuncNode::inputs---------------" );
966
967   DEBTRACE( "----------------PyFuncNode::calculation---------------" );
968 #ifdef _DEVDEBUG_
969   PyObject_Print(_pyfunc,stderr,Py_PRINT_RAW);
970   cerr << endl;
971   PyObject_Print(args,stderr,Py_PRINT_RAW);
972   cerr << endl;
973 #endif
974   DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
975   PyObject* result = PyObject_CallObject( _pyfunc , args ) ;
976   DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
977   Py_DECREF(args);
978   fflush(stdout);
979   fflush(stderr);
980   if(result == NULL)
981     {
982       _errorDetails="";
983       PyObject* new_stderr = newPyStdOut(_errorDetails);
984       PySys_SetObject((char*)"stderr", new_stderr);
985       std::ostringstream stream;
986       stream << "/tmp/PythonNode_";
987       stream << getpid();
988       ofstream errorfile(stream.str().c_str());
989       if (errorfile.is_open())
990         {
991           errorfile << _script;
992           errorfile.close();
993         }
994       PyErr_Print();
995       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
996       Py_DECREF(new_stderr);
997
998       PyGILState_Release(gstate);
999       throw Exception("Error during execution");
1000     }
1001   DEBTRACE( "----------------End PyFuncNode::calculation---------------" );
1002
1003   DEBTRACE( "-----------------PyFuncNode::outputs-----------------" );
1004   int nres=1;
1005   if(result == Py_None)
1006     nres=0;
1007   else if(PyTuple_Check(result))
1008     nres=PyTuple_Size(result);
1009
1010   if(getNumberOfOutputPorts() != nres)
1011     {
1012       std::string msg="Number of output arguments : Mismatch between definition and execution";
1013       Py_DECREF(result);
1014       PyGILState_Release(gstate);
1015       _errorDetails=msg;
1016       throw Exception(msg);
1017     }
1018
1019   pos=0;
1020 #ifdef _DEVDEBUG_
1021   PyObject_Print(result,stderr,Py_PRINT_RAW);
1022   cerr << endl;
1023 #endif
1024   list<OutputPort *>::iterator iter;
1025   try
1026     {
1027       for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
1028         {
1029           OutputPyPort *p=(OutputPyPort *)*iter;
1030           DEBTRACE( "port name: " << p->getName() );
1031           DEBTRACE( "port kind: " << p->edGetType()->kind() );
1032           DEBTRACE( "port pos : " << pos );
1033           if(PyTuple_Check(result))ob=PyTuple_GetItem(result,pos) ;
1034           else ob=result;
1035           DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1036 #ifdef _DEVDEBUG_
1037           PyObject_Print(ob,stderr,Py_PRINT_RAW);
1038           cerr << endl;
1039 #endif
1040           p->put(ob);
1041           pos++;
1042         }
1043     }
1044   catch(ConversionException& ex)
1045     {
1046       Py_DECREF(result);
1047       PyGILState_Release(gstate);
1048       _errorDetails=ex.what();
1049       throw;
1050     }
1051   DEBTRACE( "-----------------End PyFuncNode::outputs-----------------" );
1052
1053   Py_DECREF(result);
1054   PyGILState_Release(gstate);
1055   DEBTRACE( "++++++++++++++ End PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
1056 }
1057
1058 Node *PyFuncNode::simpleClone(ComposedNode *father, bool editionOnly) const
1059 {
1060   return new PyFuncNode(*this,father);
1061 }
1062
1063 //! Create a new node of same type with a given name
1064 PyFuncNode* PyFuncNode::cloneNode(const std::string& name)
1065 {
1066   PyFuncNode* n=new PyFuncNode(name);
1067   n->setScript(_script);
1068   n->setFname(_fname);
1069   list<InputPort *>::iterator iter;
1070   for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
1071     {
1072       InputPyPort *p=(InputPyPort *)*iter;
1073       n->edAddInputPort(p->getName(),p->edGetType());
1074     }
1075   list<OutputPort *>::iterator iter2;
1076   for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
1077     {
1078       OutputPyPort *p=(OutputPyPort *)*iter2;
1079       n->edAddOutputPort(p->getName(),p->edGetType());
1080     }
1081   return n;
1082 }
1083
1084 std::string PyFuncNode::getContainerLog()
1085 {
1086   if(_mode=="local")return "";
1087
1088   std::string msg;
1089   try
1090     {
1091       Engines::Container_var objContainer=((SalomeContainer*)_container)->getContainerPtr(0);
1092       CORBA::String_var logname = objContainer->logfilename();
1093       DEBTRACE(logname);
1094       msg=logname;
1095       std::string::size_type pos = msg.find(":");
1096       msg=msg.substr(pos+1);
1097     }
1098   catch(...)
1099     {
1100       msg = "Container no longer reachable";
1101     }
1102   return msg;
1103 }
1104
1105 void PyFuncNode::shutdown(int level)
1106 {
1107   DEBTRACE("PyFuncNode::shutdown " << level);
1108   if(_mode=="local")return;
1109   if(_container)
1110     {
1111       if(!CORBA::is_nil(_pynode)) _pynode->UnRegister();
1112       _pynode=Engines::PyNode::_nil();
1113       _container->shutdown(level);
1114     }
1115 }
1116