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"
30 #include "ReceiverFactory.hxx"
31 #include "SenderByteImpl.hxx"
33 #include "PyStdout.hxx"
41 #define getpid _getpid
44 #if PY_VERSION_HEX < 0x02050000
45 typedef int Py_ssize_t;
49 #include "YacsTrace.hxx"
51 using namespace YACS::ENGINE;
54 const char PythonEntry::SCRIPT_FOR_SIMPLE_SERIALIZATION[]="import pickle\n"
55 "def pickleForVarSimplePyth2009(val):\n"
56 " return pickle.dumps(val,-1)\n"
59 const char PythonNode::IMPL_NAME[]="Python";
60 const char PythonNode::KIND[]="Python";
62 const char PythonNode::SCRIPT_FOR_SERIALIZATION[]="import pickle\n"
63 "def pickleForDistPyth2009(kws):\n"
64 " return pickle.dumps(((),kws),-1)\n"
66 "def unPickleForDistPyth2009(st):\n"
67 " args=pickle.loads(st)\n"
70 const char PythonNode::REMOTE_NAME[]="remote";
72 const char PythonNode::DPL_INFO_NAME[]="my_dpl_localization";
74 const char PyFuncNode::SCRIPT_FOR_SERIALIZATION[]="import pickle\n"
75 "def pickleForDistPyth2009(*args,**kws):\n"
76 " return pickle.dumps((args,kws),-1)\n"
78 "def unPickleForDistPyth2009(st):\n"
79 " args=pickle.loads(st)\n"
82 // pickle.load concurrency issue : see https://bugs.python.org/issue12680
83 #if PY_VERSION_HEX < 0x03070000
85 static std::mutex data_mutex;
88 PythonEntry::PythonEntry():_context(0),_pyfuncSer(0),_pyfuncUnser(0),_pyfuncSimpleSer(0)
92 PythonEntry::~PythonEntry()
95 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
96 // not Py_XDECREF of _pyfuncUnser because it is returned by PyDict_GetItem -> borrowed
97 // not Py_XDECREF of _pyfuncSer because it is returned by PyDict_GetItem -> borrowed
101 void PythonEntry::loadRemoteContainer(InlineNode *reqNode)
103 DEBTRACE( "---------------PythonEntry::CommonRemoteLoad function---------------" );
104 Container *container(reqNode->getContainer());
105 bool isContAlreadyStarted(false);
110 if(hasImposedResource())
111 container->start(reqNode, _imposedResource, _imposedContainer);
114 isContAlreadyStarted=container->isAlreadyStarted(reqNode);
115 if(!isContAlreadyStarted)
116 container->start(reqNode);
121 reqNode->setErrorDetails(e.what());
127 std::string what("PythonEntry::CommonRemoteLoad : a load operation requested on \"");
128 what+=reqNode->getName(); what+="\" with no container specified.";
129 reqNode->setErrorDetails(what);
130 throw Exception(what);
134 Engines::Container_var GetContainerObj(InlineNode *reqNode, bool& isStandardCont)
136 isStandardCont = false;
137 Container *container(reqNode->getContainer());
138 Engines::Container_var objContainer(Engines::Container::_nil());
140 throw YACS::Exception("No container specified !");
141 SalomeContainer *containerCast0(dynamic_cast<SalomeContainer *>(container));
142 SalomeHPContainer *containerCast1(dynamic_cast<SalomeHPContainer *>(container));
145 isStandardCont = true;
146 objContainer=containerCast0->getContainerPtr(reqNode);
148 else if(containerCast1)
150 YACS::BASES::AutoCppPtr<SalomeContainerTmpForHP> tmpCont(SalomeContainerTmpForHP::BuildFrom(containerCast1,reqNode));
151 objContainer=tmpCont->getContainerPtr(reqNode);
154 throw YACS::Exception("Unrecognized type of container ! Salome one is expected for PythonNode/PyFuncNode !");
155 if(CORBA::is_nil(objContainer))
156 throw YACS::Exception("Container corba pointer is NULL for PythonNode !");
160 Engines::Container_var PythonEntry::loadPythonAdapter(InlineNode *reqNode, bool& isInitializeRequested)
162 bool isStandardCont(true);
163 Engines::Container_var objContainer(GetContainerObj(reqNode,isStandardCont));
164 isInitializeRequested=false;
167 Engines::PyNodeBase_var dftPyScript(retrieveDftRemotePyInterpretorIfAny(objContainer));
168 if(CORBA::is_nil(dftPyScript))
170 isInitializeRequested=!isStandardCont;
171 createRemoteAdaptedPyInterpretor(objContainer);
174 assignRemotePyInterpretor(dftPyScript);
176 catch( const SALOME::SALOME_Exception& ex )
178 std::string msg="Exception on remote python node creation ";
180 msg += ex.details.text.in();
181 reqNode->setErrorDetails(msg);
182 throw Exception(msg);
184 Engines::PyNodeBase_var pynode(getRemoteInterpreterHandle());
185 if(CORBA::is_nil(pynode))
186 throw Exception("In PythonNode the ref in NULL ! ");
190 void PythonEntry::loadRemoteContext(InlineNode *reqNode, Engines::Container_ptr objContainer, bool isInitializeRequested)
192 Container *container(reqNode->getContainer());
193 Engines::PyNodeBase_var pynode(getRemoteInterpreterHandle());
196 #if PY_VERSION_HEX < 0x03070000
197 std::unique_lock<std::mutex> lock(data_mutex);
200 const char *picklizeScript(getSerializationScript());
201 PyObject *res=PyRun_String(picklizeScript,Py_file_input,_context,_context);
202 PyObject *res2(PyRun_String(SCRIPT_FOR_SIMPLE_SERIALIZATION,Py_file_input,_context,_context));
203 if(res == NULL || res2==NULL)
205 std::string errorDetails;
206 PyObject* new_stderr = newPyStdOut(errorDetails);
207 reqNode->setErrorDetails(errorDetails);
208 PySys_SetObject((char*)"stderr", new_stderr);
210 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
211 Py_DECREF(new_stderr);
212 throw Exception("Error during load");
214 Py_DECREF(res); Py_DECREF(res2);
215 _pyfuncSer=PyDict_GetItemString(_context,"pickleForDistPyth2009");
216 _pyfuncUnser=PyDict_GetItemString(_context,"unPickleForDistPyth2009");
217 _pyfuncSimpleSer=PyDict_GetItemString(_context,"pickleForVarSimplePyth2009");
218 if(_pyfuncSer == NULL)
220 std::string errorDetails;
221 PyObject *new_stderr(newPyStdOut(errorDetails));
222 reqNode->setErrorDetails(errorDetails);
223 PySys_SetObject((char*)"stderr", new_stderr);
225 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
226 Py_DECREF(new_stderr);
227 throw Exception("Error during load");
229 if(_pyfuncUnser == NULL)
231 std::string errorDetails;
232 PyObject *new_stderr(newPyStdOut(errorDetails));
233 reqNode->setErrorDetails(errorDetails);
234 PySys_SetObject((char*)"stderr", new_stderr);
236 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
237 Py_DECREF(new_stderr);
238 throw Exception("Error during load");
240 if(_pyfuncSimpleSer == NULL)
242 std::string errorDetails;
243 PyObject *new_stderr(newPyStdOut(errorDetails));
244 reqNode->setErrorDetails(errorDetails);
245 PySys_SetObject((char*)"stderr", new_stderr);
247 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
248 Py_DECREF(new_stderr);
249 throw Exception("Error during load");
252 if(isInitializeRequested)
253 {//This one is called only once at initialization in the container if an init-script is specified.
256 std::string zeInitScriptKey(container->getProperty(HomogeneousPoolContainer::INITIALIZE_SCRIPT_KEY));
257 if(!zeInitScriptKey.empty())
258 pynode->executeAnotherPieceOfCode(zeInitScriptKey.c_str());
260 catch( const SALOME::SALOME_Exception& ex )
262 std::string msg="Exception on PythonNode::loadRemote python invocation of initializisation py script !";
264 msg += ex.details.text.in();
265 reqNode->setErrorDetails(msg);
266 throw Exception(msg);
268 DEBTRACE( "---------------End PyNode::loadRemote function---------------" );
272 std::string PythonEntry::GetContainerLog(const std::string& mode, Container *container, const Task *askingTask)
280 SalomeContainer *containerCast(dynamic_cast<SalomeContainer *>(container));
281 SalomeHPContainer *objContainer2(dynamic_cast<SalomeHPContainer *>(container));
284 Engines::Container_var objContainer(containerCast->getContainerPtr(askingTask));
285 CORBA::String_var logname = objContainer->logfilename();
288 std::string::size_type pos = msg.find(":");
289 msg=msg.substr(pos+1);
291 else if(objContainer2)
293 msg="Remote PythonNode is on HP Container : no log because no info of the location by definition of HP Container !";
297 msg="Not implemented yet for container log for that type of container !";
302 msg = "Container no longer reachable";
307 void PythonEntry::commonRemoteLoad(InlineNode *reqNode)
309 loadRemoteContainer(reqNode);
310 bool isInitializeRequested;
311 Engines::Container_var objContainer(loadPythonAdapter(reqNode,isInitializeRequested));
312 loadRemoteContext(reqNode,objContainer,isInitializeRequested);
315 bool PythonEntry::hasImposedResource()const
317 return !_imposedResource.empty() && !_imposedContainer.empty();
320 PythonNode::PythonNode(const PythonNode& other, ComposedNode *father):InlineNode(other,father),_autoSqueeze(other._autoSqueeze)
322 _pynode = Engines::PyScriptNode::_nil();
323 _implementation=IMPL_NAME;
326 _context=PyDict_New();
327 if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
330 msg << "Impossible to set builtins" << __FILE__ << ":" << __LINE__;
331 _errorDetails=msg.str();
332 throw Exception(msg.str());
337 PythonNode::PythonNode(const std::string& name):InlineNode(name)
339 _pynode = Engines::PyScriptNode::_nil();
340 _implementation=IMPL_NAME;
343 _context=PyDict_New();
344 if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
347 msg << "Impossible to set builtins" << __FILE__ << ":" << __LINE__;
348 _errorDetails=msg.str();
349 throw Exception(msg.str());
354 PythonNode::~PythonNode()
359 void PythonNode::checkBasicConsistency() const
361 DEBTRACE("checkBasicConsistency");
362 InlineNode::checkBasicConsistency();
366 res=Py_CompileString(_script.c_str(),getName().c_str(),Py_file_input);
369 std::string error="";
370 PyObject* new_stderr = newPyStdOut(error);
371 PySys_SetObject((char*)"stderr", new_stderr);
373 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
374 Py_DECREF(new_stderr);
375 throw Exception(error);
382 void PythonNode::load()
384 DEBTRACE( "---------------PyNode::load function---------------" );
385 if(_mode==PythonNode::REMOTE_NAME)
391 void PythonNode::loadLocal()
393 DEBTRACE( "---------------PyNode::loadLocal function---------------" );
397 void PythonNode::loadRemote()
399 commonRemoteLoad(this);
402 void PythonNode::execute()
404 if(_mode==PythonNode::REMOTE_NAME)
410 void PythonNode::executeRemote()
412 DEBTRACE( "++++++++++++++ PyNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
414 throw Exception("PythonNode badly loaded");
416 if(dynamic_cast<HomogeneousPoolContainer *>(getContainer()))
419 loadPythonAdapter(this,dummy);
420 _pynode->assignNewCompiledCode(getScript().c_str());
422 // not managed by unique_ptr here because destructed by the order of client.
423 SenderByteImpl *serializationInputCorba = nullptr;
424 AutoPyRef serializationInput;
426 #if PY_VERSION_HEX < 0x03070000
427 std::unique_lock<std::mutex> lock(data_mutex);
430 PyObject *args(0),*ob(0);
431 //===========================================================================
432 // Get inputs in input ports, build a Python dict and pickle it
433 //===========================================================================
435 std::list<InputPort *>::iterator iter2;
437 for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); ++iter2)
439 InputPyPort *p=(InputPyPort *)*iter2;
441 PyDict_SetItemString(args,p->getName().c_str(),ob);
445 PyObject_Print(args,stderr,Py_PRINT_RAW);
448 serializationInput.set(PyObject_CallFunctionObjArgs(_pyfuncSer,args,nullptr));
450 //The pickled string may contain NULL characters so use PyString_AsStringAndSize
451 char *serializationInputC(nullptr);
453 if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
454 throw Exception("DistributedPythonNode problem in python pickle");
455 // no copy here. The C byte array of Python is taken as this into CORBA sequence to avoid copy
456 serializationInputCorba = new SenderByteImpl(serializationInputC,len);
459 //get the list of output argument names
460 std::list<OutputPort *>::iterator iter;
461 Engines::listofstring myseq;
462 myseq.length(getNumberOfOutputPorts());
464 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); ++iter)
466 OutputPyPort *p=(OutputPyPort *)*iter;
467 myseq[pos]=p->getName().c_str();
468 DEBTRACE( "port name: " << p->getName() );
469 DEBTRACE( "port kind: " << p->edGetType()->kind() );
470 DEBTRACE( "port pos : " << pos );
473 //===========================================================================
474 // Execute in remote Python node
475 //===========================================================================
476 DEBTRACE( "-----------------starting remote python invocation-----------------" );
477 SALOME::SenderByte_var resultCorba;
480 //pass outargsname and dict serialized
481 SALOME::SenderByte_var serializationInputRef = serializationInputCorba->_this();
482 _pynode->executeFirst(serializationInputRef);
483 //serializationInput and serializationInputCorba are no more needed for server. Release it.
484 serializationInput.set(nullptr);
485 resultCorba = _pynode->executeSecond(myseq);
487 catch( const SALOME::SALOME_Exception& ex )
489 std::ostringstream msg; msg << "Exception on remote python invocation" << std::endl << ex.details.text.in() << std::endl;
490 msg << "PyScriptNode CORBA ref : ";
492 CORBA::ORB_ptr orb(getSALOMERuntime()->getOrb());
493 if(!CORBA::is_nil(orb))
495 CORBA::String_var IOR(orb->object_to_string(_pynode));
500 _errorDetails=msg.str();
501 throw Exception(msg.str());
503 catch(CORBA::COMM_FAILURE& ex)
505 std::ostringstream msg;
506 msg << "Exception on remote python invocation." << std::endl ;
507 msg << "Caught system exception COMM_FAILURE -- unable to contact the "
508 << "object." << std::endl;
509 _errorDetails=msg.str();
510 throw Exception(msg.str());
512 catch(CORBA::SystemException& ex)
514 std::ostringstream msg;
515 msg << "Exception on remote python invocation." << std::endl ;
516 msg << "Caught a CORBA::SystemException." ;
519 CORBA::TypeCode_var tc = tmp.type();
520 const char *p = tc->name();
526 _errorDetails=msg.str();
527 throw Exception(msg.str());
529 catch(CORBA::Exception& ex)
531 std::ostringstream msg;
532 msg << "Exception on remote python invocation." << std::endl ;
533 msg << "Caught CORBA::Exception. " ;
536 CORBA::TypeCode_var tc = tmp.type();
537 const char *p = tc->name();
543 _errorDetails=msg.str();
544 throw Exception(msg.str());
546 catch(omniORB::fatalException& fe)
548 std::ostringstream msg;
549 msg << "Exception on remote python invocation." << std::endl ;
550 msg << "Caught omniORB::fatalException:" << std::endl;
551 msg << " file: " << fe.file() << std::endl;
552 msg << " line: " << fe.line() << std::endl;
553 msg << " mesg: " << fe.errmsg() << std::endl;
554 _errorDetails=msg.str();
555 throw Exception(msg.str());
557 // if(!CORBA::is_nil(_pynode))
559 // _pynode->UnRegister();
561 // _pynode = Engines::PyScriptNode::_nil();
564 // Engines::Container_var cont(GetContainerObj(this,dummy));
565 // cont->removePyScriptNode(getName().c_str());
566 DEBTRACE( "-----------------end of remote python invocation-----------------" );
567 //===========================================================================
568 // Get results, unpickle and put them in output ports
569 //===========================================================================
571 #if PY_VERSION_HEX < 0x03070000
572 std::unique_lock<std::mutex> lock(data_mutex);
575 PyObject *finalResult( nullptr), *ob( nullptr );
577 SeqByteReceiver recv(resultCorba);
579 unsigned long length = 0;
580 char *resultCorbaC = recv.data(length);
581 PyObject* resultPython=PyMemoryView_FromMemory(resultCorbaC,length,PyBUF_READ);
582 args = PyTuple_New(1);
583 PyTuple_SetItem(args,0,resultPython);
584 finalResult = PyObject_CallObject(_pyfuncUnser,args);
588 if (finalResult == NULL)
590 std::stringstream msg;
591 msg << "Conversion with pickle of output ports failed !";
592 msg << " : " << __FILE__ << ":" << __LINE__;
593 _errorDetails=msg.str();
594 throw YACS::ENGINE::ConversionException(msg.str());
597 DEBTRACE( "-----------------PythonNode::outputs-----------------" );
599 if(finalResult == Py_None)
601 else if(PyTuple_Check(finalResult))
602 nres=PyTuple_Size(finalResult);
604 if(getNumberOfOutputPorts() != nres)
606 std::string msg="Number of output arguments : Mismatch between definition and execution";
607 Py_DECREF(finalResult);
609 throw Exception(msg);
615 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); ++iter)
617 OutputPyPort *p=(OutputPyPort *)*iter;
618 DEBTRACE( "port name: " << p->getName() );
619 DEBTRACE( "port kind: " << p->edGetType()->kind() );
620 DEBTRACE( "port pos : " << pos );
621 if(PyTuple_Check(finalResult))
622 ob=PyTuple_GetItem(finalResult,pos) ;
625 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
629 Py_DECREF(finalResult);
631 catch(ConversionException& ex)
633 Py_DECREF(finalResult);
634 _errorDetails=ex.what();
638 squeezeMemoryRemote();
641 if(!isUsingPythonCache())
645 Engines::Container_var cont(GetContainerObj(this,dummy));
646 cont->removePyScriptNode(getName().c_str());
648 DEBTRACE( "++++++++++++++ ENDOF PyNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
651 void PythonNode::executeLocal()
653 DEBTRACE( "++++++++++++++ PyNode::executeLocal: " << getName() << " ++++++++++++++++++++" );
657 DEBTRACE( "---------------PyNode::inputs---------------" );
658 list<InputPort *>::iterator iter2;
659 for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
661 InputPyPort *p=(InputPyPort *)*iter2;
662 DEBTRACE( "port name: " << p->getName() );
663 DEBTRACE( "port kind: " << p->edGetType()->kind() );
664 PyObject* ob=p->getPyObj();
665 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
667 PyObject_Print(ob,stderr,Py_PRINT_RAW);
670 int ier=PyDict_SetItemString(_context,p->getName().c_str(),ob);
671 DEBTRACE( "after PyDict_SetItemString:ob refcnt: " << ob->ob_refcnt );
674 DEBTRACE( "---------------End PyNode::inputs---------------" );
677 DEBTRACE( "----------------PyNode::calculation---------------" );
679 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
681 std::ostringstream stream;
682 stream << "/tmp/PythonNode_";
685 PyObject* code=Py_CompileString(_script.c_str(), stream.str().c_str(), Py_file_input);
689 PyObject* new_stderr = newPyStdOut(_errorDetails);
690 PySys_SetObject((char*)"stderr", new_stderr);
692 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
693 Py_DECREF(new_stderr);
694 throw Exception("Error during execution");
696 PyObject *res = PyEval_EvalCode( code, _context, _context);
700 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
703 if(PyErr_Occurred ())
706 PyObject* new_stderr = newPyStdOut(_errorDetails);
707 PySys_SetObject((char*)"stderr", new_stderr);
708 ofstream errorfile(stream.str().c_str());
709 if (errorfile.is_open())
711 errorfile << _script;
715 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
716 Py_DECREF(new_stderr);
717 throw Exception("Error during execution");
720 DEBTRACE( "-----------------PyNode::outputs-----------------" );
721 list<OutputPort *>::iterator iter;
724 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
726 OutputPyPort *p=(OutputPyPort *)*iter;
727 DEBTRACE( "port name: " << p->getName() );
728 DEBTRACE( "port kind: " << p->edGetType()->kind() );
729 PyObject *ob=PyDict_GetItemString(_context,p->getName().c_str());
732 std::string msg="Error during execution: there is no variable ";
733 msg=msg+p->getName()+" in node context";
735 throw Exception(msg);
737 DEBTRACE( "PyNode::outputs::ob refcnt: " << ob->ob_refcnt );
739 PyObject_Print(ob,stderr,Py_PRINT_RAW);
745 catch(ConversionException& ex)
747 _errorDetails=ex.what();
752 DEBTRACE( "-----------------End PyNode::outputs-----------------" );
754 DEBTRACE( "++++++++++++++ End PyNode::execute: " << getName() << " ++++++++++++++++++++" );
757 void PythonNode::squeezeMemorySafe()
760 if(_mode==PythonNode::REMOTE_NAME)
761 this->squeezeMemoryRemote();
763 this->squeezeMemory();
766 void PythonNode::squeezeMemory()
768 for(auto p : _setOfInputPort)
770 PyDict_DelItemString(_context,p->getName().c_str());
771 InputPyPort *p2(static_cast<InputPyPort *>(p));
772 if(p2->canSafelySqueezeMemory())
775 for(auto p : _setOfOutputPort)
777 PyDict_DelItemString(_context,p->getName().c_str());
778 OutputPyPort *p2(static_cast<OutputPyPort *>(p));
779 p2->putWithoutForward(Py_None);
783 void PythonNode::squeezeMemoryRemote()
785 for(auto p : _setOfInputPort)
787 InputPyPort *p2(static_cast<InputPyPort *>(p));
788 if(p2->canSafelySqueezeMemory())
791 for(auto p : _setOfOutputPort)
793 OutputPyPort *p2(static_cast<OutputPyPort *>(p));
794 p2->putWithoutForward(Py_None);
798 std::string PythonNode::getContainerLog()
800 return PythonEntry::GetContainerLog(_mode,_container,this);
803 void PythonNode::shutdown(int level)
805 DEBTRACE("PythonNode::shutdown " << level);
806 if(_mode=="local")return;
810 _container->shutdown(level);
814 void PythonNode::imposeResource(const std::string& resource_name,
815 const std::string& container_name)
817 if(!resource_name.empty() && !container_name.empty())
819 _imposedResource = resource_name;
820 _imposedContainer = container_name;
824 bool PythonNode::canAcceptImposedResource()
826 return _container != nullptr && _container->canAcceptImposedResource();
829 bool PythonNode::hasImposedResource()const
831 return PythonEntry::hasImposedResource();
834 std::string PythonNode::pythonEntryName()const
836 if(isUsingPythonCache())
837 return "DEFAULT_NAME_FOR_UNIQUE_PYTHON_NODE_ENTRY";
842 bool PythonNode::isUsingPythonCache()const
846 found = _container->isUsingPythonCache();
850 void PythonNode::freeKernelPynode()
852 if(!CORBA::is_nil(_pynode))
856 _pynode->UnRegister();
860 DEBTRACE("Trouble when pynode->UnRegister!")
862 _pynode = Engines::PyScriptNode::_nil();
866 Node *PythonNode::simpleClone(ComposedNode *father, bool editionOnly) const
868 return new PythonNode(*this,father);
871 void PythonNode::createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)
874 _pynode=objContainer->createPyScriptNode(pythonEntryName().c_str(),getScript().c_str());
878 Engines::PyNodeBase_var PythonNode::retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const
880 Engines::PyScriptNode_var ret(objContainer->getDefaultPyScriptNode(pythonEntryName().c_str()));
881 if(!CORBA::is_nil(ret))
885 return Engines::PyNodeBase::_narrow(ret);
888 void PythonNode::assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)
890 if(CORBA::is_nil(_pynode))
891 _pynode=Engines::PyScriptNode::_narrow(remoteInterp);
894 Engines::PyScriptNode_var tmpp(Engines::PyScriptNode::_narrow(remoteInterp));
895 if(!_pynode->_is_equivalent(tmpp))
898 _pynode=Engines::PyScriptNode::_narrow(remoteInterp);
901 _pynode->assignNewCompiledCode(getScript().c_str());
904 Engines::PyNodeBase_var PythonNode::getRemoteInterpreterHandle()
906 return Engines::PyNodeBase::_narrow(_pynode);
909 //! Create a new node of same type with a given name
910 PythonNode* PythonNode::cloneNode(const std::string& name)
912 PythonNode* n=new PythonNode(name);
913 n->setScript(_script);
914 list<InputPort *>::iterator iter;
915 for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
917 InputPyPort *p=(InputPyPort *)*iter;
918 DEBTRACE( "port name: " << p->getName() );
919 DEBTRACE( "port kind: " << p->edGetType()->kind() );
920 n->edAddInputPort(p->getName(),p->edGetType());
922 list<OutputPort *>::iterator iter2;
923 for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
925 OutputPyPort *p=(OutputPyPort *)*iter2;
926 DEBTRACE( "port name: " << p->getName() );
927 DEBTRACE( "port kind: " << p->edGetType()->kind() );
928 n->edAddOutputPort(p->getName(),p->edGetType());
933 void PythonNode::applyDPLScope(ComposedNode *gfn)
935 std::vector< std::pair<std::string,int> > ret(getDPLScopeInfo(gfn));
942 std::size_t sz(ret.size());
944 for(std::size_t i=0;i<sz;i++)
946 const std::pair<std::string,int>& p(ret[i]);
947 PyObject *elt(PyTuple_New(2));
948 PyTuple_SetItem(elt,0,PyUnicode_FromString(p.first.c_str()));
949 PyTuple_SetItem(elt,1,PyLong_FromLong(p.second));
950 PyList_SetItem(ob,i,elt);
953 if(_mode==REMOTE_NAME)
955 Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);
958 PyObject *serializationInput(PyObject_CallFunctionObjArgs(_pyfuncSimpleSer,ob,NULL));
960 char *serializationInputC(0);
962 if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
963 throw Exception("DistributedPythonNode problem in python pickle");
964 serializationInputCorba->length(len);
965 for(int i=0; i < len ; i++)
966 serializationInputCorba[i]=serializationInputC[i];
967 Py_XDECREF(serializationInput);
969 _pynode->defineNewCustomVar(DPL_INFO_NAME,serializationInputCorba);
974 PyDict_SetItemString(_context,DPL_INFO_NAME,ob);
979 PyFuncNode::PyFuncNode(const PyFuncNode& other, ComposedNode *father):InlineFuncNode(other,father),_pyfunc(0)
981 _implementation = PythonNode::IMPL_NAME;
984 _context=PyDict_New();
985 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
986 if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
989 msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
990 _errorDetails=msg.str();
991 throw Exception(msg.str());
996 PyFuncNode::PyFuncNode(const std::string& name): InlineFuncNode(name),_pyfunc(0)
999 _implementation = PythonNode::IMPL_NAME;
1000 DEBTRACE( "PyFuncNode::PyFuncNode " << name );
1003 _context=PyDict_New();
1004 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1005 if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
1008 msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
1009 _errorDetails=msg.str();
1010 throw Exception(msg.str());
1015 PyFuncNode::~PyFuncNode()
1017 if(!CORBA::is_nil(_pynode))
1019 _pynode->UnRegister();
1023 void PyFuncNode::init(bool start)
1025 initCommonPartWithoutStateManagement(start);
1026 if(_state == YACS::DISABLED)
1028 exDisabledState(); // to refresh propagation of DISABLED state
1031 if(start) //complete initialization
1032 setState(YACS::READY);
1033 else if(_state > YACS::LOADED)// WARNING FuncNode has internal vars (CEA usecase) ! Partial initialization (inside a loop). Exclusivity of funcNode.
1034 setState(YACS::TORECONNECT);
1037 void PyFuncNode::checkBasicConsistency() const
1039 DEBTRACE("checkBasicConsistency");
1040 InlineFuncNode::checkBasicConsistency();
1044 res=Py_CompileString(_script.c_str(),getName().c_str(),Py_file_input);
1047 std::string error="";
1048 PyObject* new_stderr = newPyStdOut(error);
1049 PySys_SetObject((char*)"stderr", new_stderr);
1051 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1052 Py_DECREF(new_stderr);
1053 throw Exception(error);
1060 void PyFuncNode::load()
1062 DEBTRACE( "---------------PyfuncNode::load function---------------" );
1063 if(_mode==PythonNode::REMOTE_NAME)
1069 void PyFuncNode::loadRemote()
1071 commonRemoteLoad(this);
1074 void PyFuncNode::loadLocal()
1076 DEBTRACE( "---------------PyFuncNode::load function " << getName() << " ---------------" );
1077 DEBTRACE( _script );
1080 list<OutputPort *>::iterator iter;
1081 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
1083 OutputPyPort *p=(OutputPyPort *)*iter;
1084 DEBTRACE( "port name: " << p->getName() );
1085 DEBTRACE( "port kind: " << p->edGetType()->kind() );
1091 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1093 std::ostringstream stream;
1094 stream << "/tmp/PythonNode_";
1097 PyObject* code=Py_CompileString(_script.c_str(), stream.str().c_str(), Py_file_input);
1101 PyObject* new_stderr = newPyStdOut(_errorDetails);
1102 PySys_SetObject((char*)"stderr", new_stderr);
1104 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1105 Py_DECREF(new_stderr);
1106 throw Exception("Error during execution");
1108 PyObject *res = PyEval_EvalCode( code, _context, _context);
1112 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1113 if(PyErr_Occurred ())
1116 PyObject* new_stderr = newPyStdOut(_errorDetails);
1117 PySys_SetObject((char*)"stderr", new_stderr);
1118 ofstream errorfile(stream.str().c_str());
1119 if (errorfile.is_open())
1121 errorfile << _script;
1125 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1126 Py_DECREF(new_stderr);
1127 throw Exception("Error during execution");
1130 _pyfunc=PyDict_GetItemString(_context,_fname.c_str());
1131 DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1135 PyObject* new_stderr = newPyStdOut(_errorDetails);
1136 PySys_SetObject((char*)"stderr", new_stderr);
1138 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1139 Py_DECREF(new_stderr);
1140 throw Exception("Error during execution");
1142 DEBTRACE( "---------------End PyFuncNode::load function---------------" );
1146 void PyFuncNode::execute()
1148 if(_mode==PythonNode::REMOTE_NAME)
1154 void PyFuncNode::executeRemote()
1156 DEBTRACE( "++++++++++++++ PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
1158 throw Exception("DistributedPythonNode badly loaded");
1160 if(dynamic_cast<HomogeneousPoolContainer *>(getContainer()))
1163 loadPythonAdapter(this,dummy);
1164 _pynode->executeAnotherPieceOfCode(getScript().c_str());
1167 Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);;
1169 #if PY_VERSION_HEX < 0x03070000
1170 std::unique_lock<std::mutex> lock(data_mutex);
1174 //===========================================================================
1175 // Get inputs in input ports, build a Python tuple and pickle it
1176 //===========================================================================
1177 PyObject *args(PyTuple_New(getNumberOfInputPorts()));
1179 for(std::list<InputPort *>::iterator iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++,pos++)
1181 InputPyPort *p=(InputPyPort *)*iter2;
1184 PyTuple_SetItem(args,pos,ob);
1187 PyObject_Print(args,stderr,Py_PRINT_RAW);
1190 PyObject *serializationInput=PyObject_CallObject(_pyfuncSer,args);
1192 //The pickled string may contain NULL characters so use PyString_AsStringAndSize
1193 char *serializationInputC(0);
1195 if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
1196 throw Exception("DistributedPythonNode problem in python pickle");
1198 serializationInputCorba->length(len);
1199 for(int i=0; i < len ; i++)
1200 serializationInputCorba[i]=serializationInputC[i];
1201 Py_DECREF(serializationInput);
1204 //===========================================================================
1205 // Execute in remote Python node
1206 //===========================================================================
1207 DEBTRACE( "-----------------starting remote python invocation-----------------" );
1208 Engines::pickledArgs_var resultCorba;
1211 resultCorba=_pynode->execute(getFname().c_str(),serializationInputCorba);
1213 catch( const SALOME::SALOME_Exception& ex )
1215 std::string msg="Exception on remote python invocation";
1217 msg += ex.details.text.in();
1219 throw Exception(msg);
1221 catch(CORBA::COMM_FAILURE& ex)
1223 std::ostringstream msg;
1224 msg << "Exception on remote python invocation." << std::endl ;
1225 msg << "Caught system exception COMM_FAILURE -- unable to contact the "
1226 << "object." << std::endl;
1227 _errorDetails=msg.str();
1228 throw Exception(msg.str());
1230 catch(CORBA::SystemException& ex)
1232 std::ostringstream msg;
1233 msg << "Exception on remote python invocation." << std::endl ;
1234 msg << "Caught a CORBA::SystemException." ;
1237 CORBA::TypeCode_var tc = tmp.type();
1238 const char *p = tc->name();
1244 _errorDetails=msg.str();
1245 throw Exception(msg.str());
1247 catch(CORBA::Exception& ex)
1249 std::ostringstream msg;
1250 msg << "Exception on remote python invocation." << std::endl ;
1251 msg << "Caught CORBA::Exception. " ;
1254 CORBA::TypeCode_var tc = tmp.type();
1255 const char *p = tc->name();
1261 _errorDetails=msg.str();
1262 throw Exception(msg.str());
1264 catch(omniORB::fatalException& fe)
1266 std::ostringstream msg;
1267 msg << "Exception on remote python invocation." << std::endl ;
1268 msg << "Caught omniORB::fatalException:" << std::endl;
1269 msg << " file: " << fe.file() << std::endl;
1270 msg << " line: " << fe.line() << std::endl;
1271 msg << " mesg: " << fe.errmsg() << std::endl;
1272 _errorDetails=msg.str();
1273 throw Exception(msg.str());
1275 DEBTRACE( "-----------------end of remote python invocation-----------------" );
1276 //===========================================================================
1277 // Get results, unpickle and put them in output ports
1278 //===========================================================================
1279 char *resultCorbaC=new char[resultCorba->length()+1];
1280 resultCorbaC[resultCorba->length()]='\0';
1281 for(int i=0;i<resultCorba->length();i++)
1282 resultCorbaC[i]=resultCorba[i];
1285 #if PY_VERSION_HEX < 0x03070000
1286 std::unique_lock<std::mutex> lock(data_mutex);
1290 PyObject *resultPython(PyBytes_FromStringAndSize(resultCorbaC,resultCorba->length()));
1291 delete [] resultCorbaC;
1292 PyObject *args(PyTuple_New(1)),*ob(0);
1293 PyTuple_SetItem(args,0,resultPython);
1294 PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
1297 DEBTRACE( "-----------------PythonNode::outputs-----------------" );
1299 if(finalResult == Py_None)
1301 else if(PyTuple_Check(finalResult))
1302 nres=PyTuple_Size(finalResult);
1304 if(getNumberOfOutputPorts() != nres)
1306 std::string msg="Number of output arguments : Mismatch between definition and execution";
1307 Py_DECREF(finalResult);
1309 throw Exception(msg);
1315 for(std::list<OutputPort *>::iterator iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++, pos++)
1317 OutputPyPort *p=(OutputPyPort *)*iter;
1318 DEBTRACE( "port name: " << p->getName() );
1319 DEBTRACE( "port kind: " << p->edGetType()->kind() );
1320 DEBTRACE( "port pos : " << pos );
1321 if(PyTuple_Check(finalResult))
1322 ob=PyTuple_GetItem(finalResult,pos) ;
1325 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1328 Py_DECREF(finalResult);
1330 catch(ConversionException& ex)
1332 Py_DECREF(finalResult);
1333 _errorDetails=ex.what();
1338 DEBTRACE( "++++++++++++++ ENDOF PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
1341 void PyFuncNode::executeLocal()
1343 DEBTRACE( "++++++++++++++ PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
1347 if(!_pyfunc)throw Exception("PyFuncNode badly loaded");
1350 DEBTRACE( "---------------PyFuncNode::inputs---------------" );
1351 PyObject* args = PyTuple_New(getNumberOfInputPorts()) ;
1352 list<InputPort *>::iterator iter2;
1353 for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
1355 InputPyPort *p=(InputPyPort *)*iter2;
1356 DEBTRACE( "port name: " << p->getName() );
1357 DEBTRACE( "port kind: " << p->edGetType()->kind() );
1360 PyObject_Print(ob,stderr,Py_PRINT_RAW);
1363 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1365 PyTuple_SetItem(args,pos,ob);
1366 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1369 DEBTRACE( "---------------End PyFuncNode::inputs---------------" );
1371 DEBTRACE( "----------------PyFuncNode::calculation---------------" );
1373 PyObject_Print(_pyfunc,stderr,Py_PRINT_RAW);
1375 PyObject_Print(args,stderr,Py_PRINT_RAW);
1378 DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1379 PyObject* result = PyObject_CallObject( _pyfunc , args ) ;
1380 DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1387 PyObject* new_stderr = newPyStdOut(_errorDetails);
1388 PySys_SetObject((char*)"stderr", new_stderr);
1389 std::ostringstream stream;
1390 stream << "/tmp/PythonNode_";
1392 ofstream errorfile(stream.str().c_str());
1393 if (errorfile.is_open())
1395 errorfile << _script;
1399 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1400 Py_DECREF(new_stderr);
1401 throw Exception("Error during execution");
1403 DEBTRACE( "----------------End PyFuncNode::calculation---------------" );
1405 DEBTRACE( "-----------------PyFuncNode::outputs-----------------" );
1407 if(result == Py_None)
1409 else if(PyTuple_Check(result))
1410 nres=PyTuple_Size(result);
1412 if(getNumberOfOutputPorts() != nres)
1414 std::string msg="Number of output arguments : Mismatch between definition and execution";
1417 throw Exception(msg);
1422 PyObject_Print(result,stderr,Py_PRINT_RAW);
1425 list<OutputPort *>::iterator iter;
1428 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
1430 OutputPyPort *p=(OutputPyPort *)*iter;
1431 DEBTRACE( "port name: " << p->getName() );
1432 DEBTRACE( "port kind: " << p->edGetType()->kind() );
1433 DEBTRACE( "port pos : " << pos );
1434 if(PyTuple_Check(result))ob=PyTuple_GetItem(result,pos) ;
1436 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1438 PyObject_Print(ob,stderr,Py_PRINT_RAW);
1445 catch(ConversionException& ex)
1448 _errorDetails=ex.what();
1451 DEBTRACE( "-----------------End PyFuncNode::outputs-----------------" );
1454 DEBTRACE( "++++++++++++++ End PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
1457 Node *PyFuncNode::simpleClone(ComposedNode *father, bool editionOnly) const
1459 return new PyFuncNode(*this,father);
1462 void PyFuncNode::createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)
1464 if(!CORBA::is_nil(_pynode))
1465 _pynode->UnRegister();
1466 _pynode=objContainer->createPyNode(getName().c_str(),getScript().c_str());
1469 Engines::PyNodeBase_var PyFuncNode::retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const
1471 Engines::PyNode_var ret(objContainer->getDefaultPyNode(getName().c_str()));
1472 if(!CORBA::is_nil(ret))
1476 return Engines::PyNodeBase::_narrow(ret);
1479 void PyFuncNode::assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)
1481 if(!CORBA::is_nil(_pynode))
1483 Engines::PyNode_var tmpp(Engines::PyNode::_narrow(remoteInterp));
1484 if(_pynode->_is_equivalent(tmpp))
1487 if(!CORBA::is_nil(_pynode))
1488 _pynode->UnRegister();
1489 _pynode=Engines::PyNode::_narrow(remoteInterp);
1492 Engines::PyNodeBase_var PyFuncNode::getRemoteInterpreterHandle()
1494 return Engines::PyNodeBase::_narrow(_pynode);
1497 //! Create a new node of same type with a given name
1498 PyFuncNode* PyFuncNode::cloneNode(const std::string& name)
1500 PyFuncNode* n=new PyFuncNode(name);
1501 n->setScript(_script);
1502 n->setFname(_fname);
1503 list<InputPort *>::iterator iter;
1504 for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
1506 InputPyPort *p=(InputPyPort *)*iter;
1507 n->edAddInputPort(p->getName(),p->edGetType());
1509 list<OutputPort *>::iterator iter2;
1510 for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
1512 OutputPyPort *p=(OutputPyPort *)*iter2;
1513 n->edAddOutputPort(p->getName(),p->edGetType());
1518 std::string PyFuncNode::getContainerLog()
1520 return PythonEntry::GetContainerLog(_mode,_container,this);
1523 void PyFuncNode::shutdown(int level)
1525 DEBTRACE("PyFuncNode::shutdown " << level);
1526 if(_mode=="local")return;
1529 if(!CORBA::is_nil(_pynode)) _pynode->UnRegister();
1530 _pynode=Engines::PyNode::_nil();
1531 _container->shutdown(level);
1535 void PyFuncNode::imposeResource(const std::string& resource_name,
1536 const std::string& container_name)
1538 if(!resource_name.empty() && !container_name.empty())
1540 _imposedResource = resource_name;
1541 _imposedContainer = container_name;
1545 bool PyFuncNode::canAcceptImposedResource()
1547 return _container != nullptr && _container->canAcceptImposedResource();
1550 bool PyFuncNode::hasImposedResource()const
1552 return PythonEntry::hasImposedResource();