Version: 9.16.0
DistributedPythonNode.cxx
Go to the documentation of this file.
1// Copyright (C) 2006-2026 CEA, EDF
2//
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.
7//
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.
12//
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
16//
17// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18//
19
21#include "RuntimeSALOME.hxx"
22#include "SalomeContainer.hxx"
23#include "PythonNode.hxx"
24#include "SalomeHPContainer.hxx"
26#include "PythonCppUtils.hxx"
27
28#include "PythonPorts.hxx"
29#include "YacsTrace.hxx"
30#include "PyStdout.hxx"
31
32using namespace YACS::ENGINE;
33using namespace std;
34
35const char DistributedPythonNode::KIND[]="DistPython";
36const char DistributedPythonNode::IMPL_NAME[]="Python";
37const char DistributedPythonNode::SALOME_CONTAINER_METHOD_IDL[]="createPyNode";
38
39Node *DistributedPythonNode::simpleClone(ComposedNode *father, bool editionOnly) const
40{
41 return new DistributedPythonNode(*this,father);
42}
43
44DistributedPythonNode::DistributedPythonNode(const std::string& name):ServerNode(name),_context(0),_pyfuncSer(0),_pyfuncUnser(0)
45{
46 initMySelf();
47}
48
49DistributedPythonNode::DistributedPythonNode(const DistributedPythonNode& other, ComposedNode *father):ServerNode(other,father),_context(0),_pyfuncSer(0),_pyfuncUnser(0)
50{
51 initMySelf();
52}
53
55{
56 AutoGIL agil;
57 Py_DECREF(_context);
58}
59
61{
62 bool isContAlreadyStarted(false);
63 if(_container)
64 isContAlreadyStarted=_container->isAlreadyStarted(this);
66 {
67 AutoGIL agil;
68 if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
69 {
70 stringstream msg;
71 msg << "Impossible to set builtins" << __FILE__ << ":" << __LINE__;
72 _errorDetails=msg.str();
73 throw Exception(msg.str());
74 }
75 const char picklizeScript[]="import pickle\ndef pickleForDistPyth2009(*args,**kws):\n return pickle.dumps((args,kws),-1)\n\ndef unPickleForDistPyth2009(st):\n args=pickle.loads(st)\n return args\n";
76 PyObject *res=PyRun_String(picklizeScript,Py_file_input,_context,_context);
77 if(res == NULL)
78 {
80 PyObject* new_stderr = newPyStdOut(_errorDetails);
81 PySys_SetObject((char*)"stderr", new_stderr);
82 PyErr_Print();
83 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
84 Py_DECREF(new_stderr);
85 throw Exception("Error during execution");
86 return;
87 }
88 Py_DECREF(res);
89 _pyfuncSer=PyDict_GetItemString(_context,"pickleForDistPyth2009");
90 _pyfuncUnser=PyDict_GetItemString(_context,"unPickleForDistPyth2009");
91 if(_pyfuncSer == NULL)
92 {
94 PyObject* new_stderr = newPyStdOut(_errorDetails);
95 PySys_SetObject((char*)"stderr", new_stderr);
96 PyErr_Print();
97 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
98 Py_DECREF(new_stderr);
99 throw Exception("Error during execution");
100 }
101 if(_pyfuncUnser == NULL)
102 {
103 _errorDetails="";
104 PyObject* new_stderr = newPyStdOut(_errorDetails);
105 PySys_SetObject((char*)"stderr", new_stderr);
106 PyErr_Print();
107 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
108 Py_DECREF(new_stderr);
109 throw Exception("Error during execution");
110 }
111
112 Engines::Container_var objContainer=Engines::Container::_nil();
113 if(!_container)
114 throw Exception("No container specified !");
115 SalomeContainer *containerCast0(dynamic_cast<SalomeContainer *>(_container));
116 SalomeHPContainer *containerCast1(dynamic_cast<SalomeHPContainer *>(_container));
117 if(containerCast0)
118 objContainer=containerCast0->getContainerPtr(this);
119 else if(containerCast1)
120 {
122 objContainer=tmpCont->getContainerPtr(this);
123 }
124 else
125 throw Exception("Unrecognized type of container ! Salome one is expected !");
126 if(CORBA::is_nil(objContainer))
127 throw Exception("Container corba pointer is NULL !");
128
129 try
130 {
131 if(containerCast0 || !isContAlreadyStarted)
132 {
133 _pynode = objContainer->createPyNode(getName().c_str(),getScript().c_str());
134 }
135 else
136 {
137 Engines::PyNode_var dftPyScript(objContainer->getDefaultPyNode(getName().c_str()));
138 if(CORBA::is_nil(dftPyScript))
139 _pynode = objContainer->createPyNode(getName().c_str(),getScript().c_str());
140 else
141 _pynode = dftPyScript;
142 }
143 }
144 catch( const SALOME::SALOME_Exception& ex )
145 {
146 std::string msg="Exception on remote python node creation ";
147 msg += '\n';
148 msg += ex.details.text.in();
149 _errorDetails=msg;
150 throw Exception(msg);
151 }
152
153 if(CORBA::is_nil(_pynode))
154 throw Exception("In DistributedPythonNode the ref in NULL ! ");
155
156
157 DEBUG_YACSTRACE( "---------------End PyfuncSerNode::load function---------------" );
158 }
159}
160
162{
163 GURU_YACSTRACE("+++++++++++++++++ DistributedPythonNode::execute: " << getName() << " " << getFname() << " +++++++++++++++++" );
165 PyObject* ob;
166 if(!_pyfuncSer)
167 throw Exception("DistributedPythonNode badly loaded");
168 Engines::pickledArgs *serializationInputCorba(0);
169 PyObject *args(0);
170 {
171 AutoGIL agil;
172
173 GURU_YACSTRACE( "---------------DistributedPythonNode::inputs---------------" );
174 args = PyTuple_New(getNumberOfInputPorts()) ;
175 int pos=0;
176 for(list<InputPort *>::iterator iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++,pos++)
177 {
178 InputPyPort *p=(InputPyPort *)*iter2;
179 ob=p->getPyObj();
180 Py_INCREF(ob);
181 PyTuple_SetItem(args,pos,ob);
182 }
183 PyObject *serializationInput=PyObject_CallObject(_pyfuncSer,args);
184 Py_ssize_t len = PyBytes_Size(serializationInput);
185 char* serializationInputC = PyBytes_AsString(serializationInput);
186 //int ret = PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len);
187 serializationInputCorba=new Engines::pickledArgs;
188 serializationInputCorba->length(len+1);
189 for(int i=0;i<len+1;i++)
190 (*serializationInputCorba)[i]=serializationInputC[i];
191 Py_DECREF(serializationInput);
192 }
193 //serializationInputCorba[serializationInputC.length()]='\0';
194 DEBUG_YACSTRACE( "-----------------DistributedPythonNode starting remote python invocation-----------------" );
195 Engines::pickledArgs *resultCorba;
196 try
197 {
198 resultCorba=_pynode->execute(getFname().c_str(),*serializationInputCorba);
199 }
200 catch(...)
201 {
202 std::string msg="Exception on remote python invocation";
203 _errorDetails=msg;
204 throw Exception(msg);
205 }
206 DEBUG_YACSTRACE( "-----------------DistributedPythonNode end of remote python invocation-----------------" );
207 //
208 delete serializationInputCorba;
209 char *resultCorbaC=new char[resultCorba->length()+1];
210 resultCorbaC[resultCorba->length()]='\0';
211 for(int i=0;i<resultCorba->length();i++)
212 resultCorbaC[i]=(*resultCorba)[i];
213 int lenResCorba=resultCorba->length();
214 delete resultCorba;
215 {
216 AutoGIL agil;
217 args = PyTuple_New(1);
218 //PyObject* resultPython=PyBytes_FromString(resultCorbaC);
219 PyObject* resultPython=PyBytes_FromStringAndSize(resultCorbaC,lenResCorba);
220 delete [] resultCorbaC;
221 PyTuple_SetItem(args,0,resultPython);
222 PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
223 GURU_YACSTRACE( "-----------------DistributedPythonNode::outputs-----------------" );
224 if(finalResult == NULL)
225 {
226 std::stringstream msg;
227 msg << "Conversion with pickle of output ports failed !";
228 msg << " : " << __FILE__ << ":" << __LINE__;
229 _errorDetails=msg.str();
230 throw YACS::ENGINE::ConversionException(msg.str());
231 }
232 int nres=1;
233 if(finalResult == Py_None)
234 nres=0;
235 else if(PyTuple_Check(finalResult))
236 nres=PyTuple_Size(finalResult);
237
238 if(getNumberOfOutputPorts() != nres)
239 {
240 std::string msg="Number of output arguments : Mismatch between definition and execution";
241 Py_DECREF(finalResult);
242 _errorDetails=msg;
243 throw Exception(msg);
244 }
245 try
246 {
247 int pos(0);
248 for(list<OutputPort *>::iterator iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++, pos++)
249 {
250 OutputPyPort *p=(OutputPyPort *)*iter;
251 GURU_YACSTRACE( "port name: " << p->getName() );
252 GURU_YACSTRACE( "port kind: " << p->typeName() );
253 GURU_YACSTRACE( "port pos : " << pos );
254 if(PyTuple_Check(finalResult))ob=PyTuple_GetItem(finalResult,pos) ;
255 else ob=finalResult;
256 GURU_YACSTRACE( "ob refcnt: " << ob->ob_refcnt );
257 p->put(ob);
258 }
259 }
260 catch(ConversionException& ex)
261 {
262 Py_DECREF(finalResult);
263 _errorDetails=ex.what();
264 throw;
265 }
266 }
267 GURU_YACSTRACE( "++++++++++++++ End DistributedPythonNode::execute: " << getName() << " ++++++++++++++++++++" );
268}
269
271{
272 return "Salome";
273}
274
276{
278 return PythonNode::KIND;
279}
280
281ServerNode *DistributedPythonNode::createNode(const std::string& name) const
282{
283 ServerNode *ret=new DistributedPythonNode(name);
285 return ret;
286}
287
289{
291 AutoGIL agil;
292 _context=PyDict_New();
293}
294
295void DistributedPythonNode::dealException(CORBA::Exception *exc, const char *method, const char *ref)
296{
297 if( exc )
298 {
299 GURU_YACSTRACE( "An exception was thrown!" );
300 GURU_YACSTRACE( "The raised exception is of Type:" << exc->_name() );
301
302 CORBA::SystemException* sysexc;
303 sysexc=CORBA::SystemException::_downcast(exc);
304 if(sysexc != NULL)
305 {
306 // It's a SystemException
307 GURU_YACSTRACE( "minor code: " << sysexc->minor() );
308 GURU_YACSTRACE( "completion code: " << sysexc->completed() );
309 std::string text="Execution problem: ";
310 std::string excname=sysexc->_name();
311 if(excname == "BAD_OPERATION")
312 {
313 text=text+"bad operation detected";
314 }
315 else if(excname == "MARSHAL" && sysexc->minor() == omni::MARSHAL_PassEndOfMessage)
316 {
317 text=text+"probably an error in arguments of service '" + method + "' from component '" +ref+ "'";
318 }
319 else if(excname == "COMM_FAILURE" && sysexc->minor() == omni::COMM_FAILURE_UnMarshalResults)
320 {
321 text=text+"probably an error in output arguments of service '" + method + "' from component '" +ref+ "'";
322 }
323 else if(excname == "COMM_FAILURE" && sysexc->minor() == omni::COMM_FAILURE_UnMarshalArguments)
324 {
325 text=text+"probably an error in input arguments of service '" + method + "' from component '" +ref+ "'";
326 }
327 else if(excname == "COMM_FAILURE" && sysexc->minor() == omni::COMM_FAILURE_WaitingForReply)
328 {
329 text=text+"probably an error in input arguments of service '" + method + "' from component '" +ref+ "'";
330 }
331 else
332 {
333 GURU_YACSTRACE(sysexc->NP_minorString() );
334 text=text+"System Exception "+ excname;
335 }
336 _errorDetails=text;
337 throw Exception(text);
338 }
339
340 // Not a System Exception
341 CORBA::UnknownUserException* userexc;
342 userexc=CORBA::UnknownUserException::_downcast(exc);
343 if(userexc != NULL)
344 {
345 CORBA::Any anyExcept = userexc->exception();
346
347 const SALOME::SALOME_Exception* salexc;
348 if(anyExcept >>= salexc)
349 {
350 GURU_YACSTRACE("SALOME_Exception: "<< salexc->details.sourceFile);
351 GURU_YACSTRACE("SALOME_Exception: "<<salexc->details.lineNumber);
352 _errorDetails=salexc->details.text;
353 throw Exception("Execution problem: Salome Exception occurred" + getErrorDetails() );
354 }
355 std::string msg="Execution problem: User Exception occurred";
356 _errorDetails=msg;
357 throw Exception(msg);
358 }
359 std::string msg="Execution problem";
360 _errorDetails=msg;
361 throw Exception(msg);
362 }
363}
int Py_ssize_t
Definition: PythonNode.cxx:45
#define DEBUG_YACSTRACE(msg)
Definition: YacsTrace.hxx:53
#define GURU_YACSTRACE(msg)
Definition: YacsTrace.hxx:55
Base class for all composed nodes.
std::string getName() const
virtual bool isAlreadyStarted(const Task *askingNode) const =0
DistributedPythonNode(const std::string &name)
ServerNode * createNode(const std::string &name) const
std::string getKind() const
this method returns the type of input/output expected
void dealException(CORBA::Exception *exc, const char *method, const char *ref)
std::string getEffectiveKindOfServer() const
this method returns the type of container expected
std::list< InputPort * > _setOfInputPort
virtual std::string getErrorDetails()
Give a description of error when node status is ERROR.
std::list< OutputPort * > _setOfOutputPort
virtual std::string getFname()
Definition: InlineNode.hxx:101
virtual void setContainer(Container *container)
Definition: InlineNode.cxx:105
virtual std::string getScript()
Definition: InlineNode.hxx:51
Class for Python Ports.
Definition: PythonPorts.hxx:74
Base class for all nodes.
Definition: Node.hxx:70
const std::string & getName() const
Definition: Node.hxx:125
std::string _implementation
Definition: Node.hxx:97
std::string _errorDetails
Definition: Node.hxx:93
virtual std::string typeName()
Definition: Proc.hxx:84
static const char KIND[]
Definition: PythonNode.hxx:122
static SalomeContainerTmpForHP * BuildFrom(const SalomeHPContainer *cont, const Task *askingNode)
Engines::Container_ptr getContainerPtr(const Task *askingNode) const
Proc * p
Definition: driver.cxx:216
YACSRUNTIMESALOME_EXPORT RuntimeSALOME * getSALOMERuntime()
PyObject * newPyStdOut(std::string &out)
Definition: PyStdout.cxx:129
def ref(target, callback=None)
Definition: CONNECTOR.py:120