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