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