예제 #1
0
/*
 * 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;
    }
예제 #2
0
// 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;
}