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