]> SALOME platform Git repositories - modules/yacs.git/blob - src/runtime/PythonNode.cxx
Salome HOME
[EDF30875] : mistype leading to a non activation of squeeze mode
[modules/yacs.git] / src / runtime / PythonNode.cxx
1 // Copyright (C) 2006-2024  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       DEBUG_YACSTRACE("Before execute first of " << getId());
582       _pynode->executeFirst(serializationInputRef);
583       //serializationInput and serializationInputCorba are no more needed for server. Release it.
584       serializationInput.set(nullptr);
585       resultCorba.reset( _pynode->executeSecond(myseq) );
586       DEBUG_YACSTRACE("After execute second of " << getId());
587     }
588   catch( const SALOME::SALOME_Exception& ex )
589     {
590       std::ostringstream msg; msg << "Exception on remote python invocation" << std::endl << ex.details.text.in() << std::endl;
591       msg << "PyScriptNode CORBA ref : ";
592       {
593         CORBA::ORB_ptr orb(getSALOMERuntime()->getOrb());
594         if(!CORBA::is_nil(orb))
595         {
596           CORBA::String_var IOR(orb->object_to_string(_pynode));
597           msg << IOR;
598         }
599       }
600       msg << std::endl;
601       _errorDetails=msg.str();
602       throw Exception(msg.str());
603     }
604   catch(CORBA::COMM_FAILURE& ex)
605     {
606       std::ostringstream msg;
607       msg << "Exception on remote python invocation." << std::endl ;
608       msg << "Caught system exception COMM_FAILURE -- unable to contact the "
609           << "object." << std::endl;
610       _errorDetails=msg.str();
611       throw Exception(msg.str());
612     }
613   catch(CORBA::SystemException& ex)
614     {
615       std::ostringstream msg;
616       msg << "Exception on remote python invocation." << std::endl ;
617       msg << "Caught a CORBA::SystemException." ;
618       CORBA::Any tmp;
619       tmp <<= ex;
620       CORBA::TypeCode_var tc = tmp.type();
621       const char *p = tc->name();
622       if ( *p != '\0' )
623         msg <<p;
624       else
625         msg  << tc->id();
626       msg << std::endl;
627       _errorDetails=msg.str();
628       throw Exception(msg.str());
629     }
630   catch(CORBA::Exception& ex)
631     {
632       std::ostringstream msg;
633       msg << "Exception on remote python invocation." << std::endl ;
634       msg << "Caught CORBA::Exception. " ;
635       CORBA::Any tmp;
636       tmp <<= ex;
637       CORBA::TypeCode_var tc = tmp.type();
638       const char *p = tc->name();
639       if ( *p != '\0' )
640         msg <<p;
641       else
642         msg  << tc->id();
643       msg << std::endl;
644       _errorDetails=msg.str();
645       throw Exception(msg.str());
646     }
647   catch(omniORB::fatalException& fe)
648     {
649       std::ostringstream msg;
650       msg << "Exception on remote python invocation." << std::endl ;
651       msg << "Caught omniORB::fatalException:" << std::endl;
652       msg << "  file: " << fe.file() << std::endl;
653       msg << "  line: " << fe.line() << std::endl;
654       msg << "  mesg: " << fe.errmsg() << std::endl;
655       _errorDetails=msg.str();
656       throw Exception(msg.str());
657     }
658   DEBTRACE( "-----------------end of remote python invocation-----------------" );
659   //===========================================================================
660   // Get results, unpickle and put them in output ports
661   //===========================================================================
662   {
663 #if PY_VERSION_HEX < 0x03070000
664       std::unique_lock<std::mutex> lock(data_mutex);
665 #endif
666       AutoGIL agil;
667       DEBTRACE( "-----------------PythonNode::outputs-----------------" );
668       int nres( resultCorba->length() );
669
670       if(getNumberOfOutputPorts() != nres)
671         {
672           std::string msg="Number of output arguments : Mismatch between definition and execution";
673           _errorDetails=msg;
674           throw Exception(msg);
675         }
676       pos=0;
677       try
678       {
679           for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); ++iter)
680             {
681               OutputPyPort *p=(OutputPyPort *)*iter;
682               DEBUG_YACSTRACE("Start of dealing with output " << p->getName() << " of "<< getId());
683               DEBTRACE( "port name: " << p->getName() );
684               DEBTRACE( "port kind: " << p->edGetType()->kind() );
685               DEBTRACE( "port pos : " << pos );
686               SALOME::SenderByte_var elt = (*resultCorba)[pos];
687               SeqByteReceiver recv(elt);
688               unsigned long length = 0;
689               char *resultCorbaC = recv.data(length);
690               {
691                 AutoPyRef resultPython=PyMemoryView_FromMemory(resultCorbaC,length,PyBUF_READ);
692                 AutoPyRef args = PyTuple_New(1);
693                 PyTuple_SetItem(args,0,resultPython.retn());
694                 AutoPyRef ob = PyObject_CallObject(_pyfuncUnser,args);
695                 if (!ob)
696                 {
697                   std::stringstream msg;
698                   msg << "Conversion with pickle of output ports failed !";
699                   msg << " : " << __FILE__ << ":" << __LINE__;
700                   _errorDetails=msg.str();
701                   throw YACS::ENGINE::ConversionException(msg.str());
702                 }
703                 UnlinkOnDestructorIfProxy(ob);
704                 DEBUG_YACSTRACE("Assign PyObj output " << p->getName() << " of "<< getId());
705                 p->put( ob );
706                 DEBUG_YACSTRACE("End of assign PyObj output " << p->getName() << " of "<< getId());
707               }
708               pos++;
709             }
710       }
711       catch(ConversionException& ex)
712       {
713           _errorDetails=ex.what();
714           throw;
715       }
716       if(_autoSqueeze)
717         squeezeMemoryRemote();
718   }
719   //
720   if(!isUsingPythonCache())
721   {
722     freeKernelPynode();
723     bool dummy;
724     Engines::Container_var cont(GetContainerObj(this,dummy));
725     cont->removePyScriptNode(getId().c_str());
726   }
727   DEBTRACE( "++++++++++++++ ENDOF PyNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
728 }
729
730 void PythonNode::ExecuteLocalInternal(const std::string& codeStr, PyObject *context, std::string& errorDetails)
731 {
732   DEBTRACE(  code );
733   DEBTRACE( "context refcnt: " << context->ob_refcnt );
734   std::ostringstream stream;
735   stream << "/tmp/PythonNode_";
736   stream << getpid();
737   AutoPyRef code=Py_CompileString(codeStr.c_str(), stream.str().c_str(), Py_file_input);
738   if(code == NULL)
739   {
740     errorDetails=""; 
741     AutoPyRef new_stderr = newPyStdOut(errorDetails);
742     PySys_SetObject((char*)"stderr", new_stderr);
743     PyErr_Print();
744     PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
745     throw YACS::Exception("Error during execution");
746   }
747   {
748     AutoPyRef res = PyEval_EvalCode(  code, context, context);
749   }
750   DEBTRACE( "context refcnt: " << context->ob_refcnt );
751   fflush(stdout);
752   fflush(stderr);
753   if(PyErr_Occurred ())
754   {
755     errorDetails="";
756     AutoPyRef new_stderr = newPyStdOut(errorDetails);
757     PySys_SetObject((char*)"stderr", new_stderr);
758     ofstream errorfile(stream.str().c_str());
759     if (errorfile.is_open())
760       {
761         errorfile << codeStr;
762         errorfile.close();
763       }
764     PyErr_Print();
765     PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
766     throw YACS::Exception("Error during execution");
767   }
768 }
769
770 void PythonNode::executeLocalInternal(const std::string& codeStr)
771 {
772   ExecuteLocalInternal(codeStr,_context,_errorDetails);
773 }
774
775 void PythonNode::executeLocal()
776 {
777   DEBTRACE( "++++++++++++++ PyNode::executeLocal: " << getName() << " ++++++++++++++++++++" );
778   {
779     AutoGIL agil;
780     std::ostringstream unpxy; unpxy << "from SALOME_PyNode import UnProxyObjectSimpleLocal" << std::endl;
781     DEBTRACE( "---------------PyNode::inputs---------------" );
782     list<InputPort *>::iterator iter2;
783     for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
784       {
785         InputPyPort *p=(InputPyPort *)*iter2;
786         DEBTRACE( "port name: " << p->getName() );
787         DEBTRACE( "port kind: " << p->edGetType()->kind() );
788         PyObject* ob=p->getPyObj();
789         DEBTRACE( "ob refcnt: " << ob->ob_refcnt ); 
790         unpxy << p->getName() << " = UnProxyObjectSimpleLocal( " << p->getName() << " )" << std::endl;
791 #ifdef _DEVDEBUG_
792         PyObject_Print(ob,stderr,Py_PRINT_RAW);
793         cerr << endl;
794 #endif
795         int ier=PyDict_SetItemString(_context,p->getName().c_str(),ob);
796         DEBTRACE( "after PyDict_SetItemString:ob refcnt: " << ob->ob_refcnt );
797       }
798
799     DEBTRACE( "---------------End PyNode::inputs---------------" );
800
801     //calculation
802     DEBTRACE( "----------------PyNode::calculation---------------" );
803   
804     if( ! getSqueezeStatus() )
805       executeLocalInternal( unpxy.str() );
806
807     executeLocalInternal( _script );
808
809     DEBTRACE( "-----------------PyNode::outputs-----------------" );
810     list<OutputPort *>::iterator iter;
811     try
812     {
813         for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
814           {
815             OutputPyPort *p=(OutputPyPort *)*iter;
816             DEBTRACE( "port name: " << p->getName() );
817             DEBTRACE( "port kind: " << p->edGetType()->kind() );
818             PyObject *ob=PyDict_GetItemString(_context,p->getName().c_str());
819             if(ob==NULL)
820               {
821                 std::string msg="Error during execution: there is no variable ";
822                 msg=msg+p->getName()+" in node context";
823                 _errorDetails=msg;
824                 throw Exception(msg);
825               }
826             DEBTRACE( "PyNode::outputs::ob refcnt: " << ob->ob_refcnt );
827 #ifdef _DEVDEBUG_
828             PyObject_Print(ob,stderr,Py_PRINT_RAW);
829             cerr << endl;
830 #endif
831             p->put(ob);
832             if(!isUsingPythonCache())
833               PyDict_DelItemString(_context,p->getName().c_str());
834           }
835     }
836     catch(ConversionException& ex)
837     {
838         _errorDetails=ex.what();
839         throw;
840     }
841     if(_autoSqueeze)
842       squeezeMemory();
843     DEBTRACE( "-----------------End PyNode::outputs-----------------" );
844     if(!isUsingPythonCache())
845     {
846       for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
847       {
848         AutoPyRef pStr = PyUnicode_FromString( (*iter2)->getName().c_str() );
849         if( PyDict_Contains(_context,pStr) == 1 )
850           { PyDict_DelItem(_context,pStr); }
851       }
852     }
853   }
854   DEBTRACE( "++++++++++++++ End PyNode::execute: " << getName() << " ++++++++++++++++++++" );
855 }
856
857 /*!
858  * [EDF28562]
859  * \param in squeezeExceptions list on output port name excluded from the squeeze mecanism
860  */
861 void PythonNode::setSqueezeStatusWithExceptions(bool sqStatus, const std::vector<std::string>& squeezeExceptions)
862 {
863   this->setSqueezeStatus(sqStatus);
864   this->_nonSqueezableOutputNodes = std::set<std::string>(squeezeExceptions.begin(), squeezeExceptions.end());
865 }
866
867 void PythonNode::squeezeMemorySafe()
868 {
869   AutoGIL agil;
870   if(_mode==PythonNode::REMOTE_NAME)
871     this->squeezeMemoryRemote();
872   else
873     this->squeezeMemory();
874 }
875   
876 void PythonNode::squeezeMemory()
877 {
878   for(auto p : _setOfInputPort)
879     {
880       PyDict_DelItemString(_context,p->getName().c_str());
881       InputPyPort *p2(static_cast<InputPyPort *>(p));
882       if(p2->canSafelySqueezeMemory())
883         p2->put(Py_None);
884     }
885   for(auto p : _setOfOutputPort)
886     {
887       if (!this->_nonSqueezableOutputNodes.empty() && this->_nonSqueezableOutputNodes.find(p->getName()) != this->_nonSqueezableOutputNodes.end())
888         continue;
889       PyDict_DelItemString(_context,p->getName().c_str());
890       OutputPyPort *p2(static_cast<OutputPyPort *>(p));
891       p2->putWithoutForward(Py_None);
892     }
893 }
894
895 void PythonNode::squeezeMemoryRemote()
896 {
897   for(auto p : _setOfInputPort)
898     {
899       InputPyPort *p2(static_cast<InputPyPort *>(p));
900       if(p2->canSafelySqueezeMemory())
901         p2->put(Py_None);
902     }
903   for(auto p : _setOfOutputPort)
904     {
905       if (!this->_nonSqueezableOutputNodes.empty() && this->_nonSqueezableOutputNodes.find(p->getName()) != this->_nonSqueezableOutputNodes.end())
906         continue;
907       OutputPyPort *p2(static_cast<OutputPyPort *>(p));
908       p2->putWithoutForward(Py_None);
909     }
910 }
911
912 std::string PythonNode::getContainerLog()
913 {
914   return PythonEntry::GetContainerLog(_mode,_container,this);
915 }
916
917 void PythonNode::shutdown(int level)
918 {
919   DEBTRACE("PythonNode::shutdown " << level);
920   if(_mode=="local")return;
921   if(_container)
922     {
923       freeKernelPynode();
924       _container->shutdown(level);
925     }
926 }
927
928 void PythonNode::imposeResource(const std::string& resource_name,
929                                 const std::string& container_name)
930 {
931   if(!resource_name.empty() && !container_name.empty())
932   {
933     _imposedResource = resource_name;
934     _imposedContainer = container_name;
935   }
936 }
937
938 bool PythonNode::canAcceptImposedResource()
939 {
940   return _container != nullptr && _container->canAcceptImposedResource();
941 }
942
943 bool PythonNode::hasImposedResource()const
944 {
945   return PythonEntry::hasImposedResource();
946 }
947
948 std::string PythonNode::pythonEntryName()const
949 {
950   if(isUsingPythonCache())
951     return "DEFAULT_NAME_FOR_UNIQUE_PYTHON_NODE_ENTRY";
952   else
953     return getId();
954 }
955
956 bool PythonNode::isUsingPythonCache()const
957 {
958   bool found = false;
959   if(_container)
960     found = _container->isUsingPythonCache();
961   return found;
962 }
963
964 void PythonNode::freeKernelPynode()
965 {
966   if(!CORBA::is_nil(_pynode))
967   {
968     try
969     {
970       _pynode->UnRegister();
971     }
972     catch(...)
973     {
974       DEBTRACE("Trouble when pynode->UnRegister!")
975     }
976     _pynode = Engines::PyScriptNode::_nil();
977   }
978 }
979
980 Node *PythonNode::simpleClone(ComposedNode *father, bool editionOnly) const
981 {
982   return new PythonNode(*this,father);
983 }
984
985 void PythonNode::createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)
986 {
987   freeKernelPynode();
988   _pynode=objContainer->createPyScriptNode(pythonEntryName().c_str(),getScript().c_str());
989   _pynode->Register();
990 }
991
992 Engines::PyNodeBase_var PythonNode::retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const
993 {
994   Engines::PyScriptNode_var ret(objContainer->getDefaultPyScriptNode(pythonEntryName().c_str()));
995   if(!CORBA::is_nil(ret))
996     {
997       ret->Register();
998     }
999   return Engines::PyNodeBase::_narrow(ret);
1000 }
1001
1002 void PythonNode::assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)
1003 {
1004   if(CORBA::is_nil(_pynode))
1005     _pynode=Engines::PyScriptNode::_narrow(remoteInterp);
1006   else
1007   {
1008     Engines::PyScriptNode_var tmpp(Engines::PyScriptNode::_narrow(remoteInterp));
1009     if(!_pynode->_is_equivalent(tmpp))
1010     {
1011       freeKernelPynode();
1012       _pynode=Engines::PyScriptNode::_narrow(remoteInterp);
1013     }
1014   }
1015   _pynode->assignNewCompiledCode(getScript().c_str());
1016 }
1017
1018 Engines::PyNodeBase_var PythonNode::getRemoteInterpreterHandle()
1019 {
1020   return Engines::PyNodeBase::_narrow(_pynode);
1021 }
1022
1023 //! Create a new node of same type with a given name
1024 PythonNode* PythonNode::cloneNode(const std::string& name)
1025 {
1026   PythonNode* n=new PythonNode(name);
1027   n->setScript(_script);
1028   list<InputPort *>::iterator iter;
1029   for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
1030     {
1031       InputPyPort *p=(InputPyPort *)*iter;
1032       DEBTRACE( "port name: " << p->getName() );
1033       DEBTRACE( "port kind: " << p->edGetType()->kind() );
1034       n->edAddInputPort(p->getName(),p->edGetType());
1035     }
1036   list<OutputPort *>::iterator iter2;
1037   for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
1038     {
1039       OutputPyPort *p=(OutputPyPort *)*iter2;
1040       DEBTRACE( "port name: " << p->getName() );
1041       DEBTRACE( "port kind: " << p->edGetType()->kind() );
1042       n->edAddOutputPort(p->getName(),p->edGetType());
1043     }
1044   return n;
1045 }
1046
1047 void PythonNode::applyDPLScope(ComposedNode *gfn)
1048 {
1049   std::vector< std::pair<std::string,int> > ret(getDPLScopeInfo(gfn));
1050   if(ret.empty())
1051     return ;
1052   //
1053   PyObject *ob(0);
1054   {
1055     AutoGIL agil;
1056     std::size_t sz(ret.size());
1057     ob=PyList_New(sz);
1058     for(std::size_t i=0;i<sz;i++)
1059       {
1060         const std::pair<std::string,int>& p(ret[i]);
1061         PyObject *elt(PyTuple_New(2));
1062         PyTuple_SetItem(elt,0,PyUnicode_FromString(p.first.c_str()));
1063         PyTuple_SetItem(elt,1,PyLong_FromLong(p.second));
1064         PyList_SetItem(ob,i,elt);
1065       }
1066   }
1067   if(_mode==REMOTE_NAME)
1068     {
1069       Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);
1070       {
1071         AutoGIL agil;
1072         PyObject *serializationInput(PyObject_CallFunctionObjArgs(_pyfuncSimpleSer,ob,NULL));
1073         Py_XDECREF(ob);
1074         char *serializationInputC(0);
1075         Py_ssize_t len;
1076         if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
1077           throw Exception("DistributedPythonNode problem in python pickle");
1078         serializationInputCorba->length(len);
1079         for(int i=0; i < len ; i++)
1080           serializationInputCorba[i]=serializationInputC[i];
1081         Py_XDECREF(serializationInput);
1082       }
1083       _pynode->defineNewCustomVar(DPL_INFO_NAME,serializationInputCorba);
1084     }
1085   else
1086     {
1087       AutoGIL agil;
1088       PyDict_SetItemString(_context,DPL_INFO_NAME,ob);
1089       Py_XDECREF(ob);
1090     }
1091 }
1092
1093 PyFuncNode::PyFuncNode(const PyFuncNode& other, ComposedNode *father):InlineFuncNode(other,father),_pyfunc(0)
1094 {
1095   _implementation = PythonNode::IMPL_NAME;
1096   {
1097     AutoGIL agil;
1098     _context=PyDict_New();
1099     DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1100     if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
1101       {
1102         stringstream msg;
1103         msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
1104         _errorDetails=msg.str();
1105         throw Exception(msg.str());
1106       }
1107   }
1108 }
1109
1110 PyFuncNode::PyFuncNode(const std::string& name): InlineFuncNode(name),_pyfunc(0)
1111 {
1112
1113   _implementation = PythonNode::IMPL_NAME;
1114   DEBTRACE( "PyFuncNode::PyFuncNode " << name );
1115   {
1116     AutoGIL agil;
1117     _context=PyDict_New();
1118     DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1119     if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
1120       {
1121         stringstream msg;
1122         msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
1123         _errorDetails=msg.str();
1124         throw Exception(msg.str());
1125       }
1126   }
1127 }
1128
1129 PyFuncNode::~PyFuncNode()
1130 {
1131   if(!CORBA::is_nil(_pynode))
1132     {
1133       _pynode->UnRegister();
1134     }
1135 }
1136
1137 void PyFuncNode::init(bool start)
1138 {
1139   initCommonPartWithoutStateManagement(start);
1140   if(_state == YACS::DISABLED)
1141     {
1142       exDisabledState(); // to refresh propagation of DISABLED state
1143       return ;
1144     }
1145   if(start) //complete initialization
1146     setState(YACS::READY);
1147   else if(_state > YACS::LOADED)// WARNING FuncNode has internal vars (CEA usecase) ! Partial initialization (inside a loop). Exclusivity of funcNode.
1148     setState(YACS::TORECONNECT);
1149 }
1150
1151 void PyFuncNode::checkBasicConsistency() const
1152 {
1153   DEBTRACE("checkBasicConsistency");
1154   InlineFuncNode::checkBasicConsistency();
1155   {
1156     AutoGIL agil;
1157     PyObject* res;
1158     res=Py_CompileString(_script.c_str(),getName().c_str(),Py_file_input);
1159     if(res == NULL)
1160       {
1161         std::string error="";
1162         PyObject* new_stderr = newPyStdOut(error);
1163         PySys_SetObject((char*)"stderr", new_stderr);
1164         PyErr_Print();
1165         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1166         Py_DECREF(new_stderr);
1167         throw Exception(error);
1168       }
1169     else
1170       Py_XDECREF(res);
1171   }
1172 }
1173
1174 void PyFuncNode::load()
1175 {
1176   DEBTRACE( "---------------PyfuncNode::load function---------------" );
1177   if(_mode==PythonNode::REMOTE_NAME)
1178     loadRemote();
1179   else
1180     loadLocal();
1181 }
1182
1183 void PyFuncNode::loadRemote()
1184 {
1185   commonRemoteLoad(this);
1186 }
1187
1188 void PyFuncNode::loadLocal()
1189 {
1190   DEBTRACE( "---------------PyFuncNode::load function " << getName() << " ---------------" );
1191   DEBTRACE(  _script );
1192
1193 #ifdef _DEVDEBUG_
1194   list<OutputPort *>::iterator iter;
1195   for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
1196     {
1197       OutputPyPort *p=(OutputPyPort *)*iter;
1198       DEBTRACE( "port name: " << p->getName() );
1199       DEBTRACE( "port kind: " << p->edGetType()->kind() );
1200     }
1201 #endif
1202
1203   {
1204     AutoGIL agil;
1205     DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1206
1207     std::ostringstream stream;
1208     stream << "/tmp/PythonNode_";
1209     stream << getpid();
1210
1211     PyObject* code=Py_CompileString(_script.c_str(), stream.str().c_str(), Py_file_input);
1212     if(code == NULL)
1213       {
1214         _errorDetails="";
1215         PyObject* new_stderr = newPyStdOut(_errorDetails);
1216         PySys_SetObject((char*)"stderr", new_stderr);
1217         PyErr_Print();
1218         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1219         Py_DECREF(new_stderr);
1220         throw Exception("Error during execution");
1221       }
1222     PyObject *res = PyEval_EvalCode( code, _context, _context);
1223     Py_DECREF(code);
1224     Py_XDECREF(res);
1225
1226     DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1227     if(PyErr_Occurred ())
1228       {
1229         _errorDetails="";
1230         PyObject* new_stderr = newPyStdOut(_errorDetails);
1231         PySys_SetObject((char*)"stderr", new_stderr);
1232         ofstream errorfile(stream.str().c_str());
1233         if (errorfile.is_open())
1234           {
1235             errorfile << _script;
1236             errorfile.close();
1237           }
1238         PyErr_Print();
1239         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1240         Py_DECREF(new_stderr);
1241         throw Exception("Error during execution");
1242         return;
1243       }
1244     _pyfunc=PyDict_GetItemString(_context,_fname.c_str());
1245     DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1246     if(_pyfunc == NULL)
1247       {
1248         _errorDetails="";
1249         PyObject* new_stderr = newPyStdOut(_errorDetails);
1250         PySys_SetObject((char*)"stderr", new_stderr);
1251         PyErr_Print();
1252         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1253         Py_DECREF(new_stderr);
1254         throw Exception("Error during execution");
1255       }
1256     DEBTRACE( "---------------End PyFuncNode::load function---------------" );
1257   }
1258 }
1259
1260 void PyFuncNode::execute()
1261 {
1262   if(_mode==PythonNode::REMOTE_NAME)
1263     executeRemote();
1264   else
1265     executeLocal();
1266 }
1267
1268 void PyFuncNode::executeRemote()
1269 {
1270   DEBTRACE( "++++++++++++++ PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
1271   if(!_pyfuncSer)
1272     throw Exception("DistributedPythonNode badly loaded");
1273   //
1274   if(dynamic_cast<HomogeneousPoolContainer *>(getContainer()))
1275     {
1276       bool dummy;
1277       loadPythonAdapter(this,dummy);
1278       _pynode->executeAnotherPieceOfCode(getScript().c_str());
1279     }
1280   //
1281   Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);;
1282   {
1283 #if PY_VERSION_HEX < 0x03070000
1284       std::unique_lock<std::mutex> lock(data_mutex);
1285 #endif
1286       AutoGIL agil;
1287       PyObject *ob(0);
1288       //===========================================================================
1289       // Get inputs in input ports, build a Python tuple and pickle it
1290       //===========================================================================
1291       PyObject *args(PyTuple_New(getNumberOfInputPorts()));
1292       int pos(0);
1293       for(std::list<InputPort *>::iterator iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++,pos++)
1294         {
1295           InputPyPort *p=(InputPyPort *)*iter2;
1296           ob=p->getPyObj();
1297           Py_INCREF(ob);
1298           PyTuple_SetItem(args,pos,ob);
1299         }
1300 #ifdef _DEVDEBUG_
1301       PyObject_Print(args,stderr,Py_PRINT_RAW);
1302       std::cerr << endl;
1303 #endif
1304       PyObject *serializationInput=PyObject_CallObject(_pyfuncSer,args);
1305       Py_DECREF(args);
1306       //The pickled string may contain NULL characters so use PyString_AsStringAndSize
1307       char *serializationInputC(0);
1308       Py_ssize_t len;
1309       if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
1310         throw Exception("DistributedPythonNode problem in python pickle");
1311
1312       serializationInputCorba->length(len);
1313       for(int i=0; i < len ; i++)
1314         serializationInputCorba[i]=serializationInputC[i];
1315       Py_DECREF(serializationInput);
1316   }
1317
1318   //===========================================================================
1319   // Execute in remote Python node
1320   //===========================================================================
1321   DEBTRACE( "-----------------starting remote python invocation-----------------" );
1322   Engines::pickledArgs_var resultCorba;
1323   try
1324     {
1325       resultCorba=_pynode->execute(getFname().c_str(),serializationInputCorba);
1326     }
1327   catch( const SALOME::SALOME_Exception& ex )
1328     {
1329       std::string msg="Exception on remote python invocation";
1330       msg += '\n';
1331       msg += ex.details.text.in();
1332       _errorDetails=msg;
1333       throw Exception(msg);
1334     }
1335   catch(CORBA::COMM_FAILURE& ex)
1336     {
1337       std::ostringstream msg;
1338       msg << "Exception on remote python invocation." << std::endl ;
1339       msg << "Caught system exception COMM_FAILURE -- unable to contact the "
1340           << "object." << std::endl;
1341       _errorDetails=msg.str();
1342       throw Exception(msg.str());
1343     }
1344   catch(CORBA::SystemException& ex)
1345     {
1346       std::ostringstream msg;
1347       msg << "Exception on remote python invocation." << std::endl ;
1348       msg << "Caught a CORBA::SystemException." ;
1349       CORBA::Any tmp;
1350       tmp <<= ex;
1351       CORBA::TypeCode_var tc = tmp.type();
1352       const char *p = tc->name();
1353       if ( *p != '\0' )
1354         msg <<p;
1355       else
1356         msg  << tc->id();
1357       msg << std::endl;
1358       _errorDetails=msg.str();
1359       throw Exception(msg.str());
1360     }
1361   catch(CORBA::Exception& ex)
1362     {
1363       std::ostringstream msg;
1364       msg << "Exception on remote python invocation." << std::endl ;
1365       msg << "Caught CORBA::Exception. " ;
1366       CORBA::Any tmp;
1367       tmp <<= ex;
1368       CORBA::TypeCode_var tc = tmp.type();
1369       const char *p = tc->name();
1370       if ( *p != '\0' )
1371         msg <<p;
1372       else
1373         msg  << tc->id();
1374       msg << std::endl;
1375       _errorDetails=msg.str();
1376       throw Exception(msg.str());
1377     }
1378   catch(omniORB::fatalException& fe)
1379     {
1380       std::ostringstream msg;
1381       msg << "Exception on remote python invocation." << std::endl ;
1382       msg << "Caught omniORB::fatalException:" << std::endl;
1383       msg << "  file: " << fe.file() << std::endl;
1384       msg << "  line: " << fe.line() << std::endl;
1385       msg << "  mesg: " << fe.errmsg() << std::endl;
1386       _errorDetails=msg.str();
1387       throw Exception(msg.str());
1388     }
1389   DEBTRACE( "-----------------end of remote python invocation-----------------" );
1390   //===========================================================================
1391   // Get results, unpickle and put them in output ports
1392   //===========================================================================
1393   char *resultCorbaC=new char[resultCorba->length()+1];
1394   resultCorbaC[resultCorba->length()]='\0';
1395   for(int i=0;i<resultCorba->length();i++)
1396     resultCorbaC[i]=resultCorba[i];
1397
1398   {
1399 #if PY_VERSION_HEX < 0x03070000
1400       std::unique_lock<std::mutex> lock(data_mutex);
1401 #endif
1402       AutoGIL agil;
1403
1404       PyObject *resultPython(PyBytes_FromStringAndSize(resultCorbaC,resultCorba->length()));
1405       delete [] resultCorbaC;
1406       PyObject *args(PyTuple_New(1)),*ob(0);
1407       PyTuple_SetItem(args,0,resultPython);
1408       PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
1409       Py_DECREF(args);
1410
1411       DEBTRACE( "-----------------PythonNode::outputs-----------------" );
1412       int nres=1;
1413       if(finalResult == Py_None)
1414         nres=0;
1415       else if(PyTuple_Check(finalResult))
1416         nres=PyTuple_Size(finalResult);
1417
1418       if(getNumberOfOutputPorts() != nres)
1419         {
1420           std::string msg="Number of output arguments : Mismatch between definition and execution";
1421           Py_DECREF(finalResult);
1422           _errorDetails=msg;
1423           throw Exception(msg);
1424         }
1425
1426       try
1427       {
1428           int pos(0);
1429           for(std::list<OutputPort *>::iterator iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++, pos++)
1430             {
1431               OutputPyPort *p=(OutputPyPort *)*iter;
1432               DEBTRACE( "port name: " << p->getName() );
1433               DEBTRACE( "port kind: " << p->edGetType()->kind() );
1434               DEBTRACE( "port pos : " << pos );
1435               if(PyTuple_Check(finalResult))
1436                 ob=PyTuple_GetItem(finalResult,pos) ;
1437               else
1438                 ob=finalResult;
1439               DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1440               p->put(ob);
1441             }
1442           Py_DECREF(finalResult);
1443       }
1444       catch(ConversionException& ex)
1445       {
1446           Py_DECREF(finalResult);
1447           _errorDetails=ex.what();
1448           throw;
1449       }
1450   }
1451
1452   DEBTRACE( "++++++++++++++ ENDOF PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
1453 }
1454
1455 void PyFuncNode::executeLocal()
1456 {
1457   DEBTRACE( "++++++++++++++ PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
1458
1459   int pos=0;
1460   PyObject* ob;
1461   if(!_pyfunc)throw Exception("PyFuncNode badly loaded");
1462   {
1463       AutoGIL agil;
1464       DEBTRACE( "---------------PyFuncNode::inputs---------------" );
1465       PyObject* args = PyTuple_New(getNumberOfInputPorts()) ;
1466       list<InputPort *>::iterator iter2;
1467       for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
1468         {
1469           InputPyPort *p=(InputPyPort *)*iter2;
1470           DEBTRACE( "port name: " << p->getName() );
1471           DEBTRACE( "port kind: " << p->edGetType()->kind() );
1472           ob=p->getPyObj();
1473 #ifdef _DEVDEBUG_
1474           PyObject_Print(ob,stderr,Py_PRINT_RAW);
1475           cerr << endl;
1476 #endif
1477           DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1478           Py_INCREF(ob);
1479           PyTuple_SetItem(args,pos,ob);
1480           DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1481           pos++;
1482         }
1483       DEBTRACE( "---------------End PyFuncNode::inputs---------------" );
1484
1485       DEBTRACE( "----------------PyFuncNode::calculation---------------" );
1486 #ifdef _DEVDEBUG_
1487       PyObject_Print(_pyfunc,stderr,Py_PRINT_RAW);
1488       cerr << endl;
1489       PyObject_Print(args,stderr,Py_PRINT_RAW);
1490       cerr << endl;
1491 #endif
1492       DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1493       PyObject* result = PyObject_CallObject( _pyfunc , args ) ;
1494       DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1495       Py_DECREF(args);
1496       fflush(stdout);
1497       fflush(stderr);
1498       if(result == NULL)
1499         {
1500           _errorDetails="";
1501           PyObject* new_stderr = newPyStdOut(_errorDetails);
1502           PySys_SetObject((char*)"stderr", new_stderr);
1503           std::ostringstream stream;
1504           stream << "/tmp/PythonNode_";
1505           stream << getpid();
1506           ofstream errorfile(stream.str().c_str());
1507           if (errorfile.is_open())
1508             {
1509               errorfile << _script;
1510               errorfile.close();
1511             }
1512           PyErr_Print();
1513           PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1514           Py_DECREF(new_stderr);
1515           throw Exception("Error during execution");
1516         }
1517       DEBTRACE( "----------------End PyFuncNode::calculation---------------" );
1518
1519       DEBTRACE( "-----------------PyFuncNode::outputs-----------------" );
1520       int nres=1;
1521       if(result == Py_None)
1522         nres=0;
1523       else if(PyTuple_Check(result))
1524         nres=PyTuple_Size(result);
1525
1526       if(getNumberOfOutputPorts() != nres)
1527         {
1528           std::string msg="Number of output arguments : Mismatch between definition and execution";
1529           Py_DECREF(result);
1530           _errorDetails=msg;
1531           throw Exception(msg);
1532         }
1533
1534       pos=0;
1535 #ifdef _DEVDEBUG_
1536       PyObject_Print(result,stderr,Py_PRINT_RAW);
1537       cerr << endl;
1538 #endif
1539       list<OutputPort *>::iterator iter;
1540       try
1541       {
1542           for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
1543             {
1544               OutputPyPort *p=(OutputPyPort *)*iter;
1545               DEBTRACE( "port name: " << p->getName() );
1546               DEBTRACE( "port kind: " << p->edGetType()->kind() );
1547               DEBTRACE( "port pos : " << pos );
1548               if(PyTuple_Check(result))ob=PyTuple_GetItem(result,pos) ;
1549               else ob=result;
1550               DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1551 #ifdef _DEVDEBUG_
1552               PyObject_Print(ob,stderr,Py_PRINT_RAW);
1553               cerr << endl;
1554 #endif
1555               p->put(ob);
1556               pos++;
1557             }
1558       }
1559       catch(ConversionException& ex)
1560       {
1561           Py_DECREF(result);
1562           _errorDetails=ex.what();
1563           throw;
1564       }
1565       DEBTRACE( "-----------------End PyFuncNode::outputs-----------------" );
1566       Py_DECREF(result);
1567   }
1568   DEBTRACE( "++++++++++++++ End PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
1569 }
1570
1571 Node *PyFuncNode::simpleClone(ComposedNode *father, bool editionOnly) const
1572 {
1573   return new PyFuncNode(*this,father);
1574 }
1575
1576 void PyFuncNode::createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)
1577 {
1578   if(!CORBA::is_nil(_pynode))
1579     _pynode->UnRegister();
1580   _pynode=objContainer->createPyNode(getName().c_str(),getScript().c_str());
1581 }
1582
1583 Engines::PyNodeBase_var PyFuncNode::retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const
1584 {
1585   Engines::PyNode_var ret(objContainer->getDefaultPyNode(getName().c_str()));
1586   if(!CORBA::is_nil(ret))
1587     {
1588       ret->Register();
1589     }
1590   return Engines::PyNodeBase::_narrow(ret);
1591 }
1592
1593 void PyFuncNode::assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)
1594 {
1595   if(!CORBA::is_nil(_pynode))
1596     {
1597       Engines::PyNode_var tmpp(Engines::PyNode::_narrow(remoteInterp));
1598       if(_pynode->_is_equivalent(tmpp))
1599         return ;
1600     }
1601   if(!CORBA::is_nil(_pynode))
1602     _pynode->UnRegister();
1603   _pynode=Engines::PyNode::_narrow(remoteInterp);
1604 }
1605
1606 Engines::PyNodeBase_var PyFuncNode::getRemoteInterpreterHandle()
1607 {
1608   return Engines::PyNodeBase::_narrow(_pynode);
1609 }
1610
1611 //! Create a new node of same type with a given name
1612 PyFuncNode* PyFuncNode::cloneNode(const std::string& name)
1613 {
1614   PyFuncNode* n=new PyFuncNode(name);
1615   n->setScript(_script);
1616   n->setFname(_fname);
1617   list<InputPort *>::iterator iter;
1618   for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
1619     {
1620       InputPyPort *p=(InputPyPort *)*iter;
1621       n->edAddInputPort(p->getName(),p->edGetType());
1622     }
1623   list<OutputPort *>::iterator iter2;
1624   for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
1625     {
1626       OutputPyPort *p=(OutputPyPort *)*iter2;
1627       n->edAddOutputPort(p->getName(),p->edGetType());
1628     }
1629   return n;
1630 }
1631
1632 std::string PyFuncNode::getContainerLog()
1633 {
1634   return PythonEntry::GetContainerLog(_mode,_container,this);
1635 }
1636
1637 void PyFuncNode::shutdown(int level)
1638 {
1639   DEBTRACE("PyFuncNode::shutdown " << level);
1640   if(_mode=="local")return;
1641   if(_container)
1642     {
1643       if(!CORBA::is_nil(_pynode)) _pynode->UnRegister();
1644       _pynode=Engines::PyNode::_nil();
1645       _container->shutdown(level);
1646     }
1647 }
1648
1649 void PyFuncNode::imposeResource(const std::string& resource_name,
1650                                 const std::string& container_name)
1651 {
1652   if(!resource_name.empty() && !container_name.empty())
1653   {
1654     _imposedResource = resource_name;
1655     _imposedContainer = container_name;
1656   }
1657 }
1658
1659 bool PyFuncNode::canAcceptImposedResource()
1660 {
1661   return _container != nullptr && _container->canAcceptImposedResource();
1662 }
1663
1664 bool PyFuncNode::hasImposedResource()const
1665 {
1666   return PythonEntry::hasImposedResource();
1667 }
1668