Salome HOME
7973b2cf810f8a6134ff0a5eebe6c30821915d21
[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 || !isContAlreadyStarted)
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
719   try
720     {
721       if(containerCast0 || !isContAlreadyStarted)
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             _pynode = objContainer->createPyNode(getName().c_str(),getScript().c_str());
730           else
731             _pynode = dftPyScript;
732         }
733     }
734   catch( const SALOME::SALOME_Exception& ex )
735     {
736       std::string msg="Exception on remote python node creation ";
737       msg += '\n';
738       msg += ex.details.text.in();
739       _errorDetails=msg;
740       throw Exception(msg);
741     }
742
743   if(CORBA::is_nil(_pynode))
744     throw Exception("In PyFuncNode the ref in NULL ! ");
745
746   {
747     AutoGIL agil;
748     const char picklizeScript[]="import cPickle\n"
749         "def pickleForDistPyth2009(*args,**kws):\n"
750         "  return cPickle.dumps((args,kws),-1)\n"
751         "\n"
752         "def unPickleForDistPyth2009(st):\n"
753         "  args=cPickle.loads(st)\n"
754         "  return args\n";
755     PyObject *res=PyRun_String(picklizeScript,Py_file_input,_context,_context);
756     if(res == NULL)
757       {
758         _errorDetails="";
759         PyObject* new_stderr = newPyStdOut(_errorDetails);
760         PySys_SetObject((char*)"stderr", new_stderr);
761         PyErr_Print();
762         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
763         Py_DECREF(new_stderr);
764         throw Exception("Error during load");
765       }
766     Py_DECREF(res);
767
768     _pyfuncSer=PyDict_GetItemString(_context,"pickleForDistPyth2009");
769     _pyfuncUnser=PyDict_GetItemString(_context,"unPickleForDistPyth2009");
770     if(_pyfuncSer == NULL)
771       {
772         _errorDetails="";
773         PyObject* new_stderr = newPyStdOut(_errorDetails);
774         PySys_SetObject((char*)"stderr", new_stderr);
775         PyErr_Print();
776         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
777         Py_DECREF(new_stderr);
778         throw Exception("Error during load");
779       }
780     if(_pyfuncUnser == NULL)
781       {
782         _errorDetails="";
783         PyObject* new_stderr = newPyStdOut(_errorDetails);
784         PySys_SetObject((char*)"stderr", new_stderr);
785         PyErr_Print();
786         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
787         Py_DECREF(new_stderr);
788         throw Exception("Error during load");
789       }
790     DEBTRACE( "---------------End PyfuncNode::loadRemote function---------------" );
791   }
792 }
793
794 void PyFuncNode::loadLocal()
795 {
796   DEBTRACE( "---------------PyFuncNode::load function " << getName() << " ---------------" );
797   DEBTRACE(  _script );
798
799 #ifdef _DEVDEBUG_
800   list<OutputPort *>::iterator iter;
801   for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
802     {
803       OutputPyPort *p=(OutputPyPort *)*iter;
804       DEBTRACE( "port name: " << p->getName() );
805       DEBTRACE( "port kind: " << p->edGetType()->kind() );
806     }
807 #endif
808
809   {
810     AutoGIL agil;
811     DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
812
813     std::ostringstream stream;
814     stream << "/tmp/PythonNode_";
815     stream << getpid();
816
817     PyObject* code=Py_CompileString(_script.c_str(), stream.str().c_str(), Py_file_input);
818     if(code == 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         throw Exception("Error during execution");
827       }
828     PyObject *res = PyEval_EvalCode((PyCodeObject *)code, _context, _context);
829     Py_DECREF(code);
830     Py_XDECREF(res);
831
832     DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
833     if(PyErr_Occurred ())
834       {
835         _errorDetails="";
836         PyObject* new_stderr = newPyStdOut(_errorDetails);
837         PySys_SetObject((char*)"stderr", new_stderr);
838         ofstream errorfile(stream.str().c_str());
839         if (errorfile.is_open())
840           {
841             errorfile << _script;
842             errorfile.close();
843           }
844         PyErr_Print();
845         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
846         Py_DECREF(new_stderr);
847         throw Exception("Error during execution");
848         return;
849       }
850     _pyfunc=PyDict_GetItemString(_context,_fname.c_str());
851     DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
852     if(_pyfunc == NULL)
853       {
854         _errorDetails="";
855         PyObject* new_stderr = newPyStdOut(_errorDetails);
856         PySys_SetObject((char*)"stderr", new_stderr);
857         PyErr_Print();
858         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
859         Py_DECREF(new_stderr);
860         throw Exception("Error during execution");
861       }
862     DEBTRACE( "---------------End PyFuncNode::load function---------------" );
863   }
864 }
865
866 void PyFuncNode::execute()
867 {
868   if(_mode=="remote")
869     executeRemote();
870   else
871     executeLocal();
872 }
873
874 void PyFuncNode::executeRemote()
875 {
876   DEBTRACE( "++++++++++++++ PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
877   if(!_pyfuncSer)
878     throw Exception("DistributedPythonNode badly loaded");
879   Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);;
880   {
881       AutoGIL agil;
882       PyObject *ob(0);
883       //===========================================================================
884       // Get inputs in input ports, build a Python tuple and pickle it
885       //===========================================================================
886       PyObject *args(PyTuple_New(getNumberOfInputPorts()));
887       int pos(0);
888       for(std::list<InputPort *>::iterator iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++,pos++)
889         {
890           InputPyPort *p=(InputPyPort *)*iter2;
891           ob=p->getPyObj();
892           Py_INCREF(ob);
893           PyTuple_SetItem(args,pos,ob);
894         }
895 #ifdef _DEVDEBUG_
896       PyObject_Print(args,stderr,Py_PRINT_RAW);
897       std::cerr << endl;
898 #endif
899       PyObject *serializationInput=PyObject_CallObject(_pyfuncSer,args);
900       Py_DECREF(args);
901       //The pickled string may contain NULL characters so use PyString_AsStringAndSize
902       char *serializationInputC(0);
903       Py_ssize_t len;
904       if (PyString_AsStringAndSize(serializationInput, &serializationInputC, &len))
905         throw Exception("DistributedPythonNode problem in python pickle");
906
907       serializationInputCorba->length(len);
908       for(int i=0; i < len ; i++)
909         serializationInputCorba[i]=serializationInputC[i];
910       Py_DECREF(serializationInput);
911   }
912
913   //===========================================================================
914   // Execute in remote Python node
915   //===========================================================================
916   DEBTRACE( "-----------------starting remote python invocation-----------------" );
917   Engines::pickledArgs_var resultCorba;
918   try
919     {
920       resultCorba=_pynode->execute(getFname().c_str(),serializationInputCorba);
921     }
922   catch( const SALOME::SALOME_Exception& ex )
923     {
924       std::string msg="Exception on remote python invocation";
925       msg += '\n';
926       msg += ex.details.text.in();
927       _errorDetails=msg;
928       throw Exception(msg);
929     }
930   DEBTRACE( "-----------------end of remote python invocation-----------------" );
931   //===========================================================================
932   // Get results, unpickle and put them in output ports
933   //===========================================================================
934   char *resultCorbaC=new char[resultCorba->length()+1];
935   resultCorbaC[resultCorba->length()]='\0';
936   for(int i=0;i<resultCorba->length();i++)
937     resultCorbaC[i]=resultCorba[i];
938
939   {
940       AutoGIL agil;
941
942       PyObject *resultPython(PyString_FromStringAndSize(resultCorbaC,resultCorba->length()));
943       delete [] resultCorbaC;
944       PyObject *args(PyTuple_New(1)),*ob(0);
945       PyTuple_SetItem(args,0,resultPython);
946       PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
947       Py_DECREF(args);
948
949       DEBTRACE( "-----------------PythonNode::outputs-----------------" );
950       int nres=1;
951       if(finalResult == Py_None)
952         nres=0;
953       else if(PyTuple_Check(finalResult))
954         nres=PyTuple_Size(finalResult);
955
956       if(getNumberOfOutputPorts() != nres)
957         {
958           std::string msg="Number of output arguments : Mismatch between definition and execution";
959           Py_DECREF(finalResult);
960           _errorDetails=msg;
961           throw Exception(msg);
962         }
963
964       try
965       {
966           int pos(0);
967           for(std::list<OutputPort *>::iterator iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++, pos++)
968             {
969               OutputPyPort *p=(OutputPyPort *)*iter;
970               DEBTRACE( "port name: " << p->getName() );
971               DEBTRACE( "port kind: " << p->edGetType()->kind() );
972               DEBTRACE( "port pos : " << pos );
973               if(PyTuple_Check(finalResult))
974                 ob=PyTuple_GetItem(finalResult,pos) ;
975               else
976                 ob=finalResult;
977               DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
978               p->put(ob);
979             }
980           Py_DECREF(finalResult);
981       }
982       catch(ConversionException& ex)
983       {
984           Py_DECREF(finalResult);
985           _errorDetails=ex.what();
986           throw;
987       }
988   }
989
990   DEBTRACE( "++++++++++++++ ENDOF PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
991 }
992
993 void PyFuncNode::executeLocal()
994 {
995   DEBTRACE( "++++++++++++++ PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
996
997   int pos=0;
998   PyObject* ob;
999   if(!_pyfunc)throw Exception("PyFuncNode badly loaded");
1000   {
1001       AutoGIL agil;
1002       DEBTRACE( "---------------PyFuncNode::inputs---------------" );
1003       PyObject* args = PyTuple_New(getNumberOfInputPorts()) ;
1004       list<InputPort *>::iterator iter2;
1005       for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
1006         {
1007           InputPyPort *p=(InputPyPort *)*iter2;
1008           DEBTRACE( "port name: " << p->getName() );
1009           DEBTRACE( "port kind: " << p->edGetType()->kind() );
1010           ob=p->getPyObj();
1011 #ifdef _DEVDEBUG_
1012           PyObject_Print(ob,stderr,Py_PRINT_RAW);
1013           cerr << endl;
1014 #endif
1015           DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1016           Py_INCREF(ob);
1017           PyTuple_SetItem(args,pos,ob);
1018           DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1019           pos++;
1020         }
1021       DEBTRACE( "---------------End PyFuncNode::inputs---------------" );
1022
1023       DEBTRACE( "----------------PyFuncNode::calculation---------------" );
1024 #ifdef _DEVDEBUG_
1025       PyObject_Print(_pyfunc,stderr,Py_PRINT_RAW);
1026       cerr << endl;
1027       PyObject_Print(args,stderr,Py_PRINT_RAW);
1028       cerr << endl;
1029 #endif
1030       DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1031       PyObject* result = PyObject_CallObject( _pyfunc , args ) ;
1032       DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1033       Py_DECREF(args);
1034       fflush(stdout);
1035       fflush(stderr);
1036       if(result == NULL)
1037         {
1038           _errorDetails="";
1039           PyObject* new_stderr = newPyStdOut(_errorDetails);
1040           PySys_SetObject((char*)"stderr", new_stderr);
1041           std::ostringstream stream;
1042           stream << "/tmp/PythonNode_";
1043           stream << getpid();
1044           ofstream errorfile(stream.str().c_str());
1045           if (errorfile.is_open())
1046             {
1047               errorfile << _script;
1048               errorfile.close();
1049             }
1050           PyErr_Print();
1051           PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1052           Py_DECREF(new_stderr);
1053           throw Exception("Error during execution");
1054         }
1055       DEBTRACE( "----------------End PyFuncNode::calculation---------------" );
1056
1057       DEBTRACE( "-----------------PyFuncNode::outputs-----------------" );
1058       int nres=1;
1059       if(result == Py_None)
1060         nres=0;
1061       else if(PyTuple_Check(result))
1062         nres=PyTuple_Size(result);
1063
1064       if(getNumberOfOutputPorts() != nres)
1065         {
1066           std::string msg="Number of output arguments : Mismatch between definition and execution";
1067           Py_DECREF(result);
1068           _errorDetails=msg;
1069           throw Exception(msg);
1070         }
1071
1072       pos=0;
1073 #ifdef _DEVDEBUG_
1074       PyObject_Print(result,stderr,Py_PRINT_RAW);
1075       cerr << endl;
1076 #endif
1077       list<OutputPort *>::iterator iter;
1078       try
1079       {
1080           for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
1081             {
1082               OutputPyPort *p=(OutputPyPort *)*iter;
1083               DEBTRACE( "port name: " << p->getName() );
1084               DEBTRACE( "port kind: " << p->edGetType()->kind() );
1085               DEBTRACE( "port pos : " << pos );
1086               if(PyTuple_Check(result))ob=PyTuple_GetItem(result,pos) ;
1087               else ob=result;
1088               DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1089 #ifdef _DEVDEBUG_
1090               PyObject_Print(ob,stderr,Py_PRINT_RAW);
1091               cerr << endl;
1092 #endif
1093               p->put(ob);
1094               pos++;
1095             }
1096       }
1097       catch(ConversionException& ex)
1098       {
1099           Py_DECREF(result);
1100           _errorDetails=ex.what();
1101           throw;
1102       }
1103       DEBTRACE( "-----------------End PyFuncNode::outputs-----------------" );
1104       Py_DECREF(result);
1105   }
1106   DEBTRACE( "++++++++++++++ End PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
1107 }
1108
1109 Node *PyFuncNode::simpleClone(ComposedNode *father, bool editionOnly) const
1110 {
1111   return new PyFuncNode(*this,father);
1112 }
1113
1114 //! Create a new node of same type with a given name
1115 PyFuncNode* PyFuncNode::cloneNode(const std::string& name)
1116 {
1117   PyFuncNode* n=new PyFuncNode(name);
1118   n->setScript(_script);
1119   n->setFname(_fname);
1120   list<InputPort *>::iterator iter;
1121   for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
1122     {
1123       InputPyPort *p=(InputPyPort *)*iter;
1124       n->edAddInputPort(p->getName(),p->edGetType());
1125     }
1126   list<OutputPort *>::iterator iter2;
1127   for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
1128     {
1129       OutputPyPort *p=(OutputPyPort *)*iter2;
1130       n->edAddOutputPort(p->getName(),p->edGetType());
1131     }
1132   return n;
1133 }
1134
1135 std::string PyFuncNode::getContainerLog()
1136 {
1137   if(_mode=="local")return "";
1138
1139   std::string msg;
1140   try
1141     {
1142       Engines::Container_var objContainer=((SalomeContainer*)_container)->getContainerPtr(this);
1143       CORBA::String_var logname = objContainer->logfilename();
1144       DEBTRACE(logname);
1145       msg=logname;
1146       std::string::size_type pos = msg.find(":");
1147       msg=msg.substr(pos+1);
1148     }
1149   catch(...)
1150     {
1151       msg = "Container no longer reachable";
1152     }
1153   return msg;
1154 }
1155
1156 void PyFuncNode::shutdown(int level)
1157 {
1158   DEBTRACE("PyFuncNode::shutdown " << level);
1159   if(_mode=="local")return;
1160   if(_container)
1161     {
1162       if(!CORBA::is_nil(_pynode)) _pynode->UnRegister();
1163       _pynode=Engines::PyNode::_nil();
1164       _container->shutdown(level);
1165     }
1166 }
1167