diff --git a/Tests/test_image_access.py b/Tests/test_image_access.py index af229d1a713..c9db3aee730 100644 --- a/Tests/test_image_access.py +++ b/Tests/test_image_access.py @@ -232,11 +232,13 @@ def test_p_putpixel_rgb_rgba(self, mode, color): assert im.convert("RGBA").getpixel((0, 0)) == (255, 0, 0, alpha) +@pytest.mark.filterwarnings("ignore::DeprecationWarning") @pytest.mark.skipif(cffi is None, reason="No CFFI") class TestCffiPutPixel(TestImagePutPixel): _need_cffi_access = True +@pytest.mark.filterwarnings("ignore::DeprecationWarning") @pytest.mark.skipif(cffi is None, reason="No CFFI") class TestCffiGetPixel(TestImageGetPixel): _need_cffi_access = True @@ -252,7 +254,8 @@ def _test_get_access(self, im): Using private interfaces, forcing a capi access and a pyaccess for the same image""" caccess = im.im.pixel_access(False) - access = PyAccess.new(im, False) + with pytest.warns(DeprecationWarning): + access = PyAccess.new(im, False) w, h = im.size for x in range(0, w, 10): @@ -264,20 +267,16 @@ def _test_get_access(self, im): access[(access.xsize + 1, access.ysize + 1)] def test_get_vs_c(self): - rgb = hopper("RGB") - rgb.load() - self._test_get_access(rgb) - self._test_get_access(hopper("RGBA")) - self._test_get_access(hopper("L")) - self._test_get_access(hopper("LA")) - self._test_get_access(hopper("1")) - self._test_get_access(hopper("P")) - # self._test_get_access(hopper('PA')) # PA -- how do I make a PA image? - self._test_get_access(hopper("F")) + with pytest.warns(DeprecationWarning): + rgb = hopper("RGB") + rgb.load() + self._test_get_access(rgb) + for mode in ("RGBA", "L", "LA", "1", "P", "F"): + self._test_get_access(hopper(mode)) - for mode in ("I;16", "I;16L", "I;16B", "I;16N", "I"): - im = Image.new(mode, (10, 10), 40000) - self._test_get_access(im) + for mode in ("I;16", "I;16L", "I;16B", "I;16N", "I"): + im = Image.new(mode, (10, 10), 40000) + self._test_get_access(im) # These don't actually appear to be modes that I can actually make, # as unpack sets them directly into the I mode. @@ -292,7 +291,8 @@ def _test_set_access(self, im, color): Using private interfaces, forcing a capi access and a pyaccess for the same image""" caccess = im.im.pixel_access(False) - access = PyAccess.new(im, False) + with pytest.warns(DeprecationWarning): + access = PyAccess.new(im, False) w, h = im.size for x in range(0, w, 10): @@ -301,13 +301,15 @@ def _test_set_access(self, im, color): assert color == caccess[(x, y)] # Attempt to set the value on a read-only image - access = PyAccess.new(im, True) + with pytest.warns(DeprecationWarning): + access = PyAccess.new(im, True) with pytest.raises(ValueError): access[(0, 0)] = color def test_set_vs_c(self): rgb = hopper("RGB") - rgb.load() + with pytest.warns(DeprecationWarning): + rgb.load() self._test_set_access(rgb, (255, 128, 0)) self._test_set_access(hopper("RGBA"), (255, 192, 128, 0)) self._test_set_access(hopper("L"), 128) @@ -326,6 +328,7 @@ def test_set_vs_c(self): # im = Image.new('I;32B', (10, 10), 2**10) # self._test_set_access(im, 2**13-1) + @pytest.mark.filterwarnings("ignore::DeprecationWarning") def test_not_implemented(self): assert PyAccess.new(hopper("BGR;15")) is None @@ -335,7 +338,8 @@ def test_reference_counting(self): for _ in range(10): # Do not save references to the image, only to the access object - px = Image.new("L", (size, 1), 0).load() + with pytest.warns(DeprecationWarning): + px = Image.new("L", (size, 1), 0).load() for i in range(size): # pixels can contain garbage if image is released assert px[i, 0] == 0 @@ -344,12 +348,13 @@ def test_reference_counting(self): def test_p_putpixel_rgb_rgba(self, mode): for color in ((255, 0, 0), (255, 0, 0, 127 if mode == "PA" else 255)): im = Image.new(mode, (1, 1)) - access = PyAccess.new(im, False) - access.putpixel((0, 0), color) + with pytest.warns(DeprecationWarning): + access = PyAccess.new(im, False) + access.putpixel((0, 0), color) - if len(color) == 3: - color += (255,) - assert im.convert("RGBA").getpixel((0, 0)) == color + if len(color) == 3: + color += (255,) + assert im.convert("RGBA").getpixel((0, 0)) == color class TestImagePutPixelError(AccessTest): diff --git a/docs/deprecations.rst b/docs/deprecations.rst index 62687d869e8..ce956cadeff 100644 --- a/docs/deprecations.rst +++ b/docs/deprecations.rst @@ -22,6 +22,18 @@ be removed in Pillow 11 (2024-10-15). This class was only made as a helper to be used internally, so there is no replacement. If you need this functionality though, it is a very short class that can easily be recreated in your own code. +PyAccess and Image.USE_CFFI_ACCESS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. deprecated:: 10.0.0 + +Since Pillow's C API is now faster than PyAccess on PyPy, +:py:mod:`~PIL.PyAccess` has been deprecated and will be removed in Pillow +11.0.0 (2024-10-15). Pillow's C API will now be used by default on PyPy instead. + +``Image.USE_CFFI_ACCESS``, for switching from the C API to PyAccess, is +similarly deprecated. + Removed features ---------------- diff --git a/docs/releasenotes/10.0.0.rst b/docs/releasenotes/10.0.0.rst index b5edd0e361b..9b92e27d84f 100644 --- a/docs/releasenotes/10.0.0.rst +++ b/docs/releasenotes/10.0.0.rst @@ -124,6 +124,19 @@ Image.coerce_e This undocumented method has been removed. +Deprecations +============ + +PyAccess and Image.USE_CFFI_ACCESS +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Since Pillow's C API is now faster than PyAccess on PyPy, +:py:mod:`~PIL.PyAccess` has been deprecated and will be removed in Pillow +11.0.0 (2024-10-15). Pillow's C API will now be used by default on PyPy instead. + +``Image.USE_CFFI_ACCESS``, for switching from the C API to PyAccess, is +similarly deprecated. + API Changes =========== diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 400edcc5b67..0cc82cee349 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -107,8 +107,7 @@ class DecompressionBombError(Exception): raise -# works everywhere, win for pypy, not cpython -USE_CFFI_ACCESS = hasattr(sys, "pypy_version_info") +USE_CFFI_ACCESS = False try: import cffi except ImportError: diff --git a/src/PIL/PyAccess.py b/src/PIL/PyAccess.py index 39747b4f311..99b46a4a66c 100644 --- a/src/PIL/PyAccess.py +++ b/src/PIL/PyAccess.py @@ -22,6 +22,8 @@ import logging import sys +from ._deprecate import deprecate + try: from cffi import FFI @@ -47,6 +49,7 @@ class PyAccess: def __init__(self, img, readonly=False): + deprecate("PyAccess", 11) vals = dict(img.im.unsafe_ptrs) self.readonly = readonly self.image8 = ffi.cast("unsigned char **", vals["image8"])