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