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