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