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