Salome HOME
Support of multi key,var append in global vars.
[modules/kernel.git] / src / SALOMESDS / SALOMESDS_PickelizedPyObjServer.cxx
1 // Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
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 // Author : Anthony GEAY (EDF R&D)
20
21 #include "SALOMESDS_PickelizedPyObjServer.hxx"
22 #include "SALOMESDS_DataScopeServer.hxx"
23 #include "SALOMESDS_Exception.hxx"
24
25 #include <iostream>
26 #include <sstream>
27
28 using namespace SALOMESDS;
29
30 PickelizedPyObjServer::PickelizedPyObjServer(DataScopeServerBase *father, const std::string& varName, const SALOME::ByteVec& value):BasicDataServer(father,varName),_self(0)
31 {
32   setSerializedContentInternal(value);
33 }
34
35 //! obj is consumed
36 PickelizedPyObjServer::PickelizedPyObjServer(DataScopeServerBase *father, const std::string& varName, PyObject *obj):BasicDataServer(father,varName),_self(0)
37 {
38   setNewPyObj(obj);
39 }
40
41 PickelizedPyObjServer::~PickelizedPyObjServer()
42 {
43   Py_XDECREF(_self);
44 }
45
46 /*!
47  * Called remotely -> to protect against throw
48  */
49 SALOME::ByteVec *PickelizedPyObjServer::fetchSerializedContent()
50 {
51   Py_XINCREF(_self);//because pickelize consume _self
52   return FromCppToByteSeq(pickelize(_self));
53 }
54
55 bool PickelizedPyObjServer::isDict()
56 {
57   if(PyDict_Check(_self))
58     return true;
59   else
60     return false;
61 }
62
63 void PickelizedPyObjServer::checkKeyNotAlreadyPresent(PyObject *key)
64 {
65   checkKeyPresence(key,false);
66 }
67
68 void PickelizedPyObjServer::checkKeyPresent(PyObject *key)
69 {
70   checkKeyPresence(key,true);
71 }
72
73 void PickelizedPyObjServer::addKeyValueHard(PyObject *key, PyObject *value)
74 {
75   bool isOK(PyDict_SetItem(_self,key,value)==0);
76   if(!isOK)
77     throw Exception("PickelizedPyObjServer::addKeyValueHard : error when trying to add key,value to dict !");
78 }
79
80 void PickelizedPyObjServer::addKeyValueErrorIfAlreadyExisting(PyObject *key, PyObject *value)
81 {
82   checkKeyNotAlreadyPresent(key);
83   bool isOK(PyDict_SetItem(_self,key,value)==0);
84   if(!isOK)
85     throw Exception("PickelizedPyObjServer::addKeyValueErrorIfAlreadyExisting : error when trying to add key,value to dict !");
86 }
87
88 void PickelizedPyObjServer::removeKeyInVarErrorIfNotAlreadyExisting(PyObject *key)
89 {
90   checkKeyPresent(key);
91   if(PyDict_DelItem(_self,key)!=0)
92     throw Exception("PickelizedPyObjServer::removeKeyInVarErrorIfNotAlreadyExisting : error during deletion of key in dict !");
93 }
94
95 void PickelizedPyObjServer::FromByteSeqToCpp(const SALOME::ByteVec& bsToBeConv, std::string& ret)
96 {
97   std::size_t sz(bsToBeConv.length());
98   ret.resize(sz,' ');
99   char *buf(const_cast<char *>(ret.c_str()));
100   for(std::size_t i=0;i<sz;i++)
101     buf[i]=bsToBeConv[i];
102 }
103
104 void PickelizedPyObjServer::FromCppToByteSeq(const std::string& strToBeConv, SALOME::ByteVec& ret)
105 {
106   const char *buf(strToBeConv.c_str());
107   std::size_t sz(strToBeConv.size());
108   ret.length(sz);
109   for(std::size_t i=0;i<sz;i++)
110     ret[i]=buf[i];
111 }
112
113 SALOME::ByteVec *PickelizedPyObjServer::FromCppToByteSeq(const std::string& strToBeConv)
114 {
115   SALOME::ByteVec *ret(new SALOME::ByteVec);
116   FromCppToByteSeq(strToBeConv,*ret);
117   return ret;
118 }
119
120 //! New reference returned
121 PyObject *PickelizedPyObjServer::GetPyObjFromPickled(const std::string& pickledData, DataScopeServerBase *dsb)
122 {
123   std::size_t sz(pickledData.size());
124   PyObject *pickledDataPy(PyString_FromStringAndSize(NULL,sz));// agy : do not use PyString_FromString because std::string hides a vector of byte.
125   char *buf(PyString_AsString(pickledDataPy));// this buf can be used thanks to python documentation.
126   const char *inBuf(pickledData.c_str());
127   std::copy(inBuf,inBuf+sz,buf);
128   PyObject *selfMeth(PyObject_GetAttrString(dsb->getPickler(),"loads"));
129   PyObject *args(PyTuple_New(1)); PyTuple_SetItem(args,0,pickledDataPy);
130   PyObject *ret(PyObject_CallObject(selfMeth,args));
131   Py_XDECREF(args);
132   Py_XDECREF(selfMeth);
133   return ret;
134 }
135
136 //! New reference returned
137 PyObject *PickelizedPyObjServer::getPyObjFromPickled(const std::string& pickledData)
138 {
139   return GetPyObjFromPickled(pickledData,_father);
140 }
141
142 //! New reference returned
143 PyObject *PickelizedPyObjServer::GetPyObjFromPickled(const std::vector<unsigned char>& pickledData, DataScopeServerBase *dsb)
144 {
145   std::size_t sz(pickledData.size());
146   PyObject *pickledDataPy(PyString_FromStringAndSize(NULL,sz));// agy : do not use PyString_FromString because std::string hides a vector of byte.
147   char *buf(PyString_AsString(pickledDataPy));// this buf can be used thanks to python documentation.
148   const unsigned char *inBuf(&pickledData[0]);
149   std::copy(inBuf,inBuf+sz,buf);
150   PyObject *selfMeth(PyObject_GetAttrString(dsb->getPickler(),"loads"));
151   PyObject *args(PyTuple_New(1)); PyTuple_SetItem(args,0,pickledDataPy);
152   PyObject *ret(PyObject_CallObject(selfMeth,args));
153   Py_XDECREF(args);
154   Py_XDECREF(selfMeth);
155   return ret;
156 }
157
158 //! New reference returned
159 PyObject *PickelizedPyObjServer::getPyObjFromPickled(const std::vector<unsigned char>& pickledData)
160 {
161   return GetPyObjFromPickled(pickledData,_father);
162 }
163
164 //! obj is consumed by this method.
165 std::string PickelizedPyObjServer::Pickelize(PyObject *obj, DataScopeServerBase *dsb)
166 {
167   PyObject *args(PyTuple_New(2));
168   PyTuple_SetItem(args,0,obj);
169   PyTuple_SetItem(args,1,PyInt_FromLong(2));// because "assert(cPickle.HIGHEST_PROTOCOL is 2)"
170   PyObject *selfMeth(PyObject_GetAttrString(dsb->getPickler(),"dumps"));
171   PyObject *retPy(PyObject_CallObject(selfMeth,args));
172   Py_XDECREF(selfMeth);
173   Py_XDECREF(args);
174   std::size_t sz(PyString_Size(retPy));
175   std::string ret(sz,'\0');
176   const char *buf(PyString_AsString(retPy));
177   char *inBuf(const_cast<char *>(ret.c_str()));
178   for(std::size_t i=0;i<sz;i++)
179     inBuf[i]=buf[i];
180   Py_XDECREF(retPy);
181   return ret;
182 }
183
184 //! obj is consumed by this method.
185 std::string PickelizedPyObjServer::pickelize(PyObject *obj)
186 {
187   return Pickelize(obj,_father);
188 }
189
190 //! obj is consumed by this method.
191 void PickelizedPyObjServer::setNewPyObj(PyObject *obj)
192 {
193   if(!obj)
194     throw Exception("PickelizedPyObjServer::setNewPyObj : trying to assign a NULL pyobject in this !");
195   if(obj==_self)
196     return ;
197   if(PyList_Check(obj)==0 && PyDict_Check(obj)==0 && PyTuple_Check(obj)==0 && PyString_Check(obj)==0 && PyInt_Check(obj)==0 && PyBool_Check(obj)==0 && PyFloat_Check(obj)==0 && obj!=Py_None)
198     throw Exception("PickelizedPyObjServer::setNewPyObj : Supported python types are [list,tuple,dict,str,int,bool,float,None] !");
199   if(_self)
200     {
201       PyObject *selfType(PyObject_Type(_self));
202       if(PyObject_IsInstance(obj,selfType)!=1)
203         {
204           Py_XDECREF(obj);
205           Py_XDECREF(selfType);
206           throw Exception("PickelizedPyObjServer::setNewPyObj : type of new object is not the same than those previously set !");
207         }
208       else
209         Py_XDECREF(selfType);
210     }
211   Py_XDECREF(_self);
212   _self=obj;
213 }
214
215 void PickelizedPyObjServer::setSerializedContentInternal(const SALOME::ByteVec& newValue)
216 {
217   std::string data;
218   FromByteSeqToCpp(newValue,data);
219   setNewPyObj(getPyObjFromPickled(data));
220 }
221
222 PyObject *PickelizedPyObjServer::CreateDftObjFromType(PyObject *globals, const std::string& typeName)
223 {
224   PyObject *builtins(PyDict_GetItemString(globals,"__builtins__"));
225   if(!builtins)
226     throw Exception("PickelizedPyObjServer constructor : no __builtins__ in globals !");
227   PyObject *builtins2(PyModule_GetDict(builtins));
228   if(!builtins2)
229     throw Exception("PickelizedPyObjServer constructor : internal error fail to invoke __dict__ on __builtins__ !");
230   PyObject *tmp(PyDict_GetItemString(builtins2,typeName.c_str()));
231   if(!tmp)
232     {
233       std::ostringstream oss; oss << "PickelizedPyObjServer::CreateDftObjFromType : Invalid type name \"" << typeName << "\" !";
234       throw Exception(oss.str());
235     }
236   PyObject *args(PyTuple_New(0));
237   PyObject *ret(PyObject_CallObject(tmp,args));
238   Py_XDECREF(args);
239   return ret;
240 }
241
242 void PickelizedPyObjServer::checkKeyPresence(PyObject *key, bool presence)
243 {
244   if(!isDict())
245     throw Exception("PickelizedPyObjServer::checkKeyPresence : not a dict !");
246   PyObject *selfMeth(PyObject_GetAttrString(_self,"__contains__"));//new ref
247   PyObject *args(PyTuple_New(1));
248   PyTuple_SetItem(args,0,key); Py_XINCREF(key);// key is stolen by PyTuple_SetItem
249   PyObject *retPy(PyObject_CallObject(selfMeth,args));
250   Py_XDECREF(args);
251   Py_XDECREF(selfMeth);
252   //
253   if(retPy!=Py_False && retPy!=Py_True)
254     throw Exception("PickelizedPyObjServer::checkKeyPresence : unexpected return of dict.__contains__ !");
255   if(!presence)
256     {
257       if(retPy==Py_True)
258         throw Exception("PickelizedPyObjServer::checkKeyPresence : key is already present and it should not !");
259     }
260   else
261     {
262       if(retPy==Py_False)
263         throw Exception("PickelizedPyObjServer::checkKeyPresence : key is not present and it should !");
264     }
265   Py_XDECREF(retPy);
266 }