1212
1313from .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-
2815numpy : ModuleType | None
2916try :
3017 import numpy
3118except 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 ]
0 commit comments