Potential Incompatibilities with Earlier Versions
=================================================

PyQt4 v4.11
-----------

Execution of Python Slots
*************************

Until the release of PyQt4 v4.9.4, when a signal was emitted to a Python slot
that was not decorated with :func:`~PyQt4.QtCore.pyqtSlot`, it would first
check that the underlying C++ receiver instance still existed.  If it didn't
then the slot was ignored thereby reflecting the standard C++ behaviour.

In v4.9.4 (strictly speaking it was the release of SIP at the time) the check
was removed. It was done so that an object could connect its
:func:`~PyQt4.QtCore.QObject.destroyed` signal to itself so that it could
monitor when its underlying C++ instance was destroyed.  Unfortunately this
turned out to be an undocumented and incompatible change and a potential source
of obscure bugs for more common code.

In v4.11 the check was reintroduced - hence creating an incompatibility for any
code that relies on the v4.9.4 behaviour.  As a workaround for this the
``no_receiver_check`` argument has been added to
:func:`~PyQt4.QtCore.QObject.connect` which allows the check to be suppressed
on a per connection basis.


PyQt4 v4.12
-----------

qSwap()
*******

The support for ``qSwap()`` has been removed from all modules.  Classes that
are supported by this function have a ``swap()`` method which can be used
instead.


PyQt4 v4.9.2
------------

QPyNullVariant
**************

In previous versions a ``QPyNullVariant`` would always evaluate to ``True``
when converted to a bool.

In this version a ``QPyNullVariant`` will always evaluate to ``False`` when
converted to a bool.  This makes it behave like ``None`` in these
circumstances.


PyQt4 v4.8.3
------------

SQL Models
**********

In previous versions, when using v2 of the QVariant API (the default for Python
v3), there was no way to represent a null ``QVariant``.  Therefore when reading
values of certain types from an SQL model it was impossible to distinguish
between, for example, a null integer and an integer with the value zero.

In this version the ``QPyNullVariant`` class is used to represent a null
QVariant.  Therefore the object read from an SQL model may now be a
``QPyNullVariant`` instance.

A null ``QVariant`` is only converted to a ``QPyNullVariant`` if the underlying
C++ type of the ``QVariant`` cannot be tested for null, i.e. it does not
implement an ``isNull()`` method.  This ensures that existing code that uses
non-SQL models will continue to work unchanged.


PyQt4 v4.8
----------

QVariantList
************

In previous versions PyQt4 would always try and convert a Python list to a
``QVariantList``.  In this version PyQt4 will first try to convert it to a
``QVariant`` containing a ``QList<QObject *>``, but only if
``QList<QObject *>`` has been registered with Qt as a meta-type.

Normally it is only the :mod:`~PyQt4.QtDeclarative` module that registers this
meta-type and so the behaviour of existing applications should be unchanged.
It is possible however that you might observe different conversion behaviour
after importing the :mod:`~PyQt4.QtDeclarative` module.


PyQt4 v4.7.4
------------

:func:`~PyQt4.QtCore.pyqtSignal` with dict and list
***************************************************

In previous versions a Qt signal defined using
:func:`~PyQt4.QtCore.pyqtSignal` that had an argument specified as a dict then,
when emitting a value, PyQt4 would try and convert the value to a
``QVariantMap`` if possible.  If it wasn't possible, normally because the dict
had non-string keys, then the value would be left as a dict object.

In this version PyQt4 will not attempt to convert the value to a
``QVariantMap`` and will always leave it as a dict object.  If you want the
value to be converted to a ``QVariantMap`` then define the signal argument as
``'QVariantMap'``.

The same applies to conversions between lists and ``QVariantList``.


PyQt4 v4.7.1
------------

QVariant
********

This version introduces a slight incompatibility in the conversion between
sub-classes of standard Python types and ``QVariant``.

Take, for example, the following code::

    from PyQt4.QtCore import QVariant

    class MyFloat(float):
        pass

    myfloat = MyFloat(5.0)
    variant = QVariant(myfloat)

With this version of PyQt4 ``myfloat`` will be converted in such a way as to
preserve any additional attributes (including methods) and will not be
converted to a C++ ``double``.  In other words, the following assertions are
true::

    assert(variant.type() != QVariant.Double)
    assert(variant.toPyObject() is myfloat)

Prior to this version ``myfloat`` would be converted to a C++ ``double``.  In
other words, the following assertions would be true::

    assert(variant.type() == QVariant.Double)
    assert(variant.toPyObject() == myfloat)
    assert(type(variant.toPyObject()) is float)

The same change also affects objects that implement the sequence protocol.
Prior to this version such an object would be converted to a ``QVariantList``
which would mean that it was converted back to a Python ``list`` rather than to
the original type.


PyQt4 v4.5
----------

QVariant
********

This version introduces a slight incompatibility in the conversion between
Python sub-classes of certain Qt classes and ``QVariant``.  The Qt classes
affected are those that ``QVariant`` has explicit support for, e.g. ``QSize``,
``QBitmap``.

Take, for example, the following code::

    from PyQt4.QtCore import QSize, QVariant

    class MySize(QSize):
        pass

    mysize = MySize(5, 5)
    variant = QVariant(mysize)

With this version of PyQt4 ``mysize`` will be converted in such a way as to
preserve any additional attributes (including methods) and will not be
converted to a C++ ``QSize`` instance.  In other words, the following
assertions are true::

    assert(variant.type() != QVariant.Size)
    assert(variant.toPyObject() is mysize)

Prior to this version ``mysize`` would be converted to a C++ ``QSize``
instance.  In other words, the following assertions would be true::

    assert(variant.type() == QVariant.Size)
    assert(variant.toPyObject() == mysize)
    assert(type(variant.toPyObject()) is QSize)

It is hoped that this change of behaviour will not have a significant impact.
However if you need the old behaviour then simply create a copy of your
sub-class instance using the base class constructor as shown below::

    variant = QVariant(QSize(mysize))

A similar issue also affects the conversion of the Python ``datetime``,
``date`` and ``time`` types to ``QVariant``.  These are no longer converted to
the corresponding ``QDateTime``, ``QDate`` and ``QTime`` classes.  The values
can be retrieved using ``QVariant.toPyObject()``.  Again, the old behaviour can
be achieved using an explicit conversion to the Qt class before converting to
``QVariant``.

A further incompatible change is the handling of Python sub-classes of
``QObject``.  In previous versions ``QVariant.userType()`` would return an
internal type and an extra reference would be kept to the Python object.  In
the current version ``QVariant.userType()`` will correctly return
``QMetaType.QObjectStar`` (or ``QMetaType.QWidgetStar``) but an extra
reference to the Python object is not kept.  To avoid a potential crash you
should ensure that you keep a separate reference to the Python object, either
explicitly or implicitly by giving it a parent.


:program:`pyrcc4` Support for Python v3
***************************************

:program:`pyrcc4` will now generate code for Python v3 when the new
:option:`-py3 <pyrcc4 -py3>` command line option is used.  The generated code
will also work with Python v2.6 and later.

By default :program:`pyrcc4` will generate code for all Python v2 versions but
you should use the new :option:`-py2 <pyrcc4 -py2>` command line option to
enforce this in case the default is changed in the future.
