Salome HOME
Merge from V7_3_BR branch 18/12/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 WIN32
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
429   Py_DECREF(code);
430   Py_XDECREF(res);
431   DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
432   fflush(stdout);
433   fflush(stderr);
434   if(PyErr_Occurred ())
435     {
436       _errorDetails="";
437       PyObject* new_stderr = newPyStdOut(_errorDetails);
438       PySys_SetObject((char*)"stderr", new_stderr);
439       ofstream errorfile(stream.str().c_str());
440       if (errorfile.is_open())
441         {
442           errorfile << _script;
443           errorfile.close();
444         }
445       PyErr_Print();
446       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
447       Py_DECREF(new_stderr);
448
449       PyGILState_Release(gstate);
450       throw Exception("Error during execution");
451     }
452   
453   DEBTRACE( "-----------------PyNode::outputs-----------------" );
454   list<OutputPort *>::iterator iter;
455   try
456     {
457       for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
458         {
459           OutputPyPort *p=(OutputPyPort *)*iter;
460           DEBTRACE( "port name: " << p->getName() );
461           DEBTRACE( "port kind: " << p->edGetType()->kind() );
462           PyObject *ob=PyDict_GetItemString(_context,p->getName().c_str());
463           if(ob==NULL){
464              PyGILState_Release(gstate);
465              std::string msg="Error during execution: there is no variable ";
466              msg=msg+p->getName()+" in node context";
467              _errorDetails=msg;
468              throw Exception(msg);
469           }
470           DEBTRACE( "PyNode::outputs::ob refcnt: " << ob->ob_refcnt );
471 #ifdef _DEVDEBUG_
472           PyObject_Print(ob,stderr,Py_PRINT_RAW);
473           cerr << endl;
474 #endif
475           p->put(ob);
476         }
477     }
478   catch(ConversionException& ex)
479     {
480       PyGILState_Release(gstate);
481       _errorDetails=ex.what();
482       throw;
483     }
484
485   DEBTRACE( "-----------------End PyNode::outputs-----------------" );
486   PyGILState_Release(gstate);
487   DEBTRACE( "++++++++++++++ End PyNode::execute: " << getName() << " ++++++++++++++++++++" );
488 }
489
490 std::string PythonNode::getContainerLog()
491 {
492   if(_mode=="local")return "";
493
494   std::string msg;
495   try
496     {
497       Engines::Container_var objContainer=((SalomeContainer*)_container)->getContainerPtr(0);
498       CORBA::String_var logname = objContainer->logfilename();
499       DEBTRACE(logname);
500       msg=logname;
501       std::string::size_type pos = msg.find(":");
502       msg=msg.substr(pos+1);
503     }
504   catch(...)
505     {
506       msg = "Container no longer reachable";
507     }
508   return msg;
509 }
510
511 void PythonNode::shutdown(int level)
512 {
513   DEBTRACE("PythonNode::shutdown " << level);
514   if(_mode=="local")return;
515   if(_container)
516     {
517       if(!CORBA::is_nil(_pynode)) _pynode->UnRegister();
518       _pynode=Engines::PyScriptNode::_nil();
519       _container->shutdown(level);
520     }
521 }
522
523 Node *PythonNode::simpleClone(ComposedNode *father, bool editionOnly) const
524 {
525   return new PythonNode(*this,father);
526 }
527
528 //! Create a new node of same type with a given name
529 PythonNode* PythonNode::cloneNode(const std::string& name)
530 {
531   PythonNode* n=new PythonNode(name);
532   n->setScript(_script);
533   list<InputPort *>::iterator iter;
534   for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
535     {
536       InputPyPort *p=(InputPyPort *)*iter;
537       DEBTRACE( "port name: " << p->getName() );
538       DEBTRACE( "port kind: " << p->edGetType()->kind() );
539       n->edAddInputPort(p->getName(),p->edGetType());
540     }
541   list<OutputPort *>::iterator iter2;
542   for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
543     {
544       OutputPyPort *p=(OutputPyPort *)*iter2;
545       DEBTRACE( "port name: " << p->getName() );
546       DEBTRACE( "port kind: " << p->edGetType()->kind() );
547       n->edAddOutputPort(p->getName(),p->edGetType());
548     }
549   return n;
550 }
551
552 PyFuncNode::PyFuncNode(const PyFuncNode& other, ComposedNode *father):InlineFuncNode(other,father),_pyfunc(0)
553 {
554   _implementation = PythonNode::IMPL_NAME;
555   PyGILState_STATE gstate = PyGILState_Ensure();
556   _context=PyDict_New();
557   DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
558   if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
559     {
560       stringstream msg;
561       msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
562       _errorDetails=msg.str();
563       PyGILState_Release(gstate);
564       throw Exception(msg.str());
565     }
566   PyGILState_Release(gstate);
567 }
568
569 PyFuncNode::PyFuncNode(const std::string& name): InlineFuncNode(name),_pyfunc(0)
570 {
571
572   _implementation = PythonNode::IMPL_NAME;
573   DEBTRACE( "PyFuncNode::PyFuncNode " << name );
574   PyGILState_STATE gstate = PyGILState_Ensure();
575   _context=PyDict_New();
576   DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
577   if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
578     {
579       stringstream msg;
580       msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
581       _errorDetails=msg.str();
582       PyGILState_Release(gstate);
583       throw Exception(msg.str());
584     }
585   PyGILState_Release(gstate);
586 }
587
588 PyFuncNode::~PyFuncNode()
589 {
590   DEBTRACE( getName() );
591   PyGILState_STATE gstate = PyGILState_Ensure();
592   DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
593   if(_pyfunc)DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
594   Py_DECREF(_context);
595   PyGILState_Release(gstate);
596   if(!CORBA::is_nil(_pynode))
597     {
598       _pynode->UnRegister();
599     }
600 }
601
602 void PyFuncNode::checkBasicConsistency() const throw(YACS::Exception)
603 {
604   DEBTRACE("checkBasicConsistency");
605   InlineFuncNode::checkBasicConsistency();
606
607   PyGILState_STATE gstate = PyGILState_Ensure();
608   PyObject* res;
609   res=Py_CompileString(_script.c_str(),getName().c_str(),Py_file_input);
610   if(res == NULL)
611     {
612       std::string error="";
613       PyObject* new_stderr = newPyStdOut(error);
614       PySys_SetObject((char*)"stderr", new_stderr);
615       PyErr_Print();
616       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
617       Py_DECREF(new_stderr);
618       PyGILState_Release(gstate);
619       throw Exception(error);
620     }
621   else
622     Py_XDECREF(res);
623   PyGILState_Release(gstate);
624 }
625
626 void PyFuncNode::load()
627 {
628   DEBTRACE( "---------------PyfuncNode::load function---------------" );
629   if(_mode=="remote")
630     loadRemote();
631   else
632     loadLocal();
633 }
634
635 void PyFuncNode::loadRemote()
636 {
637   DEBTRACE( "---------------PyfuncNode::loadRemote function---------------" );
638   if(_container)
639     {
640       if(!_container->isAlreadyStarted(0))
641         {
642           try
643             {
644               _container->start(0);
645             }
646           catch(Exception& e)
647             {
648               _errorDetails=e.what();
649               throw e;
650             }
651         }
652     }
653   else
654     {
655       std::string what("PyFuncNode::loadRemote : a load operation requested on \"");
656       what+=_name; what+="\" with no container specified.";
657       _errorDetails=what;
658       throw Exception(what);
659     }
660
661   Engines::Container_var objContainer=((SalomeContainer*)_container)->getContainerPtr(0);
662   try
663     {
664       _pynode = objContainer->createPyNode(getName().c_str(),getScript().c_str());
665     }
666   catch( const SALOME::SALOME_Exception& ex )
667     {
668       std::string msg="Exception on remote python node creation ";
669       msg += '\n';
670       msg += ex.details.text.in();
671       _errorDetails=msg;
672       throw Exception(msg);
673     }
674
675   PyGILState_STATE gstate = PyGILState_Ensure();
676   const char picklizeScript[]="import cPickle\n"
677                               "def pickleForDistPyth2009(*args,**kws):\n"
678                               "  return cPickle.dumps((args,kws),-1)\n"
679                               "\n"
680                               "def unPickleForDistPyth2009(st):\n"
681                               "  args=cPickle.loads(st)\n"
682                               "  return args\n";
683   PyObject *res=PyRun_String(picklizeScript,Py_file_input,_context,_context);
684   if(res == NULL)
685     {
686       _errorDetails="";
687       PyObject* new_stderr = newPyStdOut(_errorDetails);
688       PySys_SetObject((char*)"stderr", new_stderr);
689       PyErr_Print();
690       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
691       Py_DECREF(new_stderr);
692
693       PyGILState_Release(gstate);
694       throw Exception("Error during load");
695     }
696   Py_DECREF(res);
697
698   _pyfuncSer=PyDict_GetItemString(_context,"pickleForDistPyth2009");
699   _pyfuncUnser=PyDict_GetItemString(_context,"unPickleForDistPyth2009");
700   if(_pyfuncSer == NULL)
701     {
702       _errorDetails="";
703       PyObject* new_stderr = newPyStdOut(_errorDetails);
704       PySys_SetObject((char*)"stderr", new_stderr);
705       PyErr_Print();
706       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
707       Py_DECREF(new_stderr);
708
709       PyGILState_Release(gstate);
710       throw Exception("Error during load");
711     }
712   if(_pyfuncUnser == NULL)
713     {
714       _errorDetails="";
715       PyObject* new_stderr = newPyStdOut(_errorDetails);
716       PySys_SetObject((char*)"stderr", new_stderr);
717       PyErr_Print();
718       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
719       Py_DECREF(new_stderr);
720
721       PyGILState_Release(gstate);
722       throw Exception("Error during load");
723     }
724   DEBTRACE( "---------------End PyfuncNode::loadRemote function---------------" );
725   PyGILState_Release(gstate);
726 }
727
728 void PyFuncNode::loadLocal()
729 {
730   DEBTRACE( "---------------PyFuncNode::load function " << getName() << " ---------------" );
731   DEBTRACE(  _script );
732
733 #ifdef _DEVDEBUG_
734   list<OutputPort *>::iterator iter;
735   for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
736     {
737       OutputPyPort *p=(OutputPyPort *)*iter;
738       DEBTRACE( "port name: " << p->getName() );
739       DEBTRACE( "port kind: " << p->edGetType()->kind() );
740     }
741 #endif
742
743   PyGILState_STATE gstate = PyGILState_Ensure();
744   DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
745
746   std::ostringstream stream;
747   stream << "/tmp/PythonNode_";
748   stream << getpid();
749
750   PyObject* code=Py_CompileString(_script.c_str(), stream.str().c_str(), Py_file_input);
751   if(code == NULL)
752     {
753       _errorDetails="";
754       PyObject* new_stderr = newPyStdOut(_errorDetails);
755       PySys_SetObject((char*)"stderr", new_stderr);
756       PyErr_Print();
757       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
758       Py_DECREF(new_stderr);
759       PyGILState_Release(gstate);
760       throw Exception("Error during execution");
761     }
762   PyObject *res = PyEval_EvalCode((PyCodeObject *)code, _context, _context);
763   Py_DECREF(code);
764   Py_XDECREF(res);
765
766   DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
767   if(PyErr_Occurred ())
768     {
769       _errorDetails="";
770       PyObject* new_stderr = newPyStdOut(_errorDetails);
771       PySys_SetObject((char*)"stderr", new_stderr);
772       ofstream errorfile(stream.str().c_str());
773       if (errorfile.is_open())
774         {
775           errorfile << _script;
776           errorfile.close();
777         }
778       PyErr_Print();
779       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
780       Py_DECREF(new_stderr);
781
782       PyGILState_Release(gstate);
783       throw Exception("Error during execution");
784       return;
785     }
786   _pyfunc=PyDict_GetItemString(_context,_fname.c_str());
787   DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
788   if(_pyfunc == NULL)
789     {
790       _errorDetails="";
791       PyObject* new_stderr = newPyStdOut(_errorDetails);
792       PySys_SetObject((char*)"stderr", new_stderr);
793       PyErr_Print();
794       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
795       Py_DECREF(new_stderr);
796
797       PyGILState_Release(gstate);
798       throw Exception("Error during execution");
799     }
800   DEBTRACE( "---------------End PyFuncNode::load function---------------" );
801   PyGILState_Release(gstate);
802 }
803
804 void PyFuncNode::execute()
805 {
806   if(_mode=="remote")
807     executeRemote();
808   else
809     executeLocal();
810 }
811
812 void PyFuncNode::executeRemote()
813 {
814   DEBTRACE( "++++++++++++++ PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
815   if(!_pyfuncSer)
816     throw Exception("DistributedPythonNode badly loaded");
817   PyGILState_STATE gstate = PyGILState_Ensure();
818
819   //===========================================================================
820   // Get inputs in input ports, build a Python tuple and pickle it
821   //===========================================================================
822   PyObject* ob;
823   PyObject* args = PyTuple_New(getNumberOfInputPorts());
824   std::list<InputPort *>::iterator iter2;
825   int pos=0;
826   for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); ++iter2)
827     {
828       InputPyPort *p=(InputPyPort *)*iter2;
829       ob=p->getPyObj();
830       Py_INCREF(ob);
831       PyTuple_SetItem(args,pos,ob);
832       pos++;
833     }
834 #ifdef _DEVDEBUG_
835   PyObject_Print(args,stderr,Py_PRINT_RAW);
836   std::cerr << endl;
837 #endif
838   PyObject *serializationInput=PyObject_CallObject(_pyfuncSer,args);
839   //The pickled string may contain NULL characters so use PyString_AsStringAndSize
840   char* serializationInputC;
841   Py_ssize_t len;
842   if (PyString_AsStringAndSize(serializationInput, &serializationInputC, &len))
843     {
844       PyGILState_Release(gstate);
845       throw Exception("DistributedPythonNode problem in python pickle");
846     }
847   PyGILState_Release(gstate);
848
849   Engines::pickledArgs_var serializationInputCorba=new Engines::pickledArgs;
850   serializationInputCorba->length(len);
851   for(int i=0; i < len ; i++)
852     serializationInputCorba[i]=serializationInputC[i];
853
854   //===========================================================================
855   // Execute in remote Python node
856   //===========================================================================
857   DEBTRACE( "-----------------starting remote python invocation-----------------" );
858   Engines::pickledArgs_var resultCorba;
859   try
860     {
861       resultCorba=_pynode->execute(getFname().c_str(),serializationInputCorba);
862     }
863   catch( const SALOME::SALOME_Exception& ex )
864     {
865       std::string msg="Exception on remote python invocation";
866       msg += '\n';
867       msg += ex.details.text.in();
868       _errorDetails=msg;
869       throw Exception(msg);
870     }
871   DEBTRACE( "-----------------end of remote python invocation-----------------" );
872   //===========================================================================
873   // Get results, unpickle and put them in output ports
874   //===========================================================================
875   char *resultCorbaC=new char[resultCorba->length()+1];
876   resultCorbaC[resultCorba->length()]='\0';
877   for(int i=0;i<resultCorba->length();i++)
878     resultCorbaC[i]=resultCorba[i];
879
880   gstate = PyGILState_Ensure();
881
882   PyObject* resultPython=PyString_FromStringAndSize(resultCorbaC,resultCorba->length());
883   delete [] resultCorbaC;
884   args = PyTuple_New(1);
885   PyTuple_SetItem(args,0,resultPython);
886   PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
887   Py_DECREF(args);
888
889   DEBTRACE( "-----------------PythonNode::outputs-----------------" );
890   int nres=1;
891   if(finalResult == Py_None)
892     nres=0;
893   else if(PyTuple_Check(finalResult))
894     nres=PyTuple_Size(finalResult);
895
896   if(getNumberOfOutputPorts() != nres)
897     {
898       std::string msg="Number of output arguments : Mismatch between definition and execution";
899       Py_DECREF(finalResult);
900       PyGILState_Release(gstate);
901       _errorDetails=msg;
902       throw Exception(msg);
903     }
904
905   pos=0;
906   std::list<OutputPort *>::iterator iter;
907   try
908     {
909       for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); ++iter)
910         {
911           OutputPyPort *p=(OutputPyPort *)*iter;
912           DEBTRACE( "port name: " << p->getName() );
913           DEBTRACE( "port kind: " << p->edGetType()->kind() );
914           DEBTRACE( "port pos : " << pos );
915           if(PyTuple_Check(finalResult))
916             ob=PyTuple_GetItem(finalResult,pos) ;
917           else 
918             ob=finalResult;
919           DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
920           p->put(ob);
921           pos++;
922         }
923       Py_DECREF(finalResult);
924     }
925   catch(ConversionException& ex)
926     {
927       Py_DECREF(finalResult);
928       PyGILState_Release(gstate);
929       _errorDetails=ex.what();
930       throw;
931     }
932
933   PyGILState_Release(gstate);
934
935   DEBTRACE( "++++++++++++++ ENDOF PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
936 }
937
938 void PyFuncNode::executeLocal()
939 {
940   DEBTRACE( "++++++++++++++ PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
941
942   int pos=0;
943   PyObject* ob;
944   if(!_pyfunc)throw Exception("PyFuncNode badly loaded");
945   PyGILState_STATE gstate = PyGILState_Ensure();
946
947   DEBTRACE( "---------------PyFuncNode::inputs---------------" );
948   PyObject* args = PyTuple_New(getNumberOfInputPorts()) ;
949   list<InputPort *>::iterator iter2;
950   for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
951     {
952       InputPyPort *p=(InputPyPort *)*iter2;
953       DEBTRACE( "port name: " << p->getName() );
954       DEBTRACE( "port kind: " << p->edGetType()->kind() );
955       ob=p->getPyObj();
956 #ifdef _DEVDEBUG_
957       PyObject_Print(ob,stderr,Py_PRINT_RAW);
958       cerr << endl;
959 #endif
960       DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
961       Py_INCREF(ob);
962       PyTuple_SetItem(args,pos,ob);
963       DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
964       pos++;
965     }
966   DEBTRACE( "---------------End PyFuncNode::inputs---------------" );
967
968   DEBTRACE( "----------------PyFuncNode::calculation---------------" );
969 #ifdef _DEVDEBUG_
970   PyObject_Print(_pyfunc,stderr,Py_PRINT_RAW);
971   cerr << endl;
972   PyObject_Print(args,stderr,Py_PRINT_RAW);
973   cerr << endl;
974 #endif
975   DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
976   PyObject* result = PyObject_CallObject( _pyfunc , args ) ;
977   DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
978   Py_DECREF(args);
979   fflush(stdout);
980   fflush(stderr);
981   if(result == NULL)
982     {
983       _errorDetails="";
984       PyObject* new_stderr = newPyStdOut(_errorDetails);
985       PySys_SetObject((char*)"stderr", new_stderr);
986       std::ostringstream stream;
987       stream << "/tmp/PythonNode_";
988       stream << getpid();
989       ofstream errorfile(stream.str().c_str());
990       if (errorfile.is_open())
991         {
992           errorfile << _script;
993           errorfile.close();
994         }
995       PyErr_Print();
996       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
997       Py_DECREF(new_stderr);
998
999       PyGILState_Release(gstate);
1000       throw Exception("Error during execution");
1001     }
1002   DEBTRACE( "----------------End PyFuncNode::calculation---------------" );
1003
1004   DEBTRACE( "-----------------PyFuncNode::outputs-----------------" );
1005   int nres=1;
1006   if(result == Py_None)
1007     nres=0;
1008   else if(PyTuple_Check(result))
1009     nres=PyTuple_Size(result);
1010
1011   if(getNumberOfOutputPorts() != nres)
1012     {
1013       std::string msg="Number of output arguments : Mismatch between definition and execution";
1014       Py_DECREF(result);
1015       PyGILState_Release(gstate);
1016       _errorDetails=msg;
1017       throw Exception(msg);
1018     }
1019
1020   pos=0;
1021 #ifdef _DEVDEBUG_
1022   PyObject_Print(result,stderr,Py_PRINT_RAW);
1023   cerr << endl;
1024 #endif
1025   list<OutputPort *>::iterator iter;
1026   try
1027     {
1028       for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
1029         {
1030           OutputPyPort *p=(OutputPyPort *)*iter;
1031           DEBTRACE( "port name: " << p->getName() );
1032           DEBTRACE( "port kind: " << p->edGetType()->kind() );
1033           DEBTRACE( "port pos : " << pos );
1034           if(PyTuple_Check(result))ob=PyTuple_GetItem(result,pos) ;
1035           else ob=result;
1036           DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1037 #ifdef _DEVDEBUG_
1038           PyObject_Print(ob,stderr,Py_PRINT_RAW);
1039           cerr << endl;
1040 #endif
1041           p->put(ob);
1042           pos++;
1043         }
1044     }
1045   catch(ConversionException& ex)
1046     {
1047       Py_DECREF(result);
1048       PyGILState_Release(gstate);
1049       _errorDetails=ex.what();
1050       throw;
1051     }
1052   DEBTRACE( "-----------------End PyFuncNode::outputs-----------------" );
1053
1054   Py_DECREF(result);
1055   PyGILState_Release(gstate);
1056   DEBTRACE( "++++++++++++++ End PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
1057 }
1058
1059 Node *PyFuncNode::simpleClone(ComposedNode *father, bool editionOnly) const
1060 {
1061   return new PyFuncNode(*this,father);
1062 }
1063
1064 //! Create a new node of same type with a given name
1065 PyFuncNode* PyFuncNode::cloneNode(const std::string& name)
1066 {
1067   PyFuncNode* n=new PyFuncNode(name);
1068   n->setScript(_script);
1069   n->setFname(_fname);
1070   list<InputPort *>::iterator iter;
1071   for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
1072     {
1073       InputPyPort *p=(InputPyPort *)*iter;
1074       n->edAddInputPort(p->getName(),p->edGetType());
1075     }
1076   list<OutputPort *>::iterator iter2;
1077   for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
1078     {
1079       OutputPyPort *p=(OutputPyPort *)*iter2;
1080       n->edAddOutputPort(p->getName(),p->edGetType());
1081     }
1082   return n;
1083 }
1084
1085 std::string PyFuncNode::getContainerLog()
1086 {
1087   if(_mode=="local")return "";
1088
1089   std::string msg;
1090   try
1091     {
1092       Engines::Container_var objContainer=((SalomeContainer*)_container)->getContainerPtr(0);
1093       CORBA::String_var logname = objContainer->logfilename();
1094       DEBTRACE(logname);
1095       msg=logname;
1096       std::string::size_type pos = msg.find(":");
1097       msg=msg.substr(pos+1);
1098     }
1099   catch(...)
1100     {
1101       msg = "Container no longer reachable";
1102     }
1103   return msg;
1104 }
1105
1106 void PyFuncNode::shutdown(int level)
1107 {
1108   DEBTRACE("PyFuncNode::shutdown " << level);
1109   if(_mode=="local")return;
1110   if(_container)
1111     {
1112       if(!CORBA::is_nil(_pynode)) _pynode->UnRegister();
1113       _pynode=Engines::PyNode::_nil();
1114       _container->shutdown(level);
1115     }
1116 }
1117