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