Salome HOME
Do not fetch data on local python node in case of squeeze memory
[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     if( ! getSqueezeStatus() )
757       executeLocalInternal( unpxy.str() );
758
759     executeLocalInternal( _script );
760
761     DEBTRACE( "-----------------PyNode::outputs-----------------" );
762     list<OutputPort *>::iterator iter;
763     try
764     {
765         for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
766           {
767             OutputPyPort *p=(OutputPyPort *)*iter;
768             DEBTRACE( "port name: " << p->getName() );
769             DEBTRACE( "port kind: " << p->edGetType()->kind() );
770             PyObject *ob=PyDict_GetItemString(_context,p->getName().c_str());
771             if(ob==NULL)
772               {
773                 std::string msg="Error during execution: there is no variable ";
774                 msg=msg+p->getName()+" in node context";
775                 _errorDetails=msg;
776                 throw Exception(msg);
777               }
778             DEBTRACE( "PyNode::outputs::ob refcnt: " << ob->ob_refcnt );
779 #ifdef _DEVDEBUG_
780             PyObject_Print(ob,stderr,Py_PRINT_RAW);
781             cerr << endl;
782 #endif
783             p->put(ob);
784             if(!isUsingPythonCache())
785               PyDict_DelItemString(_context,p->getName().c_str());
786           }
787     }
788     catch(ConversionException& ex)
789     {
790         _errorDetails=ex.what();
791         throw;
792     }
793     if(_autoSqueeze)
794       squeezeMemory();
795     DEBTRACE( "-----------------End PyNode::outputs-----------------" );
796     if(!isUsingPythonCache())
797     {
798       for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
799       {
800         AutoPyRef pStr = PyUnicode_FromString( (*iter2)->getName().c_str() );
801         if( PyDict_Contains(_context,pStr) == 1 )
802           { PyDict_DelItem(_context,pStr); }
803       }
804     }
805   }
806   DEBTRACE( "++++++++++++++ End PyNode::execute: " << getName() << " ++++++++++++++++++++" );
807 }
808
809 void PythonNode::squeezeMemorySafe()
810 {
811   AutoGIL agil;
812   if(_mode==PythonNode::REMOTE_NAME)
813     this->squeezeMemoryRemote();
814   else
815     this->squeezeMemory();
816 }
817   
818 void PythonNode::squeezeMemory()
819 {
820   for(auto p : _setOfInputPort)
821     {
822       PyDict_DelItemString(_context,p->getName().c_str());
823       InputPyPort *p2(static_cast<InputPyPort *>(p));
824       if(p2->canSafelySqueezeMemory())
825         p2->put(Py_None);
826     }
827   for(auto p : _setOfOutputPort)
828     {
829       PyDict_DelItemString(_context,p->getName().c_str());
830       OutputPyPort *p2(static_cast<OutputPyPort *>(p));
831       p2->putWithoutForward(Py_None);
832     }
833 }
834
835 void PythonNode::squeezeMemoryRemote()
836 {
837   for(auto p : _setOfInputPort)
838     {
839       InputPyPort *p2(static_cast<InputPyPort *>(p));
840       if(p2->canSafelySqueezeMemory())
841         p2->put(Py_None);
842     }
843   for(auto p : _setOfOutputPort)
844     {
845       OutputPyPort *p2(static_cast<OutputPyPort *>(p));
846       p2->putWithoutForward(Py_None);
847     }
848 }
849
850 std::string PythonNode::getContainerLog()
851 {
852   return PythonEntry::GetContainerLog(_mode,_container,this);
853 }
854
855 void PythonNode::shutdown(int level)
856 {
857   DEBTRACE("PythonNode::shutdown " << level);
858   if(_mode=="local")return;
859   if(_container)
860     {
861       freeKernelPynode();
862       _container->shutdown(level);
863     }
864 }
865
866 void PythonNode::imposeResource(const std::string& resource_name,
867                                 const std::string& container_name)
868 {
869   if(!resource_name.empty() && !container_name.empty())
870   {
871     _imposedResource = resource_name;
872     _imposedContainer = container_name;
873   }
874 }
875
876 bool PythonNode::canAcceptImposedResource()
877 {
878   return _container != nullptr && _container->canAcceptImposedResource();
879 }
880
881 bool PythonNode::hasImposedResource()const
882 {
883   return PythonEntry::hasImposedResource();
884 }
885
886 std::string PythonNode::pythonEntryName()const
887 {
888   if(isUsingPythonCache())
889     return "DEFAULT_NAME_FOR_UNIQUE_PYTHON_NODE_ENTRY";
890   else
891     return getName();
892 }
893
894 bool PythonNode::isUsingPythonCache()const
895 {
896   bool found = false;
897   if(_container)
898     found = _container->isUsingPythonCache();
899   return found;
900 }
901
902 void PythonNode::freeKernelPynode()
903 {
904   if(!CORBA::is_nil(_pynode))
905   {
906     try
907     {
908       _pynode->UnRegister();
909     }
910     catch(...)
911     {
912       DEBTRACE("Trouble when pynode->UnRegister!")
913     }
914     _pynode = Engines::PyScriptNode::_nil();
915   }
916 }
917
918 Node *PythonNode::simpleClone(ComposedNode *father, bool editionOnly) const
919 {
920   return new PythonNode(*this,father);
921 }
922
923 void PythonNode::createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)
924 {
925   freeKernelPynode();
926   _pynode=objContainer->createPyScriptNode(pythonEntryName().c_str(),getScript().c_str());
927   _pynode->Register();
928 }
929
930 Engines::PyNodeBase_var PythonNode::retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const
931 {
932   Engines::PyScriptNode_var ret(objContainer->getDefaultPyScriptNode(pythonEntryName().c_str()));
933   if(!CORBA::is_nil(ret))
934     {
935       ret->Register();
936     }
937   return Engines::PyNodeBase::_narrow(ret);
938 }
939
940 void PythonNode::assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)
941 {
942   if(CORBA::is_nil(_pynode))
943     _pynode=Engines::PyScriptNode::_narrow(remoteInterp);
944   else
945   {
946     Engines::PyScriptNode_var tmpp(Engines::PyScriptNode::_narrow(remoteInterp));
947     if(!_pynode->_is_equivalent(tmpp))
948     {
949       freeKernelPynode();
950       _pynode=Engines::PyScriptNode::_narrow(remoteInterp);
951     }
952   }
953   _pynode->assignNewCompiledCode(getScript().c_str());
954 }
955
956 Engines::PyNodeBase_var PythonNode::getRemoteInterpreterHandle()
957 {
958   return Engines::PyNodeBase::_narrow(_pynode);
959 }
960
961 //! Create a new node of same type with a given name
962 PythonNode* PythonNode::cloneNode(const std::string& name)
963 {
964   PythonNode* n=new PythonNode(name);
965   n->setScript(_script);
966   list<InputPort *>::iterator iter;
967   for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
968     {
969       InputPyPort *p=(InputPyPort *)*iter;
970       DEBTRACE( "port name: " << p->getName() );
971       DEBTRACE( "port kind: " << p->edGetType()->kind() );
972       n->edAddInputPort(p->getName(),p->edGetType());
973     }
974   list<OutputPort *>::iterator iter2;
975   for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
976     {
977       OutputPyPort *p=(OutputPyPort *)*iter2;
978       DEBTRACE( "port name: " << p->getName() );
979       DEBTRACE( "port kind: " << p->edGetType()->kind() );
980       n->edAddOutputPort(p->getName(),p->edGetType());
981     }
982   return n;
983 }
984
985 void PythonNode::applyDPLScope(ComposedNode *gfn)
986 {
987   std::vector< std::pair<std::string,int> > ret(getDPLScopeInfo(gfn));
988   if(ret.empty())
989     return ;
990   //
991   PyObject *ob(0);
992   {
993     AutoGIL agil;
994     std::size_t sz(ret.size());
995     ob=PyList_New(sz);
996     for(std::size_t i=0;i<sz;i++)
997       {
998         const std::pair<std::string,int>& p(ret[i]);
999         PyObject *elt(PyTuple_New(2));
1000         PyTuple_SetItem(elt,0,PyUnicode_FromString(p.first.c_str()));
1001         PyTuple_SetItem(elt,1,PyLong_FromLong(p.second));
1002         PyList_SetItem(ob,i,elt);
1003       }
1004   }
1005   if(_mode==REMOTE_NAME)
1006     {
1007       Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);
1008       {
1009         AutoGIL agil;
1010         PyObject *serializationInput(PyObject_CallFunctionObjArgs(_pyfuncSimpleSer,ob,NULL));
1011         Py_XDECREF(ob);
1012         char *serializationInputC(0);
1013         Py_ssize_t len;
1014         if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
1015           throw Exception("DistributedPythonNode problem in python pickle");
1016         serializationInputCorba->length(len);
1017         for(int i=0; i < len ; i++)
1018           serializationInputCorba[i]=serializationInputC[i];
1019         Py_XDECREF(serializationInput);
1020       }
1021       _pynode->defineNewCustomVar(DPL_INFO_NAME,serializationInputCorba);
1022     }
1023   else
1024     {
1025       AutoGIL agil;
1026       PyDict_SetItemString(_context,DPL_INFO_NAME,ob);
1027       Py_XDECREF(ob);
1028     }
1029 }
1030
1031 PyFuncNode::PyFuncNode(const PyFuncNode& other, ComposedNode *father):InlineFuncNode(other,father),_pyfunc(0)
1032 {
1033   _implementation = PythonNode::IMPL_NAME;
1034   {
1035     AutoGIL agil;
1036     _context=PyDict_New();
1037     DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1038     if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
1039       {
1040         stringstream msg;
1041         msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
1042         _errorDetails=msg.str();
1043         throw Exception(msg.str());
1044       }
1045   }
1046 }
1047
1048 PyFuncNode::PyFuncNode(const std::string& name): InlineFuncNode(name),_pyfunc(0)
1049 {
1050
1051   _implementation = PythonNode::IMPL_NAME;
1052   DEBTRACE( "PyFuncNode::PyFuncNode " << name );
1053   {
1054     AutoGIL agil;
1055     _context=PyDict_New();
1056     DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1057     if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
1058       {
1059         stringstream msg;
1060         msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
1061         _errorDetails=msg.str();
1062         throw Exception(msg.str());
1063       }
1064   }
1065 }
1066
1067 PyFuncNode::~PyFuncNode()
1068 {
1069   if(!CORBA::is_nil(_pynode))
1070     {
1071       _pynode->UnRegister();
1072     }
1073 }
1074
1075 void PyFuncNode::init(bool start)
1076 {
1077   initCommonPartWithoutStateManagement(start);
1078   if(_state == YACS::DISABLED)
1079     {
1080       exDisabledState(); // to refresh propagation of DISABLED state
1081       return ;
1082     }
1083   if(start) //complete initialization
1084     setState(YACS::READY);
1085   else if(_state > YACS::LOADED)// WARNING FuncNode has internal vars (CEA usecase) ! Partial initialization (inside a loop). Exclusivity of funcNode.
1086     setState(YACS::TORECONNECT);
1087 }
1088
1089 void PyFuncNode::checkBasicConsistency() const
1090 {
1091   DEBTRACE("checkBasicConsistency");
1092   InlineFuncNode::checkBasicConsistency();
1093   {
1094     AutoGIL agil;
1095     PyObject* res;
1096     res=Py_CompileString(_script.c_str(),getName().c_str(),Py_file_input);
1097     if(res == NULL)
1098       {
1099         std::string error="";
1100         PyObject* new_stderr = newPyStdOut(error);
1101         PySys_SetObject((char*)"stderr", new_stderr);
1102         PyErr_Print();
1103         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1104         Py_DECREF(new_stderr);
1105         throw Exception(error);
1106       }
1107     else
1108       Py_XDECREF(res);
1109   }
1110 }
1111
1112 void PyFuncNode::load()
1113 {
1114   DEBTRACE( "---------------PyfuncNode::load function---------------" );
1115   if(_mode==PythonNode::REMOTE_NAME)
1116     loadRemote();
1117   else
1118     loadLocal();
1119 }
1120
1121 void PyFuncNode::loadRemote()
1122 {
1123   commonRemoteLoad(this);
1124 }
1125
1126 void PyFuncNode::loadLocal()
1127 {
1128   DEBTRACE( "---------------PyFuncNode::load function " << getName() << " ---------------" );
1129   DEBTRACE(  _script );
1130
1131 #ifdef _DEVDEBUG_
1132   list<OutputPort *>::iterator iter;
1133   for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
1134     {
1135       OutputPyPort *p=(OutputPyPort *)*iter;
1136       DEBTRACE( "port name: " << p->getName() );
1137       DEBTRACE( "port kind: " << p->edGetType()->kind() );
1138     }
1139 #endif
1140
1141   {
1142     AutoGIL agil;
1143     DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1144
1145     std::ostringstream stream;
1146     stream << "/tmp/PythonNode_";
1147     stream << getpid();
1148
1149     PyObject* code=Py_CompileString(_script.c_str(), stream.str().c_str(), Py_file_input);
1150     if(code == NULL)
1151       {
1152         _errorDetails="";
1153         PyObject* new_stderr = newPyStdOut(_errorDetails);
1154         PySys_SetObject((char*)"stderr", new_stderr);
1155         PyErr_Print();
1156         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1157         Py_DECREF(new_stderr);
1158         throw Exception("Error during execution");
1159       }
1160     PyObject *res = PyEval_EvalCode( code, _context, _context);
1161     Py_DECREF(code);
1162     Py_XDECREF(res);
1163
1164     DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1165     if(PyErr_Occurred ())
1166       {
1167         _errorDetails="";
1168         PyObject* new_stderr = newPyStdOut(_errorDetails);
1169         PySys_SetObject((char*)"stderr", new_stderr);
1170         ofstream errorfile(stream.str().c_str());
1171         if (errorfile.is_open())
1172           {
1173             errorfile << _script;
1174             errorfile.close();
1175           }
1176         PyErr_Print();
1177         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1178         Py_DECREF(new_stderr);
1179         throw Exception("Error during execution");
1180         return;
1181       }
1182     _pyfunc=PyDict_GetItemString(_context,_fname.c_str());
1183     DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1184     if(_pyfunc == NULL)
1185       {
1186         _errorDetails="";
1187         PyObject* new_stderr = newPyStdOut(_errorDetails);
1188         PySys_SetObject((char*)"stderr", new_stderr);
1189         PyErr_Print();
1190         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1191         Py_DECREF(new_stderr);
1192         throw Exception("Error during execution");
1193       }
1194     DEBTRACE( "---------------End PyFuncNode::load function---------------" );
1195   }
1196 }
1197
1198 void PyFuncNode::execute()
1199 {
1200   if(_mode==PythonNode::REMOTE_NAME)
1201     executeRemote();
1202   else
1203     executeLocal();
1204 }
1205
1206 void PyFuncNode::executeRemote()
1207 {
1208   DEBTRACE( "++++++++++++++ PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
1209   if(!_pyfuncSer)
1210     throw Exception("DistributedPythonNode badly loaded");
1211   //
1212   if(dynamic_cast<HomogeneousPoolContainer *>(getContainer()))
1213     {
1214       bool dummy;
1215       loadPythonAdapter(this,dummy);
1216       _pynode->executeAnotherPieceOfCode(getScript().c_str());
1217     }
1218   //
1219   Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);;
1220   {
1221 #if PY_VERSION_HEX < 0x03070000
1222       std::unique_lock<std::mutex> lock(data_mutex);
1223 #endif
1224       AutoGIL agil;
1225       PyObject *ob(0);
1226       //===========================================================================
1227       // Get inputs in input ports, build a Python tuple and pickle it
1228       //===========================================================================
1229       PyObject *args(PyTuple_New(getNumberOfInputPorts()));
1230       int pos(0);
1231       for(std::list<InputPort *>::iterator iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++,pos++)
1232         {
1233           InputPyPort *p=(InputPyPort *)*iter2;
1234           ob=p->getPyObj();
1235           Py_INCREF(ob);
1236           PyTuple_SetItem(args,pos,ob);
1237         }
1238 #ifdef _DEVDEBUG_
1239       PyObject_Print(args,stderr,Py_PRINT_RAW);
1240       std::cerr << endl;
1241 #endif
1242       PyObject *serializationInput=PyObject_CallObject(_pyfuncSer,args);
1243       Py_DECREF(args);
1244       //The pickled string may contain NULL characters so use PyString_AsStringAndSize
1245       char *serializationInputC(0);
1246       Py_ssize_t len;
1247       if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
1248         throw Exception("DistributedPythonNode problem in python pickle");
1249
1250       serializationInputCorba->length(len);
1251       for(int i=0; i < len ; i++)
1252         serializationInputCorba[i]=serializationInputC[i];
1253       Py_DECREF(serializationInput);
1254   }
1255
1256   //===========================================================================
1257   // Execute in remote Python node
1258   //===========================================================================
1259   DEBTRACE( "-----------------starting remote python invocation-----------------" );
1260   Engines::pickledArgs_var resultCorba;
1261   try
1262     {
1263       resultCorba=_pynode->execute(getFname().c_str(),serializationInputCorba);
1264     }
1265   catch( const SALOME::SALOME_Exception& ex )
1266     {
1267       std::string msg="Exception on remote python invocation";
1268       msg += '\n';
1269       msg += ex.details.text.in();
1270       _errorDetails=msg;
1271       throw Exception(msg);
1272     }
1273   catch(CORBA::COMM_FAILURE& ex)
1274     {
1275       std::ostringstream msg;
1276       msg << "Exception on remote python invocation." << std::endl ;
1277       msg << "Caught system exception COMM_FAILURE -- unable to contact the "
1278           << "object." << std::endl;
1279       _errorDetails=msg.str();
1280       throw Exception(msg.str());
1281     }
1282   catch(CORBA::SystemException& ex)
1283     {
1284       std::ostringstream msg;
1285       msg << "Exception on remote python invocation." << std::endl ;
1286       msg << "Caught a CORBA::SystemException." ;
1287       CORBA::Any tmp;
1288       tmp <<= ex;
1289       CORBA::TypeCode_var tc = tmp.type();
1290       const char *p = tc->name();
1291       if ( *p != '\0' )
1292         msg <<p;
1293       else
1294         msg  << tc->id();
1295       msg << std::endl;
1296       _errorDetails=msg.str();
1297       throw Exception(msg.str());
1298     }
1299   catch(CORBA::Exception& ex)
1300     {
1301       std::ostringstream msg;
1302       msg << "Exception on remote python invocation." << std::endl ;
1303       msg << "Caught CORBA::Exception. " ;
1304       CORBA::Any tmp;
1305       tmp <<= ex;
1306       CORBA::TypeCode_var tc = tmp.type();
1307       const char *p = tc->name();
1308       if ( *p != '\0' )
1309         msg <<p;
1310       else
1311         msg  << tc->id();
1312       msg << std::endl;
1313       _errorDetails=msg.str();
1314       throw Exception(msg.str());
1315     }
1316   catch(omniORB::fatalException& fe)
1317     {
1318       std::ostringstream msg;
1319       msg << "Exception on remote python invocation." << std::endl ;
1320       msg << "Caught omniORB::fatalException:" << std::endl;
1321       msg << "  file: " << fe.file() << std::endl;
1322       msg << "  line: " << fe.line() << std::endl;
1323       msg << "  mesg: " << fe.errmsg() << std::endl;
1324       _errorDetails=msg.str();
1325       throw Exception(msg.str());
1326     }
1327   DEBTRACE( "-----------------end of remote python invocation-----------------" );
1328   //===========================================================================
1329   // Get results, unpickle and put them in output ports
1330   //===========================================================================
1331   char *resultCorbaC=new char[resultCorba->length()+1];
1332   resultCorbaC[resultCorba->length()]='\0';
1333   for(int i=0;i<resultCorba->length();i++)
1334     resultCorbaC[i]=resultCorba[i];
1335
1336   {
1337 #if PY_VERSION_HEX < 0x03070000
1338       std::unique_lock<std::mutex> lock(data_mutex);
1339 #endif
1340       AutoGIL agil;
1341
1342       PyObject *resultPython(PyBytes_FromStringAndSize(resultCorbaC,resultCorba->length()));
1343       delete [] resultCorbaC;
1344       PyObject *args(PyTuple_New(1)),*ob(0);
1345       PyTuple_SetItem(args,0,resultPython);
1346       PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
1347       Py_DECREF(args);
1348
1349       DEBTRACE( "-----------------PythonNode::outputs-----------------" );
1350       int nres=1;
1351       if(finalResult == Py_None)
1352         nres=0;
1353       else if(PyTuple_Check(finalResult))
1354         nres=PyTuple_Size(finalResult);
1355
1356       if(getNumberOfOutputPorts() != nres)
1357         {
1358           std::string msg="Number of output arguments : Mismatch between definition and execution";
1359           Py_DECREF(finalResult);
1360           _errorDetails=msg;
1361           throw Exception(msg);
1362         }
1363
1364       try
1365       {
1366           int pos(0);
1367           for(std::list<OutputPort *>::iterator iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++, pos++)
1368             {
1369               OutputPyPort *p=(OutputPyPort *)*iter;
1370               DEBTRACE( "port name: " << p->getName() );
1371               DEBTRACE( "port kind: " << p->edGetType()->kind() );
1372               DEBTRACE( "port pos : " << pos );
1373               if(PyTuple_Check(finalResult))
1374                 ob=PyTuple_GetItem(finalResult,pos) ;
1375               else
1376                 ob=finalResult;
1377               DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1378               p->put(ob);
1379             }
1380           Py_DECREF(finalResult);
1381       }
1382       catch(ConversionException& ex)
1383       {
1384           Py_DECREF(finalResult);
1385           _errorDetails=ex.what();
1386           throw;
1387       }
1388   }
1389
1390   DEBTRACE( "++++++++++++++ ENDOF PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
1391 }
1392
1393 void PyFuncNode::executeLocal()
1394 {
1395   DEBTRACE( "++++++++++++++ PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
1396
1397   int pos=0;
1398   PyObject* ob;
1399   if(!_pyfunc)throw Exception("PyFuncNode badly loaded");
1400   {
1401       AutoGIL agil;
1402       DEBTRACE( "---------------PyFuncNode::inputs---------------" );
1403       PyObject* args = PyTuple_New(getNumberOfInputPorts()) ;
1404       list<InputPort *>::iterator iter2;
1405       for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
1406         {
1407           InputPyPort *p=(InputPyPort *)*iter2;
1408           DEBTRACE( "port name: " << p->getName() );
1409           DEBTRACE( "port kind: " << p->edGetType()->kind() );
1410           ob=p->getPyObj();
1411 #ifdef _DEVDEBUG_
1412           PyObject_Print(ob,stderr,Py_PRINT_RAW);
1413           cerr << endl;
1414 #endif
1415           DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1416           Py_INCREF(ob);
1417           PyTuple_SetItem(args,pos,ob);
1418           DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1419           pos++;
1420         }
1421       DEBTRACE( "---------------End PyFuncNode::inputs---------------" );
1422
1423       DEBTRACE( "----------------PyFuncNode::calculation---------------" );
1424 #ifdef _DEVDEBUG_
1425       PyObject_Print(_pyfunc,stderr,Py_PRINT_RAW);
1426       cerr << endl;
1427       PyObject_Print(args,stderr,Py_PRINT_RAW);
1428       cerr << endl;
1429 #endif
1430       DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1431       PyObject* result = PyObject_CallObject( _pyfunc , args ) ;
1432       DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1433       Py_DECREF(args);
1434       fflush(stdout);
1435       fflush(stderr);
1436       if(result == NULL)
1437         {
1438           _errorDetails="";
1439           PyObject* new_stderr = newPyStdOut(_errorDetails);
1440           PySys_SetObject((char*)"stderr", new_stderr);
1441           std::ostringstream stream;
1442           stream << "/tmp/PythonNode_";
1443           stream << getpid();
1444           ofstream errorfile(stream.str().c_str());
1445           if (errorfile.is_open())
1446             {
1447               errorfile << _script;
1448               errorfile.close();
1449             }
1450           PyErr_Print();
1451           PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1452           Py_DECREF(new_stderr);
1453           throw Exception("Error during execution");
1454         }
1455       DEBTRACE( "----------------End PyFuncNode::calculation---------------" );
1456
1457       DEBTRACE( "-----------------PyFuncNode::outputs-----------------" );
1458       int nres=1;
1459       if(result == Py_None)
1460         nres=0;
1461       else if(PyTuple_Check(result))
1462         nres=PyTuple_Size(result);
1463
1464       if(getNumberOfOutputPorts() != nres)
1465         {
1466           std::string msg="Number of output arguments : Mismatch between definition and execution";
1467           Py_DECREF(result);
1468           _errorDetails=msg;
1469           throw Exception(msg);
1470         }
1471
1472       pos=0;
1473 #ifdef _DEVDEBUG_
1474       PyObject_Print(result,stderr,Py_PRINT_RAW);
1475       cerr << endl;
1476 #endif
1477       list<OutputPort *>::iterator iter;
1478       try
1479       {
1480           for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
1481             {
1482               OutputPyPort *p=(OutputPyPort *)*iter;
1483               DEBTRACE( "port name: " << p->getName() );
1484               DEBTRACE( "port kind: " << p->edGetType()->kind() );
1485               DEBTRACE( "port pos : " << pos );
1486               if(PyTuple_Check(result))ob=PyTuple_GetItem(result,pos) ;
1487               else ob=result;
1488               DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1489 #ifdef _DEVDEBUG_
1490               PyObject_Print(ob,stderr,Py_PRINT_RAW);
1491               cerr << endl;
1492 #endif
1493               p->put(ob);
1494               pos++;
1495             }
1496       }
1497       catch(ConversionException& ex)
1498       {
1499           Py_DECREF(result);
1500           _errorDetails=ex.what();
1501           throw;
1502       }
1503       DEBTRACE( "-----------------End PyFuncNode::outputs-----------------" );
1504       Py_DECREF(result);
1505   }
1506   DEBTRACE( "++++++++++++++ End PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
1507 }
1508
1509 Node *PyFuncNode::simpleClone(ComposedNode *father, bool editionOnly) const
1510 {
1511   return new PyFuncNode(*this,father);
1512 }
1513
1514 void PyFuncNode::createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)
1515 {
1516   if(!CORBA::is_nil(_pynode))
1517     _pynode->UnRegister();
1518   _pynode=objContainer->createPyNode(getName().c_str(),getScript().c_str());
1519 }
1520
1521 Engines::PyNodeBase_var PyFuncNode::retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const
1522 {
1523   Engines::PyNode_var ret(objContainer->getDefaultPyNode(getName().c_str()));
1524   if(!CORBA::is_nil(ret))
1525     {
1526       ret->Register();
1527     }
1528   return Engines::PyNodeBase::_narrow(ret);
1529 }
1530
1531 void PyFuncNode::assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)
1532 {
1533   if(!CORBA::is_nil(_pynode))
1534     {
1535       Engines::PyNode_var tmpp(Engines::PyNode::_narrow(remoteInterp));
1536       if(_pynode->_is_equivalent(tmpp))
1537         return ;
1538     }
1539   if(!CORBA::is_nil(_pynode))
1540     _pynode->UnRegister();
1541   _pynode=Engines::PyNode::_narrow(remoteInterp);
1542 }
1543
1544 Engines::PyNodeBase_var PyFuncNode::getRemoteInterpreterHandle()
1545 {
1546   return Engines::PyNodeBase::_narrow(_pynode);
1547 }
1548
1549 //! Create a new node of same type with a given name
1550 PyFuncNode* PyFuncNode::cloneNode(const std::string& name)
1551 {
1552   PyFuncNode* n=new PyFuncNode(name);
1553   n->setScript(_script);
1554   n->setFname(_fname);
1555   list<InputPort *>::iterator iter;
1556   for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
1557     {
1558       InputPyPort *p=(InputPyPort *)*iter;
1559       n->edAddInputPort(p->getName(),p->edGetType());
1560     }
1561   list<OutputPort *>::iterator iter2;
1562   for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
1563     {
1564       OutputPyPort *p=(OutputPyPort *)*iter2;
1565       n->edAddOutputPort(p->getName(),p->edGetType());
1566     }
1567   return n;
1568 }
1569
1570 std::string PyFuncNode::getContainerLog()
1571 {
1572   return PythonEntry::GetContainerLog(_mode,_container,this);
1573 }
1574
1575 void PyFuncNode::shutdown(int level)
1576 {
1577   DEBTRACE("PyFuncNode::shutdown " << level);
1578   if(_mode=="local")return;
1579   if(_container)
1580     {
1581       if(!CORBA::is_nil(_pynode)) _pynode->UnRegister();
1582       _pynode=Engines::PyNode::_nil();
1583       _container->shutdown(level);
1584     }
1585 }
1586
1587 void PyFuncNode::imposeResource(const std::string& resource_name,
1588                                 const std::string& container_name)
1589 {
1590   if(!resource_name.empty() && !container_name.empty())
1591   {
1592     _imposedResource = resource_name;
1593     _imposedContainer = container_name;
1594   }
1595 }
1596
1597 bool PyFuncNode::canAcceptImposedResource()
1598 {
1599   return _container != nullptr && _container->canAcceptImposedResource();
1600 }
1601
1602 bool PyFuncNode::hasImposedResource()const
1603 {
1604   return PythonEntry::hasImposedResource();
1605 }
1606