Skip to content

Commit 43cc1e3

Browse files
committed
Removed PyAccess and Image.USE_CFFI_ACCESS
1 parent eb5bf18 commit 43cc1e3

19 files changed

+33
-700
lines changed

.ci/install.sh

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@ fi
2828

2929
python3 -m pip install --upgrade pip
3030
python3 -m pip install --upgrade wheel
31-
# TODO Update condition when cffi supports 3.13
32-
if ! [[ "$GHA_PYTHON_VERSION" == "3.13" ]]; then PYTHONOPTIMIZE=0 python3 -m pip install cffi ; fi
3331
python3 -m pip install coverage
3432
python3 -m pip install defusedxml
3533
python3 -m pip install olefile

.coveragerc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,5 @@ exclude_also =
1919
[run]
2020
omit =
2121
Tests/32bit_segfault_check.py
22-
Tests/bench_cffi_access.py
2322
Tests/check_*.py
2423
Tests/createfontdatachunk.py

.github/workflows/macos-install.sh

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ else
1818
fi
1919
export PKG_CONFIG_PATH="/usr/local/opt/openblas/lib/pkgconfig"
2020

21-
# TODO Update condition when cffi supports 3.13
22-
if ! [[ "$GHA_PYTHON_VERSION" == "3.13" ]]; then PYTHONOPTIMIZE=0 python3 -m pip install cffi ; fi
23-
2421
python3 -m pip install coverage
2522
python3 -m pip install defusedxml
2623
python3 -m pip install olefile

.github/workflows/test-cygwin.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ jobs:
7272
make
7373
netpbm
7474
perl
75-
python3${{ matrix.python-minor-version }}-cffi
7675
python3${{ matrix.python-minor-version }}-cython
7776
python3${{ matrix.python-minor-version }}-devel
7877
python3${{ matrix.python-minor-version }}-numpy

.github/workflows/test-mingw.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ jobs:
6464
mingw-w64-x86_64-libtiff \
6565
mingw-w64-x86_64-libwebp \
6666
mingw-w64-x86_64-openjpeg2 \
67-
mingw-w64-x86_64-python3-cffi \
6867
mingw-w64-x86_64-python3-numpy \
6968
mingw-w64-x86_64-python3-olefile \
7069
mingw-w64-x86_64-python3-setuptools \

Tests/bench_cffi_access.py

Lines changed: 0 additions & 54 deletions
This file was deleted.

Tests/test_image_access.py

Lines changed: 9 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -12,41 +12,14 @@
1212

1313
from .helper import assert_image_equal, hopper, is_win32
1414

15-
# CFFI imports pycparser which doesn't support PYTHONOPTIMIZE=2
16-
# https://github.com/eliben/pycparser/pull/198#issuecomment-317001670
17-
cffi: ModuleType | None
18-
if os.environ.get("PYTHONOPTIMIZE") == "2":
19-
cffi = None
20-
else:
21-
try:
22-
import cffi
23-
24-
from PIL import PyAccess
25-
except ImportError:
26-
cffi = None
27-
2815
numpy: ModuleType | None
2916
try:
3017
import numpy
3118
except ImportError:
3219
numpy = None
3320

3421

35-
class AccessTest:
36-
# Initial value
37-
_init_cffi_access = Image.USE_CFFI_ACCESS
38-
_need_cffi_access = False
39-
40-
@classmethod
41-
def setup_class(cls) -> None:
42-
Image.USE_CFFI_ACCESS = cls._need_cffi_access
43-
44-
@classmethod
45-
def teardown_class(cls) -> None:
46-
Image.USE_CFFI_ACCESS = cls._init_cffi_access
47-
48-
49-
class TestImagePutPixel(AccessTest):
22+
class TestImagePutPixel:
5023
def test_sanity(self) -> None:
5124
im1 = hopper()
5225
im2 = Image.new(im1.mode, im1.size, 0)
@@ -131,7 +104,7 @@ def test_numpy(self) -> None:
131104
assert pix[numpy.int32(1), numpy.int32(2)] == (18, 20, 59)
132105

133106

134-
class TestImageGetPixel(AccessTest):
107+
class TestImageGetPixel:
135108
@staticmethod
136109
def color(mode: str) -> int | tuple[int, ...]:
137110
bands = Image.getmodebands(mode)
@@ -144,9 +117,6 @@ def color(mode: str) -> int | tuple[int, ...]:
144117
return tuple(range(1, bands + 1))
145118

