Salome HOME
Release input CORBA sequence to reduce memory peak
[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   {
414       AutoGIL agil;
415       PyObject *args(0),*ob(0);
416       //===========================================================================
417       // Get inputs in input ports, build a Python dict and pickle it
418       //===========================================================================
419       args = PyDict_New();
420       std::list<InputPort *>::iterator iter2;
421       int pos(0);
422       for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); ++iter2)
423         {
424           InputPyPort *p=(InputPyPort *)*iter2;
425           ob=p->getPyObj();
426           PyDict_SetItemString(args,p->getName().c_str(),ob);
427           pos++;
428         }
429 #ifdef _DEVDEBUG_
430       PyObject_Print(args,stderr,Py_PRINT_RAW);
431       std::cerr << endl;
432 #endif
433       PyObject *serializationInput(PyObject_CallFunctionObjArgs(_pyfuncSer,args,NULL));
434       Py_DECREF(args);
435       //The pickled string may contain NULL characters so use PyString_AsStringAndSize
436       char *serializationInputC(0);
437       Py_ssize_t len;
438       if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
439         throw Exception("DistributedPythonNode problem in python pickle");
440       serializationInputCorba->length(len);
441       for(int i=0; i < len ; i++)
442         (*serializationInputCorba.get())[i]=serializationInputC[i];
443       Py_DECREF(serializationInput);
444   }
445
446   //get the list of output argument names
447   std::list<OutputPort *>::iterator iter;
448   Engines::listofstring myseq;
449   myseq.length(getNumberOfOutputPorts());
450   int pos=0;
451   for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); ++iter)
452     {
453       OutputPyPort *p=(OutputPyPort *)*iter;
454       myseq[pos]=p->getName().c_str();
455       DEBTRACE( "port name: " << p->getName() );
456       DEBTRACE( "port kind: " << p->edGetType()->kind() );
457       DEBTRACE( "port pos : " << pos );
458       pos++;
459     }
460   //===========================================================================
461   // Execute in remote Python node
462   //===========================================================================
463   DEBTRACE( "-----------------starting remote python invocation-----------------" );
464   Engines::pickledArgs *resultCorba(nullptr);
465   try
466     {
467       //pass outargsname and dict serialized
468       resultCorba=_pynode->execute(myseq,*(serializationInputCorba.get()));
469     }
470   catch( const SALOME::SALOME_Exception& ex )
471     {
472       std::string msg="Exception on remote python invocation";
473       msg += '\n';
474       msg += ex.details.text.in();
475       _errorDetails=msg;
476       throw Exception(msg);
477     }
478   if(!CORBA::is_nil(_pynode))
479     {
480       _pynode->UnRegister();
481     }
482   serializationInputCorba.reset(nullptr);
483   _pynode = Engines::PyScriptNode::_nil();
484   //
485   bool dummy;
486   Engines::Container_var cont(GetContainerObj(this,dummy));
487   cont->removePyScriptNode(getName().c_str());
488   DEBTRACE( "-----------------end of remote python invocation-----------------" );
489   //===========================================================================
490   // Get results, unpickle and put them in output ports
491   //===========================================================================
492   auto length(resultCorba->length());
493   char *resultCorbaC(reinterpret_cast<char *>(resultCorba->get_buffer()));
494   {
495       AutoGIL agil;
496       PyObject *args(0),*ob(0);
497       PyObject* resultPython=PyMemoryView_FromMemory(resultCorbaC,length,PyBUF_READ);
498       args = PyTuple_New(1);
499       PyTuple_SetItem(args,0,resultPython);
500       PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
501       delete resultCorba; resultCorba=nullptr;
502       Py_DECREF(args);
503
504       if (finalResult == NULL)
505         {
506           std::stringstream msg;
507           msg << "Conversion with pickle of output ports failed !";
508           msg << " : " << __FILE__ << ":" << __LINE__;
509           _errorDetails=msg.str();
510           throw YACS::ENGINE::ConversionException(msg.str());
511         }
512
513       DEBTRACE( "-----------------PythonNode::outputs-----------------" );
514       int nres=1;
515       if(finalResult == Py_None)
516         nres=0;
517       else if(PyTuple_Check(finalResult))
518         nres=PyTuple_Size(finalResult);
519
520       if(getNumberOfOutputPorts() != nres)
521         {
522           std::string msg="Number of output arguments : Mismatch between definition and execution";
523           Py_DECREF(finalResult);
524           _errorDetails=msg;
525           throw Exception(msg);
526         }
527
528       pos=0;
529       try
530       {
531           for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); ++iter)
532             {
533               OutputPyPort *p=(OutputPyPort *)*iter;
534               DEBTRACE( "port name: " << p->getName() );
535               DEBTRACE( "port kind: " << p->edGetType()->kind() );
536               DEBTRACE( "port pos : " << pos );
537               if(PyTuple_Check(finalResult))
538                 ob=PyTuple_GetItem(finalResult,pos) ;
539               else
540                 ob=finalResult;
541               DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
542               p->put(ob);
543               pos++;
544             }
545           Py_DECREF(finalResult);
546       }
547       catch(ConversionException& ex)
548       {
549           Py_DECREF(finalResult);
550           _errorDetails=ex.what();
551           throw;
552       }
553       if(_autoSqueeze)
554         squeezeMemoryRemote();
555   }
556   DEBTRACE( "++++++++++++++ ENDOF PyNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
557 }
558
559 void PythonNode::executeLocal()
560 {
561   DEBTRACE( "++++++++++++++ PyNode::executeLocal: " << getName() << " ++++++++++++++++++++" );
562   {
563     AutoGIL agil;
564
565     DEBTRACE( "---------------PyNode::inputs---------------" );
566     list<InputPort *>::iterator iter2;
567     for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
568       {
569         InputPyPort *p=(InputPyPort *)*iter2;
570         DEBTRACE( "port name: " << p->getName() );
571         DEBTRACE( "port kind: " << p->edGetType()->kind() );
572         PyObject* ob=p->getPyObj();
573         DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
574 #ifdef _DEVDEBUG_
575         PyObject_Print(ob,stderr,Py_PRINT_RAW);
576         cerr << endl;
577 #endif
578         int ier=PyDict_SetItemString(_context,p->getName().c_str(),ob);
579         DEBTRACE( "after PyDict_SetItemString:ob refcnt: " << ob->ob_refcnt );
580       }
581
582     DEBTRACE( "---------------End PyNode::inputs---------------" );
583
584     //calculation
585     DEBTRACE( "----------------PyNode::calculation---------------" );
586     DEBTRACE(  _script );
587     DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
588
589     std::ostringstream stream;
590     stream << "/tmp/PythonNode_";
591     stream << getpid();
592
593     PyObject* code=Py_CompileString(_script.c_str(), stream.str().c_str(), Py_file_input);
594     if(code == NULL)
595       {
596         _errorDetails=""; 
597         PyObject* new_stderr = newPyStdOut(_errorDetails);
598         PySys_SetObject((char*)"stderr", new_stderr);
599         PyErr_Print();
600         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
601         Py_DECREF(new_stderr);
602         throw Exception("Error during execution");
603       }
604     PyObject *res = PyEval_EvalCode(  code, _context, _context);
605
606     Py_DECREF(code);
607     Py_XDECREF(res);
608     DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
609     fflush(stdout);
610     fflush(stderr);
611     if(PyErr_Occurred ())
612       {
613         _errorDetails="";
614         PyObject* new_stderr = newPyStdOut(_errorDetails);
615         PySys_SetObject((char*)"stderr", new_stderr);
616         ofstream errorfile(stream.str().c_str());
617         if (errorfile.is_open())
618           {
619             errorfile << _script;
620             errorfile.close();
621           }
622         PyErr_Print();
623         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
624         Py_DECREF(new_stderr);
625         throw Exception("Error during execution");
626       }
627
628     DEBTRACE( "-----------------PyNode::outputs-----------------" );
629     list<OutputPort *>::iterator iter;
630     try
631     {
632         for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
633           {
634             OutputPyPort *p=(OutputPyPort *)*iter;
635             DEBTRACE( "port name: " << p->getName() );
636             DEBTRACE( "port kind: " << p->edGetType()->kind() );
637             PyObject *ob=PyDict_GetItemString(_context,p->getName().c_str());
638             if(ob==NULL)
639               {
640                 std::string msg="Error during execution: there is no variable ";
641                 msg=msg+p->getName()+" in node context";
642                 _errorDetails=msg;
643                 throw Exception(msg);
644               }
645             DEBTRACE( "PyNode::outputs::ob refcnt: " << ob->ob_refcnt );
646 #ifdef _DEVDEBUG_
647             PyObject_Print(ob,stderr,Py_PRINT_RAW);
648             cerr << endl;
649 #endif
650             p->put(ob);
651           }
652     }
653     catch(ConversionException& ex)
654     {
655         _errorDetails=ex.what();
656         throw;
657     }
658     if(_autoSqueeze)
659       squeezeMemory();
660     DEBTRACE( "-----------------End PyNode::outputs-----------------" );
661   }
662   DEBTRACE( "++++++++++++++ End PyNode::execute: " << getName() << " ++++++++++++++++++++" );
663 }
664
665 void PythonNode::squeezeMemorySafe()
666 {
667   AutoGIL agil;
668   if(_mode==PythonNode::REMOTE_NAME)
669     this->squeezeMemoryRemote();
670   else
671     this->squeezeMemory();
672 }
673   
674 void PythonNode::squeezeMemory()
675 {
676   for(auto p : _setOfInputPort)
677     {
678       PyDict_DelItemString(_context,p->getName().c_str());
679       InputPyPort *p2(static_cast<InputPyPort *>(p));
680       if(p2->canSafelySqueezeMemory())
681         p2->put(Py_None);
682     }
683   for(auto p : _setOfOutputPort)
684     {
685       PyDict_DelItemString(_context,p->getName().c_str());
686       OutputPyPort *p2(static_cast<OutputPyPort *>(p));
687       p2->putWithoutForward(Py_None);
688     }
689 }
690
691 void PythonNode::squeezeMemoryRemote()
692 {
693   for(auto p : _setOfInputPort)
694     {
695       InputPyPort *p2(static_cast<InputPyPort *>(p));
696       if(p2->canSafelySqueezeMemory())
697         p2->put(Py_None);
698     }
699   for(auto p : _setOfOutputPort)
700     {
701       OutputPyPort *p2(static_cast<OutputPyPort *>(p));
702       p2->putWithoutForward(Py_None);
703     }
704 }
705
706 std::string PythonNode::getContainerLog()
707 {
708   return PythonEntry::GetContainerLog(_mode,_container,this);
709 }
710
711 void PythonNode::shutdown(int level)
712 {
713   DEBTRACE("PythonNode::shutdown " << level);
714   if(_mode=="local")return;
715   if(_container)
716     {
717       if(!CORBA::is_nil(_pynode)) _pynode->UnRegister();
718       _pynode=Engines::PyScriptNode::_nil();
719       _container->shutdown(level);
720     }
721 }
722
723 Node *PythonNode::simpleClone(ComposedNode *father, bool editionOnly) const
724 {
725   return new PythonNode(*this,father);
726 }
727
728 void PythonNode::createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)
729 {
730   if(!CORBA::is_nil(_pynode))
731     _pynode->UnRegister();
732   _pynode=objContainer->createPyScriptNode(getName().c_str(),getScript().c_str());
733   _pynode->Register();
734 }
735
736 Engines::PyNodeBase_var PythonNode::retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const
737 {
738   Engines::PyScriptNode_var ret(objContainer->getDefaultPyScriptNode(getName().c_str()));
739   if(!CORBA::is_nil(ret))
740     {
741       ret->Register();
742     }
743   return Engines::PyNodeBase::_narrow(ret);
744 }
745
746 void PythonNode::assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)
747 {
748   if(!CORBA::is_nil(_pynode))
749     {
750       Engines::PyScriptNode_var tmpp(Engines::PyScriptNode::_narrow(remoteInterp));
751       if(_pynode->_is_equivalent(tmpp))
752         {
753           _pynode->UnRegister();
754           return ;
755         }
756     }
757   if(!CORBA::is_nil(_pynode))
758     _pynode->UnRegister();
759   _pynode=Engines::PyScriptNode::_narrow(remoteInterp);
760 }
761
762 Engines::PyNodeBase_var PythonNode::getRemoteInterpreterHandle()
763 {
764   return Engines::PyNodeBase::_narrow(_pynode);
765 }
766
767 //! Create a new node of same type with a given name
768 PythonNode* PythonNode::cloneNode(const std::string& name)
769 {
770   PythonNode* n=new PythonNode(name);
771   n->setScript(_script);
772   list<InputPort *>::iterator iter;
773   for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
774     {
775       InputPyPort *p=(InputPyPort *)*iter;
776       DEBTRACE( "port name: " << p->getName() );
777       DEBTRACE( "port kind: " << p->edGetType()->kind() );
778       n->edAddInputPort(p->getName(),p->edGetType());
779     }
780   list<OutputPort *>::iterator iter2;
781   for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
782     {
783       OutputPyPort *p=(OutputPyPort *)*iter2;
784       DEBTRACE( "port name: " << p->getName() );
785       DEBTRACE( "port kind: " << p->edGetType()->kind() );
786       n->edAddOutputPort(p->getName(),p->edGetType());
787     }
788   return n;
789 }
790
791 void PythonNode::applyDPLScope(ComposedNode *gfn)
792 {
793   std::vector< std::pair<std::string,int> > ret(getDPLScopeInfo(gfn));
794   if(ret.empty())
795     return ;
796   //
797   PyObject *ob(0);
798   {
799     AutoGIL agil;
800     std::size_t sz(ret.size());
801     ob=PyList_New(sz);
802     for(std::size_t i=0;i<sz;i++)
803       {
804         const std::pair<std::string,int>& p(ret[i]);
805         PyObject *elt(PyTuple_New(2));
806         PyTuple_SetItem(elt,0,PyUnicode_FromString(p.first.c_str()));
807         PyTuple_SetItem(elt,1,PyLong_FromLong(p.second));
808         PyList_SetItem(ob,i,elt);
809       }
810   }
811   if(_mode==REMOTE_NAME)
812     {
813       Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);
814       {
815         AutoGIL agil;
816         PyObject *serializationInput(PyObject_CallFunctionObjArgs(_pyfuncSimpleSer,ob,NULL));
817         Py_XDECREF(ob);
818         char *serializationInputC(0);
819         Py_ssize_t len;
820         if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
821           throw Exception("DistributedPythonNode problem in python pickle");
822         serializationInputCorba->length(len);
823         for(int i=0; i < len ; i++)
824           serializationInputCorba[i]=serializationInputC[i];
825         Py_XDECREF(serializationInput);
826       }
827       _pynode->defineNewCustomVar(DPL_INFO_NAME,serializationInputCorba);
828     }
829   else
830     {
831       AutoGIL agil;
832       PyDict_SetItemString(_context,DPL_INFO_NAME,ob);
833       Py_XDECREF(ob);
834     }
835 }
836
837 PyFuncNode::PyFuncNode(const PyFuncNode& other, ComposedNode *father):InlineFuncNode(other,father),_pyfunc(0)
838 {
839   _implementation = PythonNode::IMPL_NAME;
840   {
841     AutoGIL agil;
842     _context=PyDict_New();
843     DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
844     if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
845       {
846         stringstream msg;
847         msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
848         _errorDetails=msg.str();
849         throw Exception(msg.str());
850       }
851   }
852 }
853
854 PyFuncNode::PyFuncNode(const std::string& name): InlineFuncNode(name),_pyfunc(0)
855 {
856
857   _implementation = PythonNode::IMPL_NAME;
858   DEBTRACE( "PyFuncNode::PyFuncNode " << name );
859   {
860     AutoGIL agil;
861     _context=PyDict_New();
862     DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
863     if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
864       {
865         stringstream msg;
866         msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
867         _errorDetails=msg.str();
868         throw Exception(msg.str());
869       }
870   }
871 }
872
873 PyFuncNode::~PyFuncNode()
874 {
875   if(!CORBA::is_nil(_pynode))
876     {
877       _pynode->UnRegister();
878     }
879 }
880
881 void PyFuncNode::init(bool start)
882 {
883   initCommonPartWithoutStateManagement(start);
884   if(_state == YACS::DISABLED)
885     {
886       exDisabledState(); // to refresh propagation of DISABLED state
887       return ;
888     }
889   if(start) //complete initialization
890     setState(YACS::READY);
891   else if(_state > YACS::LOADED)// WARNING FuncNode has internal vars (CEA usecase) ! Partial initialization (inside a loop). Exclusivity of funcNode.
892     setState(YACS::TORECONNECT);
893 }
894
895 void PyFuncNode::checkBasicConsistency() const throw(YACS::Exception)
896 {
897   DEBTRACE("checkBasicConsistency");
898   InlineFuncNode::checkBasicConsistency();
899   {
900     AutoGIL agil;
901     PyObject* res;
902     res=Py_CompileString(_script.c_str(),getName().c_str(),Py_file_input);
903     if(res == NULL)
904       {
905         std::string error="";
906         PyObject* new_stderr = newPyStdOut(error);
907         PySys_SetObject((char*)"stderr", new_stderr);
908         PyErr_Print();
909         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
910         Py_DECREF(new_stderr);
911         throw Exception(error);
912       }
913     else
914       Py_XDECREF(res);
915   }
916 }
917
918 void PyFuncNode::load()
919 {
920   DEBTRACE( "---------------PyfuncNode::load function---------------" );
921   if(_mode==PythonNode::REMOTE_NAME)
922     loadRemote();
923   else
924     loadLocal();
925 }
926
927 void PyFuncNode::loadRemote()
928 {
929   commonRemoteLoad(this);
930 }
931
932 void PyFuncNode::loadLocal()
933 {
934   DEBTRACE( "---------------PyFuncNode::load function " << getName() << " ---------------" );
935   DEBTRACE(  _script );
936
937 #ifdef _DEVDEBUG_
938   list<OutputPort *>::iterator iter;
939   for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
940     {
941       OutputPyPort *p=(OutputPyPort *)*iter;
942       DEBTRACE( "port name: " << p->getName() );
943       DEBTRACE( "port kind: " << p->edGetType()->kind() );
944     }
945 #endif
946
947   {
948     AutoGIL agil;
949     DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
950
951     std::ostringstream stream;
952     stream << "/tmp/PythonNode_";
953     stream << getpid();
954
955     PyObject* code=Py_CompileString(_script.c_str(), stream.str().c_str(), Py_file_input);
956     if(code == NULL)
957       {
958         _errorDetails="";
959         PyObject* new_stderr = newPyStdOut(_errorDetails);
960         PySys_SetObject((char*)"stderr", new_stderr);
961         PyErr_Print();
962         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
963         Py_DECREF(new_stderr);
964         throw Exception("Error during execution");
965       }
966     PyObject *res = PyEval_EvalCode( code, _context, _context);
967     Py_DECREF(code);
968     Py_XDECREF(res);
969
970     DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
971     if(PyErr_Occurred ())
972       {
973         _errorDetails="";
974         PyObject* new_stderr = newPyStdOut(_errorDetails);
975         PySys_SetObject((char*)"stderr", new_stderr);
976         ofstream errorfile(stream.str().c_str());
977         if (errorfile.is_open())
978           {
979             errorfile << _script;
980             errorfile.close();
981           }
982         PyErr_Print();
983         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
984         Py_DECREF(new_stderr);
985         throw Exception("Error during execution");
986         return;
987       }
988     _pyfunc=PyDict_GetItemString(_context,_fname.c_str());
989     DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
990     if(_pyfunc == NULL)
991       {
992         _errorDetails="";
993         PyObject* new_stderr = newPyStdOut(_errorDetails);
994         PySys_SetObject((char*)"stderr", new_stderr);
995         PyErr_Print();
996         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
997         Py_DECREF(new_stderr);
998         throw Exception("Error during execution");
999       }
1000     DEBTRACE( "---------------End PyFuncNode::load function---------------" );
1001   }
1002 }
1003
1004 void PyFuncNode::execute()
1005 {
1006   if(_mode==PythonNode::REMOTE_NAME)
1007     executeRemote();
1008   else
1009     executeLocal();
1010 }
1011
1012 void PyFuncNode::executeRemote()
1013 {
1014   DEBTRACE( "++++++++++++++ PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
1015   if(!_pyfuncSer)
1016     throw Exception("DistributedPythonNode badly loaded");
1017   //
1018   if(dynamic_cast<HomogeneousPoolContainer *>(getContainer()))
1019     {
1020       bool dummy;
1021       commonRemoteLoadPart2(this,dummy);
1022       _pynode->executeAnotherPieceOfCode(getScript().c_str());
1023     }
1024   //
1025   Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);;
1026   {
1027       AutoGIL agil;
1028       PyObject *ob(0);
1029       //===========================================================================
1030       // Get inputs in input ports, build a Python tuple and pickle it
1031       //===========================================================================
1032       PyObject *args(PyTuple_New(getNumberOfInputPorts()));
1033       int pos(0);
1034       for(std::list<InputPort *>::iterator iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++,pos++)
1035         {
1036           InputPyPort *p=(InputPyPort *)*iter2;
1037           ob=p->getPyObj();
1038           Py_INCREF(ob);
1039           PyTuple_SetItem(args,pos,ob);
1040         }
1041 #ifdef _DEVDEBUG_
1042       PyObject_Print(args,stderr,Py_PRINT_RAW);
1043       std::cerr << endl;
1044 #endif
1045       PyObject *serializationInput=PyObject_CallObject(_pyfuncSer,args);
1046       Py_DECREF(args);
1047       //The pickled string may contain NULL characters so use PyString_AsStringAndSize
1048       char *serializationInputC(0);
1049       Py_ssize_t len;
1050       if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
1051         throw Exception("DistributedPythonNode problem in python pickle");
1052
1053       serializationInputCorba->length(len);
1054       for(int i=0; i < len ; i++)
1055         serializationInputCorba[i]=serializationInputC[i];
1056       Py_DECREF(serializationInput);
1057   }
1058
1059   //===========================================================================
1060   // Execute in remote Python node
1061   //===========================================================================
1062   DEBTRACE( "-----------------starting remote python invocation-----------------" );
1063   Engines::pickledArgs_var resultCorba;
1064   try
1065     {
1066       resultCorba=_pynode->execute(getFname().c_str(),serializationInputCorba);
1067     }
1068   catch( const SALOME::SALOME_Exception& ex )
1069     {
1070       std::string msg="Exception on remote python invocation";
1071       msg += '\n';
1072       msg += ex.details.text.in();
1073       _errorDetails=msg;
1074       throw Exception(msg);
1075     }
1076   DEBTRACE( "-----------------end of remote python invocation-----------------" );
1077   //===========================================================================
1078   // Get results, unpickle and put them in output ports
1079   //===========================================================================
1080   char *resultCorbaC=new char[resultCorba->length()+1];
1081   resultCorbaC[resultCorba->length()]='\0';
1082   for(int i=0;i<resultCorba->length();i++)
1083     resultCorbaC[i]=resultCorba[i];
1084
1085   {
1086       AutoGIL agil;
1087
1088       PyObject *resultPython(PyBytes_FromStringAndSize(resultCorbaC,resultCorba->length()));
1089       delete [] resultCorbaC;
1090       PyObject *args(PyTuple_New(1)),*ob(0);
1091       PyTuple_SetItem(args,0,resultPython);
1092       PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
1093       Py_DECREF(args);
1094
1095       DEBTRACE( "-----------------PythonNode::outputs-----------------" );
1096       int nres=1;
1097       if(finalResult == Py_None)
1098         nres=0;
1099       else if(PyTuple_Check(finalResult))
1100         nres=PyTuple_Size(finalResult);
1101
1102       if(getNumberOfOutputPorts() != nres)
1103         {
1104           std::string msg="Number of output arguments : Mismatch between definition and execution";
1105           Py_DECREF(finalResult);
1106           _errorDetails=msg;
1107           throw Exception(msg);
1108         }
1109
1110       try
1111       {
1112           int pos(0);
1113           for(std::list<OutputPort *>::iterator iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++, pos++)
1114             {
1115               OutputPyPort *p=(OutputPyPort *)*iter;
1116               DEBTRACE( "port name: " << p->getName() );
1117               DEBTRACE( "port kind: " << p->edGetType()->kind() );
1118               DEBTRACE( "port pos : " << pos );
1119               if(PyTuple_Check(finalResult))
1120                 ob=PyTuple_GetItem(finalResult,pos) ;
1121               else
1122                 ob=finalResult;
1123               DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1124               p->put(ob);
1125             }
1126           Py_DECREF(finalResult);
1127       }
1128       catch(ConversionException& ex)
1129       {
1130           Py_DECREF(finalResult);
1131           _errorDetails=ex.what();
1132           throw;
1133       }
1134   }
1135
1136   DEBTRACE( "++++++++++++++ ENDOF PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
1137 }
1138
1139 void PyFuncNode::executeLocal()
1140 {
1141   DEBTRACE( "++++++++++++++ PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
1142
1143   int pos=0;
1144   PyObject* ob;
1145   if(!_pyfunc)throw Exception("PyFuncNode badly loaded");
1146   {
1147       AutoGIL agil;
1148       DEBTRACE( "---------------PyFuncNode::inputs---------------" );
1149       PyObject* args = PyTuple_New(getNumberOfInputPorts()) ;
1150       list<InputPort *>::iterator iter2;
1151       for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
1152         {
1153           InputPyPort *p=(InputPyPort *)*iter2;
1154           DEBTRACE( "port name: " << p->getName() );
1155           DEBTRACE( "port kind: " << p->edGetType()->kind() );
1156           ob=p->getPyObj();
1157 #ifdef _DEVDEBUG_
1158           PyObject_Print(ob,stderr,Py_PRINT_RAW);
1159           cerr << endl;
1160 #endif
1161           DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1162           Py_INCREF(ob);
1163           PyTuple_SetItem(args,pos,ob);
1164           DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1165           pos++;
1166         }
1167       DEBTRACE( "---------------End PyFuncNode::inputs---------------" );
1168
1169       DEBTRACE( "----------------PyFuncNode::calculation---------------" );
1170 #ifdef _DEVDEBUG_
1171       PyObject_Print(_pyfunc,stderr,Py_PRINT_RAW);
1172       cerr << endl;
1173       PyObject_Print(args,stderr,Py_PRINT_RAW);
1174       cerr << endl;
1175 #endif
1176       DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1177       PyObject* result = PyObject_CallObject( _pyfunc , args ) ;
1178       DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1179       Py_DECREF(args);
1180       fflush(stdout);
1181       fflush(stderr);
1182       if(result == NULL)
1183         {
1184           _errorDetails="";
1185           PyObject* new_stderr = newPyStdOut(_errorDetails);
1186           PySys_SetObject((char*)"stderr", new_stderr);
1187           std::ostringstream stream;
1188           stream << "/tmp/PythonNode_";
1189           stream << getpid();
1190           ofstream errorfile(stream.str().c_str());
1191           if (errorfile.is_open())
1192             {
1193               errorfile << _script;
1194               errorfile.close();
1195             }
1196           PyErr_Print();
1197           PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1198           Py_DECREF(new_stderr);
1199           throw Exception("Error during execution");
1200         }
1201       DEBTRACE( "----------------End PyFuncNode::calculation---------------" );
1202
1203       DEBTRACE( "-----------------PyFuncNode::outputs-----------------" );
1204       int nres=1;
1205       if(result == Py_None)
1206         nres=0;
1207       else if(PyTuple_Check(result))
1208         nres=PyTuple_Size(result);
1209
1210       if(getNumberOfOutputPorts() != nres)
1211         {
1212           std::string msg="Number of output arguments : Mismatch between definition and execution";
1213           Py_DECREF(result);
1214           _errorDetails=msg;
1215           throw Exception(msg);
1216         }
1217
1218       pos=0;
1219 #ifdef _DEVDEBUG_
1220       PyObject_Print(result,stderr,Py_PRINT_RAW);
1221       cerr << endl;
1222 #endif
1223       list<OutputPort *>::iterator iter;
1224       try
1225       {
1226           for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
1227             {
1228               OutputPyPort *p=(OutputPyPort *)*iter;
1229               DEBTRACE( "port name: " << p->getName() );
1230               DEBTRACE( "port kind: " << p->edGetType()->kind() );
1231               DEBTRACE( "port pos : " << pos );
1232               if(PyTuple_Check(result))ob=PyTuple_GetItem(result,pos) ;
1233               else ob=result;
1234               DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1235 #ifdef _DEVDEBUG_
1236               PyObject_Print(ob,stderr,Py_PRINT_RAW);
1237               cerr << endl;
1238 #endif
1239               p->put(ob);
1240               pos++;
1241             }
1242       }
1243       catch(ConversionException& ex)
1244       {
1245           Py_DECREF(result);
1246           _errorDetails=ex.what();
1247           throw;
1248       }
1249       DEBTRACE( "-----------------End PyFuncNode::outputs-----------------" );
1250       Py_DECREF(result);
1251   }
1252   DEBTRACE( "++++++++++++++ End PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
1253 }
1254
1255 Node *PyFuncNode::simpleClone(ComposedNode *father, bool editionOnly) const
1256 {
1257   return new PyFuncNode(*this,father);
1258 }
1259
1260 void PyFuncNode::createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)
1261 {
1262   if(!CORBA::is_nil(_pynode))
1263     _pynode->UnRegister();
1264   _pynode=objContainer->createPyNode(getName().c_str(),getScript().c_str());
1265 }
1266
1267 Engines::PyNodeBase_var PyFuncNode::retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const
1268 {
1269   Engines::PyNode_var ret(objContainer->getDefaultPyNode(getName().c_str()));
1270   if(!CORBA::is_nil(ret))
1271     {
1272       ret->Register();
1273     }
1274   return Engines::PyNodeBase::_narrow(ret);
1275 }
1276
1277 void PyFuncNode::assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)
1278 {
1279   if(!CORBA::is_nil(_pynode))
1280     {
1281       Engines::PyNode_var tmpp(Engines::PyNode::_narrow(remoteInterp));
1282       if(_pynode->_is_equivalent(tmpp))
1283         return ;
1284     }
1285   if(!CORBA::is_nil(_pynode))
1286     _pynode->UnRegister();
1287   _pynode=Engines::PyNode::_narrow(remoteInterp);
1288 }
1289
1290 Engines::PyNodeBase_var PyFuncNode::getRemoteInterpreterHandle()
1291 {
1292   return Engines::PyNodeBase::_narrow(_pynode);
1293 }
1294
1295 //! Create a new node of same type with a given name
1296 PyFuncNode* PyFuncNode::cloneNode(const std::string& name)
1297 {
1298   PyFuncNode* n=new PyFuncNode(name);
1299   n->setScript(_script);
1300   n->setFname(_fname);
1301   list<InputPort *>::iterator iter;
1302   for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
1303     {
1304       InputPyPort *p=(InputPyPort *)*iter;
1305       n->edAddInputPort(p->getName(),p->edGetType());
1306     }
1307   list<OutputPort *>::iterator iter2;
1308   for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
1309     {
1310       OutputPyPort *p=(OutputPyPort *)*iter2;
1311       n->edAddOutputPort(p->getName(),p->edGetType());
1312     }
1313   return n;
1314 }
1315
1316 std::string PyFuncNode::getContainerLog()
1317 {
1318   return PythonEntry::GetContainerLog(_mode,_container,this);
1319 }
1320
1321 void PyFuncNode::shutdown(int level)
1322 {
1323   DEBTRACE("PyFuncNode::shutdown " << level);
1324   if(_mode=="local")return;
1325   if(_container)
1326     {
1327       if(!CORBA::is_nil(_pynode)) _pynode->UnRegister();
1328       _pynode=Engines::PyNode::_nil();
1329       _container->shutdown(level);
1330     }
1331 }
1332