1 // Copyright (C) 2006-2022 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 "PythonCppUtils.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"
39 #define getpid _getpid
42 #if PY_VERSION_HEX < 0x02050000
43 typedef int Py_ssize_t;
47 #include "YacsTrace.hxx"
49 using namespace YACS::ENGINE;
52 const char PythonEntry::SCRIPT_FOR_SIMPLE_SERIALIZATION[]="import pickle\n"
53 "def pickleForVarSimplePyth2009(val):\n"
54 " return pickle.dumps(val,-1)\n"
57 const char PythonNode::IMPL_NAME[]="Python";
58 const char PythonNode::KIND[]="Python";
60 const char PythonNode::SCRIPT_FOR_SERIALIZATION[]="import pickle\n"
61 "def pickleForDistPyth2009(kws):\n"
62 " return pickle.dumps(((),kws),-1)\n"
64 "def unPickleForDistPyth2009(st):\n"
65 " args=pickle.loads(st)\n"
68 const char PythonNode::REMOTE_NAME[]="remote";
70 const char PythonNode::DPL_INFO_NAME[]="my_dpl_localization";
72 const char PyFuncNode::SCRIPT_FOR_SERIALIZATION[]="import pickle\n"
73 "def pickleForDistPyth2009(*args,**kws):\n"
74 " return pickle.dumps((args,kws),-1)\n"
76 "def unPickleForDistPyth2009(st):\n"
77 " args=pickle.loads(st)\n"
80 // pickle.load concurrency issue : see https://bugs.python.org/issue12680
81 #if PY_VERSION_HEX < 0x03070000
83 static std::mutex data_mutex;
86 PythonEntry::PythonEntry():_context(0),_pyfuncSer(0),_pyfuncUnser(0),_pyfuncSimpleSer(0)
90 PythonEntry::~PythonEntry()
93 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
94 // not Py_XDECREF of _pyfuncUnser because it is returned by PyDict_GetItem -> borrowed
95 // not Py_XDECREF of _pyfuncSer because it is returned by PyDict_GetItem -> borrowed
99 void PythonEntry::loadRemoteContainer(InlineNode *reqNode)
101 DEBTRACE( "---------------PythonEntry::CommonRemoteLoad function---------------" );
102 Container *container(reqNode->getContainer());
103 bool isContAlreadyStarted(false);
108 if(hasImposedResource())
109 container->start(reqNode, _imposedResource, _imposedContainer);
112 isContAlreadyStarted=container->isAlreadyStarted(reqNode);
113 if(!isContAlreadyStarted)
114 container->start(reqNode);
119 reqNode->setErrorDetails(e.what());
125 std::string what("PythonEntry::CommonRemoteLoad : a load operation requested on \"");
126 what+=reqNode->getName(); what+="\" with no container specified.";
127 reqNode->setErrorDetails(what);
128 throw Exception(what);
132 Engines::Container_var GetContainerObj(InlineNode *reqNode, bool& isStandardCont)
134 isStandardCont = false;
135 Container *container(reqNode->getContainer());
136 Engines::Container_var objContainer(Engines::Container::_nil());
138 throw YACS::Exception("No container specified !");
139 SalomeContainer *containerCast0(dynamic_cast<SalomeContainer *>(container));
140 SalomeHPContainer *containerCast1(dynamic_cast<SalomeHPContainer *>(container));
143 isStandardCont = true;
144 objContainer=containerCast0->getContainerPtr(reqNode);
146 else if(containerCast1)
148 YACS::BASES::AutoCppPtr<SalomeContainerTmpForHP> tmpCont(SalomeContainerTmpForHP::BuildFrom(containerCast1,reqNode));
149 objContainer=tmpCont->getContainerPtr(reqNode);
152 throw YACS::Exception("Unrecognized type of container ! Salome one is expected for PythonNode/PyFuncNode !");
153 if(CORBA::is_nil(objContainer))
154 throw YACS::Exception("Container corba pointer is NULL for PythonNode !");
158 Engines::Container_var PythonEntry::loadPythonAdapter(InlineNode *reqNode, bool& isInitializeRequested)
160 bool isStandardCont(true);
161 Engines::Container_var objContainer(GetContainerObj(reqNode,isStandardCont));
162 isInitializeRequested=false;
165 Engines::PyNodeBase_var dftPyScript(retrieveDftRemotePyInterpretorIfAny(objContainer));
166 if(CORBA::is_nil(dftPyScript))
168 isInitializeRequested=!isStandardCont;
169 createRemoteAdaptedPyInterpretor(objContainer);
172 assignRemotePyInterpretor(dftPyScript);
174 catch( const SALOME::SALOME_Exception& ex )
176 std::string msg="Exception on remote python node creation ";
178 msg += ex.details.text.in();
179 reqNode->setErrorDetails(msg);
180 throw Exception(msg);
182 Engines::PyNodeBase_var pynode(getRemoteInterpreterHandle());
183 if(CORBA::is_nil(pynode))
184 throw Exception("In PythonNode the ref in NULL ! ");
188 void PythonEntry::loadRemoteContext(InlineNode *reqNode, Engines::Container_ptr objContainer, bool isInitializeRequested)
190 Container *container(reqNode->getContainer());
191 Engines::PyNodeBase_var pynode(getRemoteInterpreterHandle());
194 #if PY_VERSION_HEX < 0x03070000
195 std::unique_lock<std::mutex> lock(data_mutex);
198 const char *picklizeScript(getSerializationScript());
199 PyObject *res=PyRun_String(picklizeScript,Py_file_input,_context,_context);
200 PyObject *res2(PyRun_String(SCRIPT_FOR_SIMPLE_SERIALIZATION,Py_file_input,_context,_context));
201 if(res == NULL || res2==NULL)
203 std::string errorDetails;
204 PyObject* new_stderr = newPyStdOut(errorDetails);
205 reqNode->setErrorDetails(errorDetails);
206 PySys_SetObject((char*)"stderr", new_stderr);
208 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
209 Py_DECREF(new_stderr);
210 throw Exception("Error during load");
212 Py_DECREF(res); Py_DECREF(res2);
213 _pyfuncSer=PyDict_GetItemString(_context,"pickleForDistPyth2009");
214 _pyfuncUnser=PyDict_GetItemString(_context,"unPickleForDistPyth2009");
215 _pyfuncSimpleSer=PyDict_GetItemString(_context,"pickleForVarSimplePyth2009");
216 if(_pyfuncSer == NULL)
218 std::string errorDetails;
219 PyObject *new_stderr(newPyStdOut(errorDetails));
220 reqNode->setErrorDetails(errorDetails);
221 PySys_SetObject((char*)"stderr", new_stderr);
223 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
224 Py_DECREF(new_stderr);
225 throw Exception("Error during load");
227 if(_pyfuncUnser == NULL)
229 std::string errorDetails;
230 PyObject *new_stderr(newPyStdOut(errorDetails));
231 reqNode->setErrorDetails(errorDetails);
232 PySys_SetObject((char*)"stderr", new_stderr);
234 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
235 Py_DECREF(new_stderr);
236 throw Exception("Error during load");
238 if(_pyfuncSimpleSer == NULL)
240 std::string errorDetails;
241 PyObject *new_stderr(newPyStdOut(errorDetails));
242 reqNode->setErrorDetails(errorDetails);
243 PySys_SetObject((char*)"stderr", new_stderr);
245 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
246 Py_DECREF(new_stderr);
247 throw Exception("Error during load");
250 if(isInitializeRequested)
251 {//This one is called only once at initialization in the container if an init-script is specified.
254 std::string zeInitScriptKey(container->getProperty(HomogeneousPoolContainer::INITIALIZE_SCRIPT_KEY));
255 if(!zeInitScriptKey.empty())
256 pynode->executeAnotherPieceOfCode(zeInitScriptKey.c_str());
258 catch( const SALOME::SALOME_Exception& ex )
260 std::string msg="Exception on PythonNode::loadRemote python invocation of initializisation py script !";
262 msg += ex.details.text.in();
263 reqNode->setErrorDetails(msg);
264 throw Exception(msg);
266 DEBTRACE( "---------------End PyNode::loadRemote function---------------" );
270 std::string PythonEntry::GetContainerLog(const std::string& mode, Container *container, const Task *askingTask)
278 SalomeContainer *containerCast(dynamic_cast<SalomeContainer *>(container));
279 SalomeHPContainer *objContainer2(dynamic_cast<SalomeHPContainer *>(container));
282 Engines::Container_var objContainer(containerCast->getContainerPtr(askingTask));
283 CORBA::String_var logname = objContainer->logfilename();
286 std::string::size_type pos = msg.find(":");
287 msg=msg.substr(pos+1);
289 else if(objContainer2)
291 msg="Remote PythonNode is on HP Container : no log because no info of the location by definition of HP Container !";
295 msg="Not implemented yet for container log for that type of container !";
300 msg = "Container no longer reachable";
305 void PythonEntry::commonRemoteLoad(InlineNode *reqNode)
307 loadRemoteContainer(reqNode);
308 bool isInitializeRequested;
309 Engines::Container_var objContainer(loadPythonAdapter(reqNode,isInitializeRequested));
310 loadRemoteContext(reqNode,objContainer,isInitializeRequested);
313 bool PythonEntry::hasImposedResource()const
315 return !_imposedResource.empty() && !_imposedContainer.empty();
318 PythonNode::PythonNode(const PythonNode& other, ComposedNode *father):InlineNode(other,father),_autoSqueeze(other._autoSqueeze)
320 _pynode = Engines::PyScriptNode::_nil();
321 _implementation=IMPL_NAME;
324 _context=PyDict_New();
325 if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
328 msg << "Impossible to set builtins" << __FILE__ << ":" << __LINE__;
329 _errorDetails=msg.str();
330 throw Exception(msg.str());
335 PythonNode::PythonNode(const std::string& name):InlineNode(name)
337 _pynode = Engines::PyScriptNode::_nil();
338 _implementation=IMPL_NAME;
341 _context=PyDict_New();
342 if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
345 msg << "Impossible to set builtins" << __FILE__ << ":" << __LINE__;
346 _errorDetails=msg.str();
347 throw Exception(msg.str());
352 PythonNode::~PythonNode()
357 void PythonNode::checkBasicConsistency() const
359 DEBTRACE("checkBasicConsistency");
360 InlineNode::checkBasicConsistency();
364 res=Py_CompileString(_script.c_str(),getName().c_str(),Py_file_input);
367 std::string error="";
368 PyObject* new_stderr = newPyStdOut(error);
369 PySys_SetObject((char*)"stderr", new_stderr);
371 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
372 Py_DECREF(new_stderr);
373 throw Exception(error);
380 void PythonNode::load()
382 DEBTRACE( "---------------PyNode::load function---------------" );
383 if(_mode==PythonNode::REMOTE_NAME)
389 void PythonNode::loadLocal()
391 DEBTRACE( "---------------PyNode::loadLocal function---------------" );
395 void PythonNode::loadRemote()
397 commonRemoteLoad(this);
400 void PythonNode::execute()
402 if(_mode==PythonNode::REMOTE_NAME)
408 void PythonNode::executeRemote()
410 DEBTRACE( "++++++++++++++ PyNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
412 throw Exception("PythonNode badly loaded");
414 if(dynamic_cast<HomogeneousPoolContainer *>(getContainer()))
417 loadPythonAdapter(this,dummy);
418 _pynode->assignNewCompiledCode(getScript().c_str());
421 std::unique_ptr<Engines::pickledArgs> serializationInputCorba(new Engines::pickledArgs);
422 AutoPyRef serializationInput;
424 #if PY_VERSION_HEX < 0x03070000
425 std::unique_lock<std::mutex> lock(data_mutex);
428 PyObject *args(0),*ob(0);
429 //===========================================================================
430 // Get inputs in input ports, build a Python dict and pickle it
431 //===========================================================================
433 std::list<InputPort *>::iterator iter2;
435 for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); ++iter2)
437 InputPyPort *p=(InputPyPort *)*iter2;
439 PyDict_SetItemString(args,p->getName().c_str(),ob);
443 PyObject_Print(args,stderr,Py_PRINT_RAW);
446 serializationInput.set(PyObject_CallFunctionObjArgs(_pyfuncSer,args,nullptr));
448 //The pickled string may contain NULL characters so use PyString_AsStringAndSize
449 char *serializationInputC(0);
451 if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
452 throw Exception("DistributedPythonNode problem in python pickle");
453 // no copy here. The C byte array of Python is taken as this into CORBA sequence to avoid copy
454 serializationInputCorba.reset(new Engines::pickledArgs(len,len,reinterpret_cast<CORBA::Octet *>(serializationInputC),0));
457 //get the list of output argument names
458 std::list<OutputPort *>::iterator iter;
459 Engines::listofstring myseq;
460 myseq.length(getNumberOfOutputPorts());
462 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); ++iter)
464 OutputPyPort *p=(OutputPyPort *)*iter;
465 myseq[pos]=p->getName().c_str();
466 DEBTRACE( "port name: " << p->getName() );
467 DEBTRACE( "port kind: " << p->edGetType()->kind() );
468 DEBTRACE( "port pos : " << pos );
471 //===========================================================================
472 // Execute in remote Python node
473 //===========================================================================
474 DEBTRACE( "-----------------starting remote python invocation-----------------" );
475 std::unique_ptr<Engines::pickledArgs> resultCorba;
478 //pass outargsname and dict serialized
479 _pynode->executeFirst(*(serializationInputCorba.get()));
480 //serializationInput and serializationInputCorba are no more needed for server. Release it.
481 serializationInputCorba.reset(nullptr); serializationInput.set(nullptr);
482 resultCorba.reset(_pynode->executeSecond(myseq));
484 catch( const SALOME::SALOME_Exception& ex )
486 std::ostringstream msg; msg << "Exception on remote python invocation" << std::endl << ex.details.text.in() << std::endl;
487 msg << "PyScriptNode CORBA ref : ";
489 CORBA::ORB_ptr orb(getSALOMERuntime()->getOrb());
490 if(!CORBA::is_nil(orb))
492 CORBA::String_var IOR(orb->object_to_string(_pynode));
497 _errorDetails=msg.str();
498 throw Exception(msg.str());
500 catch(CORBA::COMM_FAILURE& ex)
502 std::ostringstream msg;
503 msg << "Exception on remote python invocation." << std::endl ;
504 msg << "Caught system exception COMM_FAILURE -- unable to contact the "
505 << "object." << std::endl;
506 _errorDetails=msg.str();
507 throw Exception(msg.str());
509 catch(CORBA::SystemException& ex)
511 std::ostringstream msg;
512 msg << "Exception on remote python invocation." << std::endl ;
513 msg << "Caught a CORBA::SystemException." ;
516 CORBA::TypeCode_var tc = tmp.type();
517 const char *p = tc->name();
523 _errorDetails=msg.str();
524 throw Exception(msg.str());
526 catch(CORBA::Exception& ex)
528 std::ostringstream msg;
529 msg << "Exception on remote python invocation." << std::endl ;
530 msg << "Caught CORBA::Exception. " ;
533 CORBA::TypeCode_var tc = tmp.type();
534 const char *p = tc->name();
540 _errorDetails=msg.str();
541 throw Exception(msg.str());
543 catch(omniORB::fatalException& fe)
545 std::ostringstream msg;
546 msg << "Exception on remote python invocation." << std::endl ;
547 msg << "Caught omniORB::fatalException:" << std::endl;
548 msg << " file: " << fe.file() << std::endl;
549 msg << " line: " << fe.line() << std::endl;
550 msg << " mesg: " << fe.errmsg() << std::endl;
551 _errorDetails=msg.str();
552 throw Exception(msg.str());
554 // if(!CORBA::is_nil(_pynode))
556 // _pynode->UnRegister();
558 // _pynode = Engines::PyScriptNode::_nil();
561 // Engines::Container_var cont(GetContainerObj(this,dummy));
562 // cont->removePyScriptNode(getName().c_str());
563 DEBTRACE( "-----------------end of remote python invocation-----------------" );
564 //===========================================================================
565 // Get results, unpickle and put them in output ports
566 //===========================================================================
567 auto length(resultCorba->length());
568 char *resultCorbaC(reinterpret_cast<char *>(resultCorba->get_buffer()));
570 #if PY_VERSION_HEX < 0x03070000
571 std::unique_lock<std::mutex> lock(data_mutex);
574 PyObject *args(0),*ob(0);
575 PyObject* resultPython=PyMemoryView_FromMemory(resultCorbaC,length,PyBUF_READ);
576 args = PyTuple_New(1);
577 PyTuple_SetItem(args,0,resultPython);
578 PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
579 resultCorba.reset(nullptr);
582 if (finalResult == NULL)
584 std::stringstream msg;
585 msg << "Conversion with pickle of output ports failed !";
586 msg << " : " << __FILE__ << ":" << __LINE__;
587 _errorDetails=msg.str();
588 throw YACS::ENGINE::ConversionException(msg.str());
591 DEBTRACE( "-----------------PythonNode::outputs-----------------" );
593 if(finalResult == Py_None)
595 else if(PyTuple_Check(finalResult))
596 nres=PyTuple_Size(finalResult);
598 if(getNumberOfOutputPorts() != nres)
600 std::string msg="Number of output arguments : Mismatch between definition and execution";
601 Py_DECREF(finalResult);
603 throw Exception(msg);
609 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); ++iter)
611 OutputPyPort *p=(OutputPyPort *)*iter;
612 DEBTRACE( "port name: " << p->getName() );
613 DEBTRACE( "port kind: " << p->edGetType()->kind() );
614 DEBTRACE( "port pos : " << pos );
615 if(PyTuple_Check(finalResult))
616 ob=PyTuple_GetItem(finalResult,pos) ;
619 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
623 Py_DECREF(finalResult);
625 catch(ConversionException& ex)
627 Py_DECREF(finalResult);
628 _errorDetails=ex.what();
632 squeezeMemoryRemote();
635 if(!isUsingPythonCache())
639 Engines::Container_var cont(GetContainerObj(this,dummy));
640 cont->removePyScriptNode(getName().c_str());
642 DEBTRACE( "++++++++++++++ ENDOF PyNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
645 void PythonNode::executeLocal()
647 DEBTRACE( "++++++++++++++ PyNode::executeLocal: " << getName() << " ++++++++++++++++++++" );
651 DEBTRACE( "---------------PyNode::inputs---------------" );
652 list<InputPort *>::iterator iter2;
653 for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
655 InputPyPort *p=(InputPyPort *)*iter2;
656 DEBTRACE( "port name: " << p->getName() );
657 DEBTRACE( "port kind: " << p->edGetType()->kind() );
658 PyObject* ob=p->getPyObj();
659 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
661 PyObject_Print(ob,stderr,Py_PRINT_RAW);
664 int ier=PyDict_SetItemString(_context,p->getName().c_str(),ob);
665 DEBTRACE( "after PyDict_SetItemString:ob refcnt: " << ob->ob_refcnt );
668 DEBTRACE( "---------------End PyNode::inputs---------------" );
671 DEBTRACE( "----------------PyNode::calculation---------------" );
673 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
675 std::ostringstream stream;
676 stream << "/tmp/PythonNode_";
679 PyObject* code=Py_CompileString(_script.c_str(), stream.str().c_str(), Py_file_input);
683 PyObject* new_stderr = newPyStdOut(_errorDetails);
684 PySys_SetObject((char*)"stderr", new_stderr);
686 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
687 Py_DECREF(new_stderr);
688 throw Exception("Error during execution");
690 PyObject *res = PyEval_EvalCode( code, _context, _context);
694 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
697 if(PyErr_Occurred ())
700 PyObject* new_stderr = newPyStdOut(_errorDetails);
701 PySys_SetObject((char*)"stderr", new_stderr);
702 ofstream errorfile(stream.str().c_str());
703 if (errorfile.is_open())
705 errorfile << _script;
709 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
710 Py_DECREF(new_stderr);
711 throw Exception("Error during execution");
714 DEBTRACE( "-----------------PyNode::outputs-----------------" );
715 list<OutputPort *>::iterator iter;
718 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
720 OutputPyPort *p=(OutputPyPort *)*iter;
721 DEBTRACE( "port name: " << p->getName() );
722 DEBTRACE( "port kind: " << p->edGetType()->kind() );
723 PyObject *ob=PyDict_GetItemString(_context,p->getName().c_str());
726 std::string msg="Error during execution: there is no variable ";
727 msg=msg+p->getName()+" in node context";
729 throw Exception(msg);
731 DEBTRACE( "PyNode::outputs::ob refcnt: " << ob->ob_refcnt );
733 PyObject_Print(ob,stderr,Py_PRINT_RAW);
739 catch(ConversionException& ex)
741 _errorDetails=ex.what();
746 DEBTRACE( "-----------------End PyNode::outputs-----------------" );
748 DEBTRACE( "++++++++++++++ End PyNode::execute: " << getName() << " ++++++++++++++++++++" );
751 void PythonNode::squeezeMemorySafe()
754 if(_mode==PythonNode::REMOTE_NAME)
755 this->squeezeMemoryRemote();
757 this->squeezeMemory();
760 void PythonNode::squeezeMemory()
762 for(auto p : _setOfInputPort)
764 PyDict_DelItemString(_context,p->getName().c_str());
765 InputPyPort *p2(static_cast<InputPyPort *>(p));
766 if(p2->canSafelySqueezeMemory())
769 for(auto p : _setOfOutputPort)
771 PyDict_DelItemString(_context,p->getName().c_str());
772 OutputPyPort *p2(static_cast<OutputPyPort *>(p));
773 p2->putWithoutForward(Py_None);
777 void PythonNode::squeezeMemoryRemote()
779 for(auto p : _setOfInputPort)
781 InputPyPort *p2(static_cast<InputPyPort *>(p));
782 if(p2->canSafelySqueezeMemory())
785 for(auto p : _setOfOutputPort)
787 OutputPyPort *p2(static_cast<OutputPyPort *>(p));
788 p2->putWithoutForward(Py_None);
792 std::string PythonNode::getContainerLog()
794 return PythonEntry::GetContainerLog(_mode,_container,this);
797 void PythonNode::shutdown(int level)
799 DEBTRACE("PythonNode::shutdown " << level);
800 if(_mode=="local")return;
804 _container->shutdown(level);
808 void PythonNode::imposeResource(const std::string& resource_name,
809 const std::string& container_name)
811 if(!resource_name.empty() && !container_name.empty())
813 _imposedResource = resource_name;
814 _imposedContainer = container_name;
818 bool PythonNode::canAcceptImposedResource()
820 return _container != nullptr && _container->canAcceptImposedResource();
823 bool PythonNode::hasImposedResource()const
825 return PythonEntry::hasImposedResource();
828 std::string PythonNode::pythonEntryName()const
830 if(isUsingPythonCache())
831 return "DEFAULT_NAME_FOR_UNIQUE_PYTHON_NODE_ENTRY";
836 bool PythonNode::isUsingPythonCache()const
840 found = _container->isUsingPythonCache();
844 void PythonNode::freeKernelPynode()
846 if(!CORBA::is_nil(_pynode))
850 _pynode->UnRegister();
854 DEBTRACE("Trouble when pynode->UnRegister!")
856 _pynode = Engines::PyScriptNode::_nil();
860 Node *PythonNode::simpleClone(ComposedNode *father, bool editionOnly) const
862 return new PythonNode(*this,father);
865 void PythonNode::createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)
868 _pynode=objContainer->createPyScriptNode(pythonEntryName().c_str(),getScript().c_str());
872 Engines::PyNodeBase_var PythonNode::retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const
874 Engines::PyScriptNode_var ret(objContainer->getDefaultPyScriptNode(pythonEntryName().c_str()));
875 if(!CORBA::is_nil(ret))
879 return Engines::PyNodeBase::_narrow(ret);
882 void PythonNode::assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)
884 if(CORBA::is_nil(_pynode))
885 _pynode=Engines::PyScriptNode::_narrow(remoteInterp);
888 Engines::PyScriptNode_var tmpp(Engines::PyScriptNode::_narrow(remoteInterp));
889 if(!_pynode->_is_equivalent(tmpp))
892 _pynode=Engines::PyScriptNode::_narrow(remoteInterp);
895 _pynode->assignNewCompiledCode(getScript().c_str());
898 Engines::PyNodeBase_var PythonNode::getRemoteInterpreterHandle()
900 return Engines::PyNodeBase::_narrow(_pynode);
903 //! Create a new node of same type with a given name
904 PythonNode* PythonNode::cloneNode(const std::string& name)
906 PythonNode* n=new PythonNode(name);
907 n->setScript(_script);
908 list<InputPort *>::iterator iter;
909 for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
911 InputPyPort *p=(InputPyPort *)*iter;
912 DEBTRACE( "port name: " << p->getName() );
913 DEBTRACE( "port kind: " << p->edGetType()->kind() );
914 n->edAddInputPort(p->getName(),p->edGetType());
916 list<OutputPort *>::iterator iter2;
917 for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
919 OutputPyPort *p=(OutputPyPort *)*iter2;
920 DEBTRACE( "port name: " << p->getName() );
921 DEBTRACE( "port kind: " << p->edGetType()->kind() );
922 n->edAddOutputPort(p->getName(),p->edGetType());
927 void PythonNode::applyDPLScope(ComposedNode *gfn)
929 std::vector< std::pair<std::string,int> > ret(getDPLScopeInfo(gfn));
936 std::size_t sz(ret.size());
938 for(std::size_t i=0;i<sz;i++)
940 const std::pair<std::string,int>& p(ret[i]);
941 PyObject *elt(PyTuple_New(2));
942 PyTuple_SetItem(elt,0,PyUnicode_FromString(p.first.c_str()));
943 PyTuple_SetItem(elt,1,PyLong_FromLong(p.second));
944 PyList_SetItem(ob,i,elt);
947 if(_mode==REMOTE_NAME)
949 Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);
952 PyObject *serializationInput(PyObject_CallFunctionObjArgs(_pyfuncSimpleSer,ob,NULL));
954 char *serializationInputC(0);
956 if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
957 throw Exception("DistributedPythonNode problem in python pickle");
958 serializationInputCorba->length(len);
959 for(int i=0; i < len ; i++)
960 serializationInputCorba[i]=serializationInputC[i];
961 Py_XDECREF(serializationInput);
963 _pynode->defineNewCustomVar(DPL_INFO_NAME,serializationInputCorba);
968 PyDict_SetItemString(_context,DPL_INFO_NAME,ob);
973 PyFuncNode::PyFuncNode(const PyFuncNode& other, ComposedNode *father):InlineFuncNode(other,father),_pyfunc(0)
975 _implementation = PythonNode::IMPL_NAME;
978 _context=PyDict_New();
979 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
980 if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
983 msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
984 _errorDetails=msg.str();
985 throw Exception(msg.str());
990 PyFuncNode::PyFuncNode(const std::string& name): InlineFuncNode(name),_pyfunc(0)
993 _implementation = PythonNode::IMPL_NAME;
994 DEBTRACE( "PyFuncNode::PyFuncNode " << name );
997 _context=PyDict_New();
998 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
999 if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
1002 msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
1003 _errorDetails=msg.str();
1004 throw Exception(msg.str());
1009 PyFuncNode::~PyFuncNode()
1011 if(!CORBA::is_nil(_pynode))
1013 _pynode->UnRegister();
1017 void PyFuncNode::init(bool start)
1019 initCommonPartWithoutStateManagement(start);
1020 if(_state == YACS::DISABLED)
1022 exDisabledState(); // to refresh propagation of DISABLED state
1025 if(start) //complete initialization
1026 setState(YACS::READY);
1027 else if(_state > YACS::LOADED)// WARNING FuncNode has internal vars (CEA usecase) ! Partial initialization (inside a loop). Exclusivity of funcNode.
1028 setState(YACS::TORECONNECT);
1031 void PyFuncNode::checkBasicConsistency() const
1033 DEBTRACE("checkBasicConsistency");
1034 InlineFuncNode::checkBasicConsistency();
1038 res=Py_CompileString(_script.c_str(),getName().c_str(),Py_file_input);
1041 std::string error="";
1042 PyObject* new_stderr = newPyStdOut(error);
1043 PySys_SetObject((char*)"stderr", new_stderr);
1045 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1046 Py_DECREF(new_stderr);
1047 throw Exception(error);
1054 void PyFuncNode::load()
1056 DEBTRACE( "---------------PyfuncNode::load function---------------" );
1057 if(_mode==PythonNode::REMOTE_NAME)
1063 void PyFuncNode::loadRemote()
1065 commonRemoteLoad(this);
1068 void PyFuncNode::loadLocal()
1070 DEBTRACE( "---------------PyFuncNode::load function " << getName() << " ---------------" );
1071 DEBTRACE( _script );
1074 list<OutputPort *>::iterator iter;
1075 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
1077 OutputPyPort *p=(OutputPyPort *)*iter;
1078 DEBTRACE( "port name: " << p->getName() );
1079 DEBTRACE( "port kind: " << p->edGetType()->kind() );
1085 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1087 std::ostringstream stream;
1088 stream << "/tmp/PythonNode_";
1091 PyObject* code=Py_CompileString(_script.c_str(), stream.str().c_str(), Py_file_input);
1095 PyObject* new_stderr = newPyStdOut(_errorDetails);
1096 PySys_SetObject((char*)"stderr", new_stderr);
1098 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1099 Py_DECREF(new_stderr);
1100 throw Exception("Error during execution");
1102 PyObject *res = PyEval_EvalCode( code, _context, _context);
1106 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1107 if(PyErr_Occurred ())
1110 PyObject* new_stderr = newPyStdOut(_errorDetails);
1111 PySys_SetObject((char*)"stderr", new_stderr);
1112 ofstream errorfile(stream.str().c_str());
1113 if (errorfile.is_open())
1115 errorfile << _script;
1119 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1120 Py_DECREF(new_stderr);
1121 throw Exception("Error during execution");
1124 _pyfunc=PyDict_GetItemString(_context,_fname.c_str());
1125 DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1129 PyObject* new_stderr = newPyStdOut(_errorDetails);
1130 PySys_SetObject((char*)"stderr", new_stderr);
1132 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1133 Py_DECREF(new_stderr);
1134 throw Exception("Error during execution");
1136 DEBTRACE( "---------------End PyFuncNode::load function---------------" );
1140 void PyFuncNode::execute()
1142 if(_mode==PythonNode::REMOTE_NAME)
1148 void PyFuncNode::executeRemote()
1150 DEBTRACE( "++++++++++++++ PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
1152 throw Exception("DistributedPythonNode badly loaded");
1154 if(dynamic_cast<HomogeneousPoolContainer *>(getContainer()))
1157 loadPythonAdapter(this,dummy);
1158 _pynode->executeAnotherPieceOfCode(getScript().c_str());
1161 Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);;
1163 #if PY_VERSION_HEX < 0x03070000
1164 std::unique_lock<std::mutex> lock(data_mutex);
1168 //===========================================================================
1169 // Get inputs in input ports, build a Python tuple and pickle it
1170 //===========================================================================
1171 PyObject *args(PyTuple_New(getNumberOfInputPorts()));
1173 for(std::list<InputPort *>::iterator iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++,pos++)
1175 InputPyPort *p=(InputPyPort *)*iter2;
1178 PyTuple_SetItem(args,pos,ob);
1181 PyObject_Print(args,stderr,Py_PRINT_RAW);
1184 PyObject *serializationInput=PyObject_CallObject(_pyfuncSer,args);
1186 //The pickled string may contain NULL characters so use PyString_AsStringAndSize
1187 char *serializationInputC(0);
1189 if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
1190 throw Exception("DistributedPythonNode problem in python pickle");
1192 serializationInputCorba->length(len);
1193 for(int i=0; i < len ; i++)
1194 serializationInputCorba[i]=serializationInputC[i];
1195 Py_DECREF(serializationInput);
1198 //===========================================================================
1199 // Execute in remote Python node
1200 //===========================================================================
1201 DEBTRACE( "-----------------starting remote python invocation-----------------" );
1202 Engines::pickledArgs_var resultCorba;
1205 resultCorba=_pynode->execute(getFname().c_str(),serializationInputCorba);
1207 catch( const SALOME::SALOME_Exception& ex )
1209 std::string msg="Exception on remote python invocation";
1211 msg += ex.details.text.in();
1213 throw Exception(msg);
1215 catch(CORBA::COMM_FAILURE& ex)
1217 std::ostringstream msg;
1218 msg << "Exception on remote python invocation." << std::endl ;
1219 msg << "Caught system exception COMM_FAILURE -- unable to contact the "
1220 << "object." << std::endl;
1221 _errorDetails=msg.str();
1222 throw Exception(msg.str());
1224 catch(CORBA::SystemException& ex)
1226 std::ostringstream msg;
1227 msg << "Exception on remote python invocation." << std::endl ;
1228 msg << "Caught a CORBA::SystemException." ;
1231 CORBA::TypeCode_var tc = tmp.type();
1232 const char *p = tc->name();
1238 _errorDetails=msg.str();
1239 throw Exception(msg.str());
1241 catch(CORBA::Exception& ex)
1243 std::ostringstream msg;
1244 msg << "Exception on remote python invocation." << std::endl ;
1245 msg << "Caught CORBA::Exception. " ;
1248 CORBA::TypeCode_var tc = tmp.type();
1249 const char *p = tc->name();
1255 _errorDetails=msg.str();
1256 throw Exception(msg.str());
1258 catch(omniORB::fatalException& fe)
1260 std::ostringstream msg;
1261 msg << "Exception on remote python invocation." << std::endl ;
1262 msg << "Caught omniORB::fatalException:" << std::endl;
1263 msg << " file: " << fe.file() << std::endl;
1264 msg << " line: " << fe.line() << std::endl;
1265 msg << " mesg: " << fe.errmsg() << std::endl;
1266 _errorDetails=msg.str();
1267 throw Exception(msg.str());
1269 DEBTRACE( "-----------------end of remote python invocation-----------------" );
1270 //===========================================================================
1271 // Get results, unpickle and put them in output ports
1272 //===========================================================================
1273 char *resultCorbaC=new char[resultCorba->length()+1];
1274 resultCorbaC[resultCorba->length()]='\0';
1275 for(int i=0;i<resultCorba->length();i++)
1276 resultCorbaC[i]=resultCorba[i];
1279 #if PY_VERSION_HEX < 0x03070000
1280 std::unique_lock<std::mutex> lock(data_mutex);
1284 PyObject *resultPython(PyBytes_FromStringAndSize(resultCorbaC,resultCorba->length()));
1285 delete [] resultCorbaC;
1286 PyObject *args(PyTuple_New(1)),*ob(0);
1287 PyTuple_SetItem(args,0,resultPython);
1288 PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
1291 DEBTRACE( "-----------------PythonNode::outputs-----------------" );
1293 if(finalResult == Py_None)
1295 else if(PyTuple_Check(finalResult))
1296 nres=PyTuple_Size(finalResult);
1298 if(getNumberOfOutputPorts() != nres)
1300 std::string msg="Number of output arguments : Mismatch between definition and execution";
1301 Py_DECREF(finalResult);
1303 throw Exception(msg);
1309 for(std::list<OutputPort *>::iterator iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++, pos++)
1311 OutputPyPort *p=(OutputPyPort *)*iter;
1312 DEBTRACE( "port name: " << p->getName() );
1313 DEBTRACE( "port kind: " << p->edGetType()->kind() );
1314 DEBTRACE( "port pos : " << pos );
1315 if(PyTuple_Check(finalResult))
1316 ob=PyTuple_GetItem(finalResult,pos) ;
1319 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1322 Py_DECREF(finalResult);
1324 catch(ConversionException& ex)
1326 Py_DECREF(finalResult);
1327 _errorDetails=ex.what();
1332 DEBTRACE( "++++++++++++++ ENDOF PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
1335 void PyFuncNode::executeLocal()
1337 DEBTRACE( "++++++++++++++ PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
1341 if(!_pyfunc)throw Exception("PyFuncNode badly loaded");
1344 DEBTRACE( "---------------PyFuncNode::inputs---------------" );
1345 PyObject* args = PyTuple_New(getNumberOfInputPorts()) ;
1346 list<InputPort *>::iterator iter2;
1347 for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
1349 InputPyPort *p=(InputPyPort *)*iter2;
1350 DEBTRACE( "port name: " << p->getName() );
1351 DEBTRACE( "port kind: " << p->edGetType()->kind() );
1354 PyObject_Print(ob,stderr,Py_PRINT_RAW);
1357 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1359 PyTuple_SetItem(args,pos,ob);
1360 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1363 DEBTRACE( "---------------End PyFuncNode::inputs---------------" );
1365 DEBTRACE( "----------------PyFuncNode::calculation---------------" );
1367 PyObject_Print(_pyfunc,stderr,Py_PRINT_RAW);
1369 PyObject_Print(args,stderr,Py_PRINT_RAW);
1372 DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1373 PyObject* result = PyObject_CallObject( _pyfunc , args ) ;
1374 DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1381 PyObject* new_stderr = newPyStdOut(_errorDetails);
1382 PySys_SetObject((char*)"stderr", new_stderr);
1383 std::ostringstream stream;
1384 stream << "/tmp/PythonNode_";
1386 ofstream errorfile(stream.str().c_str());
1387 if (errorfile.is_open())
1389 errorfile << _script;
1393 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1394 Py_DECREF(new_stderr);
1395 throw Exception("Error during execution");
1397 DEBTRACE( "----------------End PyFuncNode::calculation---------------" );
1399 DEBTRACE( "-----------------PyFuncNode::outputs-----------------" );
1401 if(result == Py_None)
1403 else if(PyTuple_Check(result))
1404 nres=PyTuple_Size(result);
1406 if(getNumberOfOutputPorts() != nres)
1408 std::string msg="Number of output arguments : Mismatch between definition and execution";
1411 throw Exception(msg);
1416 PyObject_Print(result,stderr,Py_PRINT_RAW);
1419 list<OutputPort *>::iterator iter;
1422 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
1424 OutputPyPort *p=(OutputPyPort *)*iter;
1425 DEBTRACE( "port name: " << p->getName() );
1426 DEBTRACE( "port kind: " << p->edGetType()->kind() );
1427 DEBTRACE( "port pos : " << pos );
1428 if(PyTuple_Check(result))ob=PyTuple_GetItem(result,pos) ;
1430 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1432 PyObject_Print(ob,stderr,Py_PRINT_RAW);
1439 catch(ConversionException& ex)
1442 _errorDetails=ex.what();
1445 DEBTRACE( "-----------------End PyFuncNode::outputs-----------------" );
1448 DEBTRACE( "++++++++++++++ End PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
1451 Node *PyFuncNode::simpleClone(ComposedNode *father, bool editionOnly) const
1453 return new PyFuncNode(*this,father);
1456 void PyFuncNode::createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)
1458 if(!CORBA::is_nil(_pynode))
1459 _pynode->UnRegister();
1460 _pynode=objContainer->createPyNode(getName().c_str(),getScript().c_str());
1463 Engines::PyNodeBase_var PyFuncNode::retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const
1465 Engines::PyNode_var ret(objContainer->getDefaultPyNode(getName().c_str()));
1466 if(!CORBA::is_nil(ret))
1470 return Engines::PyNodeBase::_narrow(ret);
1473 void PyFuncNode::assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)
1475 if(!CORBA::is_nil(_pynode))
1477 Engines::PyNode_var tmpp(Engines::PyNode::_narrow(remoteInterp));
1478 if(_pynode->_is_equivalent(tmpp))
1481 if(!CORBA::is_nil(_pynode))
1482 _pynode->UnRegister();
1483 _pynode=Engines::PyNode::_narrow(remoteInterp);
1486 Engines::PyNodeBase_var PyFuncNode::getRemoteInterpreterHandle()
1488 return Engines::PyNodeBase::_narrow(_pynode);
1491 //! Create a new node of same type with a given name
1492 PyFuncNode* PyFuncNode::cloneNode(const std::string& name)
1494 PyFuncNode* n=new PyFuncNode(name);
1495 n->setScript(_script);
1496 n->setFname(_fname);
1497 list<InputPort *>::iterator iter;
1498 for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
1500 InputPyPort *p=(InputPyPort *)*iter;
1501 n->edAddInputPort(p->getName(),p->edGetType());
1503 list<OutputPort *>::iterator iter2;
1504 for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
1506 OutputPyPort *p=(OutputPyPort *)*iter2;
1507 n->edAddOutputPort(p->getName(),p->edGetType());
1512 std::string PyFuncNode::getContainerLog()
1514 return PythonEntry::GetContainerLog(_mode,_container,this);
1517 void PyFuncNode::shutdown(int level)
1519 DEBTRACE("PyFuncNode::shutdown " << level);
1520 if(_mode=="local")return;
1523 if(!CORBA::is_nil(_pynode)) _pynode->UnRegister();
1524 _pynode=Engines::PyNode::_nil();
1525 _container->shutdown(level);
1529 void PyFuncNode::imposeResource(const std::string& resource_name,
1530 const std::string& container_name)
1532 if(!resource_name.empty() && !container_name.empty())
1534 _imposedResource = resource_name;
1535 _imposedContainer = container_name;
1539 bool PyFuncNode::canAcceptImposedResource()
1541 return _container != nullptr && _container->canAcceptImposedResource();
1544 bool PyFuncNode::hasImposedResource()const
1546 return PythonEntry::hasImposedResource();