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