146119
def check(self, mode: str, expected_color_int: int | None = None) -> None:
147-
if self._need_cffi_access and mode.startswith("BGR;"):
148-
pytest.skip("Support not added to deprecated module for BGR;* modes")
149-
150120
expected_color = (
151121
self.color(mode) if expected_color_int is None else expected_color_int
152122
)
@@ -171,15 +141,14 @@ def check(self, mode: str, expected_color_int: int | None = None) -> None:
171141
# Check 0x0 image with None initial color
172142
im = Image.new(mode, (0, 0), None)
173143
assert im.load() is not None
174-
error = ValueError if self._need_cffi_access else IndexError
175-
with pytest.raises(error):
144+
with pytest.raises(IndexError):
176145
im.putpixel((0, 0), expected_color)
177-
with pytest.raises(error):
146+
with pytest.raises(IndexError):
178147
im.getpixel((0, 0))
179148
# Check negative index
180-
with pytest.raises(error):
149+
with pytest.raises(IndexError):
181150
im.putpixel((-1, -1), expected_color)
182-
with pytest.raises(error):
151+
with pytest.raises(IndexError):
183152
im.getpixel((-1, -1))
184153

185154
# Check initial color
@@ -199,10 +168,10 @@ def check(self, mode: str, expected_color_int: int | None = None) -> None:
199168

200169
# Check 0x0 image with initial color
201170
im = Image.new(mode, (0, 0), expected_color)
202-
with pytest.raises(error):
171+
with pytest.raises(IndexError):
203172
im.getpixel((0, 0))
204173
# Check negative index
205-
with pytest.raises(error):
174+
with pytest.raises(IndexError):
206175
im.getpixel((-1, -1))
207176

208177
@pytest.mark.parametrize("mode", Image.MODES)
@@ -235,126 +204,7 @@ def test_p_putpixel_rgb_rgba(self, mode: str, color: tuple[int, ...]) -> None:
235204
assert im.convert("RGBA").getpixel((0, 0)) == (255, 0, 0, alpha)
236205

237206

238-
@pytest.mark.filterwarnings("ignore::DeprecationWarning")
239-
@pytest.mark.skipif(cffi is None, reason="No CFFI")
240-
class TestCffiPutPixel(TestImagePutPixel):
241-
_need_cffi_access = True
242-
243-
244-
@pytest.mark.filterwarnings("ignore::DeprecationWarning")
245-
@pytest.mark.skipif(cffi is None, reason="No CFFI")
246-
class TestCffiGetPixel(TestImageGetPixel):
247-
_need_cffi_access = True
248-
249-
250-
@pytest.mark.skipif(cffi is None, reason="No CFFI")
251-
class TestCffi(AccessTest):
252-
_need_cffi_access = True
253-
254-
def _test_get_access(self, im: Image.Image) -> None:
255-
"""Do we get the same thing as the old pixel access
256-
257-
Using private interfaces, forcing a capi access and
258-
a pyaccess for the same image"""
259-
caccess = im.im.pixel_access(False)
260-
with pytest.warns(DeprecationWarning):
261-
access = PyAccess.new(im, False)
262-
assert access is not None
263-
264-
w, h = im.size
265-
for x in range(0, w, 10):
266-
for y in range(0, h, 10):
267-
assert access[(x, y)] == caccess[(x, y)]
268-
269-
# Access an out-of-range pixel
270-
with pytest.raises(ValueError):
271-
access[(access.xsize + 1, access.ysize + 1)]
272-
273-
def test_get_vs_c(self) -> None:
274-
with pytest.warns(DeprecationWarning):
275-
rgb = hopper("RGB")
276-
rgb.load()
277-
self._test_get_access(rgb)
278-
for mode in ("RGBA", "L", "LA", "1", "P", "F"):
279-
self._test_get_access(hopper(mode))
280-
281-
for mode in ("I;16", "I;16L", "I;16B", "I;16N", "I"):
282-
im = Image.new(mode, (10, 10), 40000)
283-
self._test_get_access(im)
284-
285-
def _test_set_access(self, im: Image.Image, color: tuple[int, ...] | float) -> None:
286-
"""Are we writing the correct bits into the image?
287-
288-
Using private interfaces, forcing a capi access and
289-
a pyaccess for the same image"""
290-
caccess = im.im.pixel_access(False)
291-
with pytest.warns(DeprecationWarning):
292-
access = PyAccess.new(im, False)
293-
assert access is not None
294-
295-
w, h = im.size
296-
for x in range(0, w, 10):
297-
for y in range(0, h, 10):
298-
access[(x, y)] = color
299-
assert color == caccess[(x, y)]
300-
301-
# Attempt to set the value on a read-only image
302-
with pytest.warns(DeprecationWarning):
303-
access = PyAccess.new(im, True)
304-
assert access is not None
305-
306-
with pytest.raises(ValueError):
307-
access[(0, 0)] = color
308-
309-
def test_set_vs_c(self) -> None:
310-
rgb = hopper("RGB")
311-
with pytest.warns(DeprecationWarning):
312-
rgb.load()
313-
self._test_set_access(rgb, (255, 128, 0))
314-
self._test_set_access(hopper("RGBA"), (255, 192, 128, 0))
315-
self._test_set_access(hopper("L"), 128)
316-
self._test_set_access(hopper("LA"), (128, 128))
317-
self._test_set_access(hopper("1"), 255)
318-
self._test_set_access(hopper("P"), 128)
319-
self._test_set_access(hopper("PA"), (128, 128))
320-
self._test_set_access(hopper("F"), 1024.0)
321-
322-
for mode in ("I;16", "I;16L", "I;16B", "I;16N", "I"):
323-
im = Image.new(mode, (10, 10), 40000)
324-
self._test_set_access(im, 45000)
325-
326-
@pytest.mark.filterwarnings("ignore::DeprecationWarning")
327-
def test_not_implemented(self) -> None:
328-
assert PyAccess.new(hopper("BGR;15")) is None
329-
330-
# Ref https://github.com/python-pillow/Pillow/pull/2009
331-
def test_reference_counting(self) -> None:
332-
size = 10
333-
334-
for _ in range(10):
335-
# Do not save references to the image, only to the access object
336-
with pytest.warns(DeprecationWarning):
337-
px = Image.new("L", (size, 1), 0).load()
338-
for i in range(size):
339-
# Pixels can contain garbage if image is released
340-
assert px[i, 0] == 0
341-
342-
@pytest.mark.parametrize("mode", ("P", "PA"))
343-
def test_p_putpixel_rgb_rgba(self, mode: str) -> None:
344-
for color in ((255, 0, 0), (255, 0, 0, 127 if mode == "PA" else 255)):
345-
im = Image.new(mode, (1, 1))
346-
with pytest.warns(DeprecationWarning):
347-
access = PyAccess.new(im, False)
348-
assert access is not None
349-
350-
access.putpixel((0, 0), color)
351-
352-
if len(color) == 3:
353-
color += (255,)
354-
assert im.convert("RGBA").getpixel((0, 0)) == color
355-
356-
357-
class TestImagePutPixelError(AccessTest):
207+
class TestImagePutPixelError:
358208
IMAGE_MODES1 = ["LA", "RGB", "RGBA", "BGR;15"]
359209
IMAGE_MODES2 = ["L", "I", "I;16"]
360210
INVALID_TYPES = ["foo", 1.0, None]

