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