Version: 9.16.0
PythonNode.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
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"
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
45typedef int Py_ssize_t;
46#endif
47
48//#define _DEVDEBUG_
49#include "YacsTrace.hxx"
50
51using namespace YACS::ENGINE;
52using namespace std;
53
54const char PythonEntry::SCRIPT_FOR_SIMPLE_SERIALIZATION[]="import pickle\n"
55 "def pickleForVarSimplePyth2009(val):\n"
56 " return pickle.dumps(val,-1)\n"
57 "\n";
58
59PyObject *PythonEntry::_pyClsBigObject = nullptr;
60
61const char PythonNode::IMPL_NAME[]="Python";
62const char PythonNode::KIND[]="Python";
63
64const 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
72const char PythonNode::REMOTE_NAME[]="remote";
73
74const char PythonNode::DPL_INFO_NAME[]="my_dpl_localization";
75
76const 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
84static 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>
90static std::mutex data_mutex;
91#endif
92
93PythonEntry::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 {
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
139Engines::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
165Engines::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;
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
195void 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
283std::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
331bool 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
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
385void 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 );
403 }
404 }
405 }
406}
407
409{
410 IfProxyDoSomething(ob,"doNotTouchFile");
411}
412
414{
415 IfProxyDoSomething(ob,"unlinkOnDestructor");
416}
417
419InlineNode(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
436PythonNode::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{
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 {
585 AutoGIL agil;
586 serializationInput.set(nullptr);
587 }
588 resultCorba.reset( _pynode->executeSecond(myseq) );
589 DEBUG_YACSTRACE("After execute second of " << getId());
590 }
591 catch( const SALOME::SALOME_Exception& ex )
592 {
593 std::ostringstream msg; msg << "Exception on remote python invocation" << std::endl << ex.details.text.in() << std::endl;
594 msg << "PyScriptNode CORBA ref : ";
595 {
596 CORBA::ORB_ptr orb(getSALOMERuntime()->getOrb());
597 if(!CORBA::is_nil(orb))
598 {
599 CORBA::String_var IOR(orb->object_to_string(_pynode));
600 msg << IOR;
601 }
602 }
603 msg << std::endl;
604 _errorDetails=msg.str();
605 throw Exception(msg.str());
606 }
607 catch(CORBA::COMM_FAILURE& ex)
608 {
609 std::ostringstream msg;
610 msg << "Exception on remote python invocation." << std::endl ;
611 msg << "Caught system exception COMM_FAILURE -- unable to contact the "
612 << "object." << std::endl;
613 _errorDetails=msg.str();
614 throw Exception(msg.str());
615 }
616 catch(CORBA::SystemException& ex)
617 {
618 std::ostringstream msg;
619 msg << "Exception on remote python invocation." << std::endl ;
620 msg << "Caught a CORBA::SystemException." ;
621 CORBA::Any tmp;
622 tmp <<= ex;
623 CORBA::TypeCode_var tc = tmp.type();
624 const char *p = tc->name();
625 if ( *p != '\0' )
626 msg <<p;
627 else
628 msg << tc->id();
629 msg << std::endl;
630 _errorDetails=msg.str();
631 throw Exception(msg.str());
632 }
633 catch(CORBA::Exception& ex)
634 {
635 std::ostringstream msg;
636 msg << "Exception on remote python invocation." << std::endl ;
637 msg << "Caught CORBA::Exception. " ;
638 CORBA::Any tmp;
639 tmp <<= ex;
640 CORBA::TypeCode_var tc = tmp.type();
641 const char *p = tc->name();
642 if ( *p != '\0' )
643 msg <<p;
644 else
645 msg << tc->id();
646 msg << std::endl;
647 _errorDetails=msg.str();
648 throw Exception(msg.str());
649 }
650 catch(omniORB::fatalException& fe)
651 {
652 std::ostringstream msg;
653 msg << "Exception on remote python invocation." << std::endl ;
654 msg << "Caught omniORB::fatalException:" << std::endl;
655 msg << " file: " << fe.file() << std::endl;
656 msg << " line: " << fe.line() << std::endl;
657 msg << " mesg: " << fe.errmsg() << std::endl;
658 _errorDetails=msg.str();
659 throw Exception(msg.str());
660 }
661 DEBTRACE( "-----------------end of remote python invocation-----------------" );
662 //===========================================================================
663 // Get results, unpickle and put them in output ports
664 //===========================================================================
665 {
666#if PY_VERSION_HEX < 0x03070000
667 std::unique_lock<std::mutex> lock(data_mutex);
668#endif
669 AutoGIL agil;
670 DEBTRACE( "-----------------PythonNode::outputs-----------------" );
671 int nres( resultCorba->length() );
672
673 if(getNumberOfOutputPorts() != nres)
674 {
675 std::string msg="Number of output arguments : Mismatch between definition and execution";
676 _errorDetails=msg;
677 throw Exception(msg);
678 }
679 pos=0;
680 try
681 {
682 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); ++iter)
683 {
684 OutputPyPort *p=(OutputPyPort *)*iter;
685 DEBUG_YACSTRACE("Start of dealing with output " << p->getName() << " of "<< getId());
686 DEBTRACE( "port name: " << p->getName() );
687 DEBTRACE( "port kind: " << p->edGetType()->kind() );
688 DEBTRACE( "port pos : " << pos );
689 SALOME::SenderByte_var elt = (*resultCorba)[pos];
690 SeqByteReceiver recv(elt);
691 unsigned long length = 0;
692 char *resultCorbaC = recv.data(length);
693 {
694 AutoPyRef resultPython=PyMemoryView_FromMemory(resultCorbaC,length,PyBUF_READ);
695 AutoPyRef args = PyTuple_New(1);
696 PyTuple_SetItem(args,0,resultPython.retn());
697 AutoPyRef ob = PyObject_CallObject(_pyfuncUnser,args);
698 if (!ob)
699 {
700 std::stringstream msg;
701 msg << "Conversion with pickle of output ports failed !";
702 msg << " : " << __FILE__ << ":" << __LINE__;
703 _errorDetails=msg.str();
704 throw YACS::ENGINE::ConversionException(msg.str());
705 }
707 DEBUG_YACSTRACE("Assign PyObj output " << p->getName() << " of "<< getId());
708 p->put( ob );
709 DEBUG_YACSTRACE("End of assign PyObj output " << p->getName() << " of "<< getId());
710 }
711 pos++;
712 }
713 }
714 catch(ConversionException& ex)
715 {
716 _errorDetails=ex.what();
717 throw;
718 }
719 if(_autoSqueeze)
721 }
722 //
723 if(!isUsingPythonCache())
724 {
726 bool dummy;
727 Engines::Container_var cont(GetContainerObj(this,dummy));
728 cont->removePyScriptNode(getId().c_str());
729 }
730 DEBTRACE( "++++++++++++++ ENDOF PyNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
731}
732
733void PythonNode::ExecuteLocalInternal(const std::string& codeStr, PyObject *context, std::string& errorDetails)
734{
735 DEBTRACE( code );
736 DEBTRACE( "context refcnt: " << context->ob_refcnt );
737 std::ostringstream stream;
738 stream << "/tmp/PythonNode_";
739 stream << getpid();
740 AutoPyRef code=Py_CompileString(codeStr.c_str(), stream.str().c_str(), Py_file_input);
741 if(code == NULL)
742 {
743 errorDetails="";
744 AutoPyRef new_stderr = newPyStdOut(errorDetails);
745 PySys_SetObject((char*)"stderr", new_stderr);
746 PyErr_Print();
747 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
748 throw YACS::Exception("Error during execution");
749 }
750 {
751 AutoPyRef res = PyEval_EvalCode( code, context, context);
752 }
753 DEBTRACE( "context refcnt: " << context->ob_refcnt );
754 fflush(stdout);
755 fflush(stderr);
756 if(PyErr_Occurred ())
757 {
758 errorDetails="";
759 AutoPyRef new_stderr = newPyStdOut(errorDetails);
760 PySys_SetObject((char*)"stderr", new_stderr);
761 ofstream errorfile(stream.str().c_str());
762 if (errorfile.is_open())
763 {
764 errorfile << codeStr;
765 errorfile.close();
766 }
767 PyErr_Print();
768 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
769 throw YACS::Exception("Error during execution");
770 }
771}
772
773void PythonNode::executeLocalInternal(const std::string& codeStr)
774{
776}
777
779{
780 DEBTRACE( "++++++++++++++ PyNode::executeLocal: " << getName() << " ++++++++++++++++++++" );
781 {
782 AutoGIL agil;
783 std::ostringstream unpxy; unpxy << "from SALOME_PyNode import UnProxyObjectSimpleLocal" << std::endl;
784 DEBTRACE( "---------------PyNode::inputs---------------" );
785 list<InputPort *>::iterator iter2;
786 for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
787 {
788 InputPyPort *p=(InputPyPort *)*iter2;
789 DEBTRACE( "port name: " << p->getName() );
790 DEBTRACE( "port kind: " << p->edGetType()->kind() );
791 PyObject* ob=p->getPyObj();
792 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
793 unpxy << p->getName() << " = UnProxyObjectSimpleLocal( " << p->getName() << " )" << std::endl;
794#ifdef _DEVDEBUG_
795 PyObject_Print(ob,stderr,Py_PRINT_RAW);
796 cerr << endl;
797#endif
798 int ier=PyDict_SetItemString(_context,p->getName().c_str(),ob);
799 DEBTRACE( "after PyDict_SetItemString:ob refcnt: " << ob->ob_refcnt );
800 }
801
802 DEBTRACE( "---------------End PyNode::inputs---------------" );
803
804 //calculation
805 DEBTRACE( "----------------PyNode::calculation---------------" );
806
807 if( ! getSqueezeStatus() )
808 executeLocalInternal( unpxy.str() );
809
811
812 DEBTRACE( "-----------------PyNode::outputs-----------------" );
813 list<OutputPort *>::iterator iter;
814 try
815 {
816 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
817 {
818 OutputPyPort *p=(OutputPyPort *)*iter;
819 DEBTRACE( "port name: " << p->getName() );
820 DEBTRACE( "port kind: " << p->edGetType()->kind() );
821 PyObject *ob=PyDict_GetItemString(_context,p->getName().c_str());
822 if(ob==NULL)
823 {
824 std::string msg="Error during execution: there is no variable ";
825 msg=msg+p->getName()+" in node context";
826 _errorDetails=msg;
827 throw Exception(msg);
828 }
829 DEBTRACE( "PyNode::outputs::ob refcnt: " << ob->ob_refcnt );
830#ifdef _DEVDEBUG_
831 PyObject_Print(ob,stderr,Py_PRINT_RAW);
832 cerr << endl;
833#endif
834 p->put(ob);
835 if(!isUsingPythonCache())
836 PyDict_DelItemString(_context,p->getName().c_str());
837 }
838 }
839 catch(ConversionException& ex)
840 {
841 _errorDetails=ex.what();
842 throw;
843 }
844 if(_autoSqueeze)
846 DEBTRACE( "-----------------End PyNode::outputs-----------------" );
847 if(!isUsingPythonCache())
848 {
849 for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
850 {
851 AutoPyRef pStr = PyUnicode_FromString( (*iter2)->getName().c_str() );
852 if( PyDict_Contains(_context,pStr) == 1 )
853 { PyDict_DelItem(_context,pStr); }
854 }
855 }
856 }
857 DEBTRACE( "++++++++++++++ End PyNode::execute: " << getName() << " ++++++++++++++++++++" );
858}
859
864void PythonNode::setSqueezeStatusWithExceptions(bool sqStatus, const std::vector<std::string>& squeezeExceptions)
865{
866 this->setSqueezeStatus(sqStatus);
867 this->_nonSqueezableOutputNodes = std::set<std::string>(squeezeExceptions.begin(), squeezeExceptions.end());
868}
869
871{
872 AutoGIL agil;
874 this->squeezeMemoryRemote();
875 else
876 this->squeezeMemory();
877}
878
880{
881 for(auto p : _setOfInputPort)
882 {
883 PyDict_DelItemString(_context,p->getName().c_str());
884 InputPyPort *p2(static_cast<InputPyPort *>(p));
885 if(p2->canSafelySqueezeMemory())
886 p2->put(Py_None);
887 }
888 for(auto p : _setOfOutputPort)
889 {
890 if (!this->_nonSqueezableOutputNodes.empty() && this->_nonSqueezableOutputNodes.find(p->getName()) != this->_nonSqueezableOutputNodes.end())
891 continue;
892 PyDict_DelItemString(_context,p->getName().c_str());
893 OutputPyPort *p2(static_cast<OutputPyPort *>(p));
894 p2->putWithoutForward(Py_None);
895 }
896}
897
899{
900 for(auto p : _setOfInputPort)
901 {
902 InputPyPort *p2(static_cast<InputPyPort *>(p));
903 if(p2->canSafelySqueezeMemory())
904 p2->put(Py_None);
905 }
906 for(auto p : _setOfOutputPort)
907 {
908 if (!this->_nonSqueezableOutputNodes.empty() && this->_nonSqueezableOutputNodes.find(p->getName()) != this->_nonSqueezableOutputNodes.end())
909 continue;
910 OutputPyPort *p2(static_cast<OutputPyPort *>(p));
911 p2->putWithoutForward(Py_None);
912 }
913}
914
916{
918}
919
920void PythonNode::shutdown(int level)
921{
922 DEBTRACE("PythonNode::shutdown " << level);
923 if(_mode=="local")return;
924 if(_container)
925 {
927 _container->shutdown(level);
928 }
929}
930
931void PythonNode::imposeResource(const std::string& resource_name,
932 const std::string& container_name)
933{
934 if(!resource_name.empty() && !container_name.empty())
935 {
936 _imposedResource = resource_name;
937 _imposedContainer = container_name;
938 }
939}
940
942{
943 return _container != nullptr && _container->canAcceptImposedResource();
944}
945
947{
949}
950
952{
954 return "DEFAULT_NAME_FOR_UNIQUE_PYTHON_NODE_ENTRY";
955 else
956 return getId();
957}
958
960{
961 bool found = false;
962 if(_container)
964 return found;
965}
966
968{
969 if(!CORBA::is_nil(_pynode))
970 {
971 try
972 {
973 _pynode->UnRegister();
974 }
975 catch(...)
976 {
977 DEBTRACE("Trouble when pynode->UnRegister!")
978 }
979 _pynode = Engines::PyScriptNode::_nil();
980 }
981}
982
983Node *PythonNode::simpleClone(ComposedNode *father, bool editionOnly) const
984{
985 return new PythonNode(*this,father);
986}
987
988void PythonNode::createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)
989{
991 _pynode=objContainer->createPyScriptNode(pythonEntryName().c_str(),getScript().c_str());
992 _pynode->Register();
993}
994
995Engines::PyNodeBase_var PythonNode::retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const
996{
997 Engines::PyScriptNode_var ret(objContainer->getDefaultPyScriptNode(pythonEntryName().c_str()));
998 if(!CORBA::is_nil(ret))
999 {
1000 ret->Register();
1001 }
1002 return Engines::PyNodeBase::_narrow(ret);
1003}
1004
1005void PythonNode::assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)
1006{
1007 if(CORBA::is_nil(_pynode))
1008 _pynode=Engines::PyScriptNode::_narrow(remoteInterp);
1009 else
1010 {
1011 Engines::PyScriptNode_var tmpp(Engines::PyScriptNode::_narrow(remoteInterp));
1012 if(!_pynode->_is_equivalent(tmpp))
1013 {
1015 _pynode=Engines::PyScriptNode::_narrow(remoteInterp);
1016 }
1017 }
1018 _pynode->assignNewCompiledCode(getScript().c_str());
1019}
1020
1022{
1023 return Engines::PyNodeBase::_narrow(_pynode);
1024}
1025
1027PythonNode* PythonNode::cloneNode(const std::string& name)
1028{
1029 PythonNode* n=new PythonNode(name);
1030 n->setScript(_script);
1031 list<InputPort *>::iterator iter;
1032 for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
1033 {
1034 InputPyPort *p=(InputPyPort *)*iter;
1035 DEBTRACE( "port name: " << p->getName() );
1036 DEBTRACE( "port kind: " << p->edGetType()->kind() );
1037 n->edAddInputPort(p->getName(),p->edGetType());
1038 }
1039 list<OutputPort *>::iterator iter2;
1040 for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
1041 {
1042 OutputPyPort *p=(OutputPyPort *)*iter2;
1043 DEBTRACE( "port name: " << p->getName() );
1044 DEBTRACE( "port kind: " << p->edGetType()->kind() );
1045 n->edAddOutputPort(p->getName(),p->edGetType());
1046 }
1047 return n;
1048}
1049
1051{
1052 std::vector< std::pair<std::string,int> > ret(getDPLScopeInfo(gfn));
1053 if(ret.empty())
1054 return ;
1055 //
1056 PyObject *ob(0);
1057 {
1058 AutoGIL agil;
1059 std::size_t sz(ret.size());
1060 ob=PyList_New(sz);
1061 for(std::size_t i=0;i<sz;i++)
1062 {
1063 const std::pair<std::string,int>& p(ret[i]);
1064 PyObject *elt(PyTuple_New(2));
1065 PyTuple_SetItem(elt,0,PyUnicode_FromString(p.first.c_str()));
1066 PyTuple_SetItem(elt,1,PyLong_FromLong(p.second));
1067 PyList_SetItem(ob,i,elt);
1068 }
1069 }
1070 if(_mode==REMOTE_NAME)
1071 {
1072 Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);
1073 {
1074 AutoGIL agil;
1075 PyObject *serializationInput(PyObject_CallFunctionObjArgs(_pyfuncSimpleSer,ob,NULL));
1076 Py_XDECREF(ob);
1077 char *serializationInputC(0);
1078 Py_ssize_t len;
1079 if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
1080 throw Exception("DistributedPythonNode problem in python pickle");
1081 serializationInputCorba->length(len);
1082 for(int i=0; i < len ; i++)
1083 serializationInputCorba[i]=serializationInputC[i];
1084 Py_XDECREF(serializationInput);
1085 }
1086 _pynode->defineNewCustomVar(DPL_INFO_NAME,serializationInputCorba);
1087 }
1088 else
1089 {
1090 AutoGIL agil;
1091 PyDict_SetItemString(_context,DPL_INFO_NAME,ob);
1092 Py_XDECREF(ob);
1093 }
1094}
1095
1096PyFuncNode::PyFuncNode(const PyFuncNode& other, ComposedNode *father):InlineFuncNode(other,father),_pyfunc(0)
1097{
1099 {
1100 AutoGIL agil;
1101 _context=PyDict_New();
1102 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1103 if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
1104 {
1105 stringstream msg;
1106 msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
1107 _errorDetails=msg.str();
1108 throw Exception(msg.str());
1109 }
1110 }
1111}
1112
1113PyFuncNode::PyFuncNode(const std::string& name): InlineFuncNode(name),_pyfunc(0)
1114{
1115
1117 DEBTRACE( "PyFuncNode::PyFuncNode " << name );
1118 {
1119 AutoGIL agil;
1120 _context=PyDict_New();
1121 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1122 if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
1123 {
1124 stringstream msg;
1125 msg << "Not possible to set builtins" << __FILE__ << ":" << __LINE__;
1126 _errorDetails=msg.str();
1127 throw Exception(msg.str());
1128 }
1129 }
1130}
1131
1133{
1134 if(!CORBA::is_nil(_pynode))
1135 {
1136 _pynode->UnRegister();
1137 }
1138}
1139
1140void PyFuncNode::init(bool start)
1141{
1143 if(_state == YACS::DISABLED)
1144 {
1145 exDisabledState(); // to refresh propagation of DISABLED state
1146 return ;
1147 }
1148 if(start) //complete initialization
1150 else if(_state > YACS::LOADED)// WARNING FuncNode has internal vars (CEA usecase) ! Partial initialization (inside a loop). Exclusivity of funcNode.
1152}
1153
1155{
1156 DEBTRACE("checkBasicConsistency");
1158 {
1159 AutoGIL agil;
1160 PyObject* res;
1161 res=Py_CompileString(_script.c_str(),getName().c_str(),Py_file_input);
1162 if(res == NULL)
1163 {
1164 std::string error="";
1165 PyObject* new_stderr = newPyStdOut(error);
1166 PySys_SetObject((char*)"stderr", new_stderr);
1167 PyErr_Print();
1168 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1169 Py_DECREF(new_stderr);
1170 throw Exception(error);
1171 }
1172 else
1173 Py_XDECREF(res);
1174 }
1175}
1176
1178{
1179 DEBTRACE( "---------------PyfuncNode::load function---------------" );
1181 loadRemote();
1182 else
1183 loadLocal();
1184}
1185
1187{
1188 commonRemoteLoad(this);
1189}
1190
1192{
1193 DEBTRACE( "---------------PyFuncNode::load function " << getName() << " ---------------" );
1194 DEBTRACE( _script );
1195
1196#ifdef _DEVDEBUG_
1197 list<OutputPort *>::iterator iter;
1198 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
1199 {
1200 OutputPyPort *p=(OutputPyPort *)*iter;
1201 DEBTRACE( "port name: " << p->getName() );
1202 DEBTRACE( "port kind: " << p->edGetType()->kind() );
1203 }
1204#endif
1205
1206 {
1207 AutoGIL agil;
1208 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1209
1210 std::ostringstream stream;
1211 stream << "/tmp/PythonNode_";
1212 stream << getpid();
1213
1214 PyObject* code=Py_CompileString(_script.c_str(), stream.str().c_str(), Py_file_input);
1215 if(code == NULL)
1216 {
1217 _errorDetails="";
1218 PyObject* new_stderr = newPyStdOut(_errorDetails);
1219 PySys_SetObject((char*)"stderr", new_stderr);
1220 PyErr_Print();
1221 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1222 Py_DECREF(new_stderr);
1223 throw Exception("Error during execution");
1224 }
1225 PyObject *res = PyEval_EvalCode( code, _context, _context);
1226 Py_DECREF(code);
1227 Py_XDECREF(res);
1228
1229 DEBTRACE( "_context refcnt: " << _context->ob_refcnt );
1230 if(PyErr_Occurred ())
1231 {
1232 _errorDetails="";
1233 PyObject* new_stderr = newPyStdOut(_errorDetails);
1234 PySys_SetObject((char*)"stderr", new_stderr);
1235 ofstream errorfile(stream.str().c_str());
1236 if (errorfile.is_open())
1237 {
1238 errorfile << _script;
1239 errorfile.close();
1240 }
1241 PyErr_Print();
1242 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1243 Py_DECREF(new_stderr);
1244 throw Exception("Error during execution");
1245 return;
1246 }
1247 _pyfunc=PyDict_GetItemString(_context,_fname.c_str());
1248 DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1249 if(_pyfunc == NULL)
1250 {
1251 _errorDetails="";
1252 PyObject* new_stderr = newPyStdOut(_errorDetails);
1253 PySys_SetObject((char*)"stderr", new_stderr);
1254 PyErr_Print();
1255 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1256 Py_DECREF(new_stderr);
1257 throw Exception("Error during execution");
1258 }
1259 DEBTRACE( "---------------End PyFuncNode::load function---------------" );
1260 }
1261}
1262
1264{
1266 executeRemote();
1267 else
1268 executeLocal();
1269}
1270
1272{
1273 DEBTRACE( "++++++++++++++ PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
1274 if(!_pyfuncSer)
1275 throw Exception("DistributedPythonNode badly loaded");
1276 //
1277 if(dynamic_cast<HomogeneousPoolContainer *>(getContainer()))
1278 {
1279 bool dummy;
1280 loadPythonAdapter(this,dummy);
1281 _pynode->executeAnotherPieceOfCode(getScript().c_str());
1282 }
1283 //
1284 Engines::pickledArgs_var serializationInputCorba(new Engines::pickledArgs);;
1285 {
1286#if PY_VERSION_HEX < 0x03070000
1287 std::unique_lock<std::mutex> lock(data_mutex);
1288#endif
1289 AutoGIL agil;
1290 PyObject *ob(0);
1291 //===========================================================================
1292 // Get inputs in input ports, build a Python tuple and pickle it
1293 //===========================================================================
1294 PyObject *args(PyTuple_New(getNumberOfInputPorts()));
1295 int pos(0);
1296 for(std::list<InputPort *>::iterator iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++,pos++)
1297 {
1298 InputPyPort *p=(InputPyPort *)*iter2;
1299 ob=p->getPyObj();
1300 Py_INCREF(ob);
1301 PyTuple_SetItem(args,pos,ob);
1302 }
1303#ifdef _DEVDEBUG_
1304 PyObject_Print(args,stderr,Py_PRINT_RAW);
1305 std::cerr << endl;
1306#endif
1307 PyObject *serializationInput=PyObject_CallObject(_pyfuncSer,args);
1308 Py_DECREF(args);
1309 //The pickled string may contain NULL characters so use PyString_AsStringAndSize
1310 char *serializationInputC(0);
1311 Py_ssize_t len;
1312 if (PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len))
1313 throw Exception("DistributedPythonNode problem in python pickle");
1314
1315 serializationInputCorba->length(len);
1316 for(int i=0; i < len ; i++)
1317 serializationInputCorba[i]=serializationInputC[i];
1318 Py_DECREF(serializationInput);
1319 }
1320
1321 //===========================================================================
1322 // Execute in remote Python node
1323 //===========================================================================
1324 DEBTRACE( "-----------------starting remote python invocation-----------------" );
1325 Engines::pickledArgs_var resultCorba;
1326 try
1327 {
1328 resultCorba=_pynode->execute(getFname().c_str(),serializationInputCorba);
1329 }
1330 catch( const SALOME::SALOME_Exception& ex )
1331 {
1332 std::string msg="Exception on remote python invocation";
1333 msg += '\n';
1334 msg += ex.details.text.in();
1335 _errorDetails=msg;
1336 throw Exception(msg);
1337 }
1338 catch(CORBA::COMM_FAILURE& ex)
1339 {
1340 std::ostringstream msg;
1341 msg << "Exception on remote python invocation." << std::endl ;
1342 msg << "Caught system exception COMM_FAILURE -- unable to contact the "
1343 << "object." << std::endl;
1344 _errorDetails=msg.str();
1345 throw Exception(msg.str());
1346 }
1347 catch(CORBA::SystemException& ex)
1348 {
1349 std::ostringstream msg;
1350 msg << "Exception on remote python invocation." << std::endl ;
1351 msg << "Caught a CORBA::SystemException." ;
1352 CORBA::Any tmp;
1353 tmp <<= ex;
1354 CORBA::TypeCode_var tc = tmp.type();
1355 const char *p = tc->name();
1356 if ( *p != '\0' )
1357 msg <<p;
1358 else
1359 msg << tc->id();
1360 msg << std::endl;
1361 _errorDetails=msg.str();
1362 throw Exception(msg.str());
1363 }
1364 catch(CORBA::Exception& ex)
1365 {
1366 std::ostringstream msg;
1367 msg << "Exception on remote python invocation." << std::endl ;
1368 msg << "Caught CORBA::Exception. " ;
1369 CORBA::Any tmp;
1370 tmp <<= ex;
1371 CORBA::TypeCode_var tc = tmp.type();
1372 const char *p = tc->name();
1373 if ( *p != '\0' )
1374 msg <<p;
1375 else
1376 msg << tc->id();
1377 msg << std::endl;
1378 _errorDetails=msg.str();
1379 throw Exception(msg.str());
1380 }
1381 catch(omniORB::fatalException& fe)
1382 {
1383 std::ostringstream msg;
1384 msg << "Exception on remote python invocation." << std::endl ;
1385 msg << "Caught omniORB::fatalException:" << std::endl;
1386 msg << " file: " << fe.file() << std::endl;
1387 msg << " line: " << fe.line() << std::endl;
1388 msg << " mesg: " << fe.errmsg() << std::endl;
1389 _errorDetails=msg.str();
1390 throw Exception(msg.str());
1391 }
1392 DEBTRACE( "-----------------end of remote python invocation-----------------" );
1393 //===========================================================================
1394 // Get results, unpickle and put them in output ports
1395 //===========================================================================
1396 char *resultCorbaC=new char[resultCorba->length()+1];
1397 resultCorbaC[resultCorba->length()]='\0';
1398 for(int i=0;i<resultCorba->length();i++)
1399 resultCorbaC[i]=resultCorba[i];
1400
1401 {
1402#if PY_VERSION_HEX < 0x03070000
1403 std::unique_lock<std::mutex> lock(data_mutex);
1404#endif
1405 AutoGIL agil;
1406
1407 PyObject *resultPython(PyBytes_FromStringAndSize(resultCorbaC,resultCorba->length()));
1408 delete [] resultCorbaC;
1409 PyObject *args(PyTuple_New(1)),*ob(0);
1410 PyTuple_SetItem(args,0,resultPython);
1411 PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
1412 Py_DECREF(args);
1413
1414 DEBTRACE( "-----------------PythonNode::outputs-----------------" );
1415 int nres=1;
1416 if(finalResult == Py_None)
1417 nres=0;
1418 else if(PyTuple_Check(finalResult))
1419 nres=PyTuple_Size(finalResult);
1420
1421 if(getNumberOfOutputPorts() != nres)
1422 {
1423 std::string msg="Number of output arguments : Mismatch between definition and execution";
1424 Py_DECREF(finalResult);
1425 _errorDetails=msg;
1426 throw Exception(msg);
1427 }
1428
1429 try
1430 {
1431 int pos(0);
1432 for(std::list<OutputPort *>::iterator iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++, pos++)
1433 {
1434 OutputPyPort *p=(OutputPyPort *)*iter;
1435 DEBTRACE( "port name: " << p->getName() );
1436 DEBTRACE( "port kind: " << p->edGetType()->kind() );
1437 DEBTRACE( "port pos : " << pos );
1438 if(PyTuple_Check(finalResult))
1439 ob=PyTuple_GetItem(finalResult,pos) ;
1440 else
1441 ob=finalResult;
1442 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1443 p->put(ob);
1444 }
1445 Py_DECREF(finalResult);
1446 }
1447 catch(ConversionException& ex)
1448 {
1449 Py_DECREF(finalResult);
1450 _errorDetails=ex.what();
1451 throw;
1452 }
1453 }
1454
1455 DEBTRACE( "++++++++++++++ ENDOF PyFuncNode::executeRemote: " << getName() << " ++++++++++++++++++++" );
1456}
1457
1459{
1460 DEBTRACE( "++++++++++++++ PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
1461
1462 int pos=0;
1463 PyObject* ob;
1464 if(!_pyfunc)throw Exception("PyFuncNode badly loaded");
1465 {
1466 AutoGIL agil;
1467 DEBTRACE( "---------------PyFuncNode::inputs---------------" );
1468 PyObject* args = PyTuple_New(getNumberOfInputPorts()) ;
1469 list<InputPort *>::iterator iter2;
1470 for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
1471 {
1472 InputPyPort *p=(InputPyPort *)*iter2;
1473 DEBTRACE( "port name: " << p->getName() );
1474 DEBTRACE( "port kind: " << p->edGetType()->kind() );
1475 ob=p->getPyObj();
1476#ifdef _DEVDEBUG_
1477 PyObject_Print(ob,stderr,Py_PRINT_RAW);
1478 cerr << endl;
1479#endif
1480 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1481 Py_INCREF(ob);
1482 PyTuple_SetItem(args,pos,ob);
1483 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1484 pos++;
1485 }
1486 DEBTRACE( "---------------End PyFuncNode::inputs---------------" );
1487
1488 DEBTRACE( "----------------PyFuncNode::calculation---------------" );
1489#ifdef _DEVDEBUG_
1490 PyObject_Print(_pyfunc,stderr,Py_PRINT_RAW);
1491 cerr << endl;
1492 PyObject_Print(args,stderr,Py_PRINT_RAW);
1493 cerr << endl;
1494#endif
1495 DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1496 PyObject* result = PyObject_CallObject( _pyfunc , args ) ;
1497 DEBTRACE( "_pyfunc refcnt: " << _pyfunc->ob_refcnt );
1498 Py_DECREF(args);
1499 fflush(stdout);
1500 fflush(stderr);
1501 if(result == NULL)
1502 {
1503 _errorDetails="";
1504 PyObject* new_stderr = newPyStdOut(_errorDetails);
1505 PySys_SetObject((char*)"stderr", new_stderr);
1506 std::ostringstream stream;
1507 stream << "/tmp/PythonNode_";
1508 stream << getpid();
1509 ofstream errorfile(stream.str().c_str());
1510 if (errorfile.is_open())
1511 {
1512 errorfile << _script;
1513 errorfile.close();
1514 }
1515 PyErr_Print();
1516 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
1517 Py_DECREF(new_stderr);
1518 throw Exception("Error during execution");
1519 }
1520 DEBTRACE( "----------------End PyFuncNode::calculation---------------" );
1521
1522 DEBTRACE( "-----------------PyFuncNode::outputs-----------------" );
1523 int nres=1;
1524 if(result == Py_None)
1525 nres=0;
1526 else if(PyTuple_Check(result))
1527 nres=PyTuple_Size(result);
1528
1529 if(getNumberOfOutputPorts() != nres)
1530 {
1531 std::string msg="Number of output arguments : Mismatch between definition and execution";
1532 Py_DECREF(result);
1533 _errorDetails=msg;
1534 throw Exception(msg);
1535 }
1536
1537 pos=0;
1538#ifdef _DEVDEBUG_
1539 PyObject_Print(result,stderr,Py_PRINT_RAW);
1540 cerr << endl;
1541#endif
1542 list<OutputPort *>::iterator iter;
1543 try
1544 {
1545 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
1546 {
1547 OutputPyPort *p=(OutputPyPort *)*iter;
1548 DEBTRACE( "port name: " << p->getName() );
1549 DEBTRACE( "port kind: " << p->edGetType()->kind() );
1550 DEBTRACE( "port pos : " << pos );
1551 if(PyTuple_Check(result))ob=PyTuple_GetItem(result,pos) ;
1552 else ob=result;
1553 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
1554#ifdef _DEVDEBUG_
1555 PyObject_Print(ob,stderr,Py_PRINT_RAW);
1556 cerr << endl;
1557#endif
1558 p->put(ob);
1559 pos++;
1560 }
1561 }
1562 catch(ConversionException& ex)
1563 {
1564 Py_DECREF(result);
1565 _errorDetails=ex.what();
1566 throw;
1567 }
1568 DEBTRACE( "-----------------End PyFuncNode::outputs-----------------" );
1569 Py_DECREF(result);
1570 }
1571 DEBTRACE( "++++++++++++++ End PyFuncNode::execute: " << getName() << " ++++++++++++++++++++" );
1572}
1573
1574Node *PyFuncNode::simpleClone(ComposedNode *father, bool editionOnly) const
1575{
1576 return new PyFuncNode(*this,father);
1577}
1578
1579void PyFuncNode::createRemoteAdaptedPyInterpretor(Engines::Container_ptr objContainer)
1580{
1581 if(!CORBA::is_nil(_pynode))
1582 _pynode->UnRegister();
1583 _pynode=objContainer->createPyNode(getName().c_str(),getScript().c_str());
1584}
1585
1586Engines::PyNodeBase_var PyFuncNode::retrieveDftRemotePyInterpretorIfAny(Engines::Container_ptr objContainer) const
1587{
1588 Engines::PyNode_var ret(objContainer->getDefaultPyNode(getName().c_str()));
1589 if(!CORBA::is_nil(ret))
1590 {
1591 ret->Register();
1592 }
1593 return Engines::PyNodeBase::_narrow(ret);
1594}
1595
1596void PyFuncNode::assignRemotePyInterpretor(Engines::PyNodeBase_var remoteInterp)
1597{
1598 if(!CORBA::is_nil(_pynode))
1599 {
1600 Engines::PyNode_var tmpp(Engines::PyNode::_narrow(remoteInterp));
1601 if(_pynode->_is_equivalent(tmpp))
1602 return ;
1603 }
1604 if(!CORBA::is_nil(_pynode))
1605 _pynode->UnRegister();
1606 _pynode=Engines::PyNode::_narrow(remoteInterp);
1607}
1608
1610{
1611 return Engines::PyNodeBase::_narrow(_pynode);
1612}
1613
1615PyFuncNode* PyFuncNode::cloneNode(const std::string& name)
1616{
1617 PyFuncNode* n=new PyFuncNode(name);
1618 n->setScript(_script);
1619 n->setFname(_fname);
1620 list<InputPort *>::iterator iter;
1621 for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
1622 {
1623 InputPyPort *p=(InputPyPort *)*iter;
1624 n->edAddInputPort(p->getName(),p->edGetType());
1625 }
1626 list<OutputPort *>::iterator iter2;
1627 for(iter2 = _setOfOutputPort.begin(); iter2 != _setOfOutputPort.end(); iter2++)
1628 {
1629 OutputPyPort *p=(OutputPyPort *)*iter2;
1630 n->edAddOutputPort(p->getName(),p->edGetType());
1631 }
1632 return n;
1633}
1634
1636{
1638}
1639
1641{
1642 DEBTRACE("PyFuncNode::shutdown " << level);
1643 if(_mode=="local")return;
1644 if(_container)
1645 {
1646 if(!CORBA::is_nil(_pynode)) _pynode->UnRegister();
1647 _pynode=Engines::PyNode::_nil();
1648 _container->shutdown(level);
1649 }
1650}
1651
1652void PyFuncNode::imposeResource(const std::string& resource_name,
1653 const std::string& container_name)
1654{
1655 if(!resource_name.empty() && !container_name.empty())
1656 {
1657 _imposedResource = resource_name;
1658 _imposedContainer = container_name;
1659 }
1660}
1661
1663{
1664 return _container != nullptr && _container->canAcceptImposedResource();
1665}
1666
1668{
1670}
1671
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 & getName() const
Definition: Node.hxx:125
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
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
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
std::string _imposedResource
Definition: PythonNode.hxx:69
virtual bool hasImposedResource() const
Definition: PythonNode.cxx:326
static bool GetDestroyStatus(PyObject *ob)
Definition: PythonNode.cxx:355
virtual const char * getSerializationScript() const =0
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:951
void setSqueezeStatus(bool sqStatus)
Definition: PythonNode.hxx:111
bool hasImposedResource() const override
Definition: PythonNode.cxx:946
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:959
virtual void shutdown(int level)
Stop all pending activities of the node.
Definition: PythonNode.cxx:920
virtual void loadLocal()
Definition: PythonNode.cxx:490
static void ExecuteLocalInternal(const std::string &codeStr, PyObject *context, std::string &errorDetails)
Definition: PythonNode.cxx:733
PythonNode(const PythonNode &other, ComposedNode *father)
Definition: PythonNode.cxx:418
void executeLocalInternal(const std::string &codeStr)
Definition: PythonNode.cxx:773
Node * simpleClone(ComposedNode *father, bool editionOnly) const
Definition: PythonNode.cxx:983
bool canAcceptImposedResource() override
Definition: PythonNode.cxx:941
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:988
virtual void loadRemote()
Definition: PythonNode.cxx:496
void imposeResource(const std::string &resource_name, const std::string &container_name) override
Definition: PythonNode.cxx:931
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:778
std::string getContainerLog()
returns a string that contains the name of the container log file if it exists
Definition: PythonNode.cxx:915
void applyDPLScope(ComposedNode *gfn)
void setSqueezeStatusWithExceptions(bool sqStatus, const std::vector< std::string > &squeezeExceptions)
Definition: PythonNode.cxx:864
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:995
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