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