Version: 9.15.0
PythonNode.cxx
Go to the documentation of this file.
1 // Copyright (C) 2006-2025 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 
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"
29 #include "ConversionException.hxx"
30 #include "ReceiverFactory.hxx"
31 #include "SenderByteImpl.hxx"
32 
33 #include "PyStdout.hxx"
34 #include <iostream>
35 #include <memory>
36 #include <sstream>
37 #include <fstream>
38 
39 #ifdef WIN32
40 #include <process.h>
41 #define getpid _getpid
42 #endif
43 
44 #if PY_VERSION_HEX < 0x02050000
45 typedef int Py_ssize_t;
46 #endif
47 
48 //#define _DEVDEBUG_
49 #include "YacsTrace.hxx"
50 
51 using namespace YACS::ENGINE;
52 using namespace std;
53 
54 const char PythonEntry::SCRIPT_FOR_SIMPLE_SERIALIZATION[]="import pickle\n"
55  "def pickleForVarSimplePyth2009(val):\n"
56  " return pickle.dumps(val,-1)\n"
57  "\n";
58 
59 PyObject *PythonEntry::_pyClsBigObject = nullptr;
60 
61 const char PythonNode::IMPL_NAME[]="Python";
62 const char PythonNode::KIND[]="Python";
63 
64 const char PythonNode::SCRIPT_FOR_SERIALIZATION[]="import pickle\n"
65  "def pickleForDistPyth2009(kws):\n"
66  " return pickle.dumps(((),kws),-1)\n"
67  "\n"
68  "def unPickleForDistPyth2009(st):\n"
69  " args=pickle.loads(st)\n"
70  " return args\n";
71 
72 const char PythonNode::REMOTE_NAME[]="remote";
73 
74 const char PythonNode::DPL_INFO_NAME[]="my_dpl_localization";
75 
76 const char PyFuncNode::SCRIPT_FOR_SERIALIZATION[]="import pickle\n"
77  "def pickleForDistPyth2009(*args,**kws):\n"
78  " return pickle.dumps((args,kws),-1)\n"
79  "\n"
80  "def unPickleForDistPyth2009(st):\n"
81  " args=pickle.loads(st)\n"
82  " return args\n";
83 
84 static char SCRIPT_FOR_BIGOBJECT[]="import SALOME_PyNode\n"
85  "BigObjectOnDiskBase = SALOME_PyNode.BigObjectOnDiskBase\n";
86 
87 // pickle.load concurrency issue : see https://bugs.python.org/issue12680
88 #if PY_VERSION_HEX < 0x03070000
89 #include <mutex>
90 static std::mutex data_mutex;
91 #endif
92 
93 PythonEntry::PythonEntry():_context(0),_pyfuncSer(0),_pyfuncUnser(0),_pyfuncSimpleSer(0)
94 {
95 }
96 
98 {
99  AutoGIL agil;
100  DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
101  // not Py_XDECREF of _pyfuncUnser because it is returned by PyDict_GetItem -> borrowed
102  // not Py_XDECREF of _pyfuncSer because it is returned by PyDict_GetItem -> borrowed
103  Py_XDECREF(_context);
104 }
105 
107 {
108  DEBTRACE( "---------------PythonEntry::CommonRemoteLoad function---------------" );
109  Container *container(reqNode->getContainer());
110  bool isContAlreadyStarted(false);
111  if(container)
112  {
113  try
114  {
115  if(hasImposedResource())
116  container->start(reqNode, _imposedResource, _imposedContainer);
117  else
118  {
119  isContAlreadyStarted=container->isAlreadyStarted(reqNode);
120  if(!isContAlreadyStarted)
121  container->start(reqNode);
122  }
123  }
124  catch(Exception& e)
125  {
126  reqNode->setErrorDetails(e.what());
127  throw e;
128  }
129  }
130  else
131  {
132  std::string what("PythonEntry::CommonRemoteLoad : a load operation requested on \"");
133  what+=reqNode->getName(); what+="\" with no container specified.";
134  reqNode->setErrorDetails(what);
135  throw Exception(what);
136  }
137 }
138 
139 Engines::Container_var GetContainerObj(InlineNode *reqNode, bool& isStandardCont)
140 {
141  isStandardCont = false;
142  Container *container(reqNode->getContainer());
143  Engines::Container_var objContainer(Engines::Container::_nil());
144  if(!container)
145  throw YACS::Exception("No container specified !");
146  SalomeContainer *containerCast0(dynamic_cast<SalomeContainer *>(container));
147  SalomeHPContainer *containerCast1(dynamic_cast<SalomeHPContainer *>(container));
148  if(containerCast0)
149  {
150  isStandardCont = true;
151  objContainer=containerCast0->getContainerPtr(reqNode);
152  }
153  else if(containerCast1)
154  {
156  objContainer=tmpCont->getContainerPtr(reqNode);
157  }
158  else
159  throw YACS::Exception("Unrecognized type of container ! Salome one is expected for PythonNode/PyFuncNode !");
160  if(CORBA::is_nil(objContainer))
161  throw YACS::Exception("Container corba pointer is NULL for PythonNode !");
162  return objContainer;
163 }
164 
165 Engines::Container_var PythonEntry::loadPythonAdapter(InlineNode *reqNode, bool& isInitializeRequested)
166 {
167  bool isStandardCont(true);
168  Engines::Container_var objContainer(GetContainerObj(reqNode,isStandardCont));
169  isInitializeRequested=false;
170  try
171  {
172  Engines::PyNodeBase_var dftPyScript(retrieveDftRemotePyInterpretorIfAny(objContainer));
173  if(CORBA::is_nil(dftPyScript))
174  {
175  isInitializeRequested=!isStandardCont;
176  createRemoteAdaptedPyInterpretor(objContainer);
177  }
178  else
179  assignRemotePyInterpretor(dftPyScript);
180  }
181  catch( const SALOME::SALOME_Exception& ex )
182  {
183  std::string msg="Exception on remote python node creation ";
184  msg += '\n';
185  msg += ex.details.text.in();
186  reqNode->setErrorDetails(msg);
187  throw Exception(msg);
188  }
189  Engines::PyNodeBase_var pynode(getRemoteInterpreterHandle());
190  if(CORBA::is_nil(pynode))
191  throw Exception("In PythonNode the ref in NULL ! ");
192  return objContainer;
193 }
194 
195 void PythonEntry::loadRemoteContext(InlineNode *reqNode, Engines::Container_ptr objContainer, bool isInitializeRequested)
196 {
197  Container *container(reqNode->getContainer());
198  Engines::PyNodeBase_var pynode(getRemoteInterpreterHandle());
200  {
201 #if PY_VERSION_HEX < 0x03070000
202  std::unique_lock<std::mutex> lock(data_mutex);
203 #endif
204  AutoGIL agil;
205  const char *picklizeScript(getSerializationScript());
206  PyObject *res=PyRun_String(picklizeScript,Py_file_input,_context,_context);
207  PyObject *res2(PyRun_String(SCRIPT_FOR_SIMPLE_SERIALIZATION,Py_file_input,_context,_context));
208  if(res == NULL || res2==NULL)
209  {
210  std::string errorDetails;
211  PyObject* new_stderr = newPyStdOut(errorDetails);
212  reqNode->setErrorDetails(errorDetails);
213  PySys_SetObject((char*)"stderr", new_stderr);
214  PyErr_Print();
215  PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
216  Py_DECREF(new_stderr);
217  throw Exception("Error during load");
218  }
219  Py_DECREF(res); Py_DECREF(res2);
220  AutoPyRef res3(PyRun_String(SCRIPT_FOR_BIGOBJECT,Py_file_input,_context,_context));
221  _pyfuncSer=PyDict_GetItemString(_context,"pickleForDistPyth2009");
222  _pyfuncUnser=PyDict_GetItemString(_context,"unPickleForDistPyth2009");
223  _pyfuncSimpleSer=PyDict_GetItemString(_context,"pickleForVarSimplePyth2009");
224  if(! _pyClsBigObject )
225  {
226  _pyClsBigObject=PyDict_GetItemString(_context,"BigObjectOnDiskBase");
227  Py_INCREF(_pyClsBigObject);
228  }
229  if(_pyfuncSer == NULL)
230  {
231  std::string errorDetails;
232  PyObject *new_stderr(newPyStdOut(errorDetails));
233  reqNode->setErrorDetails(errorDetails);
234  PySys_SetObject((char*)"stderr", new_stderr);
235  PyErr_Print();
236  PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
237  Py_DECREF(new_stderr);
238  throw Exception("Error during load");
239  }
240  if(_pyfuncUnser == NULL)
241  {
242  std::string errorDetails;
243  PyObject *new_stderr(newPyStdOut(errorDetails));
244  reqNode->setErrorDetails(errorDetails);
245  PySys_SetObject((char*)"stderr", new_stderr);
246  PyErr_Print();
247  PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
248  Py_DECREF(new_stderr);
249  throw Exception("Error during load");
250  }
251  if(_pyfuncSimpleSer == NULL)
252  {
253  std::string errorDetails;
254  PyObject *new_stderr(newPyStdOut(errorDetails));
255  reqNode->setErrorDetails(errorDetails);
256  PySys_SetObject((char*)"stderr", new_stderr);
257  PyErr_Print();
258  PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
259  Py_DECREF(new_stderr);
260  throw Exception("Error during load");
261  }
262  }
263  if(isInitializeRequested)
264  {//This one is called only once at initialization in the container if an init-script is specified.
265  try
266  {
267  std::string zeInitScriptKey(container->getProperty(HomogeneousPoolContainer::INITIALIZE_SCRIPT_KEY));
268  if(!zeInitScriptKey.empty())
269  pynode->executeAnotherPieceOfCode(zeInitScriptKey.c_str());
270  }
271  catch( const SALOME::SALOME_Exception& ex )
272  {
273  std::string msg="Exception on PythonNode::loadRemote python invocation of initializisation py script !";
274  msg += '\n';
275  msg += ex.details.text.in();
276  reqNode->setErrorDetails(msg);
277  throw Exception(msg);
278  }
279  DEBTRACE( "---------------End PyNode::loadRemote function---------------" );
280  }
281 }
282 
283 std::string PythonEntry::GetContainerLog(const std::string& mode, Container *container, const Task *askingTask)
284 {
285  if(mode=="local")
286  return "";
287 
288  std::string msg;
289  try
290  {
291  SalomeContainer *containerCast(dynamic_cast<SalomeContainer *>(container));
292  SalomeHPContainer *objContainer2(dynamic_cast<SalomeHPContainer *>(container));
293  if(containerCast)
294  {
295  Engines::Container_var objContainer(containerCast->getContainerPtr(askingTask));
296  CORBA::String_var logname = objContainer->logfilename();
297  DEBTRACE(logname);
298  msg=logname;
299  std::string::size_type pos = msg.find(":");
300  msg=msg.substr(pos+1);
301  }
302  else if(objContainer2)
303  {
304  msg="Remote PythonNode is on HP Container : no log because no info of the location by definition of HP Container !";
305  }
306  else
307  {
308  msg="Not implemented yet for container log for that type of container !";
309  }
310  }
311  catch(...)
312  {
313  msg = "Container no longer reachable";
314  }
315  return msg;
316 }
317 
319 {
320  loadRemoteContainer(reqNode);
321  bool isInitializeRequested;
322  Engines::Container_var objContainer(loadPythonAdapter(reqNode,isInitializeRequested));
323  loadRemoteContext(reqNode,objContainer,isInitializeRequested);
324 }
325 
327 {
328  return !_imposedResource.empty() && !_imposedContainer.empty();
329 }
330 
331 bool PythonEntry::IsProxy( PyObject *ob )
332 {
333  if(!_pyClsBigObject)
334  return false;
335  if( PyObject_IsInstance( ob, _pyClsBigObject) == 1 )
336  {
337  return true;
338  }
339  else
340  {
341  if( PyList_Check( ob ) )
342  {
343  auto sz = PyList_Size( ob );
344  for( auto i = 0 ; i < sz ; ++i )
345  {
346  PyObject *elt = PyList_GetItem( ob, i );
347  if( PythonEntry::IsProxy(elt) )
348  return true;
349  }
350  }
351  }
352  return false;
353 }
354 
355 bool PythonEntry::GetDestroyStatus( PyObject *ob )
356 {
357  if(!_pyClsBigObject)
358  return false;
359  if( PyObject_IsInstance( ob, _pyClsBigObject) == 1 )
360  {
361  AutoPyRef unlinkOnDestructor = PyObject_GetAttrString(ob,"getDestroyStatus");
362  AutoPyRef tmp = PyObject_CallFunctionObjArgs(unlinkOnDestructor,nullptr);
363  if( PyBool_Check(tmp.get()) )
364  {
365  return tmp.get() == Py_True;
366  }
367  return false;
368  }
369  else
370  {
371  if( PyList_Check( ob ) )
372  {
373  auto sz = PyList_Size( ob );
374  for( auto i = 0 ; i < sz ; ++i )
375  {
376  PyObject *elt = PyList_GetItem( ob, i );
378  return true;
379  }
380  }
381  }
382  return false;
383 }
384 
385 void PythonEntry::IfProxyDoSomething( PyObject *ob, const char *meth )
386 {
387  if(!_pyClsBigObject)
388  return ;
389  if( PyObject_IsInstance( ob, _pyClsBigObject) == 1 )
390  {
391  AutoPyRef unlinkOnDestructor = PyObject_GetAttrString(ob,meth);
392  AutoPyRef tmp = PyObject_CallFunctionObjArgs(unlinkOnDestructor,nullptr);
393  }
394  else
395  {
396  if( PyList_Check( ob ) )
397  {
398  auto sz = PyList_Size( ob );
399  for( auto i = 0 ; i < sz ; ++i )
400  {
401  PyObject *elt = PyList_GetItem( ob, i );
402  PythonEntry::IfProxyDoSomething( elt, meth );
403  }
404  }
405  }
406 }
407 
409 {
410  IfProxyDoSomething(ob,"doNotTouchFile");
411 }
412 
414 {
415  IfProxyDoSomething(ob,"unlinkOnDestructor");
416 }
417 
419 InlineNode(other,father),_autoSqueeze(other._autoSqueeze),_nonSqueezableOutputNodes(other._nonSqueezableOutputNodes)
420 {
421  _pynode = Engines::PyScriptNode::_nil();
423  {
424  AutoGIL agil;
425  _context=PyDict_New();
426  if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
427  {
428  stringstream msg;
429  msg << "Impossible to set builtins" << __FILE__ << ":" << __LINE__;
430  _errorDetails=msg.str();
431  throw Exception(msg.str());
432  }
433  }
434 }
435 
436 PythonNode::PythonNode(const std::string& name):InlineNode(name)
437 {
438  _pynode = Engines::PyScriptNode::_nil();
440  {
441  AutoGIL agil;
442  _context=PyDict_New();
443  if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
444  {
445  stringstream msg;
446  msg << "Impossible to set builtins" << __FILE__ << ":" << __LINE__;
447  _errorDetails=msg.str();
448  throw Exception(msg.str());
449  }
450  }
451 }
452 
454 {
456 }
457 
459 {
460  DEBTRACE("checkBasicConsistency");
462  {
463  AutoGIL agil;
464  PyObject* res;
465  res=Py_CompileString(_script.c_str(),getName().c_str(),Py_file_input);
466  if(res == NULL)
467  {
468  std::string error="";
469  PyObject* new_stderr = newPyStdOut(error);
470  PySys_SetObject((char*)"stderr", new_stderr);
471  PyErr_Print();
472  PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
473  Py_DECREF(new_stderr);
474  throw Exception(error);
475  }
476  else
477  Py_XDECREF(res);
478  }
479 }
480 
482 {
483  DEBTRACE( "---------------PyNode::load function---------------" );
485  loadRemote();
486  else
487  loadLocal();
488 }
489 
491 {
492  DEBTRACE( "---------------PyNode::loadLocal function---------------" );
493  // do nothing
494 }
495 
497 {
498  commonRemoteLoad(this);
499 }
500 
502 {
504  executeRemote();
505  else
506  executeLocal();
507 }
508 
510 {
511  DEBTRACE( "++++++++++++++ PyNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
512  if(!_pyfuncSer)
513  throw Exception("PythonNode badly loaded");
514  //
515  if(dynamic_cast<HomogeneousPoolContainer *>(getContainer()))
516  {
517  bool dummy;
518  loadPythonAdapter(this,dummy);
519  _pynode->assignNewCompiledCode(getScript().c_str());
520  }
521  // not managed by unique_ptr here because destructed by the order of client.
522  SenderByteImpl *serializationInputCorba = nullptr;
523  AutoPyRef serializationInput;
524  {
525 #if PY_VERSION_HEX < 0x03070000
526  std::unique_lock<std::mutex> lock(data_mutex);
527 #endif
528  AutoGIL agil;
529  PyObject *args(0),*ob(0);
530  //===========================================================================
531  // Get inputs in input ports, build a Python dict and pickle it
532  //===========================================================================
533  args = PyDict_New();
534  std::list<InputPort *>::iterator iter2;
535  int pos(0);
536  for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); ++iter2)
537  {
538  InputPyPort *p=(InputPyPort *)*iter2;
539  ob=p->getPyObj();
540  PyDict_SetItemString(args,p->getName().c_str(),ob);
541  pos++;
542  }
543 #ifdef _DEVDEBUG_
544  PyObject_Print(args,stderr,Py_PRINT_RAW);
545  std::cerr << endl;
546 #endif
547  serializationInput.set(PyObject_CallFunctionObjArgs(_pyfuncSer,args,nullptr));
548  Py_DECREF(args);
549  //The pickled string may contain NULL characters so use PyString_AsStringAndSize
550  char *serializationInputC(nullptr);
551  Py_ssize_t len;
552  if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
553  throw Exception("DistributedPythonNode problem in python pickle");
554  // no copy here. The C byte array of Python is taken as this into CORBA sequence to avoid copy
555  serializationInputCorba = new SenderByteImpl(serializationInputC,len);
556  }
557 
558  //get the list of output argument names
559  std::list<OutputPort *>::iterator iter;
560  Engines::listofstring myseq;
561  myseq.length(getNumberOfOutputPorts());
562  int pos=0;
563  for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); ++iter)
564  {
565  OutputPyPort *p=(OutputPyPort *)*iter;
566  myseq[pos]=p->getName().c_str();
567  DEBTRACE( "port name: " << p->getName() );
568  DEBTRACE( "port kind: " << p->edGetType()->kind() );
569  DEBTRACE( "port pos : " << pos );
570  pos++;
571  }
572  //===========================================================================
573  // Execute in remote Python node
574  //===========================================================================
575  DEBTRACE( "-----------------starting remote python invocation-----------------" );
576  std::unique_ptr<SALOME::SenderByteSeq> resultCorba;
577  try
578  {
579  //pass outargsname and dict serialized
580  SALOME::SenderByte_var serializationInputRef = serializationInputCorba->_this();
581  DEBUG_YACSTRACE("Before execute first of " << getId());
582  _pynode->executeFirst(serializationInputRef);
583  //serializationInput and serializationInputCorba are no more needed for server. Release it.
584  serializationInput.set(nullptr);
585  resultCorba.reset( _pynode->executeSecond(myseq) );
586  DEBUG_YACSTRACE("After execute second of " << getId());
587  }
588  catch( const SALOME::SALOME_Exception& ex )
589  {
590  std::ostringstream msg; msg << "Exception on remote python invocation" << std::endl << ex.details.text.in() << std::endl;
591  msg << "PyScriptNode CORBA ref : ";
592  {
593  CORBA::ORB_ptr orb(getSALOMERuntime()->getOrb());
594  if(!CORBA::is_nil(orb))
595  {
596  CORBA::String_var IOR(orb->object_to_string(_pynode));
597  msg << IOR;
598  }
599  }
600  msg << std::endl;
601  _errorDetails=msg.str();
602  throw Exception(msg.str());
603  }
604  catch(CORBA::COMM_FAILURE& ex)
605  {
606  std::ostringstream msg;
607  msg << "Exception on remote python invocation." << std::endl ;
608  msg << "Caught system exception COMM_FAILURE -- unable to contact the "
609  << "object." << std::endl;
610  _errorDetails=msg.str();
611  throw Exception(msg.str());
612  }
613  catch(CORBA::SystemException& ex)
614  {
615  std::ostringstream msg;
616  msg << "Exception on remote python invocation." << std::endl ;
617  msg << "Caught a CORBA::SystemException." ;
618  CORBA::Any tmp;
619  tmp <<= ex;
620  CORBA::TypeCode_var tc = tmp.type();
621  const char *p = tc->name();
622  if ( *p != '\0' )
623  msg <<p;
624  else
625  msg << tc->id();
626  msg << std::endl;
627  _errorDetails=msg.str();
628  throw Exception(msg.str());
629  }
630  catch(CORBA::Exception& ex)
631  {
632  std::ostringstream msg;
633  msg << "Exception on remote python invocation." << std::endl ;
634  msg << "Caught CORBA::Exception. " ;
635  CORBA::Any tmp;
636  tmp <<= ex;
637  CORBA::TypeCode_var tc = tmp.type();
638  const char *p = tc->name();
639  if ( *p != '\0' )
640  msg <<p;
641  else
642  msg << tc->id();
643  msg << std::endl;
644  _errorDetails=msg.str();
645  throw Exception(msg.str());
646  }
647  catch(omniORB::fatalException& fe)
648  {
649  std::ostringstream msg;
650  msg << "Exception on remote python invocation." << std::endl ;
651  msg << "Caught omniORB::fatalException:" << std::endl;
652  msg << " file: " << fe.file() << std::endl;
653  msg << " line: " << fe.line() << std::endl;
654  msg << " mesg: " << fe.errmsg() << std::endl;
655  _errorDetails=msg.str();
656  throw Exception(msg.str());
657  }
658  DEBTRACE( "-----------------end of remote python invocation-----------------" );
659  //===========================================================================
660  // Get results, unpickle and put them in output ports
661  //===========================================================================
662  {
663 #if PY_VERSION_HEX < 0x03070000
664  std::unique_lock<std::mutex> lock(data_mutex);
665 #endif
666  AutoGIL agil;
667  DEBTRACE( "-----------------PythonNode::outputs-----------------" );
668  int nres( resultCorba->length() );
669 
670  if(getNumberOfOutputPorts() != nres)
671  {
672  std::string msg="Number of output arguments : Mismatch between definition and execution";
673  _errorDetails=msg;
674  throw Exception(msg);
675  }
676  pos=0;
677  try
678  {
679  for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); ++iter)
680  {
681  OutputPyPort *p=(OutputPyPort *)*iter;
682  DEBUG_YACSTRACE("Start of dealing with output " << p->getName() << " of "<< getId());
683  DEBTRACE( "port name: " << p->getName() );
684  DEBTRACE( "port kind: " << p->edGetType()->kind() );
685  DEBTRACE( "port pos : " << pos );
686  SALOME::SenderByte_var elt = (*resultCorba)[pos];
687  SeqByteReceiver recv(elt);
688  unsigned long length = 0;
689  char *resultCorbaC = recv.data(length);
690  {
691  AutoPyRef resultPython=PyMemoryView_FromMemory(resultCorbaC,length,PyBUF_READ);
692  AutoPyRef args = PyTuple_New(1);
693  PyTuple_SetItem(args,0,resultPython.retn());
694  AutoPyRef ob = PyObject_CallObject(_pyfuncUnser,args);
695  if (!ob)
696  {
697  std::stringstream msg;
698  msg << "Conversion with pickle of output ports failed !";
699  msg << " : " << __FILE__ << ":" << __LINE__;
700  _errorDetails=msg.str();
701  throw YACS::ENGINE::ConversionException(msg.str());
702  }
704  DEBUG_YACSTRACE("Assign PyObj output " << p->getName() << " of "<< getId());
705  p->put( ob );
706  DEBUG_YACSTRACE("End of assign PyObj output " << p->getName() << " of "<< getId());
707  }
708  pos++;
709  }
710  }
711  catch(ConversionException& ex)
712  {
713  _errorDetails=ex.what();
714  throw;
715  }
716  if(_autoSqueeze)
718  }
719  //
720  if(!isUsingPythonCache())
721  {
723  bool dummy;
724  Engines::Container_var cont(GetContainerObj(this,dummy));
725  cont->removePyScriptNode(getId().c_str());
726  }
727  DEBTRACE( "++++++++++++++ ENDOF PyNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
728 }
729 
730 void PythonNode::ExecuteLocalInternal(const std::string& codeStr, PyObject *context, std::string& errorDetails)
731 {
732  DEBTRACE( code );
733  DEBTRACE( "context refcnt: " << context->ob_refcnt );
734  std::ostringstream stream;
735  stream << "/tmp/PythonNode_";
736  stream << getpid();
737  AutoPyRef code=Py_CompileString(codeStr.c_str(), stream.str().c_str(), Py_file_input);
738  if(code == NULL)
739  {
740  errorDetails="";
741  AutoPyRef new_stderr = newPyStdOut(errorDetails);
742  PySys_SetObject((char*)"stderr", new_stderr);
743  PyErr_Print();
744  PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
745  throw YACS::Exception("Error during execution");
746  }
747  {
748  AutoPyRef res = PyEval_EvalCode( code, context, context);
749  }
750  DEBTRACE( "context refcnt: " << context->ob_refcnt );
751  fflush(stdout);
752  fflush(stderr);
753  if(PyErr_Occurred ())
754  {
755  errorDetails="";
756  AutoPyRef new_stderr = newPyStdOut(errorDetails);
757  PySys_SetObject((char*)"stderr", new_stderr);
758  ofstream errorfile(stream.str().c_str());
759  if (errorfile.is_open())
760  {
761  errorfile << codeStr;
762  errorfile.close();
763  }
764  PyErr_Print();
765  PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
766  throw YACS::Exception("Error during execution");
767  }
768 }
769 
770 void PythonNode::executeLocalInternal(const std::string& codeStr)
771 {
773 }
774 
776 {
777  DEBTRACE( "++++++++++++++ PyNode::executeLocal: " << getName() << " ++++++++++++++++++++" );
778  {
779  AutoGIL agil;
780  std::ostringstream unpxy; unpxy << "from SALOME_PyNode import UnProxyObjectSimpleLocal" << std::endl;
781  DEBTRACE( "---------------PyNode::inputs---------------" );
782  list<InputPort *>::iterator iter2;
783  for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
784  {
785  InputPyPort *p=(InputPyPort *)*iter2;
786  DEBTRACE( "port name: " << p->getName() );
787  DEBTRACE( "port kind: " << p->edGetType()->kind() );
788  PyObject* ob=p->getPyObj();
789  DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
790  unpxy << p->getName() << " = UnProxyObjectSimpleLocal( " << p->getName() << " )" << std::endl;
791 #ifdef _DEVDEBUG_
792  PyObject_Print(ob,stderr,Py_PRINT_RAW);
793  cerr << endl;
794 #endif
795  int ier=PyDict_SetItemString(_context,p->getName().c_str(),ob);
796  DEBTRACE( "after PyDict_SetItemString:ob refcnt: " << ob->ob_refcnt );
797  }
798 
799  DEBTRACE( "---------------End PyNode::inputs---------------" );
800 
801  //calculation
802  DEBTRACE( "----------------PyNode::calculation---------------" );
803 
804  if( ! getSqueezeStatus() )
805  executeLocalInternal( unpxy.str() );
806 
808 
809  DEBTRACE( "-----------------PyNode::outputs-----------------" );
810  list<OutputPort *>::iterator iter;
811  try
812  {
813  for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
814  {
815  OutputPyPort *p=(OutputPyPort *)*iter;
816  DEBTRACE( "port name: " << p->getName() );
817  DEBTRACE( "port kind: " << p->edGetType()->kind() );
818  PyObject *ob=PyDict_GetItemString(_context,p->getName().c_str());
819  if(ob==NULL)
820  {
821  std::string msg="Error during execution: there is no variable ";
822  msg=msg+p->getName()+" in node context";
823  _errorDetails=msg;
824  throw Exception(msg);
825  }
826  DEBTRACE( "PyNode::outputs::ob refcnt: " << ob->ob_refcnt );
827 #ifdef _DEVDEBUG_
828  PyObject_Print(ob,stderr,Py_PRINT_RAW);
829  cerr << endl;
830 #endif
831  p->put(ob);
832  if(!isUsingPythonCache())
833  PyDict_DelItemString(_context,p->getName().c_str());
834  }
835  }
836  catch(ConversionException& ex)
837  {
838  _errorDetails=ex.what();
839  throw;
840  }
841  if(_autoSqueeze)
842  squeezeMemory();
843  DEBTRACE( "-----------------End PyNode::outputs-----------------" );
844  if(!isUsingPythonCache())
845  {
846  for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
847  {
848  AutoPyRef pStr = PyUnicode_FromString( (*iter2)->getName().c_str() );
849  if( PyDict_Contains(_context,pStr) == 1 )
850  { PyDict_DelItem(_context,pStr); }
851  }
852  }
853  }
854  DEBTRACE( "++++++++++++++ End PyNode::execute: " << getName() << " ++++++++++++++++++++" );
855 }
856 
861 void PythonNode::setSqueezeStatusWithExceptions(bool sqStatus, const std::vector<std::string>& squeezeExceptions)
862 {
863  this->setSqueezeStatus(sqStatus);
864  this->_nonSqueezableOutputNodes = std::set<std::string>(squeezeExceptions.begin(), squeezeExceptions.end());
865 }
866 
868 {
869  AutoGIL agil;
871  this->squeezeMemoryRemote();
872  else
873  this->squeezeMemory();
874 }
875 
877 {
878  for(auto p : _setOfInputPort)
879  {
880  PyDict_DelItemString(_context,p->getName().c_str());
881  InputPyPort *p2(static_cast<InputPyPort *>(p));
882  if(p2->canSafelySqueezeMemory())
883  p2->put(Py_None);
884  }
885  for(auto p : _setOfOutputPort)
886  {
887  if (!this->_nonSqueezableOutputNodes.empty() && this->_nonSqueezableOutputNodes.find(p->getName()) != this->_nonSqueezableOutputNodes.end())
888  continue;
889  PyDict_DelItemString(_context,p->getName().c_str());
890  OutputPyPort *p2(static_cast<OutputPyPort *>(p));
891  p2->putWithoutForward(Py_None);
892  }
893 }
894 
896 {
897  for(auto p : _setOfInputPort)
898  {
899  InputPyPort *p2(static_cast<InputPyPort *>(p));
900  if(p2->canSafelySqueezeMemory())
901  p2->put(Py_None);
902  }
903  for(auto p : _setOfOutputPort)
904  {
905  if (!this->_nonSqueezableOutputNodes.empty() && this->_nonSqueezableOutputNodes.find(p->getName()) != this->_nonSqueezableOutputNodes.end())
906  continue;
907  OutputPyPort *p2(static_cast<OutputPyPort *>(p));
908  p2->putWithoutForward(Py_None);
909  }
910 }
911 
913 {
915 }
916 
917 void PythonNode::shutdown(int level)
918 {
919  DEBTRACE("PythonNode::shutdown " << level);
920  if(_mode=="local")return;
921  if(_container)
922  {
924  _container->shutdown(level);
925  }
926 }
927 
928 void PythonNode::imposeResource(const std::string& resource_name,
929  const std::string& container_name)
930 {
931  if(!resource_name.empty() && !container_name.empty())
932  {
933  _imposedResource = resource_name;
934  _imposedContainer = container_name;
935  }
936 }
937 
939 {
940  return _container != nullptr && _container->canAcceptImposedResource();
941 }
942 
944 {
946 }
947 
948 std::string PythonNode::pythonEntryName()const
949 {
950  if(isUsingPythonCache())
951  return "DEFAULT_NAME_FOR_UNIQUE_PYTHON_NODE_ENTRY";
952  else
953  return getId();
954 }
955 
957 {
958  bool found = false;
959  if(_container)
960  found = _container->isUsingPythonCache();
961  return found;
962 }
963 
965 {
966  if(!CORBA::is_nil(_pynode))
967  {
968  try
969  {
970  _pynode->UnRegister();
971  }
972  catch(...)
973  {
974  DEBTRACE("Trouble when pynode->UnRegister!")
975  }
976  _pynode = Engines::PyScriptNode::_nil();
977  }
978 }
979 
980 Node *PythonNode::simpleClone(ComposedNode *father, bool editionOnly) const
981 {
982  return new PythonNode(*this,father);
983 }
984 
985 void PythonNode::createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)
986 {
988  _pynode=objContainer->createPyScriptNode(pythonEntryName().c_str(),getScript().c_str());
989  _pynode->Register();
990 }
991 
992 Engines::PyNodeBase_var PythonNode::retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const
993 {
994  Engines::PyScriptNode_var ret(objContainer->getDefaultPyScriptNode(pythonEntryName().c_str()));
995  if(!CORBA::is_nil(ret))
996  {
997  ret->Register();
998  }
999  return Engines::PyNodeBase::_narrow(ret);
1000 }
1001 
1002 void PythonNode::assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)
1003 {
1004  if(CORBA::is_nil(_pynode))
1005  _pynode=Engines::PyScriptNode::_narrow(remoteInterp);
1006  else
1007  {
1008  Engines::PyScriptNode_var tmpp(Engines::PyScriptNode::_narrow(remoteInterp));
1009  if(!_pynode->_is_equivalent(tmpp))
1010  {
1011  freeKernelPynode();
1012  _pynode=Engines::PyScriptNode::_narrow(remoteInterp);
1013  }
1014  }
1015  _pynode->assignNewCompiledCode(getScript().c_str());
1016 }
1017 
1019 {
1020  return Engines::PyNodeBase::_narrow(_pynode);
1021 }
1022 
1024 PythonNode* PythonNode::cloneNode(const std::string& name)
1025 {
1026  PythonNode* n=new PythonNode(name);
1027  n->setScript(_script);
1028  list<InputPort *>::iterator iter;
1029  for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
1030  {
1031  InputPyPort *p=(InputPyPort *)*iter;
1032  DEBTRACE( "port name: " << p->getName() );
1033  DEBTRACE( "port kind: " << p->edGetType()->kind() );
1034  n->edAddInputPort(p->getName(),p->edGetType());
1035  }
1036  list<OutputPort *>::iterator iter2;
1037  for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
1038  {
1039  OutputPyPort *p=(OutputPyPort *)*iter2;
1040  DEBTRACE( "port name: " << p->getName() );
1041  DEBTRACE( "port kind: " << p->edGetType()->kind() );
1042  n->edAddOutputPort(p->getName(),p->edGetType());
1043  }
1044  return n;
1045 }
1046 
1048 {
1049  std::vector< std::pair<std::string,int> > ret(getDPLScopeInfo(gfn));
1050  if(ret.empty())
1051  return ;
1052  //
1053  PyObject *ob(0);
1054  {
1055  AutoGIL agil;
1056  std::size_t sz(ret.size());
1057  ob=PyList_New(sz);
1058  for(std::size_t i=0;i<sz;i++)
1059  {
1060  const std::pair<std::string,int>& p(ret[i]);
1061  PyObject *elt(PyTuple_New(2));
1062  PyTuple_SetItem(elt,0,PyUnicode_FromString(p.first.c_str()));
1063  PyTuple_SetItem(elt,1,PyLong_FromLong(p.second));
1064  PyList_SetItem(ob,i,elt);
1065  }
1066  }
1067  if(_mode==REMOTE_NAME)
1068  {
1069  Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);
1070  {
1071  AutoGIL agil;
1072  PyObject *serializationInput(PyObject_CallFunctionObjArgs(_pyfuncSimpleSer,ob,NULL));
1073  Py_XDECREF(ob);
1074  char *serializationInputC(0);
1075  Py_ssize_t len;
1076  if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
1077  throw Exception("DistributedPythonNode problem in python pickle");
1078  serializationInputCorba->length(len);
1079  for(int i=0; i < len ; i++)
1080  serializationInputCorba[i]=serializationInputC[i];
1081  Py_XDECREF(serializationInput);
1082  }
1083  _pynode->defineNewCustomVar(DPL_INFO_NAME,serializationInputCorba);
1084  }
1085  else
1086  {
1087  AutoGIL agil;
1088  PyDict_SetItemString(_context,DPL_INFO_NAME,ob);
1089  Py_XDECREF(ob);
1090  }
1091 }
1092 
1093 PyFuncNode::PyFuncNode(const PyFuncNode& other, ComposedNode *father):InlineFuncNode(other,father),_pyfunc(0)
1094 {
1096  {
1097  AutoGIL agil;
1098  _context=PyDict_New();
1099  DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1100  if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
1101  {
1102  stringstream msg;
1103  msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
1104  _errorDetails=msg.str();
1105  throw Exception(msg.str());
1106  }
1107  }
1108 }
1109 
1110 PyFuncNode::PyFuncNode(const std::string& name): InlineFuncNode(name),_pyfunc(0)
1111 {
1112 
1114  DEBTRACE( "PyFuncNode::PyFuncNode " << name );
1115  {
1116  AutoGIL agil;
1117  _context=PyDict_New();
1118  DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1119  if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
1120  {
1121  stringstream msg;
1122  msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
1123  _errorDetails=msg.str();
1124  throw Exception(msg.str());
1125  }
1126  }
1127 }
1128 
1130 {
1131  if(!CORBA::is_nil(_pynode))
1132  {
1133  _pynode->UnRegister();
1134  }
1135 }
1136 
1137 void PyFuncNode::init(bool start)
1138 {
1140  if(_state == YACS::DISABLED)
1141  {
1142  exDisabledState(); // to refresh propagation of DISABLED state
1143  return ;
1144  }
1145  if(start) //complete initialization
1147  else if(_state > YACS::LOADED)// WARNING FuncNode has internal vars (CEA usecase) ! Partial initialization (inside a loop). Exclusivity of funcNode.
1149 }
1150 
1152 {
1153  DEBTRACE("checkBasicConsistency");
1155  {
1156  AutoGIL agil;
1157  PyObject* res;
1158  res=Py_CompileString(_script.c_str(),getName().c_str(),Py_file_input);
1159  if(res == NULL)
1160  {
1161  std::string error="";
1162  PyObject* new_stderr = newPyStdOut(error);
1163  PySys_SetObject((char*)"stderr", new_stderr);
1164  PyErr_Print();
1165  PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1166  Py_DECREF(new_stderr);
1167  throw Exception(error);
1168  }
1169  else
1170  Py_XDECREF(res);
1171  }
1172 }
1173 
1175 {
1176  DEBTRACE( "---------------PyfuncNode::load function---------------" );
1178  loadRemote();
1179  else
1180  loadLocal();
1181 }
1182 
1184 {
1185  commonRemoteLoad(this);
1186 }
1187 
1189 {
1190  DEBTRACE( "---------------PyFuncNode::load function " << getName() << " ---------------" );
1191  DEBTRACE( _script );
1192 
1193 #ifdef _DEVDEBUG_
1194  list<OutputPort *>::iterator iter;
1195  for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
1196  {
1197  OutputPyPort *p=(OutputPyPort *)*iter;
1198  DEBTRACE( "port name: " << p->getName() );
1199  DEBTRACE( "port kind: " << p->edGetType()->kind() );
1200  }
1201 #endif
1202 
1203  {
1204  AutoGIL agil;
1205  DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1206 
1207  std::ostringstream stream;
1208  stream << "/tmp/PythonNode_";
1209  stream << getpid();
1210 
1211  PyObject* code=Py_CompileString(_script.c_str(), stream.str().c_str(), Py_file_input);
1212  if(code == NULL)
1213  {
1214  _errorDetails="";
1215  PyObject* new_stderr = newPyStdOut(_errorDetails);
1216  PySys_SetObject((char*)"stderr", new_stderr);
1217  PyErr_Print();
1218  PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1219  Py_DECREF(new_stderr);
1220  throw Exception("Error during execution");
1221  }
1222  PyObject *res = PyEval_EvalCode( code, _context, _context);
1223  Py_DECREF(code);
1224  Py_XDECREF(res);
1225 
1226  DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1227  if(PyErr_Occurred ())
1228  {
1229  _errorDetails="";
1230  PyObject* new_stderr = newPyStdOut(_errorDetails);
1231  PySys_SetObject((char*)"stderr", new_stderr);
1232  ofstream errorfile(stream.str().c_str());
1233  if (errorfile.is_open())
1234  {
1235  errorfile << _script;
1236  errorfile.close();
1237  }
1238  PyErr_Print();
1239  PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1240  Py_DECREF(new_stderr);
1241  throw Exception("Error during execution");
1242  return;
1243  }
1244  _pyfunc=PyDict_GetItemString(_context,_fname.c_str());
1245  DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1246  if(_pyfunc == NULL)
1247  {
1248  _errorDetails="";
1249  PyObject* new_stderr = newPyStdOut(_errorDetails);
1250  PySys_SetObject((char*)"stderr", new_stderr);
1251  PyErr_Print();
1252  PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1253  Py_DECREF(new_stderr);
1254  throw Exception("Error during execution");
1255  }
1256  DEBTRACE( "---------------End PyFuncNode::load function---------------" );
1257  }
1258 }
1259 
1261 {
1263  executeRemote();
1264  else
1265  executeLocal();
1266 }
1267 
1269 {
1270  DEBTRACE( "++++++++++++++ PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
1271  if(!_pyfuncSer)
1272  throw Exception("DistributedPythonNode badly loaded");
1273  //
1274  if(dynamic_cast<HomogeneousPoolContainer *>(getContainer()))
1275  {
1276  bool dummy;
1277  loadPythonAdapter(this,dummy);
1278  _pynode->executeAnotherPieceOfCode(getScript().c_str());
1279  }
1280  //
1281  Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);;
1282  {
1283 #if PY_VERSION_HEX < 0x03070000
1284  std::unique_lock<std::mutex> lock(data_mutex);
1285 #endif
1286  AutoGIL agil;
1287  PyObject *ob(0);
1288  //===========================================================================
1289  // Get inputs in input ports, build a Python tuple and pickle it
1290  //===========================================================================
1291  PyObject *args(PyTuple_New(getNumberOfInputPorts()));
1292  int pos(0);
1293  for(std::list<InputPort *>::iterator iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++,pos++)
1294  {
1295  InputPyPort *p=(InputPyPort *)*iter2;
1296  ob=p->getPyObj();
1297  Py_INCREF(ob);
1298  PyTuple_SetItem(args,pos,ob);
1299  }
1300 #ifdef _DEVDEBUG_
1301  PyObject_Print(args,stderr,Py_PRINT_RAW);
1302  std::cerr << endl;
1303 #endif
1304  PyObject *serializationInput=PyObject_CallObject(_pyfuncSer,args);
1305  Py_DECREF(args);
1306  //The pickled string may contain NULL characters so use PyString_AsStringAndSize
1307  char *serializationInputC(0);
1308  Py_ssize_t len;
1309  if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
1310  throw Exception("DistributedPythonNode problem in python pickle");
1311 
1312  serializationInputCorba->length(len);
1313  for(int i=0; i < len ; i++)
1314  serializationInputCorba[i]=serializationInputC[i];
1315  Py_DECREF(serializationInput);
1316  }
1317 
1318  //===========================================================================
1319  // Execute in remote Python node
1320  //===========================================================================
1321  DEBTRACE( "-----------------starting remote python invocation-----------------" );
1322  Engines::pickledArgs_var resultCorba;
1323  try
1324  {
1325  resultCorba=_pynode->execute(getFname().c_str(),serializationInputCorba);
1326  }
1327  catch( const SALOME::SALOME_Exception& ex )
1328  {
1329  std::string msg="Exception on remote python invocation";
1330  msg += '\n';
1331  msg += ex.details.text.in();
1332  _errorDetails=msg;
1333  throw Exception(msg);
1334  }
1335  catch(CORBA::COMM_FAILURE& ex)
1336  {
1337  std::ostringstream msg;
1338  msg << "Exception on remote python invocation." << std::endl ;
1339  msg << "Caught system exception COMM_FAILURE -- unable to contact the "
1340  << "object." << std::endl;
1341  _errorDetails=msg.str();
1342  throw Exception(msg.str());
1343  }
1344  catch(CORBA::SystemException& ex)
1345  {
1346  std::ostringstream msg;
1347  msg << "Exception on remote python invocation." << std::endl ;
1348  msg << "Caught a CORBA::SystemException." ;
1349  CORBA::Any tmp;
1350  tmp <<= ex;
1351  CORBA::TypeCode_var tc = tmp.type();
1352  const char *p = tc->name();
1353  if ( *p != '\0' )
1354  msg <<p;
1355  else
1356  msg << tc->id();
1357  msg << std::endl;
1358  _errorDetails=msg.str();
1359  throw Exception(msg.str());
1360  }
1361  catch(CORBA::Exception& ex)
1362  {
1363  std::ostringstream msg;
1364  msg << "Exception on remote python invocation." << std::endl ;
1365  msg << "Caught CORBA::Exception. " ;
1366  CORBA::Any tmp;
1367  tmp <<= ex;
1368  CORBA::TypeCode_var tc = tmp.type();
1369  const char *p = tc->name();
1370  if ( *p != '\0' )
1371  msg <<p;
1372  else
1373  msg << tc->id();
1374  msg << std::endl;
1375  _errorDetails=msg.str();
1376  throw Exception(msg.str());
1377  }
1378  catch(omniORB::fatalException& fe)
1379  {
1380  std::ostringstream msg;
1381  msg << "Exception on remote python invocation." << std::endl ;
1382  msg << "Caught omniORB::fatalException:" << std::endl;
1383  msg << " file: " << fe.file() << std::endl;
1384  msg << " line: " << fe.line() << std::endl;
1385  msg << " mesg: " << fe.errmsg() << std::endl;
1386  _errorDetails=msg.str();
1387  throw Exception(msg.str());
1388  }
1389  DEBTRACE( "-----------------end of remote python invocation-----------------" );
1390  //===========================================================================
1391  // Get results, unpickle and put them in output ports
1392  //===========================================================================
1393  char *resultCorbaC=new char[resultCorba->length()+1];
1394  resultCorbaC[resultCorba->length()]='\0';
1395  for(int i=0;i<resultCorba->length();i++)
1396  resultCorbaC[i]=resultCorba[i];
1397 
1398  {
1399 #if PY_VERSION_HEX < 0x03070000
1400  std::unique_lock<std::mutex> lock(data_mutex);
1401 #endif
1402  AutoGIL agil;
1403 
1404  PyObject *resultPython(PyBytes_FromStringAndSize(resultCorbaC,resultCorba->length()));
1405  delete [] resultCorbaC;
1406  PyObject *args(PyTuple_New(1)),*ob(0);
1407  PyTuple_SetItem(args,0,resultPython);
1408  PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
1409  Py_DECREF(args);
1410 
1411  DEBTRACE( "-----------------PythonNode::outputs-----------------" );
1412  int nres=1;
1413  if(finalResult == Py_None)
1414  nres=0;
1415  else if(PyTuple_Check(finalResult))
1416  nres=PyTuple_Size(finalResult);
1417 
1418  if(getNumberOfOutputPorts() != nres)
1419  {
1420  std::string msg="Number of output arguments : Mismatch between definition and execution";
1421  Py_DECREF(finalResult);
1422  _errorDetails=msg;
1423  throw Exception(msg);
1424  }
1425 
1426  try
1427  {
1428  int pos(0);
1429  for(std::list<OutputPort *>::iterator iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++, pos++)
1430  {
1431  OutputPyPort *p=(OutputPyPort *)*iter;
1432  DEBTRACE( "port name: " << p->getName() );
1433  DEBTRACE( "port kind: " << p->edGetType()->kind() );
1434  DEBTRACE( "port pos : " << pos );
1435  if(PyTuple_Check(finalResult))
1436  ob=PyTuple_GetItem(finalResult,pos) ;
1437  else
1438  ob=finalResult;
1439  DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1440  p->put(ob);
1441  }
1442  Py_DECREF(finalResult);
1443  }
1444  catch(ConversionException& ex)
1445  {
1446  Py_DECREF(finalResult);
1447  _errorDetails=ex.what();
1448  throw;
1449  }
1450  }
1451 
1452  DEBTRACE( "++++++++++++++ ENDOF PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
1453 }
1454 
1456 {
1457  DEBTRACE( "++++++++++++++ PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
1458 
1459  int pos=0;
1460  PyObject* ob;
1461  if(!_pyfunc)throw Exception("PyFuncNode badly loaded");
1462  {
1463  AutoGIL agil;
1464  DEBTRACE( "---------------PyFuncNode::inputs---------------" );
1465  PyObject* args = PyTuple_New(getNumberOfInputPorts()) ;
1466  list<InputPort *>::iterator iter2;
1467  for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
1468  {
1469  InputPyPort *p=(InputPyPort *)*iter2;
1470  DEBTRACE( "port name: " << p->getName() );
1471  DEBTRACE( "port kind: " << p->edGetType()->kind() );
1472  ob=p->getPyObj();
1473 #ifdef _DEVDEBUG_
1474  PyObject_Print(ob,stderr,Py_PRINT_RAW);
1475  cerr << endl;
1476 #endif
1477  DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1478  Py_INCREF(ob);
1479  PyTuple_SetItem(args,pos,ob);
1480  DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1481  pos++;
1482  }
1483  DEBTRACE( "---------------End PyFuncNode::inputs---------------" );
1484 
1485  DEBTRACE( "----------------PyFuncNode::calculation---------------" );
1486 #ifdef _DEVDEBUG_
1487  PyObject_Print(_pyfunc,stderr,Py_PRINT_RAW);
1488  cerr << endl;
1489  PyObject_Print(args,stderr,Py_PRINT_RAW);
1490  cerr << endl;
1491 #endif
1492  DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1493  PyObject* result = PyObject_CallObject( _pyfunc , args ) ;
1494  DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1495  Py_DECREF(args);
1496  fflush(stdout);
1497  fflush(stderr);
1498  if(result == NULL)
1499  {
1500  _errorDetails="";
1501  PyObject* new_stderr = newPyStdOut(_errorDetails);
1502  PySys_SetObject((char*)"stderr", new_stderr);
1503  std::ostringstream stream;
1504  stream << "/tmp/PythonNode_";
1505  stream << getpid();
1506  ofstream errorfile(stream.str().c_str());
1507  if (errorfile.is_open())
1508  {
1509  errorfile << _script;
1510  errorfile.close();
1511  }
1512  PyErr_Print();
1513  PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1514  Py_DECREF(new_stderr);
1515  throw Exception("Error during execution");
1516  }
1517  DEBTRACE( "----------------End PyFuncNode::calculation---------------" );
1518 
1519  DEBTRACE( "-----------------PyFuncNode::outputs-----------------" );
1520  int nres=1;
1521  if(result == Py_None)
1522  nres=0;
1523  else if(PyTuple_Check(result))
1524  nres=PyTuple_Size(result);
1525 
1526  if(getNumberOfOutputPorts() != nres)
1527  {
1528  std::string msg="Number of output arguments : Mismatch between definition and execution";
1529  Py_DECREF(result);
1530  _errorDetails=msg;
1531  throw Exception(msg);
1532  }
1533 
1534  pos=0;
1535 #ifdef _DEVDEBUG_
1536  PyObject_Print(result,stderr,Py_PRINT_RAW);
1537  cerr << endl;
1538 #endif
1539  list<OutputPort *>::iterator iter;
1540  try
1541  {
1542  for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
1543  {
1544  OutputPyPort *p=(OutputPyPort *)*iter;
1545  DEBTRACE( "port name: " << p->getName() );
1546  DEBTRACE( "port kind: " << p->edGetType()->kind() );
1547  DEBTRACE( "port pos : " << pos );
1548  if(PyTuple_Check(result))ob=PyTuple_GetItem(result,pos) ;
1549  else ob=result;
1550  DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1551 #ifdef _DEVDEBUG_
1552  PyObject_Print(ob,stderr,Py_PRINT_RAW);
1553  cerr << endl;
1554 #endif
1555  p->put(ob);
1556  pos++;
1557  }
1558  }
1559  catch(ConversionException& ex)
1560  {
1561  Py_DECREF(result);
1562  _errorDetails=ex.what();
1563  throw;
1564  }
1565  DEBTRACE( "-----------------End PyFuncNode::outputs-----------------" );
1566  Py_DECREF(result);
1567  }
1568  DEBTRACE( "++++++++++++++ End PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
1569 }
1570 
1571 Node *PyFuncNode::simpleClone(ComposedNode *father, bool editionOnly) const
1572 {
1573  return new PyFuncNode(*this,father);
1574 }
1575 
1576 void PyFuncNode::createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)
1577 {
1578  if(!CORBA::is_nil(_pynode))
1579  _pynode->UnRegister();
1580  _pynode=objContainer->createPyNode(getName().c_str(),getScript().c_str());
1581 }
1582 
1583 Engines::PyNodeBase_var PyFuncNode::retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const
1584 {
1585  Engines::PyNode_var ret(objContainer->getDefaultPyNode(getName().c_str()));
1586  if(!CORBA::is_nil(ret))
1587  {
1588  ret->Register();
1589  }
1590  return Engines::PyNodeBase::_narrow(ret);
1591 }
1592 
1593 void PyFuncNode::assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)
1594 {
1595  if(!CORBA::is_nil(_pynode))
1596  {
1597  Engines::PyNode_var tmpp(Engines::PyNode::_narrow(remoteInterp));
1598  if(_pynode->_is_equivalent(tmpp))
1599  return ;
1600  }
1601  if(!CORBA::is_nil(_pynode))
1602  _pynode->UnRegister();
1603  _pynode=Engines::PyNode::_narrow(remoteInterp);
1604 }
1605 
1607 {
1608  return Engines::PyNodeBase::_narrow(_pynode);
1609 }
1610 
1612 PyFuncNode* PyFuncNode::cloneNode(const std::string& name)
1613 {
1614  PyFuncNode* n=new PyFuncNode(name);
1615  n->setScript(_script);
1616  n->setFname(_fname);
1617  list<InputPort *>::iterator iter;
1618  for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
1619  {
1620  InputPyPort *p=(InputPyPort *)*iter;
1621  n->edAddInputPort(p->getName(),p->edGetType());
1622  }
1623  list<OutputPort *>::iterator iter2;
1624  for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
1625  {
1626  OutputPyPort *p=(OutputPyPort *)*iter2;
1627  n->edAddOutputPort(p->getName(),p->edGetType());
1628  }
1629  return n;
1630 }
1631 
1633 {
1635 }
1636 
1637 void PyFuncNode::shutdown(int level)
1638 {
1639  DEBTRACE("PyFuncNode::shutdown " << level);
1640  if(_mode=="local")return;
1641  if(_container)
1642  {
1643  if(!CORBA::is_nil(_pynode)) _pynode->UnRegister();
1644  _pynode=Engines::PyNode::_nil();
1645  _container->shutdown(level);
1646  }
1647 }
1648 
1649 void PyFuncNode::imposeResource(const std::string& resource_name,
1650  const std::string& container_name)
1651 {
1652  if(!resource_name.empty() && !container_name.empty())
1653  {
1654  _imposedResource = resource_name;
1655  _imposedContainer = container_name;
1656  }
1657 }
1658 
1660 {
1661  return _container != nullptr && _container->canAcceptImposedResource();
1662 }
1663 
1665 {
1667 }
1668 
int Py_ssize_t
Definition: PythonNode.cxx:45
static char SCRIPT_FOR_BIGOBJECT[]
Definition: PythonNode.cxx:84
static std::mutex data_mutex
Definition: PythonNode.cxx:90
Engines::Container_var GetContainerObj(InlineNode *reqNode, bool &isStandardCont)
Definition: PythonNode.cxx:139
#define DEBUG_YACSTRACE(msg)
Definition: YacsTrace.hxx:53
#define DEBTRACE(msg)
Definition: YacsTrace.hxx:31
Base class for all composed nodes.
std::string getName() const
virtual void start(const Task *askingNode)=0
virtual void shutdown(int level)=0
virtual bool isAlreadyStarted(const Task *askingNode) const =0
virtual std::string getProperty(const std::string &name) const =0
virtual bool isUsingPythonCache()
Definition: Container.cxx:109
virtual bool canAcceptImposedResource()
Definition: Container.cxx:59
std::list< InputPort * > _setOfInputPort
void initCommonPartWithoutStateManagement(bool start)
std::list< OutputPort * > _setOfOutputPort
virtual void checkBasicConsistency() const
bool canSafelySqueezeMemory() const
Definition: InPort.cxx:73
Class for calculation node (function) inlined (and executed) in the schema.
Definition: InlineNode.hxx:93
virtual void checkBasicConsistency() const
Definition: InlineNode.cxx:75
virtual std::string getFname()
Definition: InlineNode.hxx:101
Class for calculation node (script) inlined (and executed) in the schema.
Definition: InlineNode.hxx:44
virtual Container * getContainer()
Definition: InlineNode.cxx:100
virtual std::string getScript()
Definition: InlineNode.hxx:51
Class for Python Ports.
Definition: PythonPorts.hxx:74
virtual void put(const void *data)
Base class for all nodes.
Definition: Node.hxx:70
virtual void setErrorDetails(const std::string &error)
Definition: Node.hxx:191
std::vector< std::pair< std::string, int > > getDPLScopeInfo(ComposedNode *gfn)
Definition: Node.cxx:660
const std::string getId() const
Definition: Node.cxx:478
void setState(YACS::StatesForNode theState)
Sets the given state for node.
Definition: Node.cxx:652
std::string _implementation
Definition: Node.hxx:97
virtual void exDisabledState()
Notify this node that it has been disabled.
Definition: Node.cxx:232
const std::string & getName() const
Definition: Node.hxx:125
std::string _errorDetails
Definition: Node.hxx:93
YACS::StatesForNode _state
Definition: Node.hxx:91
void putWithoutForward(PyObject *data)
Engines::PyNodeBase_var getRemoteInterpreterHandle()
bool hasImposedResource() const override
virtual void shutdown(int level)
Stop all pending activities of the node.
virtual void loadLocal()
virtual void executeRemote()
virtual void loadRemote()
virtual void executeLocal()
virtual void checkBasicConsistency() const
static const char SCRIPT_FOR_SERIALIZATION[]
Definition: PythonNode.hxx:165
std::string getContainerLog()
returns a string that contains the name of the container log file if it exists
void imposeResource(const std::string &resource_name, const std::string &container_name) override
Node * simpleClone(ComposedNode *father, bool editionOnly) const
Engines::PyNodeBase_var retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const
returns (if any) an object, you have to deal with (UnRegister)
void assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)
PyFuncNode * cloneNode(const std::string &name)
Create a new node of same type with a given name.
virtual void init(bool start=true)
void createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)
returns an object, you have to deal with (UnRegister)
bool canAcceptImposedResource() override
Engines::PyNode_var _pynode
Definition: PythonNode.hxx:168
PyFuncNode(const PyFuncNode &other, ComposedNode *father)
void loadRemoteContext(InlineNode *reqNode, Engines::Container_ptr objContainer, bool isInitializeRequested)
Definition: PythonNode.cxx:195
static void UnlinkOnDestructorIfProxy(PyObject *ob)
Definition: PythonNode.cxx:413
virtual const char * getSerializationScript() const =0
std::string _imposedResource
Definition: PythonNode.hxx:69
virtual bool hasImposedResource() const
Definition: PythonNode.cxx:326
static bool GetDestroyStatus(PyObject *ob)
Definition: PythonNode.cxx:355
void commonRemoteLoad(InlineNode *reqNode)
Definition: PythonNode.cxx:318
virtual Engines::PyNodeBase_var retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const =0
returns (if any) an object, you have to deal with (UnRegister)
static PyObject * _pyClsBigObject
Definition: PythonNode.hxx:68
static void IfProxyDoSomething(PyObject *ob, const char *meth)
Definition: PythonNode.cxx:385
Engines::Container_var loadPythonAdapter(InlineNode *reqNode, bool &isInitializeRequested)
Definition: PythonNode.cxx:165
static void DoNotTouchFileIfProxy(PyObject *ob)
Definition: PythonNode.cxx:408
static const char SCRIPT_FOR_SIMPLE_SERIALIZATION[]
Definition: PythonNode.hxx:72
void loadRemoteContainer(InlineNode *reqNode)
Definition: PythonNode.cxx:106
static std::string GetContainerLog(const std::string &mode, Container *container, const Task *askingTask)
Definition: PythonNode.cxx:283
static bool IsProxy(PyObject *ob)
Definition: PythonNode.cxx:331
virtual void createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)=0
returns an object, you have to deal with (UnRegister)
virtual Engines::PyNodeBase_var getRemoteInterpreterHandle()=0
std::string _imposedContainer
Definition: PythonNode.hxx:70
virtual void assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)=0
virtual void checkBasicConsistency() const
Definition: PythonNode.cxx:458
std::string pythonEntryName() const
Definition: PythonNode.cxx:948
void setSqueezeStatus(bool sqStatus)
Definition: PythonNode.hxx:111
bool hasImposedResource() const override
Definition: PythonNode.cxx:943
Engines::PyScriptNode_var _pynode
Definition: PythonNode.hxx:131
virtual void executeRemote()
Definition: PythonNode.cxx:509
static const char REMOTE_NAME[]
Definition: PythonNode.hxx:125
bool isUsingPythonCache() const
Definition: PythonNode.cxx:956
virtual void shutdown(int level)
Stop all pending activities of the node.
Definition: PythonNode.cxx:917
static const char SCRIPT_FOR_SERIALIZATION[]
Definition: PythonNode.hxx:124
virtual void loadLocal()
Definition: PythonNode.cxx:490
static void ExecuteLocalInternal(const std::string &codeStr, PyObject *context, std::string &errorDetails)
Definition: PythonNode.cxx:730
PythonNode(const PythonNode &other, ComposedNode *father)
Definition: PythonNode.cxx:418
void executeLocalInternal(const std::string &codeStr)
Definition: PythonNode.cxx:770
Node * simpleClone(ComposedNode *father, bool editionOnly) const
Definition: PythonNode.cxx:980
bool canAcceptImposedResource() override
Definition: PythonNode.cxx:938
static const char IMPL_NAME[]
Definition: PythonNode.hxx:123
void createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)
returns an object, you have to deal with (UnRegister)
Definition: PythonNode.cxx:985
virtual void loadRemote()
Definition: PythonNode.cxx:496
void imposeResource(const std::string &resource_name, const std::string &container_name) override
Definition: PythonNode.cxx:928
std::set< std::string > _nonSqueezableOutputNodes
list on output port name excluded from the squeeze mecanism
Definition: PythonNode.hxx:130
Engines::PyNodeBase_var getRemoteInterpreterHandle()
static const char DPL_INFO_NAME[]
Definition: PythonNode.hxx:126
void assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)
virtual void executeLocal()
Definition: PythonNode.cxx:775
static const char KIND[]
Definition: PythonNode.hxx:122
std::string getContainerLog()
returns a string that contains the name of the container log file if it exists
Definition: PythonNode.cxx:912
void applyDPLScope(ComposedNode *gfn)
void setSqueezeStatusWithExceptions(bool sqStatus, const std::vector< std::string > &squeezeExceptions)
Definition: PythonNode.cxx:861
virtual void execute()
Definition: PythonNode.cxx:501
Engines::PyNodeBase_var retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const
returns (if any) an object, you have to deal with (UnRegister)
Definition: PythonNode.cxx:992
bool getSqueezeStatus() const
Definition: PythonNode.hxx:112
PythonNode * cloneNode(const std::string &name)
Create a new node of same type with a given name.
static SalomeContainerTmpForHP * BuildFrom(const SalomeHPContainer *cont, const Task *askingNode)
Engines::Container_ptr getContainerPtr(const Task *askingNode) const
const char * what(void) const noexcept
Definition: Exception.cxx:50
Proc * p
Definition: driver.cxx:216
YACSRUNTIMESALOME_EXPORT RuntimeSALOME * getSALOMERuntime()
PyObject * newPyStdOut(std::string &out)
Definition: PyStdout.cxx:129
@ LOADED
Definition: define.hxx:39
@ READY
Definition: define.hxx:37
@ DISABLED
Definition: define.hxx:50
@ TORECONNECT
Definition: define.hxx:48
CORBA::ORB_ptr orb
Definition: yacsSrv.cxx:39