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