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