1**************************** 2User Defined Type Conversion 3**************************** 4 5In the process of creating Python bindings of a C++ library, most of the C++ 6classes will have wrappers representing them in Python land. 7But there may be other classes that are very simple and/or have a Python type 8as a direct counter part. (Example: a "Complex" class, that represents complex 9numbers, has a Python equivalent in the "complex" type.) Such classes, instead 10of getting a Python wrapper, normally have conversions rules, from Python to 11C++ and vice-versa. 12 13 .. code-block:: c++ 14 15 // C++ class 16 struct Complex { 17 Complex(double real, double imag); 18 double real() const; 19 double imag() const; 20 }; 21 22 // Converting from C++ to Python using the CPython API: 23 PyObject* pyCpxObj = PyComplex_FromDoubles(complex.real(), complex.imag()); 24 25 // Converting from Python to C++: 26 double real = PyComplex_RealAsDouble(pyCpxObj); 27 double imag = PyComplex_ImagAsDouble(pyCpxObj); 28 Complex cpx(real, imag); 29 30 31For the user defined conversion code to be inserted in the proper places, 32the "<conversion-rule>" tag must be used. 33 34 .. code-block:: xml 35 36 <primitive-type name="Complex" target-lang-api-name="PyComplex"> 37 <include file-name="complex.h" location="global"/> 38 39 <conversion-rule> 40 41 <native-to-target> 42 return PyComplex_FromDoubles(%in.real(), %in.imag()); 43 </native-to-target> 44 45 <target-to-native> 46 <!-- The 'check' attribute can be derived from the 'type' attribute, 47 it is defined here to test the CHECKTYPE type system variable. --> 48 <add-conversion type="PyComplex" check="%CHECKTYPE[Complex](%in)"> 49 double real = PyComplex_RealAsDouble(%in); 50 double imag = PyComplex_ImagAsDouble(%in); 51 %out = %OUTTYPE(real, imag); 52 </add-conversion> 53 </target-to-native> 54 55 </conversion-rule> 56 57 </primitive-type> 58 59 60The details will be given later, but the gist of it are the tags 61:ref:`native-to-target <native-to-target>`, which has only one conversion from C++ to Python, and 62:ref:`native-to-native <target-to-native>`, that may define the conversion of multiple Python types 63to C++'s "Complex" type. 64 65.. image:: images/converter.png 66 :height: 240px 67 :align: center 68 69|project| expects the code for :ref:`native-to-target <native-to-target>`, to directly return the 70Python result of the conversion, and the added conversions inside the 71:ref:`target-to-native <target-to-native>` must attribute the Python to C++ conversion result to 72the :ref:`%out <out>` variable. 73 74Expanding on the last example, if the binding developer want a Python 2-tuple 75of numbers to be accepted by wrapped C++ functions with "Complex" arguments, 76an :ref:`add-conversion <add-conversion>` tag and a custom check must be added. 77Here's how to do it: 78 79 .. code-block:: xml 80 81 <!-- Code injection at module level. --> 82 <inject-code class="native" position="beginning"> 83 static bool Check2TupleOfNumbers(PyObject* pyIn) { 84 if (!PySequence_Check(pyIn) || !(PySequence_Size(pyIn) == 2)) 85 return false; 86 Shiboken::AutoDecRef pyReal(PySequence_GetItem(pyIn, 0)); 87 if (!SbkNumber_Check(pyReal)) 88 return false; 89 Shiboken::AutoDecRef pyImag(PySequence_GetItem(pyIn, 1)); 90 if (!SbkNumber_Check(pyImag)) 91 return false; 92 return true; 93 } 94 </inject-code> 95 96 <primitive-type name="Complex" target-lang-api-name="PyComplex"> 97 <include file-name="complex.h" location="global"/> 98 99 <conversion-rule> 100 101 <native-to-target> 102 return PyComplex_FromDoubles(%in.real(), %in.imag()); 103 </native-to-target> 104 105 <target-to-native> 106 107 <add-conversion type="PyComplex"> 108 double real = PyComplex_RealAsDouble(%in); 109 double imag = PyComplex_ImagAsDouble(%in); 110 %out = %OUTTYPE(real, imag); 111 </add-conversion> 112 113 <add-conversion type="PySequence" check="Check2TupleOfNumbers(%in)"> 114 Shiboken::AutoDecRef pyReal(PySequence_GetItem(%in, 0)); 115 Shiboken::AutoDecRef pyImag(PySequence_GetItem(%in, 1)); 116 double real = %CONVERTTOCPP[double](pyReal); 117 double imag = %CONVERTTOCPP[double](pyImag); 118 %out = %OUTTYPE(real, imag); 119 </add-conversion> 120 121 </target-to-native> 122 123 </conversion-rule> 124 125 </primitive-type> 126 127 128.. _container_conversions: 129 130Container Conversions 131===================== 132 133Converters for :ref:`container-type <container-type>` are pretty much the same as for other type, 134except that they make use of the type system variables 135:ref:`%INTYPE_# <intype_n>` and :ref:`%OUTTYPE_# <outtype_n>`. 136|project| combines the conversion code for containers with the conversion 137defined (or automatically generated) for the containers. 138 139 .. code-block:: xml 140 141 <container-type name="std::map" type="map"> 142 <include file-name="map" location="global"/> 143 144 <conversion-rule> 145 146 <native-to-target> 147 PyObject* %out = PyDict_New(); 148 %INTYPE::const_iterator it = %in.begin(); 149 for (; it != %in.end(); ++it) { 150 %INTYPE_0 key = it->first; 151 %INTYPE_1 value = it->second; 152 PyDict_SetItem(%out, 153 %CONVERTTOPYTHON[%INTYPE_0](key), 154 %CONVERTTOPYTHON[%INTYPE_1](value)); 155 } 156 return %out; 157 </native-to-target> 158 159 <target-to-native> 160 161 <add-conversion type="PyDict"> 162 PyObject* key; 163 PyObject* value; 164 Py_ssize_t pos = 0; 165 while (PyDict_Next(%in, &pos, &key, &value)) { 166 %OUTTYPE_0 cppKey = %CONVERTTOCPP[%OUTTYPE_0](key); 167 %OUTTYPE_1 cppValue = %CONVERTTOCPP[%OUTTYPE_1](value); 168 %out.insert(%OUTTYPE::value_type(cppKey, cppValue)); 169 } 170 </add-conversion> 171 172 </target-to-native> 173 </conversion-rule> 174 </container-type> 175 176 177.. _variables_and_functions: 178 179Variables & Functions 180===================== 181 182 183.. _in: 184 185**%in** 186 187 Variable replaced by the C++ input variable. 188 189 190.. _out: 191 192**%out** 193 194 Variable replaced by the C++ output variable. Needed to convey the 195 result of a Python to C++ conversion. 196 197 198.. _intype: 199 200**%INTYPE** 201 202 Used in Python to C++ conversions. It is replaced by the name of type for 203 which the conversion is being defined. Don't use the type's name directly. 204 205 206.. _intype_n: 207 208**%INTYPE_#** 209 210 Replaced by the name of the #th type used in a container. 211 212 213.. _outtype: 214 215**%OUTTYPE** 216 217 Used in Python to C++ conversions. It is replaced by the name of type for 218 which the conversion is being defined. Don't use the type's name directly. 219 220 221.. _outtype_n: 222 223**%OUTTYPE_#** 224 225 Replaced by the name of the #th type used in a container. 226 227 228.. _checktype: 229 230**%CHECKTYPE[CPPTYPE]** 231 232 Replaced by a |project| type checking function for a Python variable. 233 The C++ type is indicated by ``CPPTYPE``. 234 235 236.. _oldconverters: 237 238Converting The Old Converters 239============================= 240 241If you use |project| for your bindings, and has defined some type conversions 242using the ``Shiboken::Converter`` template, then you must update your converters 243to the new scheme. 244 245Previously your conversion rules were declared in one line, like this: 246 247 248 .. code-block:: xml 249 250 <primitive-type name="Complex" target-lang-api-name="PyComplex"> 251 <include file-name="complex.h" location="global"/> 252 <conversion-rule file="complex_conversions.h"/> 253 </primitive-type> 254 255 256And implemented in a separate C++ file, like this: 257 258 259 .. code-block:: c++ 260 261 namespace Shiboken { 262 template<> struct Converter<Complex> 263 { 264 static inline bool checkType(PyObject* pyObj) { 265 return PyComplex_Check(pyObj); 266 } 267 static inline bool isConvertible(PyObject* pyObj) { 268 return PyComplex_Check(pyObj); 269 } 270 static inline PyObject* toPython(void* cppobj) { 271 return toPython(*reinterpret_cast<Complex*>(cppobj)); 272 } 273 static inline PyObject* toPython(const Complex& cpx) { 274 return PyComplex_FromDoubles(cpx.real(), cpx.imag()); 275 } 276 static inline Complex toCpp(PyObject* pyobj) { 277 double real = PyComplex_RealAsDouble(pyobj); 278 double imag = PyComplex_ImagAsDouble(pyobj); 279 return Complex(real, imag); 280 } 281 }; 282 } 283 284 285In this case, the parts of the implementation that will be used in the new 286conversion-rule are the ones in the two last method 287``static inline PyObject* toPython(const Complex& cpx)`` and 288``static inline Complex toCpp(PyObject* pyobj)``. The ``isConvertible`` method 289is gone, and the ``checkType`` is now an attribute of the :ref:`add-conversion <add-conversion>` 290tag. Refer back to the first example in this page and you will be able to 291correlate the above template with the new scheme of conversion rule definition. 292