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