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