Salome HOME
Addition of non regression tests on HPContainers.
[modules/yacs.git] / src / runtime / PythonNode.cxx
1 // Copyright (C) 2006-2014  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 PythonNode::IMPL_NAME[]="Python";
52 const char PythonNode::KIND[]="Python";
53
54 const char PythonNode::SCRIPT_FOR_SERIALIZATION[]="import cPickle\n"
55     "def pickleForDistPyth2009(kws):\n"
56     "  return cPickle.dumps(((),kws),-1)\n"
57     "\n"
58     "def unPickleForDistPyth2009(st):\n"
59     "  args=cPickle.loads(st)\n"
60     "  return args\n";
61
62 const char PyFuncNode::SCRIPT_FOR_SERIALIZATION[]="import cPickle\n"
63     "def pickleForDistPyth2009(*args,**kws):\n"
64     "  return cPickle.dumps((args,kws),-1)\n"
65     "\n"
66     "def unPickleForDistPyth2009(st):\n"
67     "  args=cPickle.loads(st)\n"
68     "  return args\n";
69
70 PythonEntry::PythonEntry():_context(0),_pyfuncSer(0),_pyfuncUnser(0)
71 {
72 }
73
74 PythonEntry::~PythonEntry()
75 {
76   AutoGIL agil;
77   DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
78   // not Py_XDECREF of _pyfuncUnser because it is returned by PyDict_GetItem -> borrowed
79   // not Py_XDECREF of _pyfuncSer because it is returned by PyDict_GetItem -> borrowed
80   Py_XDECREF(_context);
81 }
82
83 void PythonEntry::commonRemoteLoad(InlineNode *reqNode)
84 {
85   DEBTRACE( "---------------PythonEntry::CommonRemoteLoad function---------------" );
86   Container *container(reqNode->getContainer());
87   bool isContAlreadyStarted(false);
88   if(container)
89     {
90       isContAlreadyStarted=container->isAlreadyStarted(reqNode);
91       if(!isContAlreadyStarted)
92         {
93           try
94           {
95               container->start(reqNode);
96           }
97           catch(Exception& e)
98           {
99               reqNode->setErrorDetails(e.what());
100               throw e;
101           }
102         }
103     }
104   else
105     {
106       std::string what("PythonEntry::CommonRemoteLoad : a load operation requested on \"");
107       what+=reqNode->getName(); what+="\" with no container specified.";
108       reqNode->setErrorDetails(what);
109       throw Exception(what);
110     }
111   Engines::Container_var objContainer=Engines::Container::_nil();
112   if(!container)
113     throw Exception("No container specified !");
114   SalomeContainer *containerCast0(dynamic_cast<SalomeContainer *>(container));
115   SalomeHPContainer *containerCast1(dynamic_cast<SalomeHPContainer *>(container));
116   if(containerCast0)
117     objContainer=containerCast0->getContainerPtr(reqNode);
118   else if(containerCast1)
119     {
120       YACS::BASES::AutoCppPtr<SalomeContainerTmpForHP> tmpCont(SalomeContainerTmpForHP::BuildFrom(containerCast1,reqNode));
121       objContainer=tmpCont->getContainerPtr(reqNode);
122     }
123   else
124     throw Exception("Unrecognized type of container ! Salome one is expected for PythonNode/PyFuncNode !");
125   if(CORBA::is_nil(objContainer))
126     throw Exception("Container corba pointer is NULL for PythonNode !");
127   bool isInitializeRequested(false);
128   try
129   {
130       if(containerCast0)
131         {
132           createRemoteAdaptedPyInterpretor(objContainer);
133         }
134       else
135         {
136           Engines::PyNodeBase_var dftPyScript(retrieveDftRemotePyInterpretorIfAny(objContainer));
137           if(CORBA::is_nil(dftPyScript))
138             {
139               isInitializeRequested=true;
140               createRemoteAdaptedPyInterpretor(objContainer);
141             }
142           else
143             assignRemotePyInterpretor(dftPyScript);
144         }
145   }
146   catch( const SALOME::SALOME_Exception& ex )
147   {
148       std::string msg="Exception on remote python node creation ";
149       msg += '\n';
150       msg += ex.details.text.in();
151       reqNode->setErrorDetails(msg);
152       throw Exception(msg);
153   }
154   Engines::PyNodeBase_var pynode(getRemoteInterpreterHandle());
155   if(CORBA::is_nil(pynode))
156     throw Exception("In PythonNode the ref in NULL ! ");
157   ///
158   {
159       AutoGIL agil;
160       const char *picklizeScript(getSerializationScript());
161       PyObject *res=PyRun_String(picklizeScript,Py_file_input,_context,_context);
162       if(res == NULL)
163         {
164           std::string errorDetails;
165           PyObject* new_stderr = newPyStdOut(errorDetails);
166           reqNode->setErrorDetails(errorDetails);
167           PySys_SetObject((char*)"stderr", new_stderr);
168           PyErr_Print();
169           PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
170           Py_DECREF(new_stderr);
171           throw Exception("Error during load");
172         }
173       Py_DECREF(res);
174       _pyfuncSer=PyDict_GetItemString(_context,"pickleForDistPyth2009");
175       _pyfuncUnser=PyDict_GetItemString(_context,"unPickleForDistPyth2009");
176       if(_pyfuncSer == NULL)
177         {
178           std::string errorDetails;
179           PyObject *new_stderr(newPyStdOut(errorDetails));
180           reqNode->setErrorDetails(errorDetails);
181           PySys_SetObject((char*)"stderr", new_stderr);
182           PyErr_Print();
183           PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
184           Py_DECREF(new_stderr);
185           throw Exception("Error during load");
186         }
187       if(_pyfuncUnser == NULL)
188         {
189           std::string errorDetails;
190           PyObject *new_stderr(newPyStdOut(errorDetails));
191           reqNode->setErrorDetails(errorDetails);
192           PySys_SetObject((char*)"stderr", new_stderr);
193           PyErr_Print();
194           PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
195           Py_DECREF(new_stderr);
196           throw Exception("Error during load");
197         }
198       if(isInitializeRequested)
199         {//This one is called only once at initialization in the container if an init-script is specified.
200           try
201           {
202               std::string zeInitScriptKey(container->getProperty(HomogeneousPoolContainer::INITIALIZE_SCRIPT_KEY));
203               if(!zeInitScriptKey.empty())
204                 pynode->executeAnotherPieceOfCode(zeInitScriptKey.c_str());
205           }
206           catch( const SALOME::SALOME_Exception& ex )
207           {
208               std::string msg="Exception on PythonNode::loadRemote python invocation of initializisation py script !";
209               msg += '\n';
210               msg += ex.details.text.in();
211               reqNode->setErrorDetails(msg);
212               throw Exception(msg);
213           }
214         }
215       DEBTRACE( "---------------End PyNode::loadRemote function---------------" );
216   }
217 }
218
219 PythonNode::PythonNode(const PythonNode& other, ComposedNode *father):InlineNode(other,father)
220 {
221   _implementation=IMPL_NAME;
222   {
223     AutoGIL agil;
224     _context=PyDict_New();
225     if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
226       {
227         stringstream msg;
228         msg << "Impossible to set builtins" << __FILE__ << ":" << __LINE__;
229         _errorDetails=msg.str();
230         throw Exception(msg.str());
231       }
232   }
233 }
234
235 PythonNode::PythonNode(const std::string& name):InlineNode(name)
236 {
237   _implementation=IMPL_NAME;
238   {
239     AutoGIL agil;
240     _context=PyDict_New();
241     if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
242       {
243         stringstream msg;
244         msg << "Impossible to set builtins" << __FILE__ << ":" << __LINE__;
245         _errorDetails=msg.str();
246         throw Exception(msg.str());
247       }
248   }
249 }
250
251 PythonNode::~PythonNode()
252 {
253   if(!CORBA::is_nil(_pynode))
254     {
255       _pynode->UnRegister();
256     }
257 }
258
259 void PythonNode::checkBasicConsistency() const throw(YACS::Exception)
260 {
261   DEBTRACE("checkBasicConsistency");
262   InlineNode::checkBasicConsistency();
263   {
264     AutoGIL agil;
265     PyObject* res;
266     res=Py_CompileString(_script.c_str(),getName().c_str(),Py_file_input);
267     if(res == NULL)
268       {
269         std::string error="";
270         PyObject* new_stderr = newPyStdOut(error);
271         PySys_SetObject((char*)"stderr", new_stderr);
272         PyErr_Print();
273         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
274         Py_DECREF(new_stderr);
275         throw Exception(error);
276       }
277     else
278       Py_XDECREF(res);
279   }
280 }
281
282 void PythonNode::load()
283 {
284   DEBTRACE( "---------------PyNode::load function---------------" );
285   if(_mode=="remote")
286     loadRemote();
287   else
288     loadLocal();
289 }
290
291 void PythonNode::loadLocal()
292 {
293   DEBTRACE( "---------------PyNode::loadLocal function---------------" );
294   // do nothing
295 }
296
297 void PythonNode::loadRemote()
298 {
299   commonRemoteLoad(this);
300 }
301
302 void PythonNode::execute()
303 {
304   if(_mode=="remote")
305     executeRemote();
306   else
307     executeLocal();
308 }
309
310 void PythonNode::executeRemote()
311 {
312   DEBTRACE( "++++++++++++++ PyNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
313   if(!_pyfuncSer)
314     throw Exception("DistributedPythonNode badly loaded");
315   Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);
316   {
317       AutoGIL agil;
318       PyObject *args(0),*ob(0);
319       //===========================================================================
320       // Get inputs in input ports, build a Python dict and pickle it
321       //===========================================================================
322       args = PyDict_New();
323       std::list<InputPort *>::iterator iter2;
324       int pos(0);
325       for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); ++iter2)
326         {
327           InputPyPort *p=(InputPyPort *)*iter2;
328           ob=p->getPyObj();
329           PyDict_SetItemString(args,p->getName().c_str(),ob);
330           pos++;
331         }
332 #ifdef _DEVDEBUG_
333       PyObject_Print(args,stderr,Py_PRINT_RAW);
334       std::cerr << endl;
335 #endif
336       PyObject *serializationInput(PyObject_CallFunctionObjArgs(_pyfuncSer,args,NULL));
337       Py_DECREF(args);
338       //The pickled string may contain NULL characters so use PyString_AsStringAndSize
339       char *serializationInputC(0);
340       Py_ssize_t len;
341       if (PyString_AsStringAndSize(serializationInput, &serializationInputC, &len))
342         throw Exception("DistributedPythonNode problem in python pickle");
343       serializationInputCorba->length(len);
344       for(int i=0; i < len ; i++)
345         serializationInputCorba[i]=serializationInputC[i];
346       Py_DECREF(serializationInput);
347   }
348
349   //get the list of output argument names
350   std::list<OutputPort *>::iterator iter;
351   Engines::listofstring myseq;
352   myseq.length(getNumberOfOutputPorts());
353   int pos=0;
354   for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); ++iter)
355     {
356       OutputPyPort *p=(OutputPyPort *)*iter;
357       myseq[pos]=p->getName().c_str();
358       DEBTRACE( "port name: " << p->getName() );
359       DEBTRACE( "port kind: " << p->edGetType()->kind() );
360       DEBTRACE( "port pos : " << pos );
361       pos++;
362     }
363   //===========================================================================
364   // Execute in remote Python node
365   //===========================================================================
366   DEBTRACE( "-----------------starting remote python invocation-----------------" );
367   Engines::pickledArgs_var resultCorba;
368   try
369     {
370       //pass outargsname and dict serialized
371       resultCorba=_pynode->execute(myseq,serializationInputCorba);
372     }
373   catch( const SALOME::SALOME_Exception& ex )
374     {
375       std::string msg="Exception on remote python invocation";
376       msg += '\n';
377       msg += ex.details.text.in();
378       _errorDetails=msg;
379       throw Exception(msg);
380     }
381   DEBTRACE( "-----------------end of remote python invocation-----------------" );
382   //===========================================================================
383   // Get results, unpickle and put them in output ports
384   //===========================================================================
385   char *resultCorbaC=new char[resultCorba->length()+1];
386   resultCorbaC[resultCorba->length()]='\0';
387   for(int i=0;i<resultCorba->length();i++)
388     resultCorbaC[i]=resultCorba[i];
389
390   {
391       AutoGIL agil;
392       PyObject *args(0),*ob(0);
393       PyObject* resultPython=PyString_FromStringAndSize(resultCorbaC,resultCorba->length());
394       delete [] resultCorbaC;
395       args = PyTuple_New(1);
396       PyTuple_SetItem(args,0,resultPython);
397       PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
398       Py_DECREF(args);
399
400       if (finalResult == NULL)
401         {
402           std::stringstream msg;
403           msg << "Conversion with pickle of output ports failed !";
404           msg << " : " << __FILE__ << ":" << __LINE__;
405           _errorDetails=msg.str();
406           throw YACS::ENGINE::ConversionException(msg.str());
407         }
408
409       DEBTRACE( "-----------------PythonNode::outputs-----------------" );
410       int nres=1;
411       if(finalResult == Py_None)
412         nres=0;
413       else if(PyTuple_Check(finalResult))
414         nres=PyTuple_Size(finalResult);
415
416       if(getNumberOfOutputPorts() != nres)
417         {
418           std::string msg="Number of output arguments : Mismatch between definition and execution";
419           Py_DECREF(finalResult);
420           _errorDetails=msg;
421           throw Exception(msg);
422         }
423
424       pos=0;
425       try
426       {
427           for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); ++iter)
428             {
429               OutputPyPort *p=(OutputPyPort *)*iter;
430               DEBTRACE( "port name: " << p->getName() );
431               DEBTRACE( "port kind: " << p->edGetType()->kind() );
432               DEBTRACE( "port pos : " << pos );
433               if(PyTuple_Check(finalResult))
434                 ob=PyTuple_GetItem(finalResult,pos) ;
435               else
436                 ob=finalResult;
437               DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
438               p->put(ob);
439               pos++;
440             }
441           Py_DECREF(finalResult);
442       }
443       catch(ConversionException& ex)
444       {
445           Py_DECREF(finalResult);
446           _errorDetails=ex.what();
447           throw;
448       }
449   }
450   DEBTRACE( "++++++++++++++ ENDOF PyNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
451 }
452
453 void PythonNode::executeLocal()
454 {
455   DEBTRACE( "++++++++++++++ PyNode::executeLocal: " << getName() << " ++++++++++++++++++++" );
456   {
457     AutoGIL agil;
458
459     DEBTRACE( "---------------PyNode::inputs---------------" );
460     list<InputPort *>::iterator iter2;
461     for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
462       {
463         InputPyPort *p=(InputPyPort *)*iter2;
464         DEBTRACE( "port name: " << p->getName() );
465         DEBTRACE( "port kind: " << p->edGetType()->kind() );
466         PyObject* ob=p->getPyObj();
467         DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
468 #ifdef _DEVDEBUG_
469         PyObject_Print(ob,stderr,Py_PRINT_RAW);
470         cerr << endl;
471 #endif
472         int ier=PyDict_SetItemString(_context,p->getName().c_str(),ob);
473         DEBTRACE( "after PyDict_SetItemString:ob refcnt: " << ob->ob_refcnt );
474       }
475
476     DEBTRACE( "---------------End PyNode::inputs---------------" );
477
478     //calculation
479     DEBTRACE( "----------------PyNode::calculation---------------" );
480     DEBTRACE(  _script );
481     DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
482
483     std::ostringstream stream;
484     stream << "/tmp/PythonNode_";
485     stream << getpid();
486
487     PyObject* code=Py_CompileString(_script.c_str(), stream.str().c_str(), Py_file_input);
488     if(code == NULL)
489       {
490         _errorDetails="";
491         PyObject* new_stderr = newPyStdOut(_errorDetails);
492         PySys_SetObject((char*)"stderr", new_stderr);
493         PyErr_Print();
494         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
495         Py_DECREF(new_stderr);
496         throw Exception("Error during execution");
497       }
498     PyObject *res = PyEval_EvalCode((PyCodeObject *)code, _context, _context);
499
500     Py_DECREF(code);
501     Py_XDECREF(res);
502     DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
503     fflush(stdout);
504     fflush(stderr);
505     if(PyErr_Occurred ())
506       {
507         _errorDetails="";
508         PyObject* new_stderr = newPyStdOut(_errorDetails);
509         PySys_SetObject((char*)"stderr", new_stderr);
510         ofstream errorfile(stream.str().c_str());
511         if (errorfile.is_open())
512           {
513             errorfile << _script;
514             errorfile.close();
515           }
516         PyErr_Print();
517         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
518         Py_DECREF(new_stderr);
519         throw Exception("Error during execution");
520       }
521
522     DEBTRACE( "-----------------PyNode::outputs-----------------" );
523     list<OutputPort *>::iterator iter;
524     try
525     {
526         for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
527           {
528             OutputPyPort *p=(OutputPyPort *)*iter;
529             DEBTRACE( "port name: " << p->getName() );
530             DEBTRACE( "port kind: " << p->edGetType()->kind() );
531             PyObject *ob=PyDict_GetItemString(_context,p->getName().c_str());
532             if(ob==NULL)
533               {
534                 std::string msg="Error during execution: there is no variable ";
535                 msg=msg+p->getName()+" in node context";
536                 _errorDetails=msg;
537                 throw Exception(msg);
538               }
539             DEBTRACE( "PyNode::outputs::ob refcnt: " << ob->ob_refcnt );
540 #ifdef _DEVDEBUG_
541             PyObject_Print(ob,stderr,Py_PRINT_RAW);
542             cerr << endl;
543 #endif
544             p->put(ob);
545           }
546     }
547     catch(ConversionException& ex)
548     {
549         _errorDetails=ex.what();
550         throw;
551     }
552
553     DEBTRACE( "-----------------End PyNode::outputs-----------------" );
554   }
555   DEBTRACE( "++++++++++++++ End PyNode::execute: " << getName() << " ++++++++++++++++++++" );
556 }
557
558 std::string PythonNode::getContainerLog()
559 {
560   if(_mode=="local")return "";
561
562   std::string msg;
563   try
564     {
565       Engines::Container_var objContainer=((SalomeContainer*)_container)->getContainerPtr(this);
566       CORBA::String_var logname = objContainer->logfilename();
567       DEBTRACE(logname);
568       msg=logname;
569       std::string::size_type pos = msg.find(":");
570       msg=msg.substr(pos+1);
571     }
572   catch(...)
573     {
574       msg = "Container no longer reachable";
575     }
576   return msg;
577 }
578
579 void PythonNode::shutdown(int level)
580 {
581   DEBTRACE("PythonNode::shutdown " << level);
582   if(_mode=="local")return;
583   if(_container)
584     {
585       if(!CORBA::is_nil(_pynode)) _pynode->UnRegister();
586       _pynode=Engines::PyScriptNode::_nil();
587       _container->shutdown(level);
588     }
589 }
590
591 Node *PythonNode::simpleClone(ComposedNode *father, bool editionOnly) const
592 {
593   return new PythonNode(*this,father);
594 }
595
596 void PythonNode::createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)
597 {
598   if(!CORBA::is_nil(_pynode))
599     _pynode->UnRegister();
600   _pynode=objContainer->createPyScriptNode(getName().c_str(),getScript().c_str());
601 }
602
603 Engines::PyNodeBase_var PythonNode::retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const
604 {
605   Engines::PyScriptNode_var ret(objContainer->getDefaultPyScriptNode());
606   if(!CORBA::is_nil(ret))
607     {
608       ret->Register();
609     }
610   return Engines::PyNodeBase::_narrow(ret);
611 }
612
613 void PythonNode::assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)
614 {
615   if(!CORBA::is_nil(_pynode))
616     {
617       Engines::PyScriptNode_var tmpp(Engines::PyScriptNode::_narrow(remoteInterp));
618       if(_pynode->_is_equivalent(tmpp))
619         return ;
620     }
621   if(!CORBA::is_nil(_pynode))
622     _pynode->UnRegister();
623   _pynode=Engines::PyScriptNode::_narrow(remoteInterp);
624 }
625
626 Engines::PyNodeBase_var PythonNode::getRemoteInterpreterHandle()
627 {
628   return Engines::PyNodeBase::_narrow(_pynode);
629 }
630
631 //! Create a new node of same type with a given name
632 PythonNode* PythonNode::cloneNode(const std::string& name)
633 {
634   PythonNode* n=new PythonNode(name);
635   n->setScript(_script);
636   list<InputPort *>::iterator iter;
637   for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
638     {
639       InputPyPort *p=(InputPyPort *)*iter;
640       DEBTRACE( "port name: " << p->getName() );
641       DEBTRACE( "port kind: " << p->edGetType()->kind() );
642       n->edAddInputPort(p->getName(),p->edGetType());
643     }
644   list<OutputPort *>::iterator iter2;
645   for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
646     {
647       OutputPyPort *p=(OutputPyPort *)*iter2;
648       DEBTRACE( "port name: " << p->getName() );
649       DEBTRACE( "port kind: " << p->edGetType()->kind() );
650       n->edAddOutputPort(p->getName(),p->edGetType());
651     }
652   return n;
653 }
654
655 PyFuncNode::PyFuncNode(const PyFuncNode& other, ComposedNode *father):InlineFuncNode(other,father),_pyfunc(0)
656 {
657   _implementation = PythonNode::IMPL_NAME;
658   {
659     AutoGIL agil;
660     _context=PyDict_New();
661     DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
662     if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
663       {
664         stringstream msg;
665         msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
666         _errorDetails=msg.str();
667         throw Exception(msg.str());
668       }
669   }
670 }
671
672 PyFuncNode::PyFuncNode(const std::string& name): InlineFuncNode(name),_pyfunc(0)
673 {
674
675   _implementation = PythonNode::IMPL_NAME;
676   DEBTRACE( "PyFuncNode::PyFuncNode " << name );
677   {
678     AutoGIL agil;
679     _context=PyDict_New();
680     DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
681     if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
682       {
683         stringstream msg;
684         msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
685         _errorDetails=msg.str();
686         throw Exception(msg.str());
687       }
688   }
689 }
690
691 PyFuncNode::~PyFuncNode()
692 {
693   if(!CORBA::is_nil(_pynode))
694     {
695       _pynode->UnRegister();
696     }
697 }
698
699 void PyFuncNode::checkBasicConsistency() const throw(YACS::Exception)
700 {
701   DEBTRACE("checkBasicConsistency");
702   InlineFuncNode::checkBasicConsistency();
703   {
704     AutoGIL agil;
705     PyObject* res;
706     res=Py_CompileString(_script.c_str(),getName().c_str(),Py_file_input);
707     if(res == NULL)
708       {
709         std::string error="";
710         PyObject* new_stderr = newPyStdOut(error);
711         PySys_SetObject((char*)"stderr", new_stderr);
712         PyErr_Print();
713         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
714         Py_DECREF(new_stderr);
715         throw Exception(error);
716       }
717     else
718       Py_XDECREF(res);
719   }
720 }
721
722 void PyFuncNode::load()
723 {
724   DEBTRACE( "---------------PyfuncNode::load function---------------" );
725   if(_mode=="remote")
726     loadRemote();
727   else
728     loadLocal();
729 }
730
731 void PyFuncNode::loadRemote()
732 {
733   commonRemoteLoad(this);
734 }
735
736 void PyFuncNode::loadLocal()
737 {
738   DEBTRACE( "---------------PyFuncNode::load function " << getName() << " ---------------" );
739   DEBTRACE(  _script );
740
741 #ifdef _DEVDEBUG_
742   list<OutputPort *>::iterator iter;
743   for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
744     {
745       OutputPyPort *p=(OutputPyPort *)*iter;
746       DEBTRACE( "port name: " << p->getName() );
747       DEBTRACE( "port kind: " << p->edGetType()->kind() );
748     }
749 #endif
750
751   {
752     AutoGIL agil;
753     DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
754
755     std::ostringstream stream;
756     stream << "/tmp/PythonNode_";
757     stream << getpid();
758
759     PyObject* code=Py_CompileString(_script.c_str(), stream.str().c_str(), Py_file_input);
760     if(code == NULL)
761       {
762         _errorDetails="";
763         PyObject* new_stderr = newPyStdOut(_errorDetails);
764         PySys_SetObject((char*)"stderr", new_stderr);
765         PyErr_Print();
766         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
767         Py_DECREF(new_stderr);
768         throw Exception("Error during execution");
769       }
770     PyObject *res = PyEval_EvalCode((PyCodeObject *)code, _context, _context);
771     Py_DECREF(code);
772     Py_XDECREF(res);
773
774     DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
775     if(PyErr_Occurred ())
776       {
777         _errorDetails="";
778         PyObject* new_stderr = newPyStdOut(_errorDetails);
779         PySys_SetObject((char*)"stderr", new_stderr);
780         ofstream errorfile(stream.str().c_str());
781         if (errorfile.is_open())
782           {
783             errorfile << _script;
784             errorfile.close();
785           }
786         PyErr_Print();
787         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
788         Py_DECREF(new_stderr);
789         throw Exception("Error during execution");
790         return;
791       }
792     _pyfunc=PyDict_GetItemString(_context,_fname.c_str());
793     DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
794     if(_pyfunc == NULL)
795       {
796         _errorDetails="";
797         PyObject* new_stderr = newPyStdOut(_errorDetails);
798         PySys_SetObject((char*)"stderr", new_stderr);
799         PyErr_Print();
800         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
801         Py_DECREF(new_stderr);
802         throw Exception("Error during execution");
803       }
804     DEBTRACE( "---------------End PyFuncNode::load function---------------" );
805   }
806 }
807
808 void PyFuncNode::execute()
809 {
810   if(_mode=="remote")
811     executeRemote();
812   else
813     executeLocal();
814 }
815
816 void PyFuncNode::executeRemote()
817 {
818   DEBTRACE( "++++++++++++++ PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
819   if(!_pyfuncSer)
820     throw Exception("DistributedPythonNode badly loaded");
821   Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);;
822   {
823       AutoGIL agil;
824       PyObject *ob(0);
825       //===========================================================================
826       // Get inputs in input ports, build a Python tuple and pickle it
827       //===========================================================================
828       PyObject *args(PyTuple_New(getNumberOfInputPorts()));
829       int pos(0);
830       for(std::list<InputPort *>::iterator iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++,pos++)
831         {
832           InputPyPort *p=(InputPyPort *)*iter2;
833           ob=p->getPyObj();
834           Py_INCREF(ob);
835           PyTuple_SetItem(args,pos,ob);
836         }
837 #ifdef _DEVDEBUG_
838       PyObject_Print(args,stderr,Py_PRINT_RAW);
839       std::cerr << endl;
840 #endif
841       PyObject *serializationInput=PyObject_CallObject(_pyfuncSer,args);
842       Py_DECREF(args);
843       //The pickled string may contain NULL characters so use PyString_AsStringAndSize
844       char *serializationInputC(0);
845       Py_ssize_t len;
846       if (PyString_AsStringAndSize(serializationInput, &serializationInputC, &len))
847         throw Exception("DistributedPythonNode problem in python pickle");
848
849       serializationInputCorba->length(len);
850       for(int i=0; i < len ; i++)
851         serializationInputCorba[i]=serializationInputC[i];
852       Py_DECREF(serializationInput);
853   }
854
855   //===========================================================================
856   // Execute in remote Python node
857   //===========================================================================
858   DEBTRACE( "-----------------starting remote python invocation-----------------" );
859   Engines::pickledArgs_var resultCorba;
860   try
861     {
862       resultCorba=_pynode->execute(getFname().c_str(),serializationInputCorba);
863     }
864   catch( const SALOME::SALOME_Exception& ex )
865     {
866       std::string msg="Exception on remote python invocation";
867       msg += '\n';
868       msg += ex.details.text.in();
869       _errorDetails=msg;
870       throw Exception(msg);
871     }
872   DEBTRACE( "-----------------end of remote python invocation-----------------" );
873   //===========================================================================
874   // Get results, unpickle and put them in output ports
875   //===========================================================================
876   char *resultCorbaC=new char[resultCorba->length()+1];
877   resultCorbaC[resultCorba->length()]='\0';
878   for(int i=0;i<resultCorba->length();i++)
879     resultCorbaC[i]=resultCorba[i];
880
881   {
882       AutoGIL agil;
883
884       PyObject *resultPython(PyString_FromStringAndSize(resultCorbaC,resultCorba->length()));
885       delete [] resultCorbaC;
886       PyObject *args(PyTuple_New(1)),*ob(0);
887       PyTuple_SetItem(args,0,resultPython);
888       PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
889       Py_DECREF(args);
890
891       DEBTRACE( "-----------------PythonNode::outputs-----------------" );
892       int nres=1;
893       if(finalResult == Py_None)
894         nres=0;
895       else if(PyTuple_Check(finalResult))
896         nres=PyTuple_Size(finalResult);
897
898       if(getNumberOfOutputPorts() != nres)
899         {
900           std::string msg="Number of output arguments : Mismatch between definition and execution";
901           Py_DECREF(finalResult);
902           _errorDetails=msg;
903           throw Exception(msg);
904         }
905
906       try
907       {
908           int pos(0);
909           for(std::list<OutputPort *>::iterator iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++, pos++)
910             {
911               OutputPyPort *p=(OutputPyPort *)*iter;
912               DEBTRACE( "port name: " << p->getName() );
913               DEBTRACE( "port kind: " << p->edGetType()->kind() );
914               DEBTRACE( "port pos : " << pos );
915               if(PyTuple_Check(finalResult))
916                 ob=PyTuple_GetItem(finalResult,pos) ;
917               else
918                 ob=finalResult;
919               DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
920               p->put(ob);
921             }
922           Py_DECREF(finalResult);
923       }
924       catch(ConversionException& ex)
925       {
926           Py_DECREF(finalResult);
927           _errorDetails=ex.what();
928           throw;
929       }
930   }
931
932   DEBTRACE( "++++++++++++++ ENDOF PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
933 }
934
935 void PyFuncNode::executeLocal()
936 {
937   DEBTRACE( "++++++++++++++ PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
938
939   int pos=0;
940   PyObject* ob;
941   if(!_pyfunc)throw Exception("PyFuncNode badly loaded");
942   {
943       AutoGIL agil;
944       DEBTRACE( "---------------PyFuncNode::inputs---------------" );
945       PyObject* args = PyTuple_New(getNumberOfInputPorts()) ;
946       list<InputPort *>::iterator iter2;
947       for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
948         {
949           InputPyPort *p=(InputPyPort *)*iter2;
950           DEBTRACE( "port name: " << p->getName() );
951           DEBTRACE( "port kind: " << p->edGetType()->kind() );
952           ob=p->getPyObj();
953 #ifdef _DEVDEBUG_
954           PyObject_Print(ob,stderr,Py_PRINT_RAW);
955           cerr << endl;
956 #endif
957           DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
958           Py_INCREF(ob);
959           PyTuple_SetItem(args,pos,ob);
960           DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
961           pos++;
962         }
963       DEBTRACE( "---------------End PyFuncNode::inputs---------------" );
964
965       DEBTRACE( "----------------PyFuncNode::calculation---------------" );
966 #ifdef _DEVDEBUG_
967       PyObject_Print(_pyfunc,stderr,Py_PRINT_RAW);
968       cerr << endl;
969       PyObject_Print(args,stderr,Py_PRINT_RAW);
970       cerr << endl;
971 #endif
972       DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
973       PyObject* result = PyObject_CallObject( _pyfunc , args ) ;
974       DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
975       Py_DECREF(args);
976       fflush(stdout);
977       fflush(stderr);
978       if(result == NULL)
979         {
980           _errorDetails="";
981           PyObject* new_stderr = newPyStdOut(_errorDetails);
982           PySys_SetObject((char*)"stderr", new_stderr);
983           std::ostringstream stream;
984           stream << "/tmp/PythonNode_";
985           stream << getpid();
986           ofstream errorfile(stream.str().c_str());
987           if (errorfile.is_open())
988             {
989               errorfile << _script;
990               errorfile.close();
991             }
992           PyErr_Print();
993           PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
994           Py_DECREF(new_stderr);
995           throw Exception("Error during execution");
996         }
997       DEBTRACE( "----------------End PyFuncNode::calculation---------------" );
998
999       DEBTRACE( "-----------------PyFuncNode::outputs-----------------" );
1000       int nres=1;
1001       if(result == Py_None)
1002         nres=0;
1003       else if(PyTuple_Check(result))
1004         nres=PyTuple_Size(result);
1005
1006       if(getNumberOfOutputPorts() != nres)
1007         {
1008           std::string msg="Number of output arguments : Mismatch between definition and execution";
1009           Py_DECREF(result);
1010           _errorDetails=msg;
1011           throw Exception(msg);
1012         }
1013
1014       pos=0;
1015 #ifdef _DEVDEBUG_
1016       PyObject_Print(result,stderr,Py_PRINT_RAW);
1017       cerr << endl;
1018 #endif
1019       list<OutputPort *>::iterator iter;
1020       try
1021       {
1022           for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
1023             {
1024               OutputPyPort *p=(OutputPyPort *)*iter;
1025               DEBTRACE( "port name: " << p->getName() );
1026               DEBTRACE( "port kind: " << p->edGetType()->kind() );
1027               DEBTRACE( "port pos : " << pos );
1028               if(PyTuple_Check(result))ob=PyTuple_GetItem(result,pos) ;
1029               else ob=result;
1030               DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1031 #ifdef _DEVDEBUG_
1032               PyObject_Print(ob,stderr,Py_PRINT_RAW);
1033               cerr << endl;
1034 #endif
1035               p->put(ob);
1036               pos++;
1037             }
1038       }
1039       catch(ConversionException& ex)
1040       {
1041           Py_DECREF(result);
1042           _errorDetails=ex.what();
1043           throw;
1044       }
1045       DEBTRACE( "-----------------End PyFuncNode::outputs-----------------" );
1046       Py_DECREF(result);
1047   }
1048   DEBTRACE( "++++++++++++++ End PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
1049 }
1050
1051 Node *PyFuncNode::simpleClone(ComposedNode *father, bool editionOnly) const
1052 {
1053   return new PyFuncNode(*this,father);
1054 }
1055
1056 void PyFuncNode::createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)
1057 {
1058   if(!CORBA::is_nil(_pynode))
1059     _pynode->UnRegister();
1060   _pynode=objContainer->createPyNode(getName().c_str(),getScript().c_str());
1061 }
1062
1063 Engines::PyNodeBase_var PyFuncNode::retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const
1064 {
1065   Engines::PyNode_var ret(objContainer->getDefaultPyNode());
1066   if(!CORBA::is_nil(ret))
1067     {
1068       ret->Register();
1069     }
1070   return Engines::PyNodeBase::_narrow(ret);
1071 }
1072
1073 void PyFuncNode::assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)
1074 {
1075   if(!CORBA::is_nil(_pynode))
1076     {
1077       Engines::PyNode_var tmpp(Engines::PyNode::_narrow(remoteInterp));
1078       if(_pynode->_is_equivalent(tmpp))
1079         return ;
1080     }
1081   if(!CORBA::is_nil(_pynode))
1082     _pynode->UnRegister();
1083   _pynode=Engines::PyNode::_narrow(remoteInterp);
1084 }
1085
1086 Engines::PyNodeBase_var PyFuncNode::getRemoteInterpreterHandle()
1087 {
1088   return Engines::PyNodeBase::_narrow(_pynode);
1089 }
1090
1091 //! Create a new node of same type with a given name
1092 PyFuncNode* PyFuncNode::cloneNode(const std::string& name)
1093 {
1094   PyFuncNode* n=new PyFuncNode(name);
1095   n->setScript(_script);
1096   n->setFname(_fname);
1097   list<InputPort *>::iterator iter;
1098   for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
1099     {
1100       InputPyPort *p=(InputPyPort *)*iter;
1101       n->edAddInputPort(p->getName(),p->edGetType());
1102     }
1103   list<OutputPort *>::iterator iter2;
1104   for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
1105     {
1106       OutputPyPort *p=(OutputPyPort *)*iter2;
1107       n->edAddOutputPort(p->getName(),p->edGetType());
1108     }
1109   return n;
1110 }
1111
1112 std::string PyFuncNode::getContainerLog()
1113 {
1114   if(_mode=="local")return "";
1115
1116   std::string msg;
1117   try
1118     {
1119       Engines::Container_var objContainer=((SalomeContainer*)_container)->getContainerPtr(this);
1120       CORBA::String_var logname = objContainer->logfilename();
1121       DEBTRACE(logname);
1122       msg=logname;
1123       std::string::size_type pos = msg.find(":");
1124       msg=msg.substr(pos+1);
1125     }
1126   catch(...)
1127     {
1128       msg = "Container no longer reachable";
1129     }
1130   return msg;
1131 }
1132
1133 void PyFuncNode::shutdown(int level)
1134 {
1135   DEBTRACE("PyFuncNode::shutdown " << level);
1136   if(_mode=="local")return;
1137   if(_container)
1138     {
1139       if(!CORBA::is_nil(_pynode)) _pynode->UnRegister();
1140       _pynode=Engines::PyNode::_nil();
1141       _container->shutdown(level);
1142     }
1143 }
1144