/* * Get the address of an value that will be copied to an array slice. */ static void *get_slice(sipArrayObject *array, PyObject *value, SIP_SSIZE_T len) { sipArrayObject *other = (sipArrayObject *)value; if (!PyObject_IsInstance(value, (PyObject *)&sipArray_Type) || array->td != other->td || strcmp(array->format, other->format) != 0) { const char *type; if (array->td != NULL) { type = sipTypeName(array->td); } else { switch (*array->format) { case 'b': type = "char"; break; case 'B': type = "unsigned char"; break; case 'h': type = "short"; break; case 'H': type = "unsigned short"; break; case 'i': type = "int"; break; case 'I': type = "unsigned int"; break; case 'f': type = "float"; break; case 'd': type = "double"; break; default: type = ""; } } PyErr_Format(PyExc_TypeError, "can only assign another array of %s to the slice", type); return NULL; } if (other->len != len) { PyErr_Format(PyExc_TypeError, "the array being assigned must have length " SIP_SSIZE_T_FORMAT, len); return NULL; } if (other->stride == array->stride) { PyErr_Format(PyExc_TypeError, #if PY_VERSION_HEX >= 0x02050000 "the array being assigned must have stride %zu", array->stride); #else "the array being assigned must have stride %ld", (unsigned long)array->stride); #endif return NULL; }
// Parse the given Python type object. bool Chimera::parse_py_type(PyTypeObject *type_obj) { const sipTypeDef *td = sipTypeFromPyTypeObject(type_obj); if (td) { if (sipTypeIsNamespace(td)) return false; _type = td; _name = sipTypeName(td); if (sipTypeIsClass(td)) set_flag(); if (sipTypeIsEnum(td) || isFlag()) { _metatype = QMetaType::Int; } else { bool is_a_QObject = PyType_IsSubtype(type_obj, sipTypeAsPyTypeObject(sipType_QObject)); // If there is no assignment helper then assume it is a // pointer-type. if (!get_assign_helper()) _name.append('*'); _metatype = QMetaType::type(_name.constData()); // This will deal with cases where the registered type is a // super-class and specifically allows for multiple inheritance. // The problem we are solving is that we want a QGraphicsWidget to // be handled as a QGraphicsItem (which Qt registers) rather than a // QObject, specifically in the value passed as a QVariant to // QGraphicsItem::itemChange(). This solution means that it will // always be passed as a QGraphicsItem, even if there are // circumstances where it should be passed as a QObject. If we // come across such a circumstance then we may need to remove this // and implement a more specific solution in %MethodCode for the // various itemChange() implementations. if (_metatype == 0 && is_a_QObject) { PyObject *mro = type_obj->tp_mro; Q_ASSERT(PyTuple_Check(mro)); Q_ASSERT(PyTuple_GET_SIZE(mro) >= 3); for (SIP_SSIZE_T i = 1; i < PyTuple_GET_SIZE(mro) - 1; ++i) { PyTypeObject *sc = (PyTypeObject *)PyTuple_GET_ITEM(mro, i); if (sc == sipSimpleWrapper_Type || sc == sipWrapper_Type) continue; QByteArray sc_name(sc->tp_name); // QObjects are always pointers. sc_name.append('*'); _metatype = QMetaType::type(sc_name.constData()); if (_metatype >= QMetaType::User) { _type = sipTypeFromPyTypeObject(sc); _name = sc_name; _py_type = (PyObject *)sc; Py_INCREF(_py_type); return true; } } } // If it is a user type then it must be a type that SIP knows // about but was registered by Qt. if (_metatype < QMetaType::User) { if (sipType_QWidget && PyType_IsSubtype(type_obj, sipTypeAsPyTypeObject(sipType_QWidget))) { _metatype = QMetaType::QWidgetStar; } else if (is_a_QObject) { _metatype = QMetaType::QObjectStar; } else if (!sipIsExactWrappedType((sipWrapperType *)type_obj)) { // It must be a (non-QObject, non-QWidget) Python // sub-class so make sure it gets wrapped in a // PyQt_PyObject. _type = 0; _metatype = PyQt_PyObject::metatype; _name.clear(); } } } } #if PY_MAJOR_VERSION >= 3 else if (type_obj == &PyUnicode_Type) { _type = sipType_QString; _metatype = QMetaType::QString; } #else else if (type_obj == &PyString_Type || type_obj == &PyUnicode_Type) { // In this case we accept that the reverse conversion will result in an // object of a different type (i.e. a QString rather than a Python // string). _type = sipType_QString; _metatype = QMetaType::QString; } #endif else if (type_obj == &PyBool_Type) { _metatype = QMetaType::Bool; } #if PY_MAJOR_VERSION < 3 else if (type_obj == &PyInt_Type) { // We choose to map to a C++ int, even though a Python int is // potentially much larger, as it represents the most common usage in // Qt. However we will allow a larger type to be used if the context // is right. _metatype = QMetaType::Int; _inexact = true; } #endif else if (type_obj == &PyLong_Type) { // We choose to map to a C++ int for the same reasons as above and to // be consistent with Python3 where everything is a long object. If // this isn't appropriate the user can always use a string to specify // the exact C++ type they want. _metatype = QMetaType::Int; _inexact = true; } else if (type_obj == &PyFloat_Type) { _metatype = QMetaType::Double; } // Fallback to using a PyQt_PyObject. if (_metatype == QMetaType::Void) _metatype = PyQt_PyObject::metatype; // If there is no name so far then use the meta-type name. if (_name.isEmpty()) _name = QMetaType::typeName(_metatype); _py_type = (PyObject *)type_obj; Py_INCREF(_py_type); return true; }