// Serialise operator. QDataStream &operator<<(QDataStream &out, const PyQt_PyObject &obj) { PyObject *ser_obj = 0; const char *ser = 0; uint len = 0; if (obj.pyobject) { static PyObject *dumps = 0; SIP_BLOCK_THREADS if (!dumps) { PyObject *pickle = PyImport_ImportModule("pickle"); if (pickle) { dumps = PyObject_GetAttrString(pickle, "dumps"); Py_DECREF(pickle); } } if (dumps) { ser_obj = PyObject_CallFunctionObjArgs(dumps, obj.pyobject, 0); if (ser_obj) { if (SIPBytes_Check(ser_obj)) { ser = SIPBytes_AS_STRING(ser_obj); len = SIPBytes_GET_SIZE(ser_obj); } else { Py_DECREF(ser_obj); ser_obj = 0; } } else { PyErr_Print(); } } SIP_UNBLOCK_THREADS } out.writeBytes(ser, len); if (ser_obj) { SIP_BLOCK_THREADS Py_DECREF(ser_obj); SIP_UNBLOCK_THREADS } return out; }
// Convert a Python object to a QVariant. bool Chimera::fromPyObject(PyObject *py, QVariant *var, bool strict) const { // Deal with the simple case of wrapping the Python object rather than // converting it. if (_type != sipType_QVariant && _metatype == PyQt_PyObject::metatype) { // If the type was specified by a Python type (as opposed to // 'PyQt_PyObject') then check the object is an instance of it. if (_py_type && !PyObject_IsInstance(py, _py_type)) return false; *var = keep_as_pyobject(py); return true; } // Let any registered convertors have a go first. for (int i = 0; i < _registered_QVariant_convertors.count(); ++i) { bool ok; if (_registered_QVariant_convertors.at(i)(py, var, &ok)) return ok; } int iserr = 0, value_class_state; void *ptr_class, *value_class = 0; // Temporary storage for different types. union { bool tmp_bool; int tmp_int; unsigned int tmp_unsigned_int; double tmp_double; void *tmp_void_ptr; long tmp_long; qlonglong tmp_qlonglong; short tmp_short; char tmp_char; unsigned long tmp_unsigned_long; qulonglong tmp_qulonglong; unsigned short tmp_unsigned_short; unsigned char tmp_unsigned_char; float tmp_float; } tmp_storage; void *variant_data = &tmp_storage; PyErr_Clear(); QVariant variant; int metatype_used = _metatype; switch (_metatype) { case QMetaType::Bool: tmp_storage.tmp_bool = PyLong_AsLong(py); break; case QMetaType::Int: if (!_inexact || isEnum() || isFlag()) { // It must fit into a C++ int. #if PY_MAJOR_VERSION >= 3 tmp_storage.tmp_int = PyLong_AsLong(py); #else tmp_storage.tmp_int = PyInt_AsLong(py); #endif } else { // Fit it into the smallest C++ type we can. qlonglong qll = PyLong_AsLongLong(py); if (PyErr_Occurred()) { // Try again in case the value is unsigned and will fit with // the extra bit. PyErr_Clear(); qulonglong qull = static_cast<qulonglong>(PyLong_AsUnsignedLongLong(py)); if (PyErr_Occurred()) { // It won't fit into any C++ type so pass it as a Python // object. PyErr_Clear(); *var = keep_as_pyobject(py); metatype_used = QMetaType::Void; } else { tmp_storage.tmp_qulonglong = qull; metatype_used = QMetaType::ULongLong; } } else if ((qlonglong)(int)qll == qll) { // It fits in a C++ int. tmp_storage.tmp_int = qll; } else if ((qulonglong)(unsigned int)qll == (qulonglong)qll) { // The extra bit is enough for it to fit. tmp_storage.tmp_unsigned_int = qll; metatype_used = QMetaType::UInt; } else { // This fits. tmp_storage.tmp_qlonglong = qll; metatype_used = QMetaType::LongLong; } } break; case QMetaType::UInt: tmp_storage.tmp_unsigned_int = sipLong_AsUnsignedLong(py); break; case QMetaType::Double: tmp_storage.tmp_double = PyFloat_AsDouble(py); break; case QMetaType::VoidStar: tmp_storage.tmp_void_ptr = sipConvertToVoidPtr(py); break; case QMetaType::Long: tmp_storage.tmp_long = PyLong_AsLong(py); break; case QMetaType::LongLong: tmp_storage.tmp_qlonglong = PyLong_AsLongLong(py); break; case QMetaType::Short: tmp_storage.tmp_short = PyLong_AsLong(py); break; case QMetaType::Char: if (SIPBytes_Check(py) && SIPBytes_GET_SIZE(py) == 1) tmp_storage.tmp_char = *SIPBytes_AS_STRING(py); else iserr = 1; break; case QMetaType::ULong: tmp_storage.tmp_unsigned_long = sipLong_AsUnsignedLong(py); break; case QMetaType::ULongLong: tmp_storage.tmp_qulonglong = static_cast<qulonglong>(PyLong_AsUnsignedLongLong(py)); break; case QMetaType::UShort: tmp_storage.tmp_unsigned_short = sipLong_AsUnsignedLong(py); break; case QMetaType::UChar: if (SIPBytes_Check(py) && SIPBytes_GET_SIZE(py) == 1) tmp_storage.tmp_unsigned_char = *SIPBytes_AS_STRING(py); else iserr = 1; break; case QMetaType::Float: tmp_storage.tmp_float = PyFloat_AsDouble(py); break; case QMetaType::QObjectStar: tmp_storage.tmp_void_ptr = sipForceConvertToType(py, sipType_QObject, 0, SIP_NO_CONVERTORS, 0, &iserr); break; case QMetaType::QWidgetStar: if (sipType_QWidget) { tmp_storage.tmp_void_ptr = sipForceConvertToType(py, sipType_QWidget, 0, SIP_NO_CONVERTORS, 0, &iserr); } else { iserr = 1; } break; case QMetaType::QVariantList: { QVariantList ql; if (to_QVariantList(py, ql)) { *var = QVariant(ql); metatype_used = QMetaType::Void; } else { iserr = 1; } break; } case QMetaType::QVariantMap: { QVariantMap qm; if (to_QVariantMap(py, qm)) { *var = QVariant(qm); metatype_used = QMetaType::Void; } else if (strict) { iserr = 1; } else { // Assume the failure is because the key was the wrong type. PyErr_Clear(); *var = keep_as_pyobject(py); metatype_used = QMetaType::Void; } break; } #if QT_VERSION >= 0x040500 case QMetaType::QVariantHash: { QVariantHash qh; if (to_QVariantHash(py, qh)) { *var = QVariant(qh); metatype_used = QMetaType::Void; } else { iserr = 1; } break; } #endif case -1: metatype_used = QMetaType::VoidStar; if (SIPBytes_Check(py)) tmp_storage.tmp_void_ptr = SIPBytes_AS_STRING(py); else if (py == Py_None) tmp_storage.tmp_void_ptr = 0; else iserr = 1; break; default: if (_type) { if (_name.endsWith('*')) { ptr_class = sipForceConvertToType(py, _type, 0, SIP_NO_CONVERTORS, 0, &iserr); variant_data = &ptr_class; } else { value_class = sipForceConvertToType(py, _type, 0, SIP_NOT_NONE, &value_class_state, &iserr); variant_data = value_class; } } else { // This is a class we don't recognise. iserr = 1; } } if (iserr || PyErr_Occurred()) { PyErr_Format(PyExc_TypeError, "unable to convert a Python '%s' object to a C++ '%s' instance", Py_TYPE(py)->tp_name, _name.constData()); iserr = 1; } else if (_type == sipType_QVariant) { *var = QVariant(*reinterpret_cast<QVariant *>(variant_data)); } else if (metatype_used != QMetaType::Void) { *var = QVariant(metatype_used, variant_data); } // Release any temporary value-class instance now that QVariant will have // made a copy. if (value_class) sipReleaseType(value_class, _type, value_class_state); return (iserr == 0); }
// Convert a Python object to C++ at a given address. This has a lot in common // with the method that converts to a QVariant. However, unlike that method, // we have no control over the size of the destination storage and so must // convert exactly as requested. bool Chimera::fromPyObject(PyObject *py, void *cpp) const { // Let any registered convertors have a go first. for (int i = 0; i < _registered_QVariant_data_convertors.count(); ++i) { bool ok; if (_registered_QVariant_data_convertors.at(i)(py, cpp, _metatype, &ok)) return ok; } int iserr = 0; PyErr_Clear(); switch (_metatype) { case QMetaType::Bool: *reinterpret_cast<bool *>(cpp) = PyLong_AsLong(py); break; case QMetaType::Int: // Truncate it if necessary to fit into a C++ int. This will // automatically handle enums and flag types as Python knows how to // convert them to ints. #if PY_MAJOR_VERSION >= 3 *reinterpret_cast<int *>(cpp) = PyLong_AsLong(py); #else *reinterpret_cast<int *>(cpp) = PyInt_AsLong(py); #endif break; case QMetaType::UInt: *reinterpret_cast<unsigned int *>(cpp) = sipLong_AsUnsignedLong(py); break; case QMetaType::Double: *reinterpret_cast<double *>(cpp) = PyFloat_AsDouble(py); break; case QMetaType::VoidStar: *reinterpret_cast<void **>(cpp) = sipConvertToVoidPtr(py); break; case QMetaType::Long: *reinterpret_cast<long *>(cpp) = PyLong_AsLong(py); break; case QMetaType::LongLong: *reinterpret_cast<qlonglong *>(cpp) = PyLong_AsLongLong(py); break; case QMetaType::Short: *reinterpret_cast<short *>(cpp) = PyLong_AsLong(py); break; case QMetaType::Char: if (SIPBytes_Check(py) && SIPBytes_GET_SIZE(py) == 1) *reinterpret_cast<char *>(cpp) = *SIPBytes_AS_STRING(py); else iserr = 1; break; case QMetaType::ULong: *reinterpret_cast<unsigned long *>(cpp) = sipLong_AsUnsignedLong(py); break; case QMetaType::ULongLong: *reinterpret_cast<qulonglong *>(cpp) = static_cast<qulonglong>(PyLong_AsUnsignedLongLong(py)); break; case QMetaType::UShort: *reinterpret_cast<unsigned short *>(cpp) = sipLong_AsUnsignedLong(py); break; case QMetaType::UChar: if (SIPBytes_Check(py) && SIPBytes_GET_SIZE(py) == 1) *reinterpret_cast<unsigned char *>(cpp) = *SIPBytes_AS_STRING(py); else iserr = 1; break; case QMetaType::Float: *reinterpret_cast<float *>(cpp) = PyFloat_AsDouble(py); break; case QMetaType::QObjectStar: *reinterpret_cast<void **>(cpp) = sipForceConvertToType(py, sipType_QObject, 0, SIP_NO_CONVERTORS, 0, &iserr); break; case QMetaType::QWidgetStar: if (sipType_QWidget) { *reinterpret_cast<void **>(cpp) = sipForceConvertToType(py, sipType_QWidget, 0, SIP_NO_CONVERTORS, 0, &iserr); } else { iserr = 1; } break; case QMetaType::QVariantList: { QVariantList ql; if (to_QVariantList(py, ql)) *reinterpret_cast<QVariantList *>(cpp) = ql; else iserr = 1; break; } case QMetaType::QVariantMap: { QVariantMap qm; if (to_QVariantMap(py, qm)) *reinterpret_cast<QVariantMap *>(cpp) = qm; else iserr = 1; break; } #if QT_VERSION >= 0x040500 case QMetaType::QVariantHash: { QVariantHash qh; if (to_QVariantHash(py, qh)) *reinterpret_cast<QVariantHash *>(cpp) = qh; else iserr = 1; break; } #endif case -1: { char **ptr = reinterpret_cast<char **>(cpp); if (SIPBytes_Check(py)) *ptr = SIPBytes_AS_STRING(py); else if (py == Py_None) *ptr = 0; else iserr = 1; break; } default: if (_type) { if (_name.endsWith('*')) { // This must be a pointer-type. *reinterpret_cast<void **>(cpp) = sipForceConvertToType(py, _type, 0, SIP_NO_CONVERTORS, 0, &iserr); } else { // This must be a value-type. sipAssignFunc assign = get_assign_helper(); if (assign) { int state; void *value_class; value_class = sipForceConvertToType(py, _type, 0, SIP_NOT_NONE, &state, &iserr); if (!iserr) assign(cpp, 0, value_class); sipReleaseType(value_class, _type, state); } else { iserr = 1; } } } else { iserr = 1; } } if (iserr || PyErr_Occurred()) { PyErr_Format(PyExc_TypeError, "unable to convert a Python '%s' object to a C++ '%s' instance", Py_TYPE(py)->tp_name, _name.constData()); return false; } return true; }