44import subprocess
55import sys
66import sysconfig
7+ from types import ModuleType
78
89import pytest
910
2324 except ImportError :
2425 cffi = None
2526
27+ numpy : ModuleType | None
2628try :
2729 import numpy
2830except ImportError :
@@ -71,9 +73,10 @@ def test_sanity(self) -> None:
7173 pix1 = im1 .load ()
7274 pix2 = im2 .load ()
7375
74- for x , y in ((0 , "0" ), ("0" , 0 )):
75- with pytest .raises (TypeError ):
76- pix1 [x , y ]
76+ with pytest .raises (TypeError ):
77+ pix1 [0 , "0" ]
78+ with pytest .raises (TypeError ):
79+ pix1 ["0" , 0 ]
7780
7881 for y in range (im1 .size [1 ]):
7982 for x in range (im1 .size [0 ]):
@@ -123,12 +126,13 @@ def test_numpy(self) -> None:
123126 im = hopper ()
124127 pix = im .load ()
125128
129+ assert numpy is not None
126130 assert pix [numpy .int32 (1 ), numpy .int32 (2 )] == (18 , 20 , 59 )
127131
128132
129133class TestImageGetPixel (AccessTest ):
130134 @staticmethod
131- def color (mode ) :
135+ def color (mode : str ) -> int | tuple [ int , ...] :
132136 bands = Image .getmodebands (mode )
133137 if bands == 1 :
134138 return 1
@@ -138,12 +142,13 @@ def color(mode):
138142 return (16 , 32 , 49 )
139143 return tuple (range (1 , bands + 1 ))
140144
141- def check (self , mode , expected_color = None ) -> None :
145+ def check (self , mode : str , expected_color_int : int | None = None ) -> None :
142146 if self ._need_cffi_access and mode .startswith ("BGR;" ):
143147 pytest .skip ("Support not added to deprecated module for BGR;* modes" )
144148
145- if not expected_color :
146- expected_color = self .color (mode )
149+ expected_color = (
150+ self .color (mode ) if expected_color_int is None else expected_color_int
151+ )
147152
148153 # check putpixel
149154 im = Image .new (mode , (1 , 1 ), None )
@@ -222,7 +227,7 @@ def check(self, mode, expected_color=None) -> None:
222227 "YCbCr" ,
223228 ),
224229 )
225- def test_basic (self , mode ) -> None :
230+ def test_basic (self , mode : str ) -> None :
226231 self .check (mode )
227232
228233 def test_list (self ) -> None :
@@ -231,14 +236,14 @@ def test_list(self) -> None:
231236
232237 @pytest .mark .parametrize ("mode" , ("I;16" , "I;16B" ))
233238 @pytest .mark .parametrize ("expected_color" , (2 ** 15 - 1 , 2 ** 15 , 2 ** 15 + 1 , 2 ** 16 - 1 ))
234- def test_signedness (self , mode , expected_color ) -> None :
239+ def test_signedness (self , mode : str , expected_color : int ) -> None :
235240 # see https://github.com/python-pillow/Pillow/issues/452
236241 # pixelaccess is using signed int* instead of uint*
237242 self .check (mode , expected_color )
238243
239244 @pytest .mark .parametrize ("mode" , ("P" , "PA" ))
240245 @pytest .mark .parametrize ("color" , ((255 , 0 , 0 ), (255 , 0 , 0 , 255 )))
241- def test_p_putpixel_rgb_rgba (self , mode , color ) -> None :
246+ def test_p_putpixel_rgb_rgba (self , mode : str , color : tuple [ int , ...] ) -> None :
242247 im = Image .new (mode , (1 , 1 ))
243248 im .putpixel ((0 , 0 ), color )
244249
@@ -262,7 +267,7 @@ class TestCffiGetPixel(TestImageGetPixel):
262267class TestCffi (AccessTest ):
263268 _need_cffi_access = True
264269
265- def _test_get_access (self , im ) -> None :
270+ def _test_get_access (self , im : Image . Image ) -> None :
266271 """Do we get the same thing as the old pixel access
267272
268273 Using private interfaces, forcing a capi access and
@@ -299,7 +304,7 @@ def test_get_vs_c(self) -> None:
299304 # im = Image.new('I;32B', (10, 10), 2**10)
300305 # self._test_get_access(im)
301306
302- def _test_set_access (self , im , color ) -> None :
307+ def _test_set_access (self , im : Image . Image , color : tuple [ int , ...] | float ) -> None :
303308 """Are we writing the correct bits into the image?
304309
305310 Using private interfaces, forcing a capi access and
@@ -359,7 +364,7 @@ def test_reference_counting(self) -> None:
359364 assert px [i , 0 ] == 0
360365
361366 @pytest .mark .parametrize ("mode" , ("P" , "PA" ))
362- def test_p_putpixel_rgb_rgba (self , mode ) -> None :
367+ def test_p_putpixel_rgb_rgba (self , mode : str ) -> None :
363368 for color in ((255 , 0 , 0 ), (255 , 0 , 0 , 127 if mode == "PA" else 255 )):
364369 im = Image .new (mode , (1 , 1 ))
365370 with pytest .warns (DeprecationWarning ):
@@ -377,7 +382,7 @@ class TestImagePutPixelError(AccessTest):
377382 INVALID_TYPES = ["foo" , 1.0 , None ]
378383
379384 @pytest .mark .parametrize ("mode" , IMAGE_MODES1 )
380- def test_putpixel_type_error1 (self , mode ) -> None :
385+ def test_putpixel_type_error1 (self , mode : str ) -> None :
381386 im = hopper (mode )
382387 for v in self .INVALID_TYPES :
383388 with pytest .raises (TypeError , match = "color must be int or tuple" ):
@@ -400,14 +405,16 @@ def test_putpixel_type_error1(self, mode) -> None:
400405 ),
401406 ),
402407 )
403- def test_putpixel_invalid_number_of_bands (self , mode , band_numbers , match ) -> None :
408+ def test_putpixel_invalid_number_of_bands (
409+ self , mode : str , band_numbers : tuple [int , ...], match : str
410+ ) -> None :
404411 im = hopper (mode )
405412 for band_number in band_numbers :
406413 with pytest .raises (TypeError , match = match ):
407414 im .putpixel ((0 , 0 ), (0 ,) * band_number )
408415
409416 @pytest .mark .parametrize ("mode" , IMAGE_MODES2 )
410- def test_putpixel_type_error2 (self , mode ) -> None :
417+ def test_putpixel_type_error2 (self , mode : str ) -> None :
411418 im = hopper (mode )
412419 for v in self .INVALID_TYPES :
413420 with pytest .raises (
@@ -416,7 +423,7 @@ def test_putpixel_type_error2(self, mode) -> None:
416423 im .putpixel ((0 , 0 ), v )
417424
418425 @pytest .mark .parametrize ("mode" , IMAGE_MODES1 + IMAGE_MODES2 )
419- def test_putpixel_overflow_error (self , mode ) -> None :
426+ def test_putpixel_overflow_error (self , mode : str ) -> None :
420427 im = hopper (mode )
421428 with pytest .raises (OverflowError ):
422429 im .putpixel ((0 , 0 ), 2 ** 80 )
@@ -428,7 +435,7 @@ class TestEmbeddable:
428435 def test_embeddable (self ) -> None :
429436 import ctypes
430437
431- from setuptools .command . build_ext import new_compiler
438+ from setuptools .command import build_ext
432439
433440 with open ("embed_pil.c" , "w" , encoding = "utf-8" ) as fh :
434441 fh .write (
@@ -457,7 +464,7 @@ def test_embeddable(self) -> None:
457464 % sys .prefix .replace ("\\ " , "\\ \\ " )
458465 )
459466
460- compiler = new_compiler ()
467+ compiler = getattr ( build_ext , " new_compiler" ) ()
461468 compiler .add_include_dir (sysconfig .get_config_var ("INCLUDEPY" ))
462469
463470 libdir = sysconfig .get_config_var ("LIBDIR" ) or sysconfig .get_config_var (
@@ -471,7 +478,7 @@ def test_embeddable(self) -> None:
471478 env ["PATH" ] = sys .prefix + ";" + env ["PATH" ]
472479
473480 # do not display the Windows Error Reporting dialog
474- ctypes . windll .kernel32 .SetErrorMode (0x0002 )
481+ getattr ( ctypes , " windll" ) .kernel32 .SetErrorMode (0x0002 )
475482
476483 process = subprocess .Popen (["embed_pil.exe" ], env = env )
477484 process .communicate ()
0 commit comments