codecov.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,5 @@ coverage:
1717
# Matches 'omit:' in .coveragerc
1818
ignore:
1919
- "Tests/32bit_segfault_check.py"
20-
- "Tests/bench_cffi_access.py"
2120
- "Tests/check_*.py"
2221
- "Tests/createfontdatachunk.py"

docs/deprecations.rst

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,6 @@ Deprecated features
1212
Below are features which are considered deprecated. Where appropriate,
1313
a :py:exc:`DeprecationWarning` is issued.
1414

15-
PyAccess and Image.USE_CFFI_ACCESS
16-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17-
18-
.. deprecated:: 10.0.0
19-
20-
Since Pillow's C API is now faster than PyAccess on PyPy,
21-
:py:mod:`~PIL.PyAccess` has been deprecated and will be removed in Pillow
22-
11.0.0 (2024-10-15). Pillow's C API will now be used by default on PyPy instead.
23-
24-
``Image.USE_CFFI_ACCESS``, for switching from the C API to PyAccess, is
25-
similarly deprecated.
26-
2715
ImageFile.raise_oserror
2816
~~~~~~~~~~~~~~~~~~~~~~~
2917

@@ -138,6 +126,18 @@ This class was only made as a helper to be used internally,
138126
so there is no replacement. If you need this functionality though,
139127
it is a very short class that can easily be recreated in your own code.
140128

129+
PyAccess and Image.USE_CFFI_ACCESS
130+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
131+
132+
.. deprecated:: 10.0.0
133+
.. versionremoved:: 11.0.0
134+
135+
Since Pillow's C API is now faster than PyAccess on PyPy, ``PyAccess`` has been
136+
removed. Pillow's C API will now be used on PyPy instead.
137+
138+
``Image.USE_CFFI_ACCESS``, for switching from the C API to PyAccess, was
139+
similarly removed.
140+
141141
Tk/Tcl 8.4
142142
~~~~~~~~~~
143143

0 commit comments

Comments
 (0)