Salome HOME
Help to debug when troubles at launch time
[modules/yacs.git] / src / runtime / PythonPorts.cxx
1 // Copyright (C) 2006-2024  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 "PythonPorts.hxx"
21 #include "TypeConversions.hxx"
22 #include "TypeCode.hxx"
23 #include "Node.hxx"
24 #include "ConversionException.hxx"
25
26 #include <iostream>
27 #include <sstream>
28
29 //#define _DEVDEBUG_
30 #include "YacsTrace.hxx"
31
32 using namespace YACS::ENGINE;
33 using namespace std;
34
35 static void RegisterReleasePyObj(PyObject* data, const char *method1)
36 {
37   if(!data)
38     return ;
39   DEBTRACE( "data refcnt: " << data->ob_refcnt );
40   if (PyObject_HasAttrString(data, (char*)"_is_a"))
41     {
42       PyObject *result = PyObject_CallMethod(data, (char*)"_is_a", (char*)"s",(char*)"IDL:SALOME/GenericObj:1.0");
43       if(result && PyLong_Check(result))
44         {
45           if(PyLong_AS_LONG(result))
46             {
47               PyObject* o=PyObject_CallMethod(data, (char*)method1, (char*)"");
48               if(o)
49                 Py_XDECREF( o);
50               else
51                 {
52 #ifdef _DEVDEBUG_
53                   PyErr_Print();
54 #else
55                   PyErr_Clear();
56 #endif
57                   throw ConversionException("Corba object does not exist: you have perhaps forgotten to call Register on a GenericObj");      
58                 }
59             }
60           Py_XDECREF(result); 
61         }
62       if(!result)
63         {
64 #ifdef _DEVDEBUG_
65           PyErr_Print();
66 #else
67           PyErr_Clear();
68 #endif
69           throw ConversionException("Corba object does not exist: you have perhaps forgotten to call Register on a GenericObj");      
70         }
71     }
72 }
73
74 void releasePyObj(PyObject* data)
75 {
76   RegisterReleasePyObj(data,"Destroy");
77 }
78
79 void registerPyObj(PyObject* data)
80 {
81   RegisterReleasePyObj(data,"Register");
82 }
83
84 InputPyPort::InputPyPort(const std::string& name, Node *node, TypeCode * type)
85   : InputPort(name, node, type)
86   , DataPort(name, node, type)
87   , Port(node)
88   , _data(Py_None)
89   ,_initData(nullptr)
90   ,_isEmpty(true)
91 {
92   Py_INCREF(_data);
93 }
94 InputPyPort::~InputPyPort()
95 {
96   PyGILState_STATE gstate = PyGILState_Ensure();
97   DEBTRACE( "_data refcnt: " << (_data ? _data->ob_refcnt : -1) );
98   DEBTRACE( "_initData refcnt: " << (_initData ? _initData->ob_refcnt : -1));
99   // Release or not release : all GenericObj are deleted when the input port is deleted
100   releasePyObj(_data);
101   Py_XDECREF(_data); 
102   Py_XDECREF(_initData); 
103   PyGILState_Release(gstate);
104 }
105
106 InputPyPort::InputPyPort(const InputPyPort& other, Node *newHelder):InputPort(other,newHelder),DataPort(other,newHelder),Port(other,newHelder)
107 {
108   _initData=other._initData;
109   Py_XINCREF(_initData);
110   _data=other._data;
111   Py_INCREF(_data);
112   _isEmpty=other._isEmpty;
113 }
114
115 bool InputPyPort::edIsManuallyInitialized() const
116 {
117   return _initData!=nullptr;
118 }
119
120 void InputPyPort::edRemoveManInit()
121 {
122   Py_XDECREF(_initData);
123   _initData=nullptr;
124   Py_XDECREF(_data);
125   _data=Py_None;
126   Py_INCREF(_data);
127   _isEmpty=true;
128   InputPort::edRemoveManInit();
129 }
130
131 void InputPyPort::put(const void *data)
132 {
133   put((PyObject *)data);
134 }
135
136 void InputPyPort::releaseDataUnsafe()
137 {
138   releasePyObj(_data);
139   Py_XDECREF(_data); 
140   _data = nullptr;
141 }
142
143 void InputPyPort::releaseData()
144 {
145   InterpreterUnlocker l;
146   InputPyPort::releaseDataUnsafe();
147 }
148
149 void InputPyPort::put(PyObject *data)
150 {
151   InterpreterUnlocker l;
152   InputPyPort::releaseDataUnsafe();
153   _data = data;
154   _stringRef="";
155   Py_INCREF(_data); 
156   registerPyObj(_data);
157   _isEmpty=false;
158   DEBTRACE( "_data refcnt: " << _data->ob_refcnt );
159 }
160
161 InputPort *InputPyPort::clone(Node *newHelder) const
162 {
163   return new InputPyPort(*this,newHelder);
164 }
165
166 PyObject * InputPyPort::getPyObj() const
167 {
168   return _data;
169 }
170
171 void *InputPyPort::get() const
172 {
173   return (void*) _data;
174 }
175
176 std::string InputPyPort::getAsString()
177 {
178   std::string ret;
179   //protect _data against modification or delete in another thread
180   PyObject* data=_data;
181   Py_INCREF(data);
182   ret = convertPyObjectToString(data);
183   Py_XDECREF(data);
184   return ret;
185 }
186
187 std::string InputPyPort::getHumanRepr()
188 {
189   if(!_data)
190     return dump();
191   PyObject *ret(PyObject_Str(_data));
192   if(!ret)
193     return dump();
194   std::string retCpp;
195   char *val(PyBytes_AsString(ret));
196   if(val)
197     retCpp=val;
198   Py_XDECREF(ret);
199   return retCpp;
200 }
201
202 bool InputPyPort::isEmpty()
203 {
204   return _isEmpty;
205 }
206
207 //! Save the current data value for further reinitialization of the port
208 /*!
209  *
210  */
211 void InputPyPort::exSaveInit()
212 {
213   // Interpreter lock seems necessary when deleting lists in Python 2.7
214   PyGILState_STATE gstate = PyGILState_Ensure();
215   Py_XDECREF(_initData);
216   _initData=_data;
217   Py_INCREF(_initData); 
218   PyGILState_Release(gstate);
219   DEBTRACE( "_initData.ob refcnt: " << (_initData ? _initData->ob_refcnt : -1));
220   DEBTRACE( "_data.ob refcnt: " << _data->ob_refcnt );
221 }
222
223 //! Restore the saved data value to current data value
224 /*!
225  * If no data has been saved (_initData == 0) don't restore
226  */
227 void InputPyPort::exRestoreInit()
228 {
229   if(!_initData)return;
230   Py_XDECREF(_data); 
231   _data=_initData;
232   Py_XINCREF(_data);
233   _isEmpty = false;
234   DEBTRACE( "_initData.ob refcnt: " << _initData->ob_refcnt );
235   DEBTRACE( "_data.ob refcnt: " << _data->ob_refcnt );
236 }
237
238 std::string InputPyPort::dump()
239 {
240   if( _isEmpty)
241     return "<value>None</value>";
242
243   InterpreterUnlocker l;
244   return convertPyObjectXml(edGetType(), _data);
245 }
246
247 std::string InputPyPort::valToStr()
248 {
249   int isString = PyBytes_Check(getPyObj());
250   //DEBTRACE("isString=" << isString);
251   PyObject *strPyObj = PyObject_Str(getPyObj());
252   //DEBTRACE(PyString_Size(strPyObj));
253   string val = PyBytes_AsString(strPyObj);
254   if (isString)
255     val = "\"" + val + "\"";
256   //DEBTRACE(val);
257   Py_DECREF(strPyObj);
258   return val;
259 }
260
261 void InputPyPort::valFromStr(std::string valstr)
262 {
263 }
264
265
266 OutputPyPort::OutputPyPort(const std::string& name, Node *node, TypeCode * type)
267   : OutputPort(name, node, type), DataPort(name, node, type), Port(node)
268 {
269   _data = Py_None;
270   Py_INCREF(_data); 
271 }
272 OutputPyPort::~OutputPyPort()
273 {
274   PyGILState_STATE gstate = PyGILState_Ensure();
275   DEBTRACE( "_data refcnt: " << _data->ob_refcnt );
276   // Release or not release : all GenericObj are deleted when the output port is deleted
277   releasePyObj(_data);
278   Py_XDECREF(_data); 
279   PyGILState_Release(gstate);
280 }
281
282 OutputPyPort::OutputPyPort(const OutputPyPort& other, Node *newHelder):OutputPort(other,newHelder),DataPort(other,newHelder),Port(other,newHelder),
283                                                                        _data(Py_None)
284 {
285   Py_INCREF(_data);
286 }
287
288 void OutputPyPort::put(const void *data)
289 {
290   put((PyObject *)data);
291 }
292
293 void OutputPyPort::putWithoutForward(PyObject *data)
294 {
295   DEBTRACE( "OutputPyPort::put.ob refcnt: " << data->ob_refcnt );
296 #ifdef _DEVDEBUG_
297   PyObject_Print(data,stderr,Py_PRINT_RAW);
298   cerr << endl;
299 #endif
300   releasePyObj(_data);
301   Py_XDECREF(_data); 
302   _data = data;
303   Py_INCREF(_data); 
304   //no registerPyObj : we steal the output reference of the node
305 }
306
307 void OutputPyPort::put(PyObject *data)
308 {
309   putWithoutForward(data);
310   DEBTRACE( "OutputPyPort::put.ob refcnt: " << data->ob_refcnt );
311   OutputPort::put(data);
312 }
313
314 OutputPort *OutputPyPort::clone(Node *newHelder) const
315 {
316   return new OutputPyPort(*this,newHelder);
317 }
318
319 PyObject * OutputPyPort::get() const
320 {
321   return _data;
322 }
323
324 PyObject * OutputPyPort::getPyObj() const
325 {
326   return _data;
327 }
328
329 std::string OutputPyPort::getAsString()
330 {
331   std::string ret;
332   //protect _data against modification or delete in another thread
333   PyObject* data=_data;
334   Py_INCREF(data); 
335   ret = convertPyObjectToString(data);
336   Py_XDECREF(data); 
337   return ret;
338 }
339
340 std::string OutputPyPort::dump()
341 {
342   InterpreterUnlocker l;
343   string xmldump = convertPyObjectXml(edGetType(), _data);
344   return xmldump;
345 }
346
347 std::string OutputPyPort::valToStr()
348 {
349   PyObject *strPyObj = PyObject_Str(getPyObj());
350   string val = PyBytes_AsString(strPyObj);
351   Py_DECREF(strPyObj);
352   return val;
353 }
354
355 void OutputPyPort::valFromStr(std::string valstr)
356 {
357 }