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