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