From f854d7f7c98c512c81d8b36b75d079260a14c1d4 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Fri, 22 Apr 2022 12:06:20 +0300 Subject: [PATCH 1/4] Deprecate support for Qt 5 (PyQt5 and PySide2). Use Qt 6 (PyQt6 or PySide6) instead. --- Tests/test_image_fromqimage.py | 8 +++++++- Tests/test_imageqt.py | 7 +++++-- Tests/test_imageqt_deprecated.py | 18 ++++++++++++++++++ Tests/test_qt_image_qapplication.py | 6 +++++- Tests/test_qt_image_toqimage.py | 6 +++++- docs/deprecations.rst | 27 ++++++++++++++++++++------- docs/reference/ImageQt.rst | 8 ++++++++ docs/releasenotes/9.2.0.rst | 15 +++++++++++++++ src/PIL/ImageQt.py | 5 +++++ 9 files changed, 88 insertions(+), 12 deletions(-) create mode 100644 Tests/test_imageqt_deprecated.py 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..d6de69dd5 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("always", 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_imageqt_deprecated.py b/Tests/test_imageqt_deprecated.py new file mode 100644 index 000000000..2662995f7 --- /dev/null +++ b/Tests/test_imageqt_deprecated.py @@ -0,0 +1,18 @@ +import warnings + + +def test_deprecated(): + 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 + + # 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_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 From 40711f9edb20f9f2034cade8bb2ae94bbe84b4ac Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 23 Apr 2022 08:01:02 +1000 Subject: [PATCH 2/4] Run deprecated import check before imports from other tests --- Tests/test_deprecated_imageqt.py | 18 ++++++++++++++++++ Tests/test_imageqt_deprecated.py | 18 ------------------ 2 files changed, 18 insertions(+), 18 deletions(-) create mode 100644 Tests/test_deprecated_imageqt.py delete mode 100644 Tests/test_imageqt_deprecated.py 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_imageqt_deprecated.py b/Tests/test_imageqt_deprecated.py deleted file mode 100644 index 2662995f7..000000000 --- a/Tests/test_imageqt_deprecated.py +++ /dev/null @@ -1,18 +0,0 @@ -import warnings - - -def test_deprecated(): - 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 - - # 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 From 47cf0296c3a1ad444bfda9a7f431887661b72b14 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 23 Apr 2022 10:22:29 +1000 Subject: [PATCH 3/4] Updated to PyQt6 --- .ci/install.sh | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) 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 From 889ceedfb98d9db07eb044c4b43f181815b6f9a7 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sun, 24 Apr 2022 08:28:21 +0300 Subject: [PATCH 4/4] Ignore warning Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com> --- Tests/test_imageqt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/test_imageqt.py b/Tests/test_imageqt.py index d6de69dd5..2f2b07918 100644 --- a/Tests/test_imageqt.py +++ b/Tests/test_imageqt.py @@ -5,7 +5,7 @@ import pytest from .helper import assert_image_similar, hopper with warnings.catch_warnings() as w: - warnings.simplefilter("always", category=DeprecationWarning) + warnings.simplefilter("ignore", category=DeprecationWarning) from PIL import ImageQt