diff --git a/.ci/install.sh b/.ci/install.sh index efc57a641..100424ee9 100755 --- a/.ci/install.sh +++ b/.ci/install.sh @@ -34,12 +34,10 @@ python3 -m pip install pyroma python3 -m pip install test-image-results python3 -m pip install numpy -# PyQt5 doesn't support PyPy3 +# PyQt6 doesn't support PyPy3 if [[ $GHA_PYTHON_VERSION == 3.* ]]; then - # arm64, ppc64le, s390x CPUs: - # "ERROR: Could not find a version that satisfies the requirement pyqt5" - sudo apt-get -qq install libxcb-xinerama0 pyqt5-dev-tools - python3 -m pip install pyqt5 + sudo apt-get -qq install libegl1 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxkbcommon-x11-0 + python3 -m pip install pyqt6 fi # webp diff --git a/Tests/test_deprecated_imageqt.py b/Tests/test_deprecated_imageqt.py new file mode 100644 index 000000000..2528ff3f7 --- /dev/null +++ b/Tests/test_deprecated_imageqt.py @@ -0,0 +1,18 @@ +import warnings + +with warnings.catch_warnings(record=True) as w: + # Arrange: cause all warnings to always be triggered + warnings.simplefilter("always") + + # Act: trigger a warning with Qt5 + from PIL import ImageQt + + +def test_deprecated(): + # Assert + if ImageQt.qt_version in ("5", "side2"): + assert len(w) == 1 + assert issubclass(w[0].category, DeprecationWarning) + assert "deprecated" in str(w[0].message) + else: + assert len(w) == 0 diff --git a/Tests/test_image_fromqimage.py b/Tests/test_image_fromqimage.py index 5ad5b5c3c..7fe992353 100644 --- a/Tests/test_image_fromqimage.py +++ b/Tests/test_image_fromqimage.py @@ -1,6 +1,12 @@ +import warnings + import pytest -from PIL import Image, ImageQt +from PIL import Image + +with warnings.catch_warnings(): + warnings.simplefilter("ignore", category=DeprecationWarning) + from PIL import ImageQt from .helper import assert_image_equal, hopper diff --git a/Tests/test_imageqt.py b/Tests/test_imageqt.py index a42240d49..2f2b07918 100644 --- a/Tests/test_imageqt.py +++ b/Tests/test_imageqt.py @@ -2,10 +2,13 @@ import warnings import pytest -from PIL import ImageQt - from .helper import assert_image_similar, hopper +with warnings.catch_warnings() as w: + warnings.simplefilter("ignore", category=DeprecationWarning) + from PIL import ImageQt + + pytestmark = pytest.mark.skipif( not ImageQt.qt_is_installed, reason="Qt bindings are not installed" ) diff --git a/Tests/test_qt_image_qapplication.py b/Tests/test_qt_image_qapplication.py index dec790c50..1fc816146 100644 --- a/Tests/test_qt_image_qapplication.py +++ b/Tests/test_qt_image_qapplication.py @@ -1,6 +1,10 @@ +import warnings + import pytest -from PIL import ImageQt +with warnings.catch_warnings(): + warnings.simplefilter("ignore", category=DeprecationWarning) + from PIL import ImageQt from .helper import assert_image_equal, assert_image_equal_tofile, hopper diff --git a/Tests/test_qt_image_toqimage.py b/Tests/test_qt_image_toqimage.py index 2a6b29abe..60bfaeb9b 100644 --- a/Tests/test_qt_image_toqimage.py +++ b/Tests/test_qt_image_toqimage.py @@ -1,6 +1,10 @@ +import warnings + import pytest -from PIL import ImageQt +with warnings.catch_warnings(): + warnings.simplefilter("ignore", category=DeprecationWarning) + from PIL import ImageQt from .helper import assert_image_equal, assert_image_equal_tofile, hopper diff --git a/docs/deprecations.rst b/docs/deprecations.rst index 496a4df95..69044c8c8 100644 --- a/docs/deprecations.rst +++ b/docs/deprecations.rst @@ -142,13 +142,6 @@ The stub image plugin ``FitsStubImagePlugin`` has been deprecated and will be re Pillow 10.0.0 (2023-07-01). FITS images can be read without a handler through :mod:`~PIL.FitsImagePlugin` instead. -PhotoImage.paste box parameter -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. deprecated:: 9.2.0 - -The ``box`` parameter is unused. It will be removed in Pillow 10.0.0 (2023-07-01). - FreeTypeFont.getmask2 fill parameter ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -157,6 +150,26 @@ FreeTypeFont.getmask2 fill parameter The undocumented ``fill`` parameter of :py:meth:`.FreeTypeFont.getmask2` has been deprecated and will be removed in Pillow 10 (2023-07-01). +PhotoImage.paste box parameter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. deprecated:: 9.2.0 + +The ``box`` parameter is unused. It will be removed in Pillow 10.0.0 (2023-07-01). + +PyQt5 and PySide2 +~~~~~~~~~~~~~~~~~ + +.. deprecated:: 9.2.0 + +`Qt 5 reached end-of-life `_ on 2020-12-08 for +open-source users (and will reach EOL on 2023-12-08 for commercial licence holders). + +Support for PyQt5 and PySide2 has been deprecated from ``ImageQt`` and will be removed +in Pillow 10 (2023-07-01). Upgrade to +`PyQt6 `_ or +`PySide6 `_ instead. + Removed features ---------------- diff --git a/docs/reference/ImageQt.rst b/docs/reference/ImageQt.rst index 66f5880a3..15d052d1c 100644 --- a/docs/reference/ImageQt.rst +++ b/docs/reference/ImageQt.rst @@ -7,6 +7,14 @@ The :py:mod:`~PIL.ImageQt` module contains support for creating PyQt6, PySide6, PyQt5 or PySide2 QImage objects from PIL images. +`Qt 5 reached end-of-life `_ on 2020-12-08 for +open-source users (and will reach EOL on 2023-12-08 for commercial licence holders). + +Support for PyQt5 and PySide2 has been deprecated from ``ImageQt`` and will be removed +in Pillow 10 (2023-07-01). Upgrade to +`PyQt6 `_ or +`PySide6 `_ instead. + .. versionadded:: 1.1.6 .. py:class:: ImageQt(image) diff --git a/docs/releasenotes/9.2.0.rst b/docs/releasenotes/9.2.0.rst index 35e8ca2d5..c38944b10 100644 --- a/docs/releasenotes/9.2.0.rst +++ b/docs/releasenotes/9.2.0.rst @@ -10,9 +10,24 @@ TODO Deprecations ============ +PyQt5 and PySide2 +^^^^^^^^^^^^^^^^^ + +.. deprecated:: 9.2.0 + +`Qt 5 reached end-of-life `_ on 2020-12-08 for +open-source users (and will reach EOL on 2023-12-08 for commercial licence holders). + +Support for PyQt5 and PySide2 has been deprecated from ``ImageQt`` and will be removed +in Pillow 10 (2023-07-01). Upgrade to +`PyQt6 `_ or +`PySide6 `_ instead. + FreeTypeFont.getmask2 fill parameter ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. deprecated:: 9.2.0 + The undocumented ``fill`` parameter of :py:meth:`.FreeTypeFont.getmask2` has been deprecated and will be removed in Pillow 10 (2023-07-01). diff --git a/src/PIL/ImageQt.py b/src/PIL/ImageQt.py index c8143d394..a34678c78 100644 --- a/src/PIL/ImageQt.py +++ b/src/PIL/ImageQt.py @@ -20,6 +20,7 @@ import sys from io import BytesIO from . import Image +from ._deprecate import deprecate from ._util import is_path qt_versions = [ @@ -42,9 +43,13 @@ for qt_version, qt_module in qt_versions: elif qt_module == "PyQt5": from PyQt5.QtCore import QBuffer, QIODevice from PyQt5.QtGui import QImage, QPixmap, qRgba + + deprecate("Support for PyQt5", 10, "PyQt6 or PySide6") elif qt_module == "PySide2": from PySide2.QtCore import QBuffer, QIODevice from PySide2.QtGui import QImage, QPixmap, qRgba + + deprecate("Support for PySide2", 10, "PyQt6 or PySide6") except (ImportError, RuntimeError): continue qt_is_installed = True