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),_autoSqueeze(other._autoSqueeze)
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 *resultCorba(nullptr);
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 auto length(resultCorba->length());
482 char *resultCorbaC=new char[length+1];
483 for(int i=0;i<length;i++)
484 resultCorbaC[i]=(*resultCorba)[i];
485 resultCorbaC[length]='\0';
486 delete resultCorba; resultCorba=nullptr;
489 PyObject *args(0),*ob(0);
490 PyObject* resultPython=PyBytes_FromStringAndSize(resultCorbaC,length);
491 delete [] resultCorbaC;
492 args = PyTuple_New(1);
493 PyTuple_SetItem(args,0,resultPython);
494 PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
497 if (finalResult == NULL)
499 std::stringstream msg;
500 msg << "Conversion with pickle of output ports failed !";
501 msg << " : " << __FILE__ << ":" << __LINE__;
502 _errorDetails=msg.str();
503 throw YACS::ENGINE::ConversionException(msg.str());
506 DEBTRACE( "-----------------PythonNode::outputs-----------------" );
508 if(finalResult == Py_None)
510 else if(PyTuple_Check(finalResult))
511 nres=PyTuple_Size(finalResult);
513 if(getNumberOfOutputPorts() != nres)
515 std::string msg="Number of output arguments : Mismatch between definition and execution";
516 Py_DECREF(finalResult);
518 throw Exception(msg);
524 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); ++iter)
526 OutputPyPort *p=(OutputPyPort *)*iter;
527 DEBTRACE( "port name: " << p->getName() );
528 DEBTRACE( "port kind: " << p->edGetType()->kind() );
529 DEBTRACE( "port pos : " << pos );
530 if(PyTuple_Check(finalResult))
531 ob=PyTuple_GetItem(finalResult,pos) ;
534 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
538 Py_DECREF(finalResult);
540 catch(ConversionException& ex)
542 Py_DECREF(finalResult);
543 _errorDetails=ex.what();
547 squeezeMemoryRemote();
550 if(!CORBA::is_nil(_pynode))
552 _pynode->UnRegister();
554 _pynode = Engines::PyScriptNode::_nil();
556 Engines::Container_var cont(GetContainerObj(this,dummy));
557 cont->removePyScriptNode(getName().c_str());
558 DEBTRACE( "++++++++++++++ ENDOF PyNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
561 void PythonNode::executeLocal()
563 DEBTRACE( "++++++++++++++ PyNode::executeLocal: " << getName() << " ++++++++++++++++++++" );
567 DEBTRACE( "---------------PyNode::inputs---------------" );
568 list<InputPort *>::iterator iter2;
569 for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
571 InputPyPort *p=(InputPyPort *)*iter2;
572 DEBTRACE( "port name: " << p->getName() );
573 DEBTRACE( "port kind: " << p->edGetType()->kind() );
574 PyObject* ob=p->getPyObj();
575 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
577 PyObject_Print(ob,stderr,Py_PRINT_RAW);
580 int ier=PyDict_SetItemString(_context,p->getName().c_str(),ob);
581 DEBTRACE( "after PyDict_SetItemString:ob refcnt: " << ob->ob_refcnt );
584 DEBTRACE( "---------------End PyNode::inputs---------------" );
587 DEBTRACE( "----------------PyNode::calculation---------------" );
589 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
591 std::ostringstream stream;
592 stream << "/tmp/PythonNode_";
595 PyObject* code=Py_CompileString(_script.c_str(), stream.str().c_str(), Py_file_input);
599 PyObject* new_stderr = newPyStdOut(_errorDetails);
600 PySys_SetObject((char*)"stderr", new_stderr);
602 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
603 Py_DECREF(new_stderr);
604 throw Exception("Error during execution");
606 PyObject *res = PyEval_EvalCode( code, _context, _context);
610 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
613 if(PyErr_Occurred ())
616 PyObject* new_stderr = newPyStdOut(_errorDetails);
617 PySys_SetObject((char*)"stderr", new_stderr);
618 ofstream errorfile(stream.str().c_str());
619 if (errorfile.is_open())
621 errorfile << _script;
625 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
626 Py_DECREF(new_stderr);
627 throw Exception("Error during execution");
630 DEBTRACE( "-----------------PyNode::outputs-----------------" );
631 list<OutputPort *>::iterator iter;
634 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
636 OutputPyPort *p=(OutputPyPort *)*iter;
637 DEBTRACE( "port name: " << p->getName() );
638 DEBTRACE( "port kind: " << p->edGetType()->kind() );
639 PyObject *ob=PyDict_GetItemString(_context,p->getName().c_str());
642 std::string msg="Error during execution: there is no variable ";
643 msg=msg+p->getName()+" in node context";
645 throw Exception(msg);
647 DEBTRACE( "PyNode::outputs::ob refcnt: " << ob->ob_refcnt );
649 PyObject_Print(ob,stderr,Py_PRINT_RAW);
655 catch(ConversionException& ex)
657 _errorDetails=ex.what();
662 DEBTRACE( "-----------------End PyNode::outputs-----------------" );
664 DEBTRACE( "++++++++++++++ End PyNode::execute: " << getName() << " ++++++++++++++++++++" );
667 void PythonNode::squeezeMemorySafe()
670 if(_mode==PythonNode::REMOTE_NAME)
671 this->squeezeMemoryRemote();
673 this->squeezeMemory();
676 void PythonNode::squeezeMemory()
678 for(auto p : _setOfInputPort)
680 PyDict_DelItemString(_context,p->getName().c_str());
681 InputPyPort *p2(static_cast<InputPyPort *>(p));
682 if(p2->canSafelySqueezeMemory())
685 for(auto p : _setOfOutputPort)
687 PyDict_DelItemString(_context,p->getName().c_str());
688 OutputPyPort *p2(static_cast<OutputPyPort *>(p));
689 p2->putWithoutForward(Py_None);
693 void PythonNode::squeezeMemoryRemote()
695 for(auto p : _setOfInputPort)
697 InputPyPort *p2(static_cast<InputPyPort *>(p));
698 if(p2->canSafelySqueezeMemory())
701 for(auto p : _setOfOutputPort)
703 OutputPyPort *p2(static_cast<OutputPyPort *>(p));
704 p2->putWithoutForward(Py_None);
708 std::string PythonNode::getContainerLog()
710 return PythonEntry::GetContainerLog(_mode,_container,this);
713 void PythonNode::shutdown(int level)
715 DEBTRACE("PythonNode::shutdown " << level);
716 if(_mode=="local")return;
719 if(!CORBA::is_nil(_pynode)) _pynode->UnRegister();
720 _pynode=Engines::PyScriptNode::_nil();
721 _container->shutdown(level);
725 Node *PythonNode::simpleClone(ComposedNode *father, bool editionOnly) const
727 return new PythonNode(*this,father);
730 void PythonNode::createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)
732 if(!CORBA::is_nil(_pynode))
733 _pynode->UnRegister();
734 _pynode=objContainer->createPyScriptNode(getName().c_str(),getScript().c_str());
738 Engines::PyNodeBase_var PythonNode::retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const
740 Engines::PyScriptNode_var ret(objContainer->getDefaultPyScriptNode(getName().c_str()));
741 if(!CORBA::is_nil(ret))
745 return Engines::PyNodeBase::_narrow(ret);
748 void PythonNode::assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)
750 if(!CORBA::is_nil(_pynode))
752 Engines::PyScriptNode_var tmpp(Engines::PyScriptNode::_narrow(remoteInterp));
753 if(_pynode->_is_equivalent(tmpp))
755 _pynode->UnRegister();
759 if(!CORBA::is_nil(_pynode))
760 _pynode->UnRegister();
761 _pynode=Engines::PyScriptNode::_narrow(remoteInterp);
764 Engines::PyNodeBase_var PythonNode::getRemoteInterpreterHandle()
766 return Engines::PyNodeBase::_narrow(_pynode);
769 //! Create a new node of same type with a given name
770 PythonNode* PythonNode::cloneNode(const std::string& name)
772 PythonNode* n=new PythonNode(name);
773 n->setScript(_script);
774 list<InputPort *>::iterator iter;
775 for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
777 InputPyPort *p=(InputPyPort *)*iter;
778 DEBTRACE( "port name: " << p->getName() );
779 DEBTRACE( "port kind: " << p->edGetType()->kind() );
780 n->edAddInputPort(p->getName(),p->edGetType());
782 list<OutputPort *>::iterator iter2;
783 for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
785 OutputPyPort *p=(OutputPyPort *)*iter2;
786 DEBTRACE( "port name: " << p->getName() );
787 DEBTRACE( "port kind: " << p->edGetType()->kind() );
788 n->edAddOutputPort(p->getName(),p->edGetType());
793 void PythonNode::applyDPLScope(ComposedNode *gfn)
795 std::vector< std::pair<std::string,int> > ret(getDPLScopeInfo(gfn));
802 std::size_t sz(ret.size());
804 for(std::size_t i=0;i<sz;i++)
806 const std::pair<std::string,int>& p(ret[i]);
807 PyObject *elt(PyTuple_New(2));
808 PyTuple_SetItem(elt,0,PyUnicode_FromString(p.first.c_str()));
809 PyTuple_SetItem(elt,1,PyLong_FromLong(p.second));
810 PyList_SetItem(ob,i,elt);
813 if(_mode==REMOTE_NAME)
815 Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);
818 PyObject *serializationInput(PyObject_CallFunctionObjArgs(_pyfuncSimpleSer,ob,NULL));
820 char *serializationInputC(0);
822 if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
823 throw Exception("DistributedPythonNode problem in python pickle");
824 serializationInputCorba->length(len);
825 for(int i=0; i < len ; i++)
826 serializationInputCorba[i]=serializationInputC[i];
827 Py_XDECREF(serializationInput);
829 _pynode->defineNewCustomVar(DPL_INFO_NAME,serializationInputCorba);
834 PyDict_SetItemString(_context,DPL_INFO_NAME,ob);
839 PyFuncNode::PyFuncNode(const PyFuncNode& other, ComposedNode *father):InlineFuncNode(other,father),_pyfunc(0)
841 _implementation = PythonNode::IMPL_NAME;
844 _context=PyDict_New();
845 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
846 if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
849 msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
850 _errorDetails=msg.str();
851 throw Exception(msg.str());
856 PyFuncNode::PyFuncNode(const std::string& name): InlineFuncNode(name),_pyfunc(0)
859 _implementation = PythonNode::IMPL_NAME;
860 DEBTRACE( "PyFuncNode::PyFuncNode " << name );
863 _context=PyDict_New();
864 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
865 if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
868 msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
869 _errorDetails=msg.str();
870 throw Exception(msg.str());
875 PyFuncNode::~PyFuncNode()
877 if(!CORBA::is_nil(_pynode))
879 _pynode->UnRegister();
883 void PyFuncNode::init(bool start)
885 initCommonPartWithoutStateManagement(start);
886 if(_state == YACS::DISABLED)
888 exDisabledState(); // to refresh propagation of DISABLED state
891 if(start) //complete initialization
892 setState(YACS::READY);
893 else if(_state > YACS::LOADED)// WARNING FuncNode has internal vars (CEA usecase) ! Partial initialization (inside a loop). Exclusivity of funcNode.
894 setState(YACS::TORECONNECT);
897 void PyFuncNode::checkBasicConsistency() const throw(YACS::Exception)
899 DEBTRACE("checkBasicConsistency");
900 InlineFuncNode::checkBasicConsistency();
904 res=Py_CompileString(_script.c_str(),getName().c_str(),Py_file_input);
907 std::string error="";
908 PyObject* new_stderr = newPyStdOut(error);
909 PySys_SetObject((char*)"stderr", new_stderr);
911 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
912 Py_DECREF(new_stderr);
913 throw Exception(error);
920 void PyFuncNode::load()
922 DEBTRACE( "---------------PyfuncNode::load function---------------" );
923 if(_mode==PythonNode::REMOTE_NAME)
929 void PyFuncNode::loadRemote()
931 commonRemoteLoad(this);
934 void PyFuncNode::loadLocal()
936 DEBTRACE( "---------------PyFuncNode::load function " << getName() << " ---------------" );
940 list<OutputPort *>::iterator iter;
941 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
943 OutputPyPort *p=(OutputPyPort *)*iter;
944 DEBTRACE( "port name: " << p->getName() );
945 DEBTRACE( "port kind: " << p->edGetType()->kind() );
951 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
953 std::ostringstream stream;
954 stream << "/tmp/PythonNode_";
957 PyObject* code=Py_CompileString(_script.c_str(), stream.str().c_str(), Py_file_input);
961 PyObject* new_stderr = newPyStdOut(_errorDetails);
962 PySys_SetObject((char*)"stderr", new_stderr);
964 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
965 Py_DECREF(new_stderr);
966 throw Exception("Error during execution");
968 PyObject *res = PyEval_EvalCode( code, _context, _context);
972 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
973 if(PyErr_Occurred ())
976 PyObject* new_stderr = newPyStdOut(_errorDetails);
977 PySys_SetObject((char*)"stderr", new_stderr);
978 ofstream errorfile(stream.str().c_str());
979 if (errorfile.is_open())
981 errorfile << _script;
985 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
986 Py_DECREF(new_stderr);
987 throw Exception("Error during execution");
990 _pyfunc=PyDict_GetItemString(_context,_fname.c_str());
991 DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
995 PyObject* new_stderr = newPyStdOut(_errorDetails);
996 PySys_SetObject((char*)"stderr", new_stderr);
998 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
999 Py_DECREF(new_stderr);
1000 throw Exception("Error during execution");
1002 DEBTRACE( "---------------End PyFuncNode::load function---------------" );
1006 void PyFuncNode::execute()
1008 if(_mode==PythonNode::REMOTE_NAME)
1014 void PyFuncNode::executeRemote()
1016 DEBTRACE( "++++++++++++++ PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
1018 throw Exception("DistributedPythonNode badly loaded");
1020 if(dynamic_cast<HomogeneousPoolContainer *>(getContainer()))
1023 commonRemoteLoadPart2(this,dummy);
1024 _pynode->executeAnotherPieceOfCode(getScript().c_str());
1027 Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);;
1031 //===========================================================================
1032 // Get inputs in input ports, build a Python tuple and pickle it
1033 //===========================================================================
1034 PyObject *args(PyTuple_New(getNumberOfInputPorts()));
1036 for(std::list<InputPort *>::iterator iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++,pos++)
1038 InputPyPort *p=(InputPyPort *)*iter2;
1041 PyTuple_SetItem(args,pos,ob);
1044 PyObject_Print(args,stderr,Py_PRINT_RAW);
1047 PyObject *serializationInput=PyObject_CallObject(_pyfuncSer,args);
1049 //The pickled string may contain NULL characters so use PyString_AsStringAndSize
1050 char *serializationInputC(0);
1052 if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
1053 throw Exception("DistributedPythonNode problem in python pickle");
1055 serializationInputCorba->length(len);
1056 for(int i=0; i < len ; i++)
1057 serializationInputCorba[i]=serializationInputC[i];
1058 Py_DECREF(serializationInput);
1061 //===========================================================================
1062 // Execute in remote Python node
1063 //===========================================================================
1064 DEBTRACE( "-----------------starting remote python invocation-----------------" );
1065 Engines::pickledArgs_var resultCorba;
1068 resultCorba=_pynode->execute(getFname().c_str(),serializationInputCorba);
1070 catch( const SALOME::SALOME_Exception& ex )
1072 std::string msg="Exception on remote python invocation";
1074 msg += ex.details.text.in();
1076 throw Exception(msg);
1078 DEBTRACE( "-----------------end of remote python invocation-----------------" );
1079 //===========================================================================
1080 // Get results, unpickle and put them in output ports
1081 //===========================================================================
1082 char *resultCorbaC=new char[resultCorba->length()+1];
1083 resultCorbaC[resultCorba->length()]='\0';
1084 for(int i=0;i<resultCorba->length();i++)
1085 resultCorbaC[i]=resultCorba[i];
1090 PyObject *resultPython(PyBytes_FromStringAndSize(resultCorbaC,resultCorba->length()));
1091 delete [] resultCorbaC;
1092 PyObject *args(PyTuple_New(1)),*ob(0);
1093 PyTuple_SetItem(args,0,resultPython);
1094 PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
1097 DEBTRACE( "-----------------PythonNode::outputs-----------------" );
1099 if(finalResult == Py_None)
1101 else if(PyTuple_Check(finalResult))
1102 nres=PyTuple_Size(finalResult);
1104 if(getNumberOfOutputPorts() != nres)
1106 std::string msg="Number of output arguments : Mismatch between definition and execution";
1107 Py_DECREF(finalResult);
1109 throw Exception(msg);
1115 for(std::list<OutputPort *>::iterator iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++, pos++)
1117 OutputPyPort *p=(OutputPyPort *)*iter;
1118 DEBTRACE( "port name: " << p->getName() );
1119 DEBTRACE( "port kind: " << p->edGetType()->kind() );
1120 DEBTRACE( "port pos : " << pos );
1121 if(PyTuple_Check(finalResult))
1122 ob=PyTuple_GetItem(finalResult,pos) ;
1125 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1128 Py_DECREF(finalResult);
1130 catch(ConversionException& ex)
1132 Py_DECREF(finalResult);
1133 _errorDetails=ex.what();
1138 DEBTRACE( "++++++++++++++ ENDOF PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
1141 void PyFuncNode::executeLocal()
1143 DEBTRACE( "++++++++++++++ PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
1147 if(!_pyfunc)throw Exception("PyFuncNode badly loaded");
1150 DEBTRACE( "---------------PyFuncNode::inputs---------------" );
1151 PyObject* args = PyTuple_New(getNumberOfInputPorts()) ;
1152 list<InputPort *>::iterator iter2;
1153 for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
1155 InputPyPort *p=(InputPyPort *)*iter2;
1156 DEBTRACE( "port name: " << p->getName() );
1157 DEBTRACE( "port kind: " << p->edGetType()->kind() );
1160 PyObject_Print(ob,stderr,Py_PRINT_RAW);
1163 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1165 PyTuple_SetItem(args,pos,ob);
1166 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1169 DEBTRACE( "---------------End PyFuncNode::inputs---------------" );
1171 DEBTRACE( "----------------PyFuncNode::calculation---------------" );
1173 PyObject_Print(_pyfunc,stderr,Py_PRINT_RAW);
1175 PyObject_Print(args,stderr,Py_PRINT_RAW);
1178 DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1179 PyObject* result = PyObject_CallObject( _pyfunc , args ) ;
1180 DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1187 PyObject* new_stderr = newPyStdOut(_errorDetails);
1188 PySys_SetObject((char*)"stderr", new_stderr);
1189 std::ostringstream stream;
1190 stream << "/tmp/PythonNode_";
1192 ofstream errorfile(stream.str().c_str());
1193 if (errorfile.is_open())
1195 errorfile << _script;
1199 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1200 Py_DECREF(new_stderr);
1201 throw Exception("Error during execution");
1203 DEBTRACE( "----------------End PyFuncNode::calculation---------------" );
1205 DEBTRACE( "-----------------PyFuncNode::outputs-----------------" );
1207 if(result == Py_None)
1209 else if(PyTuple_Check(result))
1210 nres=PyTuple_Size(result);
1212 if(getNumberOfOutputPorts() != nres)
1214 std::string msg="Number of output arguments : Mismatch between definition and execution";
1217 throw Exception(msg);
1222 PyObject_Print(result,stderr,Py_PRINT_RAW);
1225 list<OutputPort *>::iterator iter;
1228 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
1230 OutputPyPort *p=(OutputPyPort *)*iter;
1231 DEBTRACE( "port name: " << p->getName() );
1232 DEBTRACE( "port kind: " << p->edGetType()->kind() );
1233 DEBTRACE( "port pos : " << pos );
1234 if(PyTuple_Check(result))ob=PyTuple_GetItem(result,pos) ;
1236 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1238 PyObject_Print(ob,stderr,Py_PRINT_RAW);
1245 catch(ConversionException& ex)
1248 _errorDetails=ex.what();
1251 DEBTRACE( "-----------------End PyFuncNode::outputs-----------------" );
1254 DEBTRACE( "++++++++++++++ End PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
1257 Node *PyFuncNode::simpleClone(ComposedNode *father, bool editionOnly) const
1259 return new PyFuncNode(*this,father);
1262 void PyFuncNode::createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)
1264 if(!CORBA::is_nil(_pynode))
1265 _pynode->UnRegister();
1266 _pynode=objContainer->createPyNode(getName().c_str(),getScript().c_str());
1269 Engines::PyNodeBase_var PyFuncNode::retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const
1271 Engines::PyNode_var ret(objContainer->getDefaultPyNode(getName().c_str()));
1272 if(!CORBA::is_nil(ret))
1276 return Engines::PyNodeBase::_narrow(ret);
1279 void PyFuncNode::assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)
1281 if(!CORBA::is_nil(_pynode))
1283 Engines::PyNode_var tmpp(Engines::PyNode::_narrow(remoteInterp));
1284 if(_pynode->_is_equivalent(tmpp))
1287 if(!CORBA::is_nil(_pynode))
1288 _pynode->UnRegister();
1289 _pynode=Engines::PyNode::_narrow(remoteInterp);
1292 Engines::PyNodeBase_var PyFuncNode::getRemoteInterpreterHandle()
1294 return Engines::PyNodeBase::_narrow(_pynode);
1297 //! Create a new node of same type with a given name
1298 PyFuncNode* PyFuncNode::cloneNode(const std::string& name)
1300 PyFuncNode* n=new PyFuncNode(name);
1301 n->setScript(_script);
1302 n->setFname(_fname);
1303 list<InputPort *>::iterator iter;
1304 for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
1306 InputPyPort *p=(InputPyPort *)*iter;
1307 n->edAddInputPort(p->getName(),p->edGetType());
1309 list<OutputPort *>::iterator iter2;
1310 for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
1312 OutputPyPort *p=(OutputPyPort *)*iter2;
1313 n->edAddOutputPort(p->getName(),p->edGetType());
1318 std::string PyFuncNode::getContainerLog()
1320 return PythonEntry::GetContainerLog(_mode,_container,this);
1323 void PyFuncNode::shutdown(int level)
1325 DEBTRACE("PyFuncNode::shutdown " << level);
1326 if(_mode=="local")return;
1329 if(!CORBA::is_nil(_pynode)) _pynode->UnRegister();
1330 _pynode=Engines::PyNode::_nil();
1331 _container->shutdown(level);