**************************** User Defined Type Conversion **************************** In the process of creating Python bindings of a C++ library, most of the C++ classes will have wrappers representing them in Python land. But there may be other classes that are very simple and/or have a Python type as a direct counter part. (Example: a "Complex" class, that represents complex numbers, has a Python equivalent in the "complex" type.) Such classes, instead of getting a Python wrapper, normally have conversions rules, from Python to C++ and vice-versa. .. code-block:: c++ // C++ class struct Complex { Complex(double real, double imag); double real() const; double imag() const; }; // Converting from C++ to Python using the CPython API: PyObject* pyCpxObj = PyComplex_FromDoubles(complex.real(), complex.imag()); // Converting from Python to C++: double real = PyComplex_RealAsDouble(pyCpxObj); double imag = PyComplex_ImagAsDouble(pyCpxObj); Complex cpx(real, imag); For the user defined conversion code to be inserted in the proper places, the "" tag must be used. .. code-block:: xml return PyComplex_FromDoubles(%in.real(), %in.imag()); double real = PyComplex_RealAsDouble(%in); double imag = PyComplex_ImagAsDouble(%in); %out = %OUTTYPE(real, imag); The details will be given later, but the gist of it are the tags :ref:`native-to-target `, which has only one conversion from C++ to Python, and :ref:`native-to-native `, that may define the conversion of multiple Python types to C++'s "Complex" type. .. image:: images/converter.png :height: 240px :align: center |project| expects the code for :ref:`native-to-target `, to directly return the Python result of the conversion, and the added conversions inside the :ref:`target-to-native ` must attribute the Python to C++ conversion result to the :ref:`%out ` variable. Expanding on the last example, if the binding developer want a Python 2-tuple of numbers to be accepted by wrapped C++ functions with "Complex" arguments, an :ref:`add-conversion ` tag and a custom check must be added. Here's how to do it: .. code-block:: xml static bool Check2TupleOfNumbers(PyObject* pyIn) { if (!PySequence_Check(pyIn) || !(PySequence_Size(pyIn) == 2)) return false; Shiboken::AutoDecRef pyReal(PySequence_GetItem(pyIn, 0)); if (!SbkNumber_Check(pyReal)) return false; Shiboken::AutoDecRef pyImag(PySequence_GetItem(pyIn, 1)); if (!SbkNumber_Check(pyImag)) return false; return true; } return PyComplex_FromDoubles(%in.real(), %in.imag()); double real = PyComplex_RealAsDouble(%in); double imag = PyComplex_ImagAsDouble(%in); %out = %OUTTYPE(real, imag); Shiboken::AutoDecRef pyReal(PySequence_GetItem(%in, 0)); Shiboken::AutoDecRef pyImag(PySequence_GetItem(%in, 1)); double real = %CONVERTTOCPP[double](pyReal); double imag = %CONVERTTOCPP[double](pyImag); %out = %OUTTYPE(real, imag); .. _container_conversions: Container Conversions ===================== Converters for :ref:`container-type ` are pretty much the same as for other type, except that they make use of the type system variables :ref:`%INTYPE_# ` and :ref:`%OUTTYPE_# `. |project| combines the conversion code for containers with the conversion defined (or automatically generated) for the containers. .. code-block:: xml PyObject* %out = PyDict_New(); %INTYPE::const_iterator it = %in.begin(); for (; it != %in.end(); ++it) { %INTYPE_0 key = it->first; %INTYPE_1 value = it->second; PyDict_SetItem(%out, %CONVERTTOPYTHON[%INTYPE_0](key), %CONVERTTOPYTHON[%INTYPE_1](value)); } return %out; PyObject* key; PyObject* value; Py_ssize_t pos = 0; while (PyDict_Next(%in, &pos, &key, &value)) { %OUTTYPE_0 cppKey = %CONVERTTOCPP[%OUTTYPE_0](key); %OUTTYPE_1 cppValue = %CONVERTTOCPP[%OUTTYPE_1](value); %out.insert(%OUTTYPE::value_type(cppKey, cppValue)); } .. _variables_and_functions: Variables & Functions ===================== .. _in: **%in** Variable replaced by the C++ input variable. .. _out: **%out** Variable replaced by the C++ output variable. Needed to convey the result of a Python to C++ conversion. .. _intype: **%INTYPE** Used in Python to C++ conversions. It is replaced by the name of type for which the conversion is being defined. Don't use the type's name directly. .. _intype_n: **%INTYPE_#** Replaced by the name of the #th type used in a container. .. _outtype: **%OUTTYPE** Used in Python to C++ conversions. It is replaced by the name of type for which the conversion is being defined. Don't use the type's name directly. .. _outtype_n: **%OUTTYPE_#** Replaced by the name of the #th type used in a container. .. _checktype: **%CHECKTYPE[CPPTYPE]** Replaced by a |project| type checking function for a Python variable. The C++ type is indicated by ``CPPTYPE``. .. _oldconverters: Converting The Old Converters ============================= If you use |project| for your bindings, and has defined some type conversions using the ``Shiboken::Converter`` template, then you must update your converters to the new scheme. Previously your conversion rules were declared in one line, like this: .. code-block:: xml And implemented in a separate C++ file, like this: .. code-block:: c++ namespace Shiboken { template<> struct Converter { static inline bool checkType(PyObject* pyObj) { return PyComplex_Check(pyObj); } static inline bool isConvertible(PyObject* pyObj) { return PyComplex_Check(pyObj); } static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast(cppobj)); } static inline PyObject* toPython(const Complex& cpx) { return PyComplex_FromDoubles(cpx.real(), cpx.imag()); } static inline Complex toCpp(PyObject* pyobj) { double real = PyComplex_RealAsDouble(pyobj); double imag = PyComplex_ImagAsDouble(pyobj); return Complex(real, imag); } }; } In this case, the parts of the implementation that will be used in the new conversion-rule are the ones in the two last method ``static inline PyObject* toPython(const Complex& cpx)`` and ``static inline Complex toCpp(PyObject* pyobj)``. The ``isConvertible`` method is gone, and the ``checkType`` is now an attribute of the :ref:`add-conversion ` tag. Refer back to the first example in this page and you will be able to correlate the above template with the new scheme of conversion rule definition.