Salome HOME
[EDF27816] : Get rid of SALOME session for 3 last tests (YacsLoader, YacsLoader_Swig...
[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   return PyObject_IsInstance( ob, _pyClsBigObject) == 1;
336 }
337
338 bool PythonEntry::GetDestroyStatus( PyObject *ob )
339 {
340   if(!_pyClsBigObject)
341     return false;
342   if( PyObject_IsInstance( ob, _pyClsBigObject) == 1 )
343   {
344     AutoPyRef unlinkOnDestructor = PyObject_GetAttrString(ob,"getDestroyStatus");
345     AutoPyRef tmp = PyObject_CallFunctionObjArgs(unlinkOnDestructor,nullptr);
346     if( PyBool_Check(tmp.get()) )
347     {
348       return tmp.get() == Py_True;
349     }
350     return false;
351   }
352   return false;
353 }
354
355 void PythonEntry::IfProxyDoSomething( PyObject *ob, const char *meth )
356 {
357   if(!_pyClsBigObject)
358     return ;
359   if( PyObject_IsInstance( ob, _pyClsBigObject) == 1 )
360   {
361     AutoPyRef unlinkOnDestructor = PyObject_GetAttrString(ob,meth);
362     AutoPyRef tmp = PyObject_CallFunctionObjArgs(unlinkOnDestructor,nullptr);
363   }
364 }
365
366 void PythonEntry::DoNotTouchFileIfProxy( PyObject *ob )
367 {
368   IfProxyDoSomething(ob,"doNotTouchFile");
369 }
370
371 void PythonEntry::UnlinkOnDestructorIfProxy( PyObject *ob )
372 {
373   IfProxyDoSomething(ob,"unlinkOnDestructor");
374 }
375
376 PythonNode::PythonNode(const PythonNode& other, ComposedNode *father):InlineNode(other,father),_autoSqueeze(other._autoSqueeze)
377 {
378   _pynode = Engines::PyScriptNode::_nil();
379   _implementation=IMPL_NAME;
380   {
381     AutoGIL agil;
382     _context=PyDict_New();
383     if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
384       {
385         stringstream msg;
386         msg << "Impossible to set builtins" << __FILE__ << ":" << __LINE__;
387         _errorDetails=msg.str();
388         throw Exception(msg.str());
389       }
390   }
391 }
392
393 PythonNode::PythonNode(const std::string& name):InlineNode(name)
394 {
395   _pynode = Engines::PyScriptNode::_nil();
396   _implementation=IMPL_NAME;
397   {
398     AutoGIL agil;
399     _context=PyDict_New();
400     if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
401       {
402         stringstream msg;
403         msg << "Impossible to set builtins" << __FILE__ << ":" << __LINE__;
404         _errorDetails=msg.str();
405         throw Exception(msg.str());
406       }
407   }
408 }
409
410 PythonNode::~PythonNode()
411 {
412   freeKernelPynode();
413 }
414
415 void PythonNode::checkBasicConsistency() const
416 {
417   DEBTRACE("checkBasicConsistency");
418   InlineNode::checkBasicConsistency();
419   {
420     AutoGIL agil;
421     PyObject* res;
422     res=Py_CompileString(_script.c_str(),getName().c_str(),Py_file_input);
423     if(res == NULL)
424       {
425         std::string error="";
426         PyObject* new_stderr = newPyStdOut(error);
427         PySys_SetObject((char*)"stderr", new_stderr);
428         PyErr_Print();
429         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
430         Py_DECREF(new_stderr);
431         throw Exception(error);
432       }
433     else
434       Py_XDECREF(res);
435   }
436 }
437
438 void PythonNode::load()
439 {
440   DEBTRACE( "---------------PyNode::load function---------------" );
441   if(_mode==PythonNode::REMOTE_NAME)
442     loadRemote();
443   else
444     loadLocal();
445 }
446
447 void PythonNode::loadLocal()
448 {
449   DEBTRACE( "---------------PyNode::loadLocal function---------------" );
450   // do nothing
451 }
452
453 void PythonNode::loadRemote()
454 {
455   commonRemoteLoad(this);
456 }
457
458 void PythonNode::execute()
459 {
460   if(_mode==PythonNode::REMOTE_NAME)
461     executeRemote();
462   else
463     executeLocal();
464 }
465
466 void PythonNode::executeRemote()
467 {
468   DEBTRACE( "++++++++++++++ PyNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
469   if(!_pyfuncSer)
470     throw Exception("PythonNode badly loaded");
471   //
472   if(dynamic_cast<HomogeneousPoolContainer *>(getContainer()))
473     {
474       bool dummy;
475       loadPythonAdapter(this,dummy);
476       _pynode->assignNewCompiledCode(getScript().c_str());
477     }
478   // not managed by unique_ptr here because destructed by the order of client.
479   SenderByteImpl *serializationInputCorba = nullptr;
480   AutoPyRef serializationInput;
481   {
482 #if PY_VERSION_HEX < 0x03070000
483       std::unique_lock<std::mutex> lock(data_mutex);
484 #endif
485       AutoGIL agil;
486       PyObject *args(0),*ob(0);
487       //===========================================================================
488       // Get inputs in input ports, build a Python dict and pickle it
489       //===========================================================================
490       args = PyDict_New();
491       std::list<InputPort *>::iterator iter2;
492       int pos(0);
493       for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); ++iter2)
494         {
495           InputPyPort *p=(InputPyPort *)*iter2;
496           ob=p->getPyObj();
497           PyDict_SetItemString(args,p->getName().c_str(),ob);
498           pos++;
499         }
500 #ifdef _DEVDEBUG_
501       PyObject_Print(args,stderr,Py_PRINT_RAW);
502       std::cerr << endl;
503 #endif
504       serializationInput.set(PyObject_CallFunctionObjArgs(_pyfuncSer,args,nullptr));
505       Py_DECREF(args);
506       //The pickled string may contain NULL characters so use PyString_AsStringAndSize
507       char *serializationInputC(nullptr);
508       Py_ssize_t len;
509       if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
510         throw Exception("DistributedPythonNode problem in python pickle");
511       // no copy here. The C byte array of Python is taken  as this into CORBA sequence to avoid copy
512       serializationInputCorba = new SenderByteImpl(serializationInputC,len);
513   }
514
515   //get the list of output argument names
516   std::list<OutputPort *>::iterator iter;
517   Engines::listofstring myseq;
518   myseq.length(getNumberOfOutputPorts());
519   int pos=0;
520   for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); ++iter)
521     {
522       OutputPyPort *p=(OutputPyPort *)*iter;
523       myseq[pos]=p->getName().c_str();
524       DEBTRACE( "port name: " << p->getName() );
525       DEBTRACE( "port kind: " << p->edGetType()->kind() );
526       DEBTRACE( "port pos : " << pos );
527       pos++;
528     }
529   //===========================================================================
530   // Execute in remote Python node
531   //===========================================================================
532   DEBTRACE( "-----------------starting remote python invocation-----------------" );
533   std::unique_ptr<SALOME::SenderByteSeq> resultCorba;
534   try
535     {
536       //pass outargsname and dict serialized
537       SALOME::SenderByte_var serializationInputRef = serializationInputCorba->_this();
538       _pynode->executeFirst(serializationInputRef);
539       //serializationInput and serializationInputCorba are no more needed for server. Release it.
540       serializationInput.set(nullptr);
541       resultCorba.reset( _pynode->executeSecond(myseq) );
542     }
543   catch( const SALOME::SALOME_Exception& ex )
544     {
545       std::ostringstream msg; msg << "Exception on remote python invocation" << std::endl << ex.details.text.in() << std::endl;
546       msg << "PyScriptNode CORBA ref : ";
547       {
548         CORBA::ORB_ptr orb(getSALOMERuntime()->getOrb());
549         if(!CORBA::is_nil(orb))
550         {
551           CORBA::String_var IOR(orb->object_to_string(_pynode));
552           msg << IOR;
553         }
554       }
555       msg << std::endl;
556       _errorDetails=msg.str();
557       throw Exception(msg.str());
558     }
559   catch(CORBA::COMM_FAILURE& ex)
560     {
561       std::ostringstream msg;
562       msg << "Exception on remote python invocation." << std::endl ;
563       msg << "Caught system exception COMM_FAILURE -- unable to contact the "
564           << "object." << std::endl;
565       _errorDetails=msg.str();
566       throw Exception(msg.str());
567     }
568   catch(CORBA::SystemException& ex)
569     {
570       std::ostringstream msg;
571       msg << "Exception on remote python invocation." << std::endl ;
572       msg << "Caught a CORBA::SystemException." ;
573       CORBA::Any tmp;
574       tmp <<= ex;
575       CORBA::TypeCode_var tc = tmp.type();
576       const char *p = tc->name();
577       if ( *p != '\0' )
578         msg <<p;
579       else
580         msg  << tc->id();
581       msg << std::endl;
582       _errorDetails=msg.str();
583       throw Exception(msg.str());
584     }
585   catch(CORBA::Exception& ex)
586     {
587       std::ostringstream msg;
588       msg << "Exception on remote python invocation." << std::endl ;
589       msg << "Caught CORBA::Exception. " ;
590       CORBA::Any tmp;
591       tmp <<= ex;
592       CORBA::TypeCode_var tc = tmp.type();
593       const char *p = tc->name();
594       if ( *p != '\0' )
595         msg <<p;
596       else
597         msg  << tc->id();
598       msg << std::endl;
599       _errorDetails=msg.str();
600       throw Exception(msg.str());
601     }
602   catch(omniORB::fatalException& fe)
603     {
604       std::ostringstream msg;
605       msg << "Exception on remote python invocation." << std::endl ;
606       msg << "Caught omniORB::fatalException:" << std::endl;
607       msg << "  file: " << fe.file() << std::endl;
608       msg << "  line: " << fe.line() << std::endl;
609       msg << "  mesg: " << fe.errmsg() << std::endl;
610       _errorDetails=msg.str();
611       throw Exception(msg.str());
612     }
613   DEBTRACE( "-----------------end of remote python invocation-----------------" );
614   //===========================================================================
615   // Get results, unpickle and put them in output ports
616   //===========================================================================
617   {
618 #if PY_VERSION_HEX < 0x03070000
619       std::unique_lock<std::mutex> lock(data_mutex);
620 #endif
621       AutoGIL agil;
622       DEBTRACE( "-----------------PythonNode::outputs-----------------" );
623       int nres( resultCorba->length() );
624
625       if(getNumberOfOutputPorts() != nres)
626         {
627           std::string msg="Number of output arguments : Mismatch between definition and execution";
628           _errorDetails=msg;
629           throw Exception(msg);
630         }
631       pos=0;
632       try
633       {
634           for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); ++iter)
635             {
636               OutputPyPort *p=(OutputPyPort *)*iter;
637               DEBTRACE( "port name: " << p->getName() );
638               DEBTRACE( "port kind: " << p->edGetType()->kind() );
639               DEBTRACE( "port pos : " << pos );
640               SALOME::SenderByte_var elt = (*resultCorba)[pos];
641               SeqByteReceiver recv(elt);
642               unsigned long length = 0;
643               char *resultCorbaC = recv.data(length);
644               {
645                 AutoPyRef resultPython=PyMemoryView_FromMemory(resultCorbaC,length,PyBUF_READ);
646                 AutoPyRef args = PyTuple_New(1);
647                 PyTuple_SetItem(args,0,resultPython.retn());
648                 AutoPyRef ob = PyObject_CallObject(_pyfuncUnser,args);
649                 if (!ob)
650                 {
651                   std::stringstream msg;
652                   msg << "Conversion with pickle of output ports failed !";
653                   msg << " : " << __FILE__ << ":" << __LINE__;
654                   _errorDetails=msg.str();
655                   throw YACS::ENGINE::ConversionException(msg.str());
656                 }
657                 UnlinkOnDestructorIfProxy(ob);
658                 p->put( ob );
659               }
660               pos++;
661             }
662       }
663       catch(ConversionException& ex)
664       {
665           _errorDetails=ex.what();
666           throw;
667       }
668       if(_autoSqueeze)
669         squeezeMemoryRemote();
670   }
671   //
672   if(!isUsingPythonCache())
673   {
674     freeKernelPynode();
675     bool dummy;
676     Engines::Container_var cont(GetContainerObj(this,dummy));
677     cont->removePyScriptNode(getName().c_str());
678   }
679   DEBTRACE( "++++++++++++++ ENDOF PyNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
680 }
681
682 void PythonNode::ExecuteLocalInternal(const std::string& codeStr, PyObject *context, std::string& errorDetails)
683 {
684   DEBTRACE(  code );
685   DEBTRACE( "context refcnt: " << context->ob_refcnt );
686   std::ostringstream stream;
687   stream << "/tmp/PythonNode_";
688   stream << getpid();
689   AutoPyRef code=Py_CompileString(codeStr.c_str(), stream.str().c_str(), Py_file_input);
690   if(code == NULL)
691   {
692     errorDetails=""; 
693     AutoPyRef new_stderr = newPyStdOut(errorDetails);
694     PySys_SetObject((char*)"stderr", new_stderr);
695     PyErr_Print();
696     PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
697     throw YACS::Exception("Error during execution");
698   }
699   {
700     AutoPyRef res = PyEval_EvalCode(  code, context, context);
701   }
702   DEBTRACE( "context refcnt: " << context->ob_refcnt );
703   fflush(stdout);
704   fflush(stderr);
705   if(PyErr_Occurred ())
706   {
707     errorDetails="";
708     AutoPyRef new_stderr = newPyStdOut(errorDetails);
709     PySys_SetObject((char*)"stderr", new_stderr);
710     ofstream errorfile(stream.str().c_str());
711     if (errorfile.is_open())
712       {
713         errorfile << codeStr;
714         errorfile.close();
715       }
716     PyErr_Print();
717     PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
718     throw YACS::Exception("Error during execution");
719   }
720 }
721
722 void PythonNode::executeLocalInternal(const std::string& codeStr)
723 {
724   ExecuteLocalInternal(codeStr,_context,_errorDetails);
725 }
726
727 void PythonNode::executeLocal()
728 {
729   DEBTRACE( "++++++++++++++ PyNode::executeLocal: " << getName() << " ++++++++++++++++++++" );
730   {
731     AutoGIL agil;
732     std::ostringstream unpxy; unpxy << "from SALOME_PyNode import UnProxyObjectSimpleLocal" << std::endl;
733     DEBTRACE( "---------------PyNode::inputs---------------" );
734     list<InputPort *>::iterator iter2;
735     for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
736       {
737         InputPyPort *p=(InputPyPort *)*iter2;
738         DEBTRACE( "port name: " << p->getName() );
739         DEBTRACE( "port kind: " << p->edGetType()->kind() );
740         PyObject* ob=p->getPyObj();
741         DEBTRACE( "ob refcnt: " << ob->ob_refcnt ); 
742         unpxy << p->getName() << " = UnProxyObjectSimpleLocal( " << p->getName() << " )" << std::endl;
743 #ifdef _DEVDEBUG_
744         PyObject_Print(ob,stderr,Py_PRINT_RAW);
745         cerr << endl;
746 #endif
747         int ier=PyDict_SetItemString(_context,p->getName().c_str(),ob);
748         DEBTRACE( "after PyDict_SetItemString:ob refcnt: " << ob->ob_refcnt );
749       }
750
751     DEBTRACE( "---------------End PyNode::inputs---------------" );
752
753     //calculation
754     DEBTRACE( "----------------PyNode::calculation---------------" );
755
756     executeLocalInternal( unpxy.str() );
757
758     executeLocalInternal( _script );
759
760     DEBTRACE( "-----------------PyNode::outputs-----------------" );
761     list<OutputPort *>::iterator iter;
762     try
763     {
764         for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
765           {
766             OutputPyPort *p=(OutputPyPort *)*iter;
767             DEBTRACE( "port name: " << p->getName() );
768             DEBTRACE( "port kind: " << p->edGetType()->kind() );
769             PyObject *ob=PyDict_GetItemString(_context,p->getName().c_str());
770             if(ob==NULL)
771               {
772                 std::string msg="Error during execution: there is no variable ";
773                 msg=msg+p->getName()+" in node context";
774                 _errorDetails=msg;
775                 throw Exception(msg);
776               }
777             DEBTRACE( "PyNode::outputs::ob refcnt: " << ob->ob_refcnt );
778 #ifdef _DEVDEBUG_
779             PyObject_Print(ob,stderr,Py_PRINT_RAW);
780             cerr << endl;
781 #endif
782             p->put(ob);
783           }
784     }
785     catch(ConversionException& ex)
786     {
787         _errorDetails=ex.what();
788         throw;
789     }
790     if(_autoSqueeze)
791       squeezeMemory();
792     DEBTRACE( "-----------------End PyNode::outputs-----------------" );
793   }
794   DEBTRACE( "++++++++++++++ End PyNode::execute: " << getName() << " ++++++++++++++++++++" );
795 }
796
797 void PythonNode::squeezeMemorySafe()
798 {
799   AutoGIL agil;
800   if(_mode==PythonNode::REMOTE_NAME)
801     this->squeezeMemoryRemote();
802   else
803     this->squeezeMemory();
804 }
805   
806 void PythonNode::squeezeMemory()
807 {
808   for(auto p : _setOfInputPort)
809     {
810       PyDict_DelItemString(_context,p->getName().c_str());
811       InputPyPort *p2(static_cast<InputPyPort *>(p));
812       if(p2->canSafelySqueezeMemory())
813         p2->put(Py_None);
814     }
815   for(auto p : _setOfOutputPort)
816     {
817       PyDict_DelItemString(_context,p->getName().c_str());
818       OutputPyPort *p2(static_cast<OutputPyPort *>(p));
819       p2->putWithoutForward(Py_None);
820     }
821 }
822
823 void PythonNode::squeezeMemoryRemote()
824 {
825   for(auto p : _setOfInputPort)
826     {
827       InputPyPort *p2(static_cast<InputPyPort *>(p));
828       if(p2->canSafelySqueezeMemory())
829         p2->put(Py_None);
830     }
831   for(auto p : _setOfOutputPort)
832     {
833       OutputPyPort *p2(static_cast<OutputPyPort *>(p));
834       p2->putWithoutForward(Py_None);
835     }
836 }
837
838 std::string PythonNode::getContainerLog()
839 {
840   return PythonEntry::GetContainerLog(_mode,_container,this);
841 }
842
843 void PythonNode::shutdown(int level)
844 {
845   DEBTRACE("PythonNode::shutdown " << level);
846   if(_mode=="local")return;
847   if(_container)
848     {
849       freeKernelPynode();
850       _container->shutdown(level);
851     }
852 }
853
854 void PythonNode::imposeResource(const std::string& resource_name,
855                                 const std::string& container_name)
856 {
857   if(!resource_name.empty() && !container_name.empty())
858   {
859     _imposedResource = resource_name;
860     _imposedContainer = container_name;
861   }
862 }
863
864 bool PythonNode::canAcceptImposedResource()
865 {
866   return _container != nullptr && _container->canAcceptImposedResource();
867 }
868
869 bool PythonNode::hasImposedResource()const
870 {
871   return PythonEntry::hasImposedResource();
872 }
873
874 std::string PythonNode::pythonEntryName()const
875 {
876   if(isUsingPythonCache())
877     return "DEFAULT_NAME_FOR_UNIQUE_PYTHON_NODE_ENTRY";
878   else
879     return getName();
880 }
881
882 bool PythonNode::isUsingPythonCache()const
883 {
884   bool found = false;
885   if(_container)
886     found = _container->isUsingPythonCache();
887   return found;
888 }
889
890 void PythonNode::freeKernelPynode()
891 {
892   if(!CORBA::is_nil(_pynode))
893   {
894     try
895     {
896       _pynode->UnRegister();
897     }
898     catch(...)
899     {
900       DEBTRACE("Trouble when pynode->UnRegister!")
901     }
902     _pynode = Engines::PyScriptNode::_nil();
903   }
904 }
905
906 Node *PythonNode::simpleClone(ComposedNode *father, bool editionOnly) const
907 {
908   return new PythonNode(*this,father);
909 }
910
911 void PythonNode::createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)
912 {
913   freeKernelPynode();
914   _pynode=objContainer->createPyScriptNode(pythonEntryName().c_str(),getScript().c_str());
915   _pynode->Register();
916 }
917
918 Engines::PyNodeBase_var PythonNode::retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const
919 {
920   Engines::PyScriptNode_var ret(objContainer->getDefaultPyScriptNode(pythonEntryName().c_str()));
921   if(!CORBA::is_nil(ret))
922     {
923       ret->Register();
924     }
925   return Engines::PyNodeBase::_narrow(ret);
926 }
927
928 void PythonNode::assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)
929 {
930   if(CORBA::is_nil(_pynode))
931     _pynode=Engines::PyScriptNode::_narrow(remoteInterp);
932   else
933   {
934     Engines::PyScriptNode_var tmpp(Engines::PyScriptNode::_narrow(remoteInterp));
935     if(!_pynode->_is_equivalent(tmpp))
936     {
937       freeKernelPynode();
938       _pynode=Engines::PyScriptNode::_narrow(remoteInterp);
939     }
940   }
941   _pynode->assignNewCompiledCode(getScript().c_str());
942 }
943
944 Engines::PyNodeBase_var PythonNode::getRemoteInterpreterHandle()
945 {
946   return Engines::PyNodeBase::_narrow(_pynode);
947 }
948
949 //! Create a new node of same type with a given name
950 PythonNode* PythonNode::cloneNode(const std::string& name)
951 {
952   PythonNode* n=new PythonNode(name);
953   n->setScript(_script);
954   list<InputPort *>::iterator iter;
955   for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
956     {
957       InputPyPort *p=(InputPyPort *)*iter;
958       DEBTRACE( "port name: " << p->getName() );
959       DEBTRACE( "port kind: " << p->edGetType()->kind() );
960       n->edAddInputPort(p->getName(),p->edGetType());
961     }
962   list<OutputPort *>::iterator iter2;
963   for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
964     {
965       OutputPyPort *p=(OutputPyPort *)*iter2;
966       DEBTRACE( "port name: " << p->getName() );
967       DEBTRACE( "port kind: " << p->edGetType()->kind() );
968       n->edAddOutputPort(p->getName(),p->edGetType());
969     }
970   return n;
971 }
972
973 void PythonNode::applyDPLScope(ComposedNode *gfn)
974 {
975   std::vector< std::pair<std::string,int> > ret(getDPLScopeInfo(gfn));
976   if(ret.empty())
977     return ;
978   //
979   PyObject *ob(0);
980   {
981     AutoGIL agil;
982     std::size_t sz(ret.size());
983     ob=PyList_New(sz);
984     for(std::size_t i=0;i<sz;i++)
985       {
986         const std::pair<std::string,int>& p(ret[i]);
987         PyObject *elt(PyTuple_New(2));
988         PyTuple_SetItem(elt,0,PyUnicode_FromString(p.first.c_str()));
989         PyTuple_SetItem(elt,1,PyLong_FromLong(p.second));
990         PyList_SetItem(ob,i,elt);
991       }
992   }
993   if(_mode==REMOTE_NAME)
994     {
995       Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);
996       {
997         AutoGIL agil;
998         PyObject *serializationInput(PyObject_CallFunctionObjArgs(_pyfuncSimpleSer,ob,NULL));
999         Py_XDECREF(ob);
1000         char *serializationInputC(0);
1001         Py_ssize_t len;
1002         if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
1003           throw Exception("DistributedPythonNode problem in python pickle");
1004         serializationInputCorba->length(len);
1005         for(int i=0; i < len ; i++)
1006           serializationInputCorba[i]=serializationInputC[i];
1007         Py_XDECREF(serializationInput);
1008       }
1009       _pynode->defineNewCustomVar(DPL_INFO_NAME,serializationInputCorba);
1010     }
1011   else
1012     {
1013       AutoGIL agil;
1014       PyDict_SetItemString(_context,DPL_INFO_NAME,ob);
1015       Py_XDECREF(ob);
1016     }
1017 }
1018
1019 PyFuncNode::PyFuncNode(const PyFuncNode& other, ComposedNode *father):InlineFuncNode(other,father),_pyfunc(0)
1020 {
1021   _implementation = PythonNode::IMPL_NAME;
1022   {
1023     AutoGIL agil;
1024     _context=PyDict_New();
1025     DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1026     if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
1027       {
1028         stringstream msg;
1029         msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
1030         _errorDetails=msg.str();
1031         throw Exception(msg.str());
1032       }
1033   }
1034 }
1035
1036 PyFuncNode::PyFuncNode(const std::string& name): InlineFuncNode(name),_pyfunc(0)
1037 {
1038
1039   _implementation = PythonNode::IMPL_NAME;
1040   DEBTRACE( "PyFuncNode::PyFuncNode " << name );
1041   {
1042     AutoGIL agil;
1043     _context=PyDict_New();
1044     DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1045     if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
1046       {
1047         stringstream msg;
1048         msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
1049         _errorDetails=msg.str();
1050         throw Exception(msg.str());
1051       }
1052   }
1053 }
1054
1055 PyFuncNode::~PyFuncNode()
1056 {
1057   if(!CORBA::is_nil(_pynode))
1058     {
1059       _pynode->UnRegister();
1060     }
1061 }
1062
1063 void PyFuncNode::init(bool start)
1064 {
1065   initCommonPartWithoutStateManagement(start);
1066   if(_state == YACS::DISABLED)
1067     {
1068       exDisabledState(); // to refresh propagation of DISABLED state
1069       return ;
1070     }
1071   if(start) //complete initialization
1072     setState(YACS::READY);
1073   else if(_state > YACS::LOADED)// WARNING FuncNode has internal vars (CEA usecase) ! Partial initialization (inside a loop). Exclusivity of funcNode.
1074     setState(YACS::TORECONNECT);
1075 }
1076
1077 void PyFuncNode::checkBasicConsistency() const
1078 {
1079   DEBTRACE("checkBasicConsistency");
1080   InlineFuncNode::checkBasicConsistency();
1081   {
1082     AutoGIL agil;
1083     PyObject* res;
1084     res=Py_CompileString(_script.c_str(),getName().c_str(),Py_file_input);
1085     if(res == NULL)
1086       {
1087         std::string error="";
1088         PyObject* new_stderr = newPyStdOut(error);
1089         PySys_SetObject((char*)"stderr", new_stderr);
1090         PyErr_Print();
1091         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1092         Py_DECREF(new_stderr);
1093         throw Exception(error);
1094       }
1095     else
1096       Py_XDECREF(res);
1097   }
1098 }
1099
1100 void PyFuncNode::load()
1101 {
1102   DEBTRACE( "---------------PyfuncNode::load function---------------" );
1103   if(_mode==PythonNode::REMOTE_NAME)
1104     loadRemote();
1105   else
1106     loadLocal();
1107 }
1108
1109 void PyFuncNode::loadRemote()
1110 {
1111   commonRemoteLoad(this);
1112 }
1113
1114 void PyFuncNode::loadLocal()
1115 {
1116   DEBTRACE( "---------------PyFuncNode::load function " << getName() << " ---------------" );
1117   DEBTRACE(  _script );
1118
1119 #ifdef _DEVDEBUG_
1120   list<OutputPort *>::iterator iter;
1121   for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
1122     {
1123       OutputPyPort *p=(OutputPyPort *)*iter;
1124       DEBTRACE( "port name: " << p->getName() );
1125       DEBTRACE( "port kind: " << p->edGetType()->kind() );
1126     }
1127 #endif
1128
1129   {
1130     AutoGIL agil;
1131     DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1132
1133     std::ostringstream stream;
1134     stream << "/tmp/PythonNode_";
1135     stream << getpid();
1136
1137     PyObject* code=Py_CompileString(_script.c_str(), stream.str().c_str(), Py_file_input);
1138     if(code == NULL)
1139       {
1140         _errorDetails="";
1141         PyObject* new_stderr = newPyStdOut(_errorDetails);
1142         PySys_SetObject((char*)"stderr", new_stderr);
1143         PyErr_Print();
1144         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1145         Py_DECREF(new_stderr);
1146         throw Exception("Error during execution");
1147       }
1148     PyObject *res = PyEval_EvalCode( code, _context, _context);
1149     Py_DECREF(code);
1150     Py_XDECREF(res);
1151
1152     DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1153     if(PyErr_Occurred ())
1154       {
1155         _errorDetails="";
1156         PyObject* new_stderr = newPyStdOut(_errorDetails);
1157         PySys_SetObject((char*)"stderr", new_stderr);
1158         ofstream errorfile(stream.str().c_str());
1159         if (errorfile.is_open())
1160           {
1161             errorfile << _script;
1162             errorfile.close();
1163           }
1164         PyErr_Print();
1165         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1166         Py_DECREF(new_stderr);
1167         throw Exception("Error during execution");
1168         return;
1169       }
1170     _pyfunc=PyDict_GetItemString(_context,_fname.c_str());
1171     DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1172     if(_pyfunc == NULL)
1173       {
1174         _errorDetails="";
1175         PyObject* new_stderr = newPyStdOut(_errorDetails);
1176         PySys_SetObject((char*)"stderr", new_stderr);
1177         PyErr_Print();
1178         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1179         Py_DECREF(new_stderr);
1180         throw Exception("Error during execution");
1181       }
1182     DEBTRACE( "---------------End PyFuncNode::load function---------------" );
1183   }
1184 }
1185
1186 void PyFuncNode::execute()
1187 {
1188   if(_mode==PythonNode::REMOTE_NAME)
1189     executeRemote();
1190   else
1191     executeLocal();
1192 }
1193
1194 void PyFuncNode::executeRemote()
1195 {
1196   DEBTRACE( "++++++++++++++ PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
1197   if(!_pyfuncSer)
1198     throw Exception("DistributedPythonNode badly loaded");
1199   //
1200   if(dynamic_cast<HomogeneousPoolContainer *>(getContainer()))
1201     {
1202       bool dummy;
1203       loadPythonAdapter(this,dummy);
1204       _pynode->executeAnotherPieceOfCode(getScript().c_str());
1205     }
1206   //
1207   Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);;
1208   {
1209 #if PY_VERSION_HEX < 0x03070000
1210       std::unique_lock<std::mutex> lock(data_mutex);
1211 #endif
1212       AutoGIL agil;
1213       PyObject *ob(0);
1214       //===========================================================================
1215       // Get inputs in input ports, build a Python tuple and pickle it
1216       //===========================================================================
1217       PyObject *args(PyTuple_New(getNumberOfInputPorts()));
1218       int pos(0);
1219       for(std::list<InputPort *>::iterator iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++,pos++)
1220         {
1221           InputPyPort *p=(InputPyPort *)*iter2;
1222           ob=p->getPyObj();
1223           Py_INCREF(ob);
1224           PyTuple_SetItem(args,pos,ob);
1225         }
1226 #ifdef _DEVDEBUG_
1227       PyObject_Print(args,stderr,Py_PRINT_RAW);
1228       std::cerr << endl;
1229 #endif
1230       PyObject *serializationInput=PyObject_CallObject(_pyfuncSer,args);
1231       Py_DECREF(args);
1232       //The pickled string may contain NULL characters so use PyString_AsStringAndSize
1233       char *serializationInputC(0);
1234       Py_ssize_t len;
1235       if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
1236         throw Exception("DistributedPythonNode problem in python pickle");
1237
1238       serializationInputCorba->length(len);
1239       for(int i=0; i < len ; i++)
1240         serializationInputCorba[i]=serializationInputC[i];
1241       Py_DECREF(serializationInput);
1242   }
1243
1244   //===========================================================================
1245   // Execute in remote Python node
1246   //===========================================================================
1247   DEBTRACE( "-----------------starting remote python invocation-----------------" );
1248   Engines::pickledArgs_var resultCorba;
1249   try
1250     {
1251       resultCorba=_pynode->execute(getFname().c_str(),serializationInputCorba);
1252     }
1253   catch( const SALOME::SALOME_Exception& ex )
1254     {
1255       std::string msg="Exception on remote python invocation";
1256       msg += '\n';
1257       msg += ex.details.text.in();
1258       _errorDetails=msg;
1259       throw Exception(msg);
1260     }
1261   catch(CORBA::COMM_FAILURE& ex)
1262     {
1263       std::ostringstream msg;
1264       msg << "Exception on remote python invocation." << std::endl ;
1265       msg << "Caught system exception COMM_FAILURE -- unable to contact the "
1266           << "object." << std::endl;
1267       _errorDetails=msg.str();
1268       throw Exception(msg.str());
1269     }
1270   catch(CORBA::SystemException& ex)
1271     {
1272       std::ostringstream msg;
1273       msg << "Exception on remote python invocation." << std::endl ;
1274       msg << "Caught a CORBA::SystemException." ;
1275       CORBA::Any tmp;
1276       tmp <<= ex;
1277       CORBA::TypeCode_var tc = tmp.type();
1278       const char *p = tc->name();
1279       if ( *p != '\0' )
1280         msg <<p;
1281       else
1282         msg  << tc->id();
1283       msg << std::endl;
1284       _errorDetails=msg.str();
1285       throw Exception(msg.str());
1286     }
1287   catch(CORBA::Exception& ex)
1288     {
1289       std::ostringstream msg;
1290       msg << "Exception on remote python invocation." << std::endl ;
1291       msg << "Caught CORBA::Exception. " ;
1292       CORBA::Any tmp;
1293       tmp <<= ex;
1294       CORBA::TypeCode_var tc = tmp.type();
1295       const char *p = tc->name();
1296       if ( *p != '\0' )
1297         msg <<p;
1298       else
1299         msg  << tc->id();
1300       msg << std::endl;
1301       _errorDetails=msg.str();
1302       throw Exception(msg.str());
1303     }
1304   catch(omniORB::fatalException& fe)
1305     {
1306       std::ostringstream msg;
1307       msg << "Exception on remote python invocation." << std::endl ;
1308       msg << "Caught omniORB::fatalException:" << std::endl;
1309       msg << "  file: " << fe.file() << std::endl;
1310       msg << "  line: " << fe.line() << std::endl;
1311       msg << "  mesg: " << fe.errmsg() << std::endl;
1312       _errorDetails=msg.str();
1313       throw Exception(msg.str());
1314     }
1315   DEBTRACE( "-----------------end of remote python invocation-----------------" );
1316   //===========================================================================
1317   // Get results, unpickle and put them in output ports
1318   //===========================================================================
1319   char *resultCorbaC=new char[resultCorba->length()+1];
1320   resultCorbaC[resultCorba->length()]='\0';
1321   for(int i=0;i<resultCorba->length();i++)
1322     resultCorbaC[i]=resultCorba[i];
1323
1324   {
1325 #if PY_VERSION_HEX < 0x03070000
1326       std::unique_lock<std::mutex> lock(data_mutex);
1327 #endif
1328       AutoGIL agil;
1329
1330       PyObject *resultPython(PyBytes_FromStringAndSize(resultCorbaC,resultCorba->length()));
1331       delete [] resultCorbaC;
1332       PyObject *args(PyTuple_New(1)),*ob(0);
1333       PyTuple_SetItem(args,0,resultPython);
1334       PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
1335       Py_DECREF(args);
1336
1337       DEBTRACE( "-----------------PythonNode::outputs-----------------" );
1338       int nres=1;
1339       if(finalResult == Py_None)
1340         nres=0;
1341       else if(PyTuple_Check(finalResult))
1342         nres=PyTuple_Size(finalResult);
1343
1344       if(getNumberOfOutputPorts() != nres)
1345         {
1346           std::string msg="Number of output arguments : Mismatch between definition and execution";
1347           Py_DECREF(finalResult);
1348           _errorDetails=msg;
1349           throw Exception(msg);
1350         }
1351
1352       try
1353       {
1354           int pos(0);
1355           for(std::list<OutputPort *>::iterator iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++, pos++)
1356             {
1357               OutputPyPort *p=(OutputPyPort *)*iter;
1358               DEBTRACE( "port name: " << p->getName() );
1359               DEBTRACE( "port kind: " << p->edGetType()->kind() );
1360               DEBTRACE( "port pos : " << pos );
1361               if(PyTuple_Check(finalResult))
1362                 ob=PyTuple_GetItem(finalResult,pos) ;
1363               else
1364                 ob=finalResult;
1365               DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1366               p->put(ob);
1367             }
1368           Py_DECREF(finalResult);
1369       }
1370       catch(ConversionException& ex)
1371       {
1372           Py_DECREF(finalResult);
1373           _errorDetails=ex.what();
1374           throw;
1375       }
1376   }
1377
1378   DEBTRACE( "++++++++++++++ ENDOF PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
1379 }
1380
1381 void PyFuncNode::executeLocal()
1382 {
1383   DEBTRACE( "++++++++++++++ PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
1384
1385   int pos=0;
1386   PyObject* ob;
1387   if(!_pyfunc)throw Exception("PyFuncNode badly loaded");
1388   {
1389       AutoGIL agil;
1390       DEBTRACE( "---------------PyFuncNode::inputs---------------" );
1391       PyObject* args = PyTuple_New(getNumberOfInputPorts()) ;
1392       list<InputPort *>::iterator iter2;
1393       for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
1394         {
1395           InputPyPort *p=(InputPyPort *)*iter2;
1396           DEBTRACE( "port name: " << p->getName() );
1397           DEBTRACE( "port kind: " << p->edGetType()->kind() );
1398           ob=p->getPyObj();
1399 #ifdef _DEVDEBUG_
1400           PyObject_Print(ob,stderr,Py_PRINT_RAW);
1401           cerr << endl;
1402 #endif
1403           DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1404           Py_INCREF(ob);
1405           PyTuple_SetItem(args,pos,ob);
1406           DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1407           pos++;
1408         }
1409       DEBTRACE( "---------------End PyFuncNode::inputs---------------" );
1410
1411       DEBTRACE( "----------------PyFuncNode::calculation---------------" );
1412 #ifdef _DEVDEBUG_
1413       PyObject_Print(_pyfunc,stderr,Py_PRINT_RAW);
1414       cerr << endl;
1415       PyObject_Print(args,stderr,Py_PRINT_RAW);
1416       cerr << endl;
1417 #endif
1418       DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1419       PyObject* result = PyObject_CallObject( _pyfunc , args ) ;
1420       DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1421       Py_DECREF(args);
1422       fflush(stdout);
1423       fflush(stderr);
1424       if(result == NULL)
1425         {
1426           _errorDetails="";
1427           PyObject* new_stderr = newPyStdOut(_errorDetails);
1428           PySys_SetObject((char*)"stderr", new_stderr);
1429           std::ostringstream stream;
1430           stream << "/tmp/PythonNode_";
1431           stream << getpid();
1432           ofstream errorfile(stream.str().c_str());
1433           if (errorfile.is_open())
1434             {
1435               errorfile << _script;
1436               errorfile.close();
1437             }
1438           PyErr_Print();
1439           PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1440           Py_DECREF(new_stderr);
1441           throw Exception("Error during execution");
1442         }
1443       DEBTRACE( "----------------End PyFuncNode::calculation---------------" );
1444
1445       DEBTRACE( "-----------------PyFuncNode::outputs-----------------" );
1446       int nres=1;
1447       if(result == Py_None)
1448         nres=0;
1449       else if(PyTuple_Check(result))
1450         nres=PyTuple_Size(result);
1451
1452       if(getNumberOfOutputPorts() != nres)
1453         {
1454           std::string msg="Number of output arguments : Mismatch between definition and execution";
1455           Py_DECREF(result);
1456           _errorDetails=msg;
1457           throw Exception(msg);
1458         }
1459
1460       pos=0;
1461 #ifdef _DEVDEBUG_
1462       PyObject_Print(result,stderr,Py_PRINT_RAW);
1463       cerr << endl;
1464 #endif
1465       list<OutputPort *>::iterator iter;
1466       try
1467       {
1468           for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
1469             {
1470               OutputPyPort *p=(OutputPyPort *)*iter;
1471               DEBTRACE( "port name: " << p->getName() );
1472               DEBTRACE( "port kind: " << p->edGetType()->kind() );
1473               DEBTRACE( "port pos : " << pos );
1474               if(PyTuple_Check(result))ob=PyTuple_GetItem(result,pos) ;
1475               else ob=result;
1476               DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1477 #ifdef _DEVDEBUG_
1478               PyObject_Print(ob,stderr,Py_PRINT_RAW);
1479               cerr << endl;
1480 #endif
1481               p->put(ob);
1482               pos++;
1483             }
1484       }
1485       catch(ConversionException& ex)
1486       {
1487           Py_DECREF(result);
1488           _errorDetails=ex.what();
1489           throw;
1490       }
1491       DEBTRACE( "-----------------End PyFuncNode::outputs-----------------" );
1492       Py_DECREF(result);
1493   }
1494   DEBTRACE( "++++++++++++++ End PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
1495 }
1496
1497 Node *PyFuncNode::simpleClone(ComposedNode *father, bool editionOnly) const
1498 {
1499   return new PyFuncNode(*this,father);
1500 }
1501
1502 void PyFuncNode::createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)
1503 {
1504   if(!CORBA::is_nil(_pynode))
1505     _pynode->UnRegister();
1506   _pynode=objContainer->createPyNode(getName().c_str(),getScript().c_str());
1507 }
1508
1509 Engines::PyNodeBase_var PyFuncNode::retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const
1510 {
1511   Engines::PyNode_var ret(objContainer->getDefaultPyNode(getName().c_str()));
1512   if(!CORBA::is_nil(ret))
1513     {
1514       ret->Register();
1515     }
1516   return Engines::PyNodeBase::_narrow(ret);
1517 }
1518
1519 void PyFuncNode::assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)
1520 {
1521   if(!CORBA::is_nil(_pynode))
1522     {
1523       Engines::PyNode_var tmpp(Engines::PyNode::_narrow(remoteInterp));
1524       if(_pynode->_is_equivalent(tmpp))
1525         return ;
1526     }
1527   if(!CORBA::is_nil(_pynode))
1528     _pynode->UnRegister();
1529   _pynode=Engines::PyNode::_narrow(remoteInterp);
1530 }
1531
1532 Engines::PyNodeBase_var PyFuncNode::getRemoteInterpreterHandle()
1533 {
1534   return Engines::PyNodeBase::_narrow(_pynode);
1535 }
1536
1537 //! Create a new node of same type with a given name
1538 PyFuncNode* PyFuncNode::cloneNode(const std::string& name)
1539 {
1540   PyFuncNode* n=new PyFuncNode(name);
1541   n->setScript(_script);
1542   n->setFname(_fname);
1543   list<InputPort *>::iterator iter;
1544   for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
1545     {
1546       InputPyPort *p=(InputPyPort *)*iter;
1547       n->edAddInputPort(p->getName(),p->edGetType());
1548     }
1549   list<OutputPort *>::iterator iter2;
1550   for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
1551     {
1552       OutputPyPort *p=(OutputPyPort *)*iter2;
1553       n->edAddOutputPort(p->getName(),p->edGetType());
1554     }
1555   return n;
1556 }
1557
1558 std::string PyFuncNode::getContainerLog()
1559 {
1560   return PythonEntry::GetContainerLog(_mode,_container,this);
1561 }
1562
1563 void PyFuncNode::shutdown(int level)
1564 {
1565   DEBTRACE("PyFuncNode::shutdown " << level);
1566   if(_mode=="local")return;
1567   if(_container)
1568     {
1569       if(!CORBA::is_nil(_pynode)) _pynode->UnRegister();
1570       _pynode=Engines::PyNode::_nil();
1571       _container->shutdown(level);
1572     }
1573 }
1574
1575 void PyFuncNode::imposeResource(const std::string& resource_name,
1576                                 const std::string& container_name)
1577 {
1578   if(!resource_name.empty() && !container_name.empty())
1579   {
1580     _imposedResource = resource_name;
1581     _imposedContainer = container_name;
1582   }
1583 }
1584
1585 bool PyFuncNode::canAcceptImposedResource()
1586 {
1587   return _container != nullptr && _container->canAcceptImposedResource();
1588 }
1589
1590 bool PyFuncNode::hasImposedResource()const
1591 {
1592   return PythonEntry::hasImposedResource();
1593 }
1594