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