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"
79 const char PythonNode::KEEP_CONTEXT_PROPERTY[]="keep_context";
81 PythonEntry::PythonEntry():_context(0),_pyfuncSer(0),_pyfuncUnser(0),_pyfuncSimpleSer(0)
85 PythonEntry::~PythonEntry()
88 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
89 // not Py_XDECREF of _pyfuncUnser because it is returned by PyDict_GetItem -> borrowed
90 // not Py_XDECREF of _pyfuncSer because it is returned by PyDict_GetItem -> borrowed
94 void PythonEntry::loadRemoteContainer(InlineNode *reqNode)
96 DEBTRACE( "---------------PythonEntry::CommonRemoteLoad function---------------" );
97 Container *container(reqNode->getContainer());
98 bool isContAlreadyStarted(false);
101 isContAlreadyStarted=container->isAlreadyStarted(reqNode);
102 if(!isContAlreadyStarted)
106 if(hasImposedResource())
107 container->start(reqNode, _imposedResource, _imposedContainer);
109 container->start(reqNode);
113 reqNode->setErrorDetails(e.what());
120 std::string what("PythonEntry::CommonRemoteLoad : a load operation requested on \"");
121 what+=reqNode->getName(); what+="\" with no container specified.";
122 reqNode->setErrorDetails(what);
123 throw Exception(what);
127 Engines::Container_var GetContainerObj(InlineNode *reqNode, bool& isStandardCont)
129 isStandardCont = false;
130 Container *container(reqNode->getContainer());
131 Engines::Container_var objContainer(Engines::Container::_nil());
133 throw YACS::Exception("No container specified !");
134 SalomeContainer *containerCast0(dynamic_cast<SalomeContainer *>(container));
135 SalomeHPContainer *containerCast1(dynamic_cast<SalomeHPContainer *>(container));
138 isStandardCont = true;
139 objContainer=containerCast0->getContainerPtr(reqNode);
141 else if(containerCast1)
143 YACS::BASES::AutoCppPtr<SalomeContainerTmpForHP> tmpCont(SalomeContainerTmpForHP::BuildFrom(containerCast1,reqNode));
144 objContainer=tmpCont->getContainerPtr(reqNode);
147 throw YACS::Exception("Unrecognized type of container ! Salome one is expected for PythonNode/PyFuncNode !");
148 if(CORBA::is_nil(objContainer))
149 throw YACS::Exception("Container corba pointer is NULL for PythonNode !");
153 Engines::Container_var PythonEntry::loadPythonAdapter(InlineNode *reqNode, bool& isInitializeRequested)
155 bool isStandardCont(true);
156 Engines::Container_var objContainer(GetContainerObj(reqNode,isStandardCont));
157 isInitializeRequested=false;
160 Engines::PyNodeBase_var dftPyScript(retrieveDftRemotePyInterpretorIfAny(objContainer));
161 if(CORBA::is_nil(dftPyScript))
163 isInitializeRequested=!isStandardCont;
164 createRemoteAdaptedPyInterpretor(objContainer);
167 assignRemotePyInterpretor(dftPyScript);
169 catch( const SALOME::SALOME_Exception& ex )
171 std::string msg="Exception on remote python node creation ";
173 msg += ex.details.text.in();
174 reqNode->setErrorDetails(msg);
175 throw Exception(msg);
177 Engines::PyNodeBase_var pynode(getRemoteInterpreterHandle());
178 if(CORBA::is_nil(pynode))
179 throw Exception("In PythonNode the ref in NULL ! ");
183 void PythonEntry::loadRemoteContext(InlineNode *reqNode, Engines::Container_ptr objContainer, bool isInitializeRequested)
185 Container *container(reqNode->getContainer());
186 Engines::PyNodeBase_var pynode(getRemoteInterpreterHandle());
190 const char *picklizeScript(getSerializationScript());
191 PyObject *res=PyRun_String(picklizeScript,Py_file_input,_context,_context);
192 PyObject *res2(PyRun_String(SCRIPT_FOR_SIMPLE_SERIALIZATION,Py_file_input,_context,_context));
193 if(res == NULL || res2==NULL)
195 std::string errorDetails;
196 PyObject* new_stderr = newPyStdOut(errorDetails);
197 reqNode->setErrorDetails(errorDetails);
198 PySys_SetObject((char*)"stderr", new_stderr);
200 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
201 Py_DECREF(new_stderr);
202 throw Exception("Error during load");
204 Py_DECREF(res); Py_DECREF(res2);
205 _pyfuncSer=PyDict_GetItemString(_context,"pickleForDistPyth2009");
206 _pyfuncUnser=PyDict_GetItemString(_context,"unPickleForDistPyth2009");
207 _pyfuncSimpleSer=PyDict_GetItemString(_context,"pickleForVarSimplePyth2009");
208 if(_pyfuncSer == NULL)
210 std::string errorDetails;
211 PyObject *new_stderr(newPyStdOut(errorDetails));
212 reqNode->setErrorDetails(errorDetails);
213 PySys_SetObject((char*)"stderr", new_stderr);
215 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
216 Py_DECREF(new_stderr);
217 throw Exception("Error during load");
219 if(_pyfuncUnser == NULL)
221 std::string errorDetails;
222 PyObject *new_stderr(newPyStdOut(errorDetails));
223 reqNode->setErrorDetails(errorDetails);
224 PySys_SetObject((char*)"stderr", new_stderr);
226 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
227 Py_DECREF(new_stderr);
228 throw Exception("Error during load");
230 if(_pyfuncSimpleSer == NULL)
232 std::string errorDetails;
233 PyObject *new_stderr(newPyStdOut(errorDetails));
234 reqNode->setErrorDetails(errorDetails);
235 PySys_SetObject((char*)"stderr", new_stderr);
237 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
238 Py_DECREF(new_stderr);
239 throw Exception("Error during load");
242 if(isInitializeRequested)
243 {//This one is called only once at initialization in the container if an init-script is specified.
246 std::string zeInitScriptKey(container->getProperty(HomogeneousPoolContainer::INITIALIZE_SCRIPT_KEY));
247 if(!zeInitScriptKey.empty())
248 pynode->executeAnotherPieceOfCode(zeInitScriptKey.c_str());
250 catch( const SALOME::SALOME_Exception& ex )
252 std::string msg="Exception on PythonNode::loadRemote python invocation of initializisation py script !";
254 msg += ex.details.text.in();
255 reqNode->setErrorDetails(msg);
256 throw Exception(msg);
258 DEBTRACE( "---------------End PyNode::loadRemote function---------------" );
262 std::string PythonEntry::GetContainerLog(const std::string& mode, Container *container, const Task *askingTask)
270 SalomeContainer *containerCast(dynamic_cast<SalomeContainer *>(container));
271 SalomeHPContainer *objContainer2(dynamic_cast<SalomeHPContainer *>(container));
274 Engines::Container_var objContainer(containerCast->getContainerPtr(askingTask));
275 CORBA::String_var logname = objContainer->logfilename();
278 std::string::size_type pos = msg.find(":");
279 msg=msg.substr(pos+1);
281 else if(objContainer2)
283 msg="Remote PythonNode is on HP Container : no log because no info of the location by definition of HP Container !";
287 msg="Not implemented yet for container log for that type of container !";
292 msg = "Container no longer reachable";
297 void PythonEntry::commonRemoteLoad(InlineNode *reqNode)
299 loadRemoteContainer(reqNode);
300 bool isInitializeRequested;
301 Engines::Container_var objContainer(loadPythonAdapter(reqNode,isInitializeRequested));
302 loadRemoteContext(reqNode,objContainer,isInitializeRequested);
305 bool PythonEntry::hasImposedResource()const
307 return !_imposedResource.empty() && !_imposedContainer.empty();
310 PythonNode::PythonNode(const PythonNode& other, ComposedNode *father):InlineNode(other,father),_autoSqueeze(other._autoSqueeze)
312 _pynode = Engines::PyScriptNode::_nil();
313 _implementation=IMPL_NAME;
316 _context=PyDict_New();
317 if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
320 msg << "Impossible to set builtins" << __FILE__ << ":" << __LINE__;
321 _errorDetails=msg.str();
322 throw Exception(msg.str());
327 PythonNode::PythonNode(const std::string& name):InlineNode(name)
329 _pynode = Engines::PyScriptNode::_nil();
330 _implementation=IMPL_NAME;
333 _context=PyDict_New();
334 if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
337 msg << "Impossible to set builtins" << __FILE__ << ":" << __LINE__;
338 _errorDetails=msg.str();
339 throw Exception(msg.str());
344 PythonNode::~PythonNode()
346 if(!CORBA::is_nil(_pynode))
348 _pynode->UnRegister();
352 void PythonNode::checkBasicConsistency() const
354 DEBTRACE("checkBasicConsistency");
355 InlineNode::checkBasicConsistency();
359 res=Py_CompileString(_script.c_str(),getName().c_str(),Py_file_input);
362 std::string error="";
363 PyObject* new_stderr = newPyStdOut(error);
364 PySys_SetObject((char*)"stderr", new_stderr);
366 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
367 Py_DECREF(new_stderr);
368 throw Exception(error);
375 void PythonNode::load()
377 DEBTRACE( "---------------PyNode::load function---------------" );
378 if(_mode==PythonNode::REMOTE_NAME)
384 void PythonNode::loadLocal()
386 DEBTRACE( "---------------PyNode::loadLocal function---------------" );
390 void PythonNode::loadRemote()
392 commonRemoteLoad(this);
395 void PythonNode::execute()
397 if(_mode==PythonNode::REMOTE_NAME)
403 void PythonNode::executeRemote()
405 DEBTRACE( "++++++++++++++ PyNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
407 throw Exception("DistributedPythonNode badly loaded");
409 if(dynamic_cast<HomogeneousPoolContainer *>(getContainer()))
412 loadPythonAdapter(this,dummy);
413 _pynode->assignNewCompiledCode(getScript().c_str());
416 Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);
419 PyObject *args(0),*ob(0);
420 //===========================================================================
421 // Get inputs in input ports, build a Python dict and pickle it
422 //===========================================================================
424 std::list<InputPort *>::iterator iter2;
426 for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); ++iter2)
428 InputPyPort *p=(InputPyPort *)*iter2;
430 PyDict_SetItemString(args,p->getName().c_str(),ob);
434 PyObject_Print(args,stderr,Py_PRINT_RAW);
437 PyObject *serializationInput(PyObject_CallFunctionObjArgs(_pyfuncSer,args,NULL));
439 //The pickled string may contain NULL characters so use PyString_AsStringAndSize
440 char *serializationInputC(0);
442 if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
443 throw Exception("DistributedPythonNode problem in python pickle");
444 serializationInputCorba->length(len);
445 for(int i=0; i < len ; i++)
446 serializationInputCorba[i]=serializationInputC[i];
447 Py_DECREF(serializationInput);
450 //get the list of output argument names
451 std::list<OutputPort *>::iterator iter;
452 Engines::listofstring myseq;
453 myseq.length(getNumberOfOutputPorts());
455 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); ++iter)
457 OutputPyPort *p=(OutputPyPort *)*iter;
458 myseq[pos]=p->getName().c_str();
459 DEBTRACE( "port name: " << p->getName() );
460 DEBTRACE( "port kind: " << p->edGetType()->kind() );
461 DEBTRACE( "port pos : " << pos );
464 //===========================================================================
465 // Execute in remote Python node
466 //===========================================================================
467 DEBTRACE( "-----------------starting remote python invocation-----------------" );
468 Engines::pickledArgs_var resultCorba;
471 //pass outargsname and dict serialized
472 resultCorba=_pynode->execute(myseq,serializationInputCorba);
474 catch( const SALOME::SALOME_Exception& ex )
476 std::string msg="Exception on remote python invocation";
478 msg += ex.details.text.in();
480 throw Exception(msg);
482 DEBTRACE( "-----------------end of remote python invocation-----------------" );
483 //===========================================================================
484 // Get results, unpickle and put them in output ports
485 //===========================================================================
486 char *resultCorbaC=new char[resultCorba->length()+1];
487 resultCorbaC[resultCorba->length()]='\0';
488 for(int i=0;i<resultCorba->length();i++)
489 resultCorbaC[i]=resultCorba[i];
493 PyObject *args(0),*ob(0);
494 PyObject* resultPython=PyBytes_FromStringAndSize(resultCorbaC,resultCorba->length());
495 delete [] resultCorbaC;
496 args = PyTuple_New(1);
497 PyTuple_SetItem(args,0,resultPython);
498 PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
501 if (finalResult == NULL)
503 std::stringstream msg;
504 msg << "Conversion with pickle of output ports failed !";
505 msg << " : " << __FILE__ << ":" << __LINE__;
506 _errorDetails=msg.str();
507 throw YACS::ENGINE::ConversionException(msg.str());
510 DEBTRACE( "-----------------PythonNode::outputs-----------------" );
512 if(finalResult == Py_None)
514 else if(PyTuple_Check(finalResult))
515 nres=PyTuple_Size(finalResult);
517 if(getNumberOfOutputPorts() != nres)
519 std::string msg="Number of output arguments : Mismatch between definition and execution";
520 Py_DECREF(finalResult);
522 throw Exception(msg);
528 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); ++iter)
530 OutputPyPort *p=(OutputPyPort *)*iter;
531 DEBTRACE( "port name: " << p->getName() );
532 DEBTRACE( "port kind: " << p->edGetType()->kind() );
533 DEBTRACE( "port pos : " << pos );
534 if(PyTuple_Check(finalResult))
535 ob=PyTuple_GetItem(finalResult,pos) ;
538 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
542 Py_DECREF(finalResult);
544 catch(ConversionException& ex)
546 Py_DECREF(finalResult);
547 _errorDetails=ex.what();
551 squeezeMemoryRemote();
556 if(!CORBA::is_nil(_pynode))
558 _pynode->UnRegister();
560 _pynode = Engines::PyScriptNode::_nil();
562 Engines::Container_var cont(GetContainerObj(this,dummy));
563 cont->removePyScriptNode(getName().c_str());
565 DEBTRACE( "++++++++++++++ ENDOF PyNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
568 void PythonNode::executeLocal()
570 DEBTRACE( "++++++++++++++ PyNode::executeLocal: " << getName() << " ++++++++++++++++++++" );
574 DEBTRACE( "---------------PyNode::inputs---------------" );
575 list<InputPort *>::iterator iter2;
576 for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
578 InputPyPort *p=(InputPyPort *)*iter2;
579 DEBTRACE( "port name: " << p->getName() );
580 DEBTRACE( "port kind: " << p->edGetType()->kind() );
581 PyObject* ob=p->getPyObj();
582 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
584 PyObject_Print(ob,stderr,Py_PRINT_RAW);
587 int ier=PyDict_SetItemString(_context,p->getName().c_str(),ob);
588 DEBTRACE( "after PyDict_SetItemString:ob refcnt: " << ob->ob_refcnt );
591 DEBTRACE( "---------------End PyNode::inputs---------------" );
594 DEBTRACE( "----------------PyNode::calculation---------------" );
596 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
598 std::ostringstream stream;
599 stream << "/tmp/PythonNode_";
602 PyObject* code=Py_CompileString(_script.c_str(), stream.str().c_str(), Py_file_input);
606 PyObject* new_stderr = newPyStdOut(_errorDetails);
607 PySys_SetObject((char*)"stderr", new_stderr);
609 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
610 Py_DECREF(new_stderr);
611 throw Exception("Error during execution");
613 PyObject *res = PyEval_EvalCode( code, _context, _context);
617 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
620 if(PyErr_Occurred ())
623 PyObject* new_stderr = newPyStdOut(_errorDetails);
624 PySys_SetObject((char*)"stderr", new_stderr);
625 ofstream errorfile(stream.str().c_str());
626 if (errorfile.is_open())
628 errorfile << _script;
632 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
633 Py_DECREF(new_stderr);
634 throw Exception("Error during execution");
637 DEBTRACE( "-----------------PyNode::outputs-----------------" );
638 list<OutputPort *>::iterator iter;
641 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
643 OutputPyPort *p=(OutputPyPort *)*iter;
644 DEBTRACE( "port name: " << p->getName() );
645 DEBTRACE( "port kind: " << p->edGetType()->kind() );
646 PyObject *ob=PyDict_GetItemString(_context,p->getName().c_str());
649 std::string msg="Error during execution: there is no variable ";
650 msg=msg+p->getName()+" in node context";
652 throw Exception(msg);
654 DEBTRACE( "PyNode::outputs::ob refcnt: " << ob->ob_refcnt );
656 PyObject_Print(ob,stderr,Py_PRINT_RAW);
662 catch(ConversionException& ex)
664 _errorDetails=ex.what();
669 DEBTRACE( "-----------------End PyNode::outputs-----------------" );
671 DEBTRACE( "++++++++++++++ End PyNode::execute: " << getName() << " ++++++++++++++++++++" );
674 void PythonNode::squeezeMemorySafe()
677 if(_mode==PythonNode::REMOTE_NAME)
678 this->squeezeMemoryRemote();
680 this->squeezeMemory();
683 void PythonNode::squeezeMemory()
685 for(auto p : _setOfInputPort)
687 PyDict_DelItemString(_context,p->getName().c_str());
688 InputPyPort *p2(static_cast<InputPyPort *>(p));
689 if(p2->canSafelySqueezeMemory())
692 for(auto p : _setOfOutputPort)
694 PyDict_DelItemString(_context,p->getName().c_str());
695 OutputPyPort *p2(static_cast<OutputPyPort *>(p));
696 p2->putWithoutForward(Py_None);
700 void PythonNode::squeezeMemoryRemote()
702 for(auto p : _setOfInputPort)
704 InputPyPort *p2(static_cast<InputPyPort *>(p));
705 if(p2->canSafelySqueezeMemory())
708 for(auto p : _setOfOutputPort)
710 OutputPyPort *p2(static_cast<OutputPyPort *>(p));
711 p2->putWithoutForward(Py_None);
715 std::string PythonNode::getContainerLog()
717 return PythonEntry::GetContainerLog(_mode,_container,this);
720 void PythonNode::shutdown(int level)
722 DEBTRACE("PythonNode::shutdown " << level);
723 if(_mode=="local")return;
726 if(!CORBA::is_nil(_pynode)) _pynode->UnRegister();
727 _pynode=Engines::PyScriptNode::_nil();
728 _container->shutdown(level);
732 void PythonNode::imposeResource(const std::string& resource_name,
733 const std::string& container_name)
735 if(!resource_name.empty() && !container_name.empty())
737 _imposedResource = resource_name;
738 _imposedContainer = container_name;
742 bool PythonNode::canAcceptImposedResource()
744 return _container != nullptr && _container->canAcceptImposedResource();
747 std::string PythonNode::pythonEntryName()const
750 return "DEFAULT_NAME_FOR_UNIQUE_PYTHON_NODE_ENTRY";
755 bool PythonNode::keepContext()const
760 std::string str_value = _container->getProperty(KEEP_CONTEXT_PROPERTY);
761 const char* yes_values[] = {"YES", "Yes", "yes", "TRUE", "True", "true", "1",
763 for(const char* v : yes_values)
773 Node *PythonNode::simpleClone(ComposedNode *father, bool editionOnly) const
775 return new PythonNode(*this,father);
778 void PythonNode::createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)
780 if(!CORBA::is_nil(_pynode))
781 _pynode->UnRegister();
782 _pynode=objContainer->createPyScriptNode(pythonEntryName().c_str(),getScript().c_str());
786 Engines::PyNodeBase_var PythonNode::retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const
788 Engines::PyScriptNode_var ret(objContainer->getDefaultPyScriptNode(pythonEntryName().c_str()));
789 if(!CORBA::is_nil(ret))
793 return Engines::PyNodeBase::_narrow(ret);
796 void PythonNode::assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)
798 if(CORBA::is_nil(_pynode))
799 _pynode=Engines::PyScriptNode::_narrow(remoteInterp);
802 Engines::PyScriptNode_var tmpp(Engines::PyScriptNode::_narrow(remoteInterp));
803 if(!_pynode->_is_equivalent(tmpp))
805 _pynode->UnRegister();
806 _pynode=Engines::PyScriptNode::_narrow(remoteInterp);
809 _pynode->assignNewCompiledCode(getScript().c_str());
812 Engines::PyNodeBase_var PythonNode::getRemoteInterpreterHandle()
814 return Engines::PyNodeBase::_narrow(_pynode);
817 //! Create a new node of same type with a given name
818 PythonNode* PythonNode::cloneNode(const std::string& name)
820 PythonNode* n=new PythonNode(name);
821 n->setScript(_script);
822 list<InputPort *>::iterator iter;
823 for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
825 InputPyPort *p=(InputPyPort *)*iter;
826 DEBTRACE( "port name: " << p->getName() );
827 DEBTRACE( "port kind: " << p->edGetType()->kind() );
828 n->edAddInputPort(p->getName(),p->edGetType());
830 list<OutputPort *>::iterator iter2;
831 for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
833 OutputPyPort *p=(OutputPyPort *)*iter2;
834 DEBTRACE( "port name: " << p->getName() );
835 DEBTRACE( "port kind: " << p->edGetType()->kind() );
836 n->edAddOutputPort(p->getName(),p->edGetType());
841 void PythonNode::applyDPLScope(ComposedNode *gfn)
843 std::vector< std::pair<std::string,int> > ret(getDPLScopeInfo(gfn));
850 std::size_t sz(ret.size());
852 for(std::size_t i=0;i<sz;i++)
854 const std::pair<std::string,int>& p(ret[i]);
855 PyObject *elt(PyTuple_New(2));
856 PyTuple_SetItem(elt,0,PyUnicode_FromString(p.first.c_str()));
857 PyTuple_SetItem(elt,1,PyLong_FromLong(p.second));
858 PyList_SetItem(ob,i,elt);
861 if(_mode==REMOTE_NAME)
863 Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);
866 PyObject *serializationInput(PyObject_CallFunctionObjArgs(_pyfuncSimpleSer,ob,NULL));
868 char *serializationInputC(0);
870 if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
871 throw Exception("DistributedPythonNode problem in python pickle");
872 serializationInputCorba->length(len);
873 for(int i=0; i < len ; i++)
874 serializationInputCorba[i]=serializationInputC[i];
875 Py_XDECREF(serializationInput);
877 _pynode->defineNewCustomVar(DPL_INFO_NAME,serializationInputCorba);
882 PyDict_SetItemString(_context,DPL_INFO_NAME,ob);
887 PyFuncNode::PyFuncNode(const PyFuncNode& other, ComposedNode *father):InlineFuncNode(other,father),_pyfunc(0)
889 _implementation = PythonNode::IMPL_NAME;
892 _context=PyDict_New();
893 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
894 if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
897 msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
898 _errorDetails=msg.str();
899 throw Exception(msg.str());
904 PyFuncNode::PyFuncNode(const std::string& name): InlineFuncNode(name),_pyfunc(0)
907 _implementation = PythonNode::IMPL_NAME;
908 DEBTRACE( "PyFuncNode::PyFuncNode " << name );
911 _context=PyDict_New();
912 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
913 if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
916 msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
917 _errorDetails=msg.str();
918 throw Exception(msg.str());
923 PyFuncNode::~PyFuncNode()
925 if(!CORBA::is_nil(_pynode))
927 _pynode->UnRegister();
931 void PyFuncNode::init(bool start)
933 initCommonPartWithoutStateManagement(start);
934 if(_state == YACS::DISABLED)
936 exDisabledState(); // to refresh propagation of DISABLED state
939 if(start) //complete initialization
940 setState(YACS::READY);
941 else if(_state > YACS::LOADED)// WARNING FuncNode has internal vars (CEA usecase) ! Partial initialization (inside a loop). Exclusivity of funcNode.
942 setState(YACS::TORECONNECT);
945 void PyFuncNode::checkBasicConsistency() const
947 DEBTRACE("checkBasicConsistency");
948 InlineFuncNode::checkBasicConsistency();
952 res=Py_CompileString(_script.c_str(),getName().c_str(),Py_file_input);
955 std::string error="";
956 PyObject* new_stderr = newPyStdOut(error);
957 PySys_SetObject((char*)"stderr", new_stderr);
959 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
960 Py_DECREF(new_stderr);
961 throw Exception(error);
968 void PyFuncNode::load()
970 DEBTRACE( "---------------PyfuncNode::load function---------------" );
971 if(_mode==PythonNode::REMOTE_NAME)
977 void PyFuncNode::loadRemote()
979 commonRemoteLoad(this);
982 void PyFuncNode::loadLocal()
984 DEBTRACE( "---------------PyFuncNode::load function " << getName() << " ---------------" );
988 list<OutputPort *>::iterator iter;
989 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
991 OutputPyPort *p=(OutputPyPort *)*iter;
992 DEBTRACE( "port name: " << p->getName() );
993 DEBTRACE( "port kind: " << p->edGetType()->kind() );
999 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1001 std::ostringstream stream;
1002 stream << "/tmp/PythonNode_";
1005 PyObject* code=Py_CompileString(_script.c_str(), stream.str().c_str(), Py_file_input);
1009 PyObject* new_stderr = newPyStdOut(_errorDetails);
1010 PySys_SetObject((char*)"stderr", new_stderr);
1012 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1013 Py_DECREF(new_stderr);
1014 throw Exception("Error during execution");
1016 PyObject *res = PyEval_EvalCode( code, _context, _context);
1020 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1021 if(PyErr_Occurred ())
1024 PyObject* new_stderr = newPyStdOut(_errorDetails);
1025 PySys_SetObject((char*)"stderr", new_stderr);
1026 ofstream errorfile(stream.str().c_str());
1027 if (errorfile.is_open())
1029 errorfile << _script;
1033 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1034 Py_DECREF(new_stderr);
1035 throw Exception("Error during execution");
1038 _pyfunc=PyDict_GetItemString(_context,_fname.c_str());
1039 DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1043 PyObject* new_stderr = newPyStdOut(_errorDetails);
1044 PySys_SetObject((char*)"stderr", new_stderr);
1046 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1047 Py_DECREF(new_stderr);
1048 throw Exception("Error during execution");
1050 DEBTRACE( "---------------End PyFuncNode::load function---------------" );
1054 void PyFuncNode::execute()
1056 if(_mode==PythonNode::REMOTE_NAME)
1062 void PyFuncNode::executeRemote()
1064 DEBTRACE( "++++++++++++++ PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
1066 throw Exception("DistributedPythonNode badly loaded");
1068 if(dynamic_cast<HomogeneousPoolContainer *>(getContainer()))
1071 loadPythonAdapter(this,dummy);
1072 _pynode->executeAnotherPieceOfCode(getScript().c_str());
1075 Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);;
1079 //===========================================================================
1080 // Get inputs in input ports, build a Python tuple and pickle it
1081 //===========================================================================
1082 PyObject *args(PyTuple_New(getNumberOfInputPorts()));
1084 for(std::list<InputPort *>::iterator iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++,pos++)
1086 InputPyPort *p=(InputPyPort *)*iter2;
1089 PyTuple_SetItem(args,pos,ob);
1092 PyObject_Print(args,stderr,Py_PRINT_RAW);
1095 PyObject *serializationInput=PyObject_CallObject(_pyfuncSer,args);
1097 //The pickled string may contain NULL characters so use PyString_AsStringAndSize
1098 char *serializationInputC(0);
1100 if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
1101 throw Exception("DistributedPythonNode problem in python pickle");
1103 serializationInputCorba->length(len);
1104 for(int i=0; i < len ; i++)
1105 serializationInputCorba[i]=serializationInputC[i];
1106 Py_DECREF(serializationInput);
1109 //===========================================================================
1110 // Execute in remote Python node
1111 //===========================================================================
1112 DEBTRACE( "-----------------starting remote python invocation-----------------" );
1113 Engines::pickledArgs_var resultCorba;
1116 resultCorba=_pynode->execute(getFname().c_str(),serializationInputCorba);
1118 catch( const SALOME::SALOME_Exception& ex )
1120 std::string msg="Exception on remote python invocation";
1122 msg += ex.details.text.in();
1124 throw Exception(msg);
1126 DEBTRACE( "-----------------end of remote python invocation-----------------" );
1127 //===========================================================================
1128 // Get results, unpickle and put them in output ports
1129 //===========================================================================
1130 char *resultCorbaC=new char[resultCorba->length()+1];
1131 resultCorbaC[resultCorba->length()]='\0';
1132 for(int i=0;i<resultCorba->length();i++)
1133 resultCorbaC[i]=resultCorba[i];
1138 PyObject *resultPython(PyBytes_FromStringAndSize(resultCorbaC,resultCorba->length()));
1139 delete [] resultCorbaC;
1140 PyObject *args(PyTuple_New(1)),*ob(0);
1141 PyTuple_SetItem(args,0,resultPython);
1142 PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
1145 DEBTRACE( "-----------------PythonNode::outputs-----------------" );
1147 if(finalResult == Py_None)
1149 else if(PyTuple_Check(finalResult))
1150 nres=PyTuple_Size(finalResult);
1152 if(getNumberOfOutputPorts() != nres)
1154 std::string msg="Number of output arguments : Mismatch between definition and execution";
1155 Py_DECREF(finalResult);
1157 throw Exception(msg);
1163 for(std::list<OutputPort *>::iterator iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++, pos++)
1165 OutputPyPort *p=(OutputPyPort *)*iter;
1166 DEBTRACE( "port name: " << p->getName() );
1167 DEBTRACE( "port kind: " << p->edGetType()->kind() );
1168 DEBTRACE( "port pos : " << pos );
1169 if(PyTuple_Check(finalResult))
1170 ob=PyTuple_GetItem(finalResult,pos) ;
1173 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1176 Py_DECREF(finalResult);
1178 catch(ConversionException& ex)
1180 Py_DECREF(finalResult);
1181 _errorDetails=ex.what();
1186 DEBTRACE( "++++++++++++++ ENDOF PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
1189 void PyFuncNode::executeLocal()
1191 DEBTRACE( "++++++++++++++ PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
1195 if(!_pyfunc)throw Exception("PyFuncNode badly loaded");
1198 DEBTRACE( "---------------PyFuncNode::inputs---------------" );
1199 PyObject* args = PyTuple_New(getNumberOfInputPorts()) ;
1200 list<InputPort *>::iterator iter2;
1201 for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
1203 InputPyPort *p=(InputPyPort *)*iter2;
1204 DEBTRACE( "port name: " << p->getName() );
1205 DEBTRACE( "port kind: " << p->edGetType()->kind() );
1208 PyObject_Print(ob,stderr,Py_PRINT_RAW);
1211 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1213 PyTuple_SetItem(args,pos,ob);
1214 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1217 DEBTRACE( "---------------End PyFuncNode::inputs---------------" );
1219 DEBTRACE( "----------------PyFuncNode::calculation---------------" );
1221 PyObject_Print(_pyfunc,stderr,Py_PRINT_RAW);
1223 PyObject_Print(args,stderr,Py_PRINT_RAW);
1226 DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1227 PyObject* result = PyObject_CallObject( _pyfunc , args ) ;
1228 DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1235 PyObject* new_stderr = newPyStdOut(_errorDetails);
1236 PySys_SetObject((char*)"stderr", new_stderr);
1237 std::ostringstream stream;
1238 stream << "/tmp/PythonNode_";
1240 ofstream errorfile(stream.str().c_str());
1241 if (errorfile.is_open())
1243 errorfile << _script;
1247 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1248 Py_DECREF(new_stderr);
1249 throw Exception("Error during execution");
1251 DEBTRACE( "----------------End PyFuncNode::calculation---------------" );
1253 DEBTRACE( "-----------------PyFuncNode::outputs-----------------" );
1255 if(result == Py_None)
1257 else if(PyTuple_Check(result))
1258 nres=PyTuple_Size(result);
1260 if(getNumberOfOutputPorts() != nres)
1262 std::string msg="Number of output arguments : Mismatch between definition and execution";
1265 throw Exception(msg);
1270 PyObject_Print(result,stderr,Py_PRINT_RAW);
1273 list<OutputPort *>::iterator iter;
1276 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
1278 OutputPyPort *p=(OutputPyPort *)*iter;
1279 DEBTRACE( "port name: " << p->getName() );
1280 DEBTRACE( "port kind: " << p->edGetType()->kind() );
1281 DEBTRACE( "port pos : " << pos );
1282 if(PyTuple_Check(result))ob=PyTuple_GetItem(result,pos) ;
1284 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1286 PyObject_Print(ob,stderr,Py_PRINT_RAW);
1293 catch(ConversionException& ex)
1296 _errorDetails=ex.what();
1299 DEBTRACE( "-----------------End PyFuncNode::outputs-----------------" );
1302 DEBTRACE( "++++++++++++++ End PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
1305 Node *PyFuncNode::simpleClone(ComposedNode *father, bool editionOnly) const
1307 return new PyFuncNode(*this,father);
1310 void PyFuncNode::createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)
1312 if(!CORBA::is_nil(_pynode))
1313 _pynode->UnRegister();
1314 _pynode=objContainer->createPyNode(getName().c_str(),getScript().c_str());
1317 Engines::PyNodeBase_var PyFuncNode::retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const
1319 Engines::PyNode_var ret(objContainer->getDefaultPyNode(getName().c_str()));
1320 if(!CORBA::is_nil(ret))
1324 return Engines::PyNodeBase::_narrow(ret);
1327 void PyFuncNode::assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)
1329 if(!CORBA::is_nil(_pynode))
1331 Engines::PyNode_var tmpp(Engines::PyNode::_narrow(remoteInterp));
1332 if(_pynode->_is_equivalent(tmpp))
1335 if(!CORBA::is_nil(_pynode))
1336 _pynode->UnRegister();
1337 _pynode=Engines::PyNode::_narrow(remoteInterp);
1340 Engines::PyNodeBase_var PyFuncNode::getRemoteInterpreterHandle()
1342 return Engines::PyNodeBase::_narrow(_pynode);
1345 //! Create a new node of same type with a given name
1346 PyFuncNode* PyFuncNode::cloneNode(const std::string& name)
1348 PyFuncNode* n=new PyFuncNode(name);
1349 n->setScript(_script);
1350 n->setFname(_fname);
1351 list<InputPort *>::iterator iter;
1352 for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
1354 InputPyPort *p=(InputPyPort *)*iter;
1355 n->edAddInputPort(p->getName(),p->edGetType());
1357 list<OutputPort *>::iterator iter2;
1358 for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
1360 OutputPyPort *p=(OutputPyPort *)*iter2;
1361 n->edAddOutputPort(p->getName(),p->edGetType());
1366 std::string PyFuncNode::getContainerLog()
1368 return PythonEntry::GetContainerLog(_mode,_container,this);
1371 void PyFuncNode::shutdown(int level)
1373 DEBTRACE("PyFuncNode::shutdown " << level);
1374 if(_mode=="local")return;
1377 if(!CORBA::is_nil(_pynode)) _pynode->UnRegister();
1378 _pynode=Engines::PyNode::_nil();
1379 _container->shutdown(level);
1383 void PyFuncNode::imposeResource(const std::string& resource_name,
1384 const std::string& container_name)
1386 if(!resource_name.empty() && !container_name.empty())
1388 _imposedResource = resource_name;
1389 _imposedContainer = container_name;
1393 bool PyFuncNode::canAcceptImposedResource()
1395 return _container != nullptr && _container->canAcceptImposedResource();