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