1 // Copyright (C) 2006-2019 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
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"
31 #include "PyStdout.hxx"
38 #define getpid _getpid
41 #if PY_VERSION_HEX < 0x02050000
42 typedef int Py_ssize_t;
46 #include "YacsTrace.hxx"
48 using namespace YACS::ENGINE;
51 const char PythonEntry::SCRIPT_FOR_SIMPLE_SERIALIZATION[]="import pickle\n"
52 "def pickleForVarSimplePyth2009(val):\n"
53 " return pickle.dumps(val,-1)\n"
56 const char PythonNode::IMPL_NAME[]="Python";
57 const char PythonNode::KIND[]="Python";
59 const char PythonNode::SCRIPT_FOR_SERIALIZATION[]="import pickle\n"
60 "def pickleForDistPyth2009(kws):\n"
61 " return pickle.dumps(((),kws),-1)\n"
63 "def unPickleForDistPyth2009(st):\n"
64 " args=pickle.loads(st)\n"
67 const char PythonNode::REMOTE_NAME[]="remote";
69 const char PythonNode::DPL_INFO_NAME[]="my_dpl_localization";
71 const char PyFuncNode::SCRIPT_FOR_SERIALIZATION[]="import pickle\n"
72 "def pickleForDistPyth2009(*args,**kws):\n"
73 " return pickle.dumps((args,kws),-1)\n"
75 "def unPickleForDistPyth2009(st):\n"
76 " args=pickle.loads(st)\n"
80 PythonEntry::PythonEntry():_context(0),_pyfuncSer(0),_pyfuncUnser(0),_pyfuncSimpleSer(0)
84 PythonEntry::~PythonEntry()
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
93 void PythonEntry::commonRemoteLoadPart1(InlineNode *reqNode)
95 DEBTRACE( "---------------PythonEntry::CommonRemoteLoad function---------------" );
96 Container *container(reqNode->getContainer());
97 bool isContAlreadyStarted(false);
100 isContAlreadyStarted=container->isAlreadyStarted(reqNode);
101 if(!isContAlreadyStarted)
105 container->start(reqNode);
109 reqNode->setErrorDetails(e.what());
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);
123 Engines::Container_var GetContainerObj(InlineNode *reqNode, bool& isStandardCont)
125 isStandardCont = false;
126 Container *container(reqNode->getContainer());
127 Engines::Container_var objContainer(Engines::Container::_nil());
129 throw YACS::Exception("No container specified !");
130 SalomeContainer *containerCast0(dynamic_cast<SalomeContainer *>(container));
131 SalomeHPContainerBase *containerCast1(dynamic_cast<SalomeHPContainerBase *>(container));
134 isStandardCont = true;
135 objContainer=containerCast0->getContainerPtr(reqNode);
137 else if(containerCast1)
139 objContainer=containerCast1->getContainerPtr(reqNode);
142 throw YACS::Exception("Unrecognized type of container ! Salome one is expected for PythonNode/PyFuncNode !");
143 if(CORBA::is_nil(objContainer))
144 throw YACS::Exception("Container corba pointer is NULL for PythonNode !");
148 Engines::Container_var PythonEntry::commonRemoteLoadPart2(InlineNode *reqNode, bool& isInitializeRequested)
150 bool isStandardCont(true);
151 Engines::Container_var objContainer(GetContainerObj(reqNode,isStandardCont));
152 isInitializeRequested=false;
157 createRemoteAdaptedPyInterpretor(objContainer);
161 Engines::PyNodeBase_var dftPyScript(retrieveDftRemotePyInterpretorIfAny(objContainer));
162 if(CORBA::is_nil(dftPyScript))
164 isInitializeRequested=true;
165 createRemoteAdaptedPyInterpretor(objContainer);
168 assignRemotePyInterpretor(dftPyScript);
171 catch( const SALOME::SALOME_Exception& ex )
173 std::string msg="Exception on remote python node creation ";
175 msg += ex.details.text.in();
176 reqNode->setErrorDetails(msg);
177 throw Exception(msg);
179 Engines::PyNodeBase_var pynode(getRemoteInterpreterHandle());
180 if(CORBA::is_nil(pynode))
181 throw Exception("In PythonNode the ref in NULL ! ");
185 void PythonEntry::commonRemoteLoadPart3(InlineNode *reqNode, Engines::Container_ptr objContainer, bool isInitializeRequested)
187 Container *container(reqNode->getContainer());
188 Engines::PyNodeBase_var pynode(getRemoteInterpreterHandle());
192 const char *picklizeScript(getSerializationScript());
193 PyObject *res=PyRun_String(picklizeScript,Py_file_input,_context,_context);
194 PyObject *res2(PyRun_String(SCRIPT_FOR_SIMPLE_SERIALIZATION,Py_file_input,_context,_context));
195 if(res == NULL || res2==NULL)
197 std::string errorDetails;
198 PyObject* new_stderr = newPyStdOut(errorDetails);
199 reqNode->setErrorDetails(errorDetails);
200 PySys_SetObject((char*)"stderr", new_stderr);
202 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
203 Py_DECREF(new_stderr);
204 throw Exception("Error during load");
206 Py_DECREF(res); Py_DECREF(res2);
207 _pyfuncSer=PyDict_GetItemString(_context,"pickleForDistPyth2009");
208 _pyfuncUnser=PyDict_GetItemString(_context,"unPickleForDistPyth2009");
209 _pyfuncSimpleSer=PyDict_GetItemString(_context,"pickleForVarSimplePyth2009");
210 if(_pyfuncSer == NULL)
212 std::string errorDetails;
213 PyObject *new_stderr(newPyStdOut(errorDetails));
214 reqNode->setErrorDetails(errorDetails);
215 PySys_SetObject((char*)"stderr", new_stderr);
217 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
218 Py_DECREF(new_stderr);
219 throw Exception("Error during load");
221 if(_pyfuncUnser == NULL)
223 std::string errorDetails;
224 PyObject *new_stderr(newPyStdOut(errorDetails));
225 reqNode->setErrorDetails(errorDetails);
226 PySys_SetObject((char*)"stderr", new_stderr);
228 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
229 Py_DECREF(new_stderr);
230 throw Exception("Error during load");
232 if(_pyfuncSimpleSer == NULL)
234 std::string errorDetails;
235 PyObject *new_stderr(newPyStdOut(errorDetails));
236 reqNode->setErrorDetails(errorDetails);
237 PySys_SetObject((char*)"stderr", new_stderr);
239 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
240 Py_DECREF(new_stderr);
241 throw Exception("Error during load");
244 if(isInitializeRequested)
245 {//This one is called only once at initialization in the container if an init-script is specified.
248 std::string zeInitScriptKey(container->getProperty(HomogeneousPoolContainer::INITIALIZE_SCRIPT_KEY));
249 if(!zeInitScriptKey.empty())
250 pynode->executeAnotherPieceOfCode(zeInitScriptKey.c_str());
252 catch( const SALOME::SALOME_Exception& ex )
254 std::string msg="Exception on PythonNode::loadRemote python invocation of initializisation py script !";
256 msg += ex.details.text.in();
257 reqNode->setErrorDetails(msg);
258 throw Exception(msg);
260 DEBTRACE( "---------------End PyNode::loadRemote function---------------" );
264 std::string PythonEntry::GetContainerLog(const std::string& mode, Container *container, const Task *askingTask)
272 SalomeContainer *containerCast(dynamic_cast<SalomeContainer *>(container));
273 SalomeHPContainer *objContainer2(dynamic_cast<SalomeHPContainer *>(container));
276 Engines::Container_var objContainer(containerCast->getContainerPtr(askingTask));
277 CORBA::String_var logname = objContainer->logfilename();
280 std::string::size_type pos = msg.find(":");
281 msg=msg.substr(pos+1);
283 else if(objContainer2)
285 msg="Remote PythonNode is on HP Container : no log because no info of the location by definition of HP Container !";
289 msg="Not implemented yet for container log for that type of container !";
294 msg = "Container no longer reachable";
299 void PythonEntry::commonRemoteLoad(InlineNode *reqNode)
301 commonRemoteLoadPart1(reqNode);
302 bool isInitializeRequested;
303 Engines::Container_var objContainer(commonRemoteLoadPart2(reqNode,isInitializeRequested));
304 commonRemoteLoadPart3(reqNode,objContainer,isInitializeRequested);
307 PythonNode::PythonNode(const PythonNode& other, ComposedNode *father):InlineNode(other,father)
309 _implementation=IMPL_NAME;
312 _context=PyDict_New();
313 if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
316 msg << "Impossible to set builtins" << __FILE__ << ":" << __LINE__;
317 _errorDetails=msg.str();
318 throw Exception(msg.str());
323 PythonNode::PythonNode(const std::string& name):InlineNode(name)
325 _implementation=IMPL_NAME;
328 _context=PyDict_New();
329 if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
332 msg << "Impossible to set builtins" << __FILE__ << ":" << __LINE__;
333 _errorDetails=msg.str();
334 throw Exception(msg.str());
339 PythonNode::~PythonNode()
341 if(!CORBA::is_nil(_pynode))
343 _pynode->UnRegister();
347 void PythonNode::checkBasicConsistency() const throw(YACS::Exception)
349 DEBTRACE("checkBasicConsistency");
350 InlineNode::checkBasicConsistency();
354 res=Py_CompileString(_script.c_str(),getName().c_str(),Py_file_input);
357 std::string error="";
358 PyObject* new_stderr = newPyStdOut(error);
359 PySys_SetObject((char*)"stderr", new_stderr);
361 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
362 Py_DECREF(new_stderr);
363 throw Exception(error);
370 void PythonNode::load()
372 DEBTRACE( "---------------PyNode::load function---------------" );
373 if(_mode==PythonNode::REMOTE_NAME)
379 void PythonNode::loadLocal()
381 DEBTRACE( "---------------PyNode::loadLocal function---------------" );
385 void PythonNode::loadRemote()
387 commonRemoteLoad(this);
390 void PythonNode::execute()
392 if(_mode==PythonNode::REMOTE_NAME)
398 void PythonNode::executeRemote()
400 DEBTRACE( "++++++++++++++ PyNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
402 throw Exception("DistributedPythonNode badly loaded");
404 if(dynamic_cast<HomogeneousPoolContainer *>(getContainer()))
407 commonRemoteLoadPart2(this,dummy);
408 _pynode->assignNewCompiledCode(getScript().c_str());
411 Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);
414 PyObject *args(0),*ob(0);
415 //===========================================================================
416 // Get inputs in input ports, build a Python dict and pickle it
417 //===========================================================================
419 std::list<InputPort *>::iterator iter2;
421 for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); ++iter2)
423 InputPyPort *p=(InputPyPort *)*iter2;
425 PyDict_SetItemString(args,p->getName().c_str(),ob);
429 PyObject_Print(args,stderr,Py_PRINT_RAW);
432 PyObject *serializationInput(PyObject_CallFunctionObjArgs(_pyfuncSer,args,NULL));
434 //The pickled string may contain NULL characters so use PyString_AsStringAndSize
435 char *serializationInputC(0);
437 if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
438 throw Exception("DistributedPythonNode problem in python pickle");
439 serializationInputCorba->length(len);
440 for(int i=0; i < len ; i++)
441 serializationInputCorba[i]=serializationInputC[i];
442 Py_DECREF(serializationInput);
445 //get the list of output argument names
446 std::list<OutputPort *>::iterator iter;
447 Engines::listofstring myseq;
448 myseq.length(getNumberOfOutputPorts());
450 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); ++iter)
452 OutputPyPort *p=(OutputPyPort *)*iter;
453 myseq[pos]=p->getName().c_str();
454 DEBTRACE( "port name: " << p->getName() );
455 DEBTRACE( "port kind: " << p->edGetType()->kind() );
456 DEBTRACE( "port pos : " << pos );
459 //===========================================================================
460 // Execute in remote Python node
461 //===========================================================================
462 DEBTRACE( "-----------------starting remote python invocation-----------------" );
463 Engines::pickledArgs_var resultCorba;
466 //pass outargsname and dict serialized
467 resultCorba=_pynode->execute(myseq,serializationInputCorba);
469 catch( const SALOME::SALOME_Exception& ex )
471 std::string msg="Exception on remote python invocation";
473 msg += ex.details.text.in();
475 throw Exception(msg);
477 DEBTRACE( "-----------------end of remote python invocation-----------------" );
478 //===========================================================================
479 // Get results, unpickle and put them in output ports
480 //===========================================================================
481 char *resultCorbaC=new char[resultCorba->length()+1];
482 resultCorbaC[resultCorba->length()]='\0';
483 for(int i=0;i<resultCorba->length();i++)
484 resultCorbaC[i]=resultCorba[i];
488 PyObject *args(0),*ob(0);
489 PyObject* resultPython=PyBytes_FromStringAndSize(resultCorbaC,resultCorba->length());
490 delete [] resultCorbaC;
491 args = PyTuple_New(1);
492 PyTuple_SetItem(args,0,resultPython);
493 PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
496 if (finalResult == NULL)
498 std::stringstream msg;
499 msg << "Conversion with pickle of output ports failed !";
500 msg << " : " << __FILE__ << ":" << __LINE__;
501 _errorDetails=msg.str();
502 throw YACS::ENGINE::ConversionException(msg.str());
505 DEBTRACE( "-----------------PythonNode::outputs-----------------" );
507 if(finalResult == Py_None)
509 else if(PyTuple_Check(finalResult))
510 nres=PyTuple_Size(finalResult);
512 if(getNumberOfOutputPorts() != nres)
514 std::string msg="Number of output arguments : Mismatch between definition and execution";
515 Py_DECREF(finalResult);
517 throw Exception(msg);
523 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); ++iter)
525 OutputPyPort *p=(OutputPyPort *)*iter;
526 DEBTRACE( "port name: " << p->getName() );
527 DEBTRACE( "port kind: " << p->edGetType()->kind() );
528 DEBTRACE( "port pos : " << pos );
529 if(PyTuple_Check(finalResult))
530 ob=PyTuple_GetItem(finalResult,pos) ;
533 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
537 Py_DECREF(finalResult);
539 catch(ConversionException& ex)
541 Py_DECREF(finalResult);
542 _errorDetails=ex.what();
547 if(!CORBA::is_nil(_pynode))
549 _pynode->UnRegister();
551 _pynode = Engines::PyScriptNode::_nil();
553 Engines::Container_var cont(GetContainerObj(this,dummy));
554 cont->removePyScriptNode(getName().c_str());
555 DEBTRACE( "++++++++++++++ ENDOF PyNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
558 void PythonNode::executeLocal()
560 DEBTRACE( "++++++++++++++ PyNode::executeLocal: " << getName() << " ++++++++++++++++++++" );
564 DEBTRACE( "---------------PyNode::inputs---------------" );
565 list<InputPort *>::iterator iter2;
566 for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
568 InputPyPort *p=(InputPyPort *)*iter2;
569 DEBTRACE( "port name: " << p->getName() );
570 DEBTRACE( "port kind: " << p->edGetType()->kind() );
571 PyObject* ob=p->getPyObj();
572 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
574 PyObject_Print(ob,stderr,Py_PRINT_RAW);
577 int ier=PyDict_SetItemString(_context,p->getName().c_str(),ob);
578 DEBTRACE( "after PyDict_SetItemString:ob refcnt: " << ob->ob_refcnt );
581 DEBTRACE( "---------------End PyNode::inputs---------------" );
584 DEBTRACE( "----------------PyNode::calculation---------------" );
586 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
588 std::ostringstream stream;
589 stream << "/tmp/PythonNode_";
592 PyObject* code=Py_CompileString(_script.c_str(), stream.str().c_str(), Py_file_input);
596 PyObject* new_stderr = newPyStdOut(_errorDetails);
597 PySys_SetObject((char*)"stderr", new_stderr);
599 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
600 Py_DECREF(new_stderr);
601 throw Exception("Error during execution");
603 PyObject *res = PyEval_EvalCode( code, _context, _context);
607 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
610 if(PyErr_Occurred ())
613 PyObject* new_stderr = newPyStdOut(_errorDetails);
614 PySys_SetObject((char*)"stderr", new_stderr);
615 ofstream errorfile(stream.str().c_str());
616 if (errorfile.is_open())
618 errorfile << _script;
622 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
623 Py_DECREF(new_stderr);
624 throw Exception("Error during execution");
627 DEBTRACE( "-----------------PyNode::outputs-----------------" );
628 list<OutputPort *>::iterator iter;
631 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
633 OutputPyPort *p=(OutputPyPort *)*iter;
634 DEBTRACE( "port name: " << p->getName() );
635 DEBTRACE( "port kind: " << p->edGetType()->kind() );
636 PyObject *ob=PyDict_GetItemString(_context,p->getName().c_str());
639 std::string msg="Error during execution: there is no variable ";
640 msg=msg+p->getName()+" in node context";
642 throw Exception(msg);
644 DEBTRACE( "PyNode::outputs::ob refcnt: " << ob->ob_refcnt );
646 PyObject_Print(ob,stderr,Py_PRINT_RAW);
652 catch(ConversionException& ex)
654 _errorDetails=ex.what();
658 DEBTRACE( "-----------------End PyNode::outputs-----------------" );
660 DEBTRACE( "++++++++++++++ End PyNode::execute: " << getName() << " ++++++++++++++++++++" );
663 std::string PythonNode::getContainerLog()
665 return PythonEntry::GetContainerLog(_mode,_container,this);
668 void PythonNode::shutdown(int level)
670 DEBTRACE("PythonNode::shutdown " << level);
671 if(_mode=="local")return;
674 if(!CORBA::is_nil(_pynode)) _pynode->UnRegister();
675 _pynode=Engines::PyScriptNode::_nil();
676 _container->shutdown(level);
680 Node *PythonNode::simpleClone(ComposedNode *father, bool editionOnly) const
682 return new PythonNode(*this,father);
685 void PythonNode::createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)
687 if(!CORBA::is_nil(_pynode))
688 _pynode->UnRegister();
689 _pynode=objContainer->createPyScriptNode(getName().c_str(),getScript().c_str());
693 Engines::PyNodeBase_var PythonNode::retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const
695 Engines::PyScriptNode_var ret(objContainer->getDefaultPyScriptNode(getName().c_str()));
696 if(!CORBA::is_nil(ret))
700 return Engines::PyNodeBase::_narrow(ret);
703 void PythonNode::assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)
705 if(!CORBA::is_nil(_pynode))
707 Engines::PyScriptNode_var tmpp(Engines::PyScriptNode::_narrow(remoteInterp));
708 if(_pynode->_is_equivalent(tmpp))
710 _pynode->UnRegister();
714 if(!CORBA::is_nil(_pynode))
715 _pynode->UnRegister();
716 _pynode=Engines::PyScriptNode::_narrow(remoteInterp);
719 Engines::PyNodeBase_var PythonNode::getRemoteInterpreterHandle()
721 return Engines::PyNodeBase::_narrow(_pynode);
724 //! Create a new node of same type with a given name
725 PythonNode* PythonNode::cloneNode(const std::string& name)
727 PythonNode* n=new PythonNode(name);
728 n->setScript(_script);
729 list<InputPort *>::iterator iter;
730 for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
732 InputPyPort *p=(InputPyPort *)*iter;
733 DEBTRACE( "port name: " << p->getName() );
734 DEBTRACE( "port kind: " << p->edGetType()->kind() );
735 n->edAddInputPort(p->getName(),p->edGetType());
737 list<OutputPort *>::iterator iter2;
738 for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
740 OutputPyPort *p=(OutputPyPort *)*iter2;
741 DEBTRACE( "port name: " << p->getName() );
742 DEBTRACE( "port kind: " << p->edGetType()->kind() );
743 n->edAddOutputPort(p->getName(),p->edGetType());
748 void PythonNode::applyDPLScope(ComposedNode *gfn)
750 std::vector< std::pair<std::string,int> > ret(getDPLScopeInfo(gfn));
757 std::size_t sz(ret.size());
759 for(std::size_t i=0;i<sz;i++)
761 const std::pair<std::string,int>& p(ret[i]);
762 PyObject *elt(PyTuple_New(2));
763 PyTuple_SetItem(elt,0,PyUnicode_FromString(p.first.c_str()));
764 PyTuple_SetItem(elt,1,PyLong_FromLong(p.second));
765 PyList_SetItem(ob,i,elt);
768 if(_mode==REMOTE_NAME)
770 Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);
773 PyObject *serializationInput(PyObject_CallFunctionObjArgs(_pyfuncSimpleSer,ob,NULL));
775 char *serializationInputC(0);
777 if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
778 throw Exception("DistributedPythonNode problem in python pickle");
779 serializationInputCorba->length(len);
780 for(int i=0; i < len ; i++)
781 serializationInputCorba[i]=serializationInputC[i];
782 Py_XDECREF(serializationInput);
784 _pynode->defineNewCustomVar(DPL_INFO_NAME,serializationInputCorba);
789 PyDict_SetItemString(_context,DPL_INFO_NAME,ob);
794 PyFuncNode::PyFuncNode(const PyFuncNode& other, ComposedNode *father):InlineFuncNode(other,father),_pyfunc(0)
796 _implementation = PythonNode::IMPL_NAME;
799 _context=PyDict_New();
800 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
801 if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
804 msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
805 _errorDetails=msg.str();
806 throw Exception(msg.str());
811 PyFuncNode::PyFuncNode(const std::string& name): InlineFuncNode(name),_pyfunc(0)
814 _implementation = PythonNode::IMPL_NAME;
815 DEBTRACE( "PyFuncNode::PyFuncNode " << name );
818 _context=PyDict_New();
819 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
820 if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
823 msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
824 _errorDetails=msg.str();
825 throw Exception(msg.str());
830 PyFuncNode::~PyFuncNode()
832 if(!CORBA::is_nil(_pynode))
834 _pynode->UnRegister();
838 void PyFuncNode::init(bool start)
840 initCommonPartWithoutStateManagement(start);
841 if(_state == YACS::DISABLED)
843 exDisabledState(); // to refresh propagation of DISABLED state
846 if(start) //complete initialization
847 setState(YACS::READY);
848 else if(_state > YACS::LOADED)// WARNING FuncNode has internal vars (CEA usecase) ! Partial initialization (inside a loop). Exclusivity of funcNode.
849 setState(YACS::TORECONNECT);
852 void PyFuncNode::checkBasicConsistency() const throw(YACS::Exception)
854 DEBTRACE("checkBasicConsistency");
855 InlineFuncNode::checkBasicConsistency();
859 res=Py_CompileString(_script.c_str(),getName().c_str(),Py_file_input);
862 std::string error="";
863 PyObject* new_stderr = newPyStdOut(error);
864 PySys_SetObject((char*)"stderr", new_stderr);
866 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
867 Py_DECREF(new_stderr);
868 throw Exception(error);
875 void PyFuncNode::load()
877 DEBTRACE( "---------------PyfuncNode::load function---------------" );
878 if(_mode==PythonNode::REMOTE_NAME)
884 void PyFuncNode::loadRemote()
886 commonRemoteLoad(this);
889 void PyFuncNode::loadLocal()
891 DEBTRACE( "---------------PyFuncNode::load function " << getName() << " ---------------" );
895 list<OutputPort *>::iterator iter;
896 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
898 OutputPyPort *p=(OutputPyPort *)*iter;
899 DEBTRACE( "port name: " << p->getName() );
900 DEBTRACE( "port kind: " << p->edGetType()->kind() );
906 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
908 std::ostringstream stream;
909 stream << "/tmp/PythonNode_";
912 PyObject* code=Py_CompileString(_script.c_str(), stream.str().c_str(), Py_file_input);
916 PyObject* new_stderr = newPyStdOut(_errorDetails);
917 PySys_SetObject((char*)"stderr", new_stderr);
919 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
920 Py_DECREF(new_stderr);
921 throw Exception("Error during execution");
923 PyObject *res = PyEval_EvalCode( code, _context, _context);
927 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
928 if(PyErr_Occurred ())
931 PyObject* new_stderr = newPyStdOut(_errorDetails);
932 PySys_SetObject((char*)"stderr", new_stderr);
933 ofstream errorfile(stream.str().c_str());
934 if (errorfile.is_open())
936 errorfile << _script;
940 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
941 Py_DECREF(new_stderr);
942 throw Exception("Error during execution");
945 _pyfunc=PyDict_GetItemString(_context,_fname.c_str());
946 DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
950 PyObject* new_stderr = newPyStdOut(_errorDetails);
951 PySys_SetObject((char*)"stderr", new_stderr);
953 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
954 Py_DECREF(new_stderr);
955 throw Exception("Error during execution");
957 DEBTRACE( "---------------End PyFuncNode::load function---------------" );
961 void PyFuncNode::execute()
963 if(_mode==PythonNode::REMOTE_NAME)
969 void PyFuncNode::executeRemote()
971 DEBTRACE( "++++++++++++++ PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
973 throw Exception("DistributedPythonNode badly loaded");
975 if(dynamic_cast<HomogeneousPoolContainer *>(getContainer()))
978 commonRemoteLoadPart2(this,dummy);
979 _pynode->executeAnotherPieceOfCode(getScript().c_str());
982 Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);;
986 //===========================================================================
987 // Get inputs in input ports, build a Python tuple and pickle it
988 //===========================================================================
989 PyObject *args(PyTuple_New(getNumberOfInputPorts()));
991 for(std::list<InputPort *>::iterator iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++,pos++)
993 InputPyPort *p=(InputPyPort *)*iter2;
996 PyTuple_SetItem(args,pos,ob);
999 PyObject_Print(args,stderr,Py_PRINT_RAW);
1002 PyObject *serializationInput=PyObject_CallObject(_pyfuncSer,args);
1004 //The pickled string may contain NULL characters so use PyString_AsStringAndSize
1005 char *serializationInputC(0);
1007 if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
1008 throw Exception("DistributedPythonNode problem in python pickle");
1010 serializationInputCorba->length(len);
1011 for(int i=0; i < len ; i++)
1012 serializationInputCorba[i]=serializationInputC[i];
1013 Py_DECREF(serializationInput);
1016 //===========================================================================
1017 // Execute in remote Python node
1018 //===========================================================================
1019 DEBTRACE( "-----------------starting remote python invocation-----------------" );
1020 Engines::pickledArgs_var resultCorba;
1023 resultCorba=_pynode->execute(getFname().c_str(),serializationInputCorba);
1025 catch( const SALOME::SALOME_Exception& ex )
1027 std::string msg="Exception on remote python invocation";
1029 msg += ex.details.text.in();
1031 throw Exception(msg);
1033 DEBTRACE( "-----------------end of remote python invocation-----------------" );
1034 //===========================================================================
1035 // Get results, unpickle and put them in output ports
1036 //===========================================================================
1037 char *resultCorbaC=new char[resultCorba->length()+1];
1038 resultCorbaC[resultCorba->length()]='\0';
1039 for(int i=0;i<resultCorba->length();i++)
1040 resultCorbaC[i]=resultCorba[i];
1045 PyObject *resultPython(PyBytes_FromStringAndSize(resultCorbaC,resultCorba->length()));
1046 delete [] resultCorbaC;
1047 PyObject *args(PyTuple_New(1)),*ob(0);
1048 PyTuple_SetItem(args,0,resultPython);
1049 PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
1052 DEBTRACE( "-----------------PythonNode::outputs-----------------" );
1054 if(finalResult == Py_None)
1056 else if(PyTuple_Check(finalResult))
1057 nres=PyTuple_Size(finalResult);
1059 if(getNumberOfOutputPorts() != nres)
1061 std::string msg="Number of output arguments : Mismatch between definition and execution";
1062 Py_DECREF(finalResult);
1064 throw Exception(msg);
1070 for(std::list<OutputPort *>::iterator iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++, pos++)
1072 OutputPyPort *p=(OutputPyPort *)*iter;
1073 DEBTRACE( "port name: " << p->getName() );
1074 DEBTRACE( "port kind: " << p->edGetType()->kind() );
1075 DEBTRACE( "port pos : " << pos );
1076 if(PyTuple_Check(finalResult))
1077 ob=PyTuple_GetItem(finalResult,pos) ;
1080 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1083 Py_DECREF(finalResult);
1085 catch(ConversionException& ex)
1087 Py_DECREF(finalResult);
1088 _errorDetails=ex.what();
1093 DEBTRACE( "++++++++++++++ ENDOF PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
1096 void PyFuncNode::executeLocal()
1098 DEBTRACE( "++++++++++++++ PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
1102 if(!_pyfunc)throw Exception("PyFuncNode badly loaded");
1105 DEBTRACE( "---------------PyFuncNode::inputs---------------" );
1106 PyObject* args = PyTuple_New(getNumberOfInputPorts()) ;
1107 list<InputPort *>::iterator iter2;
1108 for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
1110 InputPyPort *p=(InputPyPort *)*iter2;
1111 DEBTRACE( "port name: " << p->getName() );
1112 DEBTRACE( "port kind: " << p->edGetType()->kind() );
1115 PyObject_Print(ob,stderr,Py_PRINT_RAW);
1118 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1120 PyTuple_SetItem(args,pos,ob);
1121 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1124 DEBTRACE( "---------------End PyFuncNode::inputs---------------" );
1126 DEBTRACE( "----------------PyFuncNode::calculation---------------" );
1128 PyObject_Print(_pyfunc,stderr,Py_PRINT_RAW);
1130 PyObject_Print(args,stderr,Py_PRINT_RAW);
1133 DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1134 PyObject* result = PyObject_CallObject( _pyfunc , args ) ;
1135 DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1142 PyObject* new_stderr = newPyStdOut(_errorDetails);
1143 PySys_SetObject((char*)"stderr", new_stderr);
1144 std::ostringstream stream;
1145 stream << "/tmp/PythonNode_";
1147 ofstream errorfile(stream.str().c_str());
1148 if (errorfile.is_open())
1150 errorfile << _script;
1154 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1155 Py_DECREF(new_stderr);
1156 throw Exception("Error during execution");
1158 DEBTRACE( "----------------End PyFuncNode::calculation---------------" );
1160 DEBTRACE( "-----------------PyFuncNode::outputs-----------------" );
1162 if(result == Py_None)
1164 else if(PyTuple_Check(result))
1165 nres=PyTuple_Size(result);
1167 if(getNumberOfOutputPorts() != nres)
1169 std::string msg="Number of output arguments : Mismatch between definition and execution";
1172 throw Exception(msg);
1177 PyObject_Print(result,stderr,Py_PRINT_RAW);
1180 list<OutputPort *>::iterator iter;
1183 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
1185 OutputPyPort *p=(OutputPyPort *)*iter;
1186 DEBTRACE( "port name: " << p->getName() );
1187 DEBTRACE( "port kind: " << p->edGetType()->kind() );
1188 DEBTRACE( "port pos : " << pos );
1189 if(PyTuple_Check(result))ob=PyTuple_GetItem(result,pos) ;
1191 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1193 PyObject_Print(ob,stderr,Py_PRINT_RAW);
1200 catch(ConversionException& ex)
1203 _errorDetails=ex.what();
1206 DEBTRACE( "-----------------End PyFuncNode::outputs-----------------" );
1209 DEBTRACE( "++++++++++++++ End PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
1212 Node *PyFuncNode::simpleClone(ComposedNode *father, bool editionOnly) const
1214 return new PyFuncNode(*this,father);
1217 void PyFuncNode::createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)
1219 if(!CORBA::is_nil(_pynode))
1220 _pynode->UnRegister();
1221 _pynode=objContainer->createPyNode(getName().c_str(),getScript().c_str());
1224 Engines::PyNodeBase_var PyFuncNode::retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const
1226 Engines::PyNode_var ret(objContainer->getDefaultPyNode(getName().c_str()));
1227 if(!CORBA::is_nil(ret))
1231 return Engines::PyNodeBase::_narrow(ret);
1234 void PyFuncNode::assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)
1236 if(!CORBA::is_nil(_pynode))
1238 Engines::PyNode_var tmpp(Engines::PyNode::_narrow(remoteInterp));
1239 if(_pynode->_is_equivalent(tmpp))
1242 if(!CORBA::is_nil(_pynode))
1243 _pynode->UnRegister();
1244 _pynode=Engines::PyNode::_narrow(remoteInterp);
1247 Engines::PyNodeBase_var PyFuncNode::getRemoteInterpreterHandle()
1249 return Engines::PyNodeBase::_narrow(_pynode);
1252 //! Create a new node of same type with a given name
1253 PyFuncNode* PyFuncNode::cloneNode(const std::string& name)
1255 PyFuncNode* n=new PyFuncNode(name);
1256 n->setScript(_script);
1257 n->setFname(_fname);
1258 list<InputPort *>::iterator iter;
1259 for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
1261 InputPyPort *p=(InputPyPort *)*iter;
1262 n->edAddInputPort(p->getName(),p->edGetType());
1264 list<OutputPort *>::iterator iter2;
1265 for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
1267 OutputPyPort *p=(OutputPyPort *)*iter2;
1268 n->edAddOutputPort(p->getName(),p->edGetType());
1273 std::string PyFuncNode::getContainerLog()
1275 return PythonEntry::GetContainerLog(_mode,_container,this);
1278 void PyFuncNode::shutdown(int level)
1280 DEBTRACE("PyFuncNode::shutdown " << level);
1281 if(_mode=="local")return;
1284 if(!CORBA::is_nil(_pynode)) _pynode->UnRegister();
1285 _pynode=Engines::PyNode::_nil();
1286 _container->shutdown(level);