Merge branch 'main' into path_lists

This commit is contained in:
Hugo van Kemenade 2025-03-05 17:33:59 +02:00 committed by GitHub
commit d4a740f4b9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 51 additions and 74 deletions

View File

@ -601,7 +601,7 @@ def test_save_dispose(tmp_path: Path) -> None:
Image.new("L", (100, 100), "#111"),
Image.new("L", (100, 100), "#222"),
]
for method in range(0, 4):
for method in range(4):
im_list[0].save(out, save_all=True, append_images=im_list[1:], disposal=method)
with Image.open(out) as img:
for _ in range(2):

View File

@ -1140,11 +1140,9 @@ class TestFileLibTiff(LibTiffTestCase):
def test_realloc_overflow(self, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(TiffImagePlugin, "READ_LIBTIFF", True)
with Image.open("Tests/images/tiff_overflow_rows_per_strip.tif") as im:
with pytest.raises(OSError) as e:
im.load()
# Assert that the error code is IMAGING_CODEC_MEMORY
assert str(e.value) == "decoder error -9"
with pytest.raises(OSError, match="decoder error -9"):
im.load()
@pytest.mark.parametrize("compression", ("tiff_adobe_deflate", "jpeg"))
def test_save_multistrip(self, compression: str, tmp_path: Path) -> None:

View File

@ -293,12 +293,10 @@ def test_header_token_too_long(tmp_path: Path) -> None:
with open(path, "wb") as f:
f.write(b"P6\n 01234567890")
with pytest.raises(ValueError) as e:
with pytest.raises(ValueError, match="Token too long in file header: 01234567890"):
with Image.open(path):
pass
assert str(e.value) == "Token too long in file header: 01234567890"
def test_truncated_file(tmp_path: Path) -> None:
# Test EOF in header
@ -306,12 +304,10 @@ def test_truncated_file(tmp_path: Path) -> None:
with open(path, "wb") as f:
f.write(b"P6")
with pytest.raises(ValueError) as e:
with pytest.raises(ValueError, match="Reached EOF while reading header"):
with Image.open(path):
pass
assert str(e.value) == "Reached EOF while reading header"
# Test EOF for PyDecoder
fp = BytesIO(b"P5 3 1 4")
with Image.open(fp) as im:
@ -335,12 +331,12 @@ def test_invalid_maxval(maxval: bytes, tmp_path: Path) -> None:
with open(path, "wb") as f:
f.write(b"P6\n3 1 " + maxval)
with pytest.raises(ValueError) as e:
with pytest.raises(
ValueError, match="maxval must be greater than 0 and less than 65536"
):
with Image.open(path):
pass
assert str(e.value) == "maxval must be greater than 0 and less than 65536"
def test_neg_ppm() -> None:
# Storage.c accepted negative values for xsize, ysize. the

View File

@ -134,9 +134,8 @@ class TestFileTiff:
def test_set_legacy_api(self) -> None:
ifd = TiffImagePlugin.ImageFileDirectory_v2()
with pytest.raises(Exception) as e:
with pytest.raises(Exception, match="Not allowing setting of legacy api"):
ifd.legacy_api = False
assert str(e.value) == "Not allowing setting of legacy api"
def test_xyres_tiff(self) -> None:
filename = "Tests/images/pil168.tif"

View File

@ -154,9 +154,8 @@ class TestFileWebp:
@pytest.mark.skipif(sys.maxsize <= 2**32, reason="Requires 64-bit system")
def test_write_encoding_error_message(self, tmp_path: Path) -> None:
im = Image.new("RGB", (15000, 15000))
with pytest.raises(ValueError) as e:
with pytest.raises(ValueError, match="encoding error 6"):
im.save(tmp_path / "temp.webp", method=0)
assert str(e.value) == "encoding error 6"
@pytest.mark.skipif(sys.maxsize <= 2**32, reason="Requires 64-bit system")
def test_write_encoding_error_bad_dimension(self, tmp_path: Path) -> None:
@ -231,7 +230,7 @@ class TestFileWebp:
with Image.open(out_gif) as reread:
reread_value = reread.convert("RGB").getpixel((1, 1))
difference = sum(abs(original_value[i] - reread_value[i]) for i in range(0, 3))
difference = sum(abs(original_value[i] - reread_value[i]) for i in range(3))
assert difference < 5
def test_duration(self, tmp_path: Path) -> None:

View File

@ -65,9 +65,8 @@ class TestImage:
@pytest.mark.parametrize("mode", ("", "bad", "very very long"))
def test_image_modes_fail(self, mode: str) -> None:
with pytest.raises(ValueError) as e:
with pytest.raises(ValueError, match="unrecognized image mode"):
Image.new(mode, (1, 1))
assert str(e.value) == "unrecognized image mode"
def test_exception_inheritance(self) -> None:
assert issubclass(UnidentifiedImageError, OSError)

View File

@ -1048,8 +1048,8 @@ def create_base_image_draw(
background2: tuple[int, int, int] = GRAY,
) -> tuple[Image.Image, ImageDraw.ImageDraw]:
img = Image.new(mode, size, background1)
for x in range(0, size[0]):
for y in range(0, size[1]):
for x in range(size[0]):
for y in range(size[1]):
if (x + y) % 2 == 0:
img.putpixel((x, y), background2)
return img, ImageDraw.Draw(img)
@ -1630,7 +1630,7 @@ def test_compute_regular_polygon_vertices(
0,
ValueError,
"bounding_circle should contain 2D coordinates "
"and a radius (e.g. (x, y, r) or ((x, y), r) )",
r"and a radius \(e.g. \(x, y, r\) or \(\(x, y\), r\) \)",
),
(
3,
@ -1644,7 +1644,7 @@ def test_compute_regular_polygon_vertices(
((50, 50, 50), 25),
0,
ValueError,
"bounding_circle centre should contain 2D coordinates (e.g. (x, y))",
r"bounding_circle centre should contain 2D coordinates \(e.g. \(x, y\)\)",
),
(
3,
@ -1669,9 +1669,8 @@ def test_compute_regular_polygon_vertices_input_error_handling(
expected_error: type[Exception],
error_message: str,
) -> None:
with pytest.raises(expected_error) as e:
with pytest.raises(expected_error, match=error_message):
ImageDraw._compute_regular_polygon_vertices(bounding_circle, n_sides, rotation) # type: ignore[arg-type]
assert str(e.value) == error_message
def test_continuous_horizontal_edges_polygon() -> None:

View File

@ -176,9 +176,8 @@ class TestImageFile:
b"0" * ImageFile.SAFEBLOCK
) # only SAFEBLOCK bytes, so that the header is truncated
)
with pytest.raises(OSError) as e:
with pytest.raises(OSError, match="Truncated File Read"):
BmpImagePlugin.BmpImageFile(b)
assert str(e.value) == "Truncated File Read"
@skip_unless_feature("zlib")
def test_truncated_with_errors(self) -> None:

View File

@ -80,15 +80,12 @@ def test_lut(op: str) -> None:
def test_no_operator_loaded() -> None:
im = Image.new("L", (1, 1))
mop = ImageMorph.MorphOp()
with pytest.raises(Exception) as e:
with pytest.raises(Exception, match="No operator loaded"):
mop.apply(im)
assert str(e.value) == "No operator loaded"
with pytest.raises(Exception) as e:
with pytest.raises(Exception, match="No operator loaded"):
mop.match(im)
assert str(e.value) == "No operator loaded"
with pytest.raises(Exception) as e:
with pytest.raises(Exception, match="No operator loaded"):
mop.save_lut("")
assert str(e.value) == "No operator loaded"
# Test the named patterns
@ -238,15 +235,12 @@ def test_incorrect_mode() -> None:
im = hopper("RGB")
mop = ImageMorph.MorphOp(op_name="erosion8")
with pytest.raises(ValueError) as e:
with pytest.raises(ValueError, match="Image mode must be L"):
mop.apply(im)
assert str(e.value) == "Image mode must be L"
with pytest.raises(ValueError) as e:
with pytest.raises(ValueError, match="Image mode must be L"):
mop.match(im)
assert str(e.value) == "Image mode must be L"
with pytest.raises(ValueError) as e:
with pytest.raises(ValueError, match="Image mode must be L"):
mop.get_on_pixels(im)
assert str(e.value) == "Image mode must be L"
def test_add_patterns() -> None:
@ -279,9 +273,10 @@ def test_pattern_syntax_error() -> None:
lb.add_patterns(new_patterns)
# Act / Assert
with pytest.raises(Exception) as e:
with pytest.raises(
Exception, match='Syntax error in pattern "a pattern with a syntax error"'
):
lb.build_lut()
assert str(e.value) == 'Syntax error in pattern "a pattern with a syntax error"'
def test_load_invalid_mrl() -> None:
@ -290,9 +285,8 @@ def test_load_invalid_mrl() -> None:
mop = ImageMorph.MorphOp()
# Act / Assert
with pytest.raises(Exception) as e:
with pytest.raises(Exception, match="Wrong size operator file!"):
mop.load_lut(invalid_mrl)
assert str(e.value) == "Wrong size operator file!"
def test_roundtrip_mrl(tmp_path: Path) -> None:

View File

@ -112,7 +112,7 @@ def test_make_linear_lut() -> None:
assert isinstance(lut, list)
assert len(lut) == 256
# Check values
for i in range(0, len(lut)):
for i in range(len(lut)):
assert lut[i] == i

View File

@ -70,12 +70,9 @@ def test_path_constructors(
def test_invalid_path_constructors() -> None:
# Arrange / Act
with pytest.raises(ValueError) as e:
with pytest.raises(ValueError, match="incorrect coordinate type"):
ImagePath.Path(("a", "b"))
# Assert
assert str(e.value) == "incorrect coordinate type"
@pytest.mark.parametrize(
"coords",
@ -87,13 +84,9 @@ def test_invalid_path_constructors() -> None:
),
)
def test_path_odd_number_of_coordinates(coords: Sequence[int]) -> None:
# Act
with pytest.raises(ValueError) as e:
with pytest.raises(ValueError, match="wrong number of coordinates"):
ImagePath.Path(coords)
# Assert
assert str(e.value) == "wrong number of coordinates"
@pytest.mark.parametrize(
"coords, expected",

View File

@ -32,7 +32,7 @@ def test_sanity(tmp_path: Path) -> None:
def test_iterator() -> None:
with Image.open("Tests/images/multipage.tiff") as im:
i = ImageSequence.Iterator(im)
for index in range(0, im.n_frames):
for index in range(im.n_frames):
assert i[index] == next(i)
with pytest.raises(IndexError):
i[index + 1]

View File

@ -65,7 +65,7 @@ def helper_pickle_string(protocol: int, test_file: str, mode: str | None) -> Non
("Tests/images/itxt_chunks.png", None),
],
)
@pytest.mark.parametrize("protocol", range(0, pickle.HIGHEST_PROTOCOL + 1))
@pytest.mark.parametrize("protocol", range(pickle.HIGHEST_PROTOCOL + 1))
def test_pickle_image(
tmp_path: Path, test_file: str, test_mode: str | None, protocol: int
) -> None:
@ -92,7 +92,7 @@ def test_pickle_la_mode_with_palette(tmp_path: Path) -> None:
im = im.convert("PA")
# Act / Assert
for protocol in range(0, pickle.HIGHEST_PROTOCOL + 1):
for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
im._mode = "LA"
with open(filename, "wb") as f:
pickle.dump(im, f, protocol)
@ -133,7 +133,7 @@ def helper_assert_pickled_font_images(
@skip_unless_feature("freetype2")
@pytest.mark.parametrize("protocol", list(range(0, pickle.HIGHEST_PROTOCOL + 1)))
@pytest.mark.parametrize("protocol", list(range(pickle.HIGHEST_PROTOCOL + 1)))
def test_pickle_font_string(protocol: int) -> None:
# Arrange
font = ImageFont.truetype(FONT_PATH, FONT_SIZE)
@ -147,7 +147,7 @@ def test_pickle_font_string(protocol: int) -> None:
@skip_unless_feature("freetype2")
@pytest.mark.parametrize("protocol", list(range(0, pickle.HIGHEST_PROTOCOL + 1)))
@pytest.mark.parametrize("protocol", list(range(pickle.HIGHEST_PROTOCOL + 1)))
def test_pickle_font_file(tmp_path: Path, protocol: int) -> None:
# Arrange
font = ImageFont.truetype(FONT_PATH, FONT_SIZE)

View File

@ -121,6 +121,7 @@ lint.select = [
"ISC", # flake8-implicit-str-concat
"LOG", # flake8-logging
"PGH", # pygrep-hooks
"PIE", # flake8-pie
"PT", # flake8-pytest-style
"PYI", # flake8-pyi
"RUF100", # unused noqa (yesqa)
@ -133,6 +134,7 @@ lint.ignore = [
"E221", # Multiple spaces before operator
"E226", # Missing whitespace around arithmetic operator
"E241", # Multiple spaces after ','
"PIE790", # flake8-pie: unnecessary-placeholder
"PT001", # pytest-fixture-incorrect-parentheses-style
"PT007", # pytest-parametrize-values-wrong-type
"PT011", # pytest-raises-too-broad

View File

@ -123,8 +123,7 @@ def read_png_or_jpeg2000(
Image._decompression_bomb_check(im.size)
return {"RGBA": im}
elif (
sig.startswith(b"\xff\x4f\xff\x51")
or sig.startswith(b"\x0d\x0a\x87\x0a")
sig.startswith((b"\xff\x4f\xff\x51", b"\x0d\x0a\x87\x0a"))
or sig == b"\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a"
):
if not enable_jpeg2k:

View File

@ -1001,7 +1001,7 @@ class Image:
elif len(mode) == 3:
transparency = tuple(
convert_transparency(matrix[i * 4 : i * 4 + 4], transparency)
for i in range(0, len(transparency))
for i in range(len(transparency))
)
new_im.info["transparency"] = transparency
return new_im
@ -4003,7 +4003,7 @@ class Exif(_ExifBase):
ifd_data = tag_data[ifd_offset:]
makernote = {}
for i in range(0, struct.unpack("<H", ifd_data[:2])[0]):
for i in range(struct.unpack("<H", ifd_data[:2])[0]):
ifd_tag, typ, count, data = struct.unpack(
"<HHL4s", ifd_data[i * 12 + 2 : (i + 1) * 12 + 2]
)
@ -4038,7 +4038,7 @@ class Exif(_ExifBase):
self._ifds[tag] = dict(self._fixup_dict(makernote))
elif self.get(0x010F) == "Nintendo":
makernote = {}
for i in range(0, struct.unpack(">H", tag_data[:2])[0]):
for i in range(struct.unpack(">H", tag_data[:2])[0]):
ifd_tag, typ, count, data = struct.unpack(
">HHL4s", tag_data[i * 12 + 2 : (i + 1) * 12 + 2]
)

View File

@ -1204,7 +1204,7 @@ def _compute_regular_polygon_vertices(
degrees = 360 / n_sides
# Start with the bottom left polygon vertex
current_angle = (270 - 0.5 * degrees) + rotation
for _ in range(0, n_sides):
for _ in range(n_sides):
angles.append(current_angle)
current_angle += degrees
if current_angle > 360:
@ -1227,4 +1227,4 @@ def _color_diff(
first = color1 if isinstance(color1, tuple) else (color1,)
second = color2 if isinstance(color2, tuple) else (color2,)
return sum(abs(first[i] - second[i]) for i in range(0, len(second)))
return sum(abs(first[i] - second[i]) for i in range(len(second)))

View File

@ -213,14 +213,14 @@ def colorize(
blue = []
# Create the low-end values
for i in range(0, blackpoint):
for i in range(blackpoint):
red.append(rgb_black[0])
green.append(rgb_black[1])
blue.append(rgb_black[2])
# Create the mapping (2-color)
if rgb_mid is None:
range_map = range(0, whitepoint - blackpoint)
range_map = range(whitepoint - blackpoint)
for i in range_map:
red.append(
@ -235,8 +235,8 @@ def colorize(
# Create the mapping (3-color)
else:
range_map1 = range(0, midpoint - blackpoint)
range_map2 = range(0, whitepoint - midpoint)
range_map1 = range(midpoint - blackpoint)
range_map2 = range(whitepoint - midpoint)
for i in range_map1:
red.append(
@ -256,7 +256,7 @@ def colorize(
blue.append(rgb_mid[2] + i * (rgb_white[2] - rgb_mid[2]) // len(range_map2))
# Create the high-end values
for i in range(0, 256 - whitepoint):
for i in range(256 - whitepoint):
red.append(rgb_white[0])
green.append(rgb_white[1])
blue.append(rgb_white[2])

View File

@ -569,7 +569,7 @@ def _getmp(self: JpegImageFile) -> dict[int, Any] | None:
mpentries = []
try:
rawmpentries = mp[0xB002]
for entrynum in range(0, quant):
for entrynum in range(quant):
unpackedentry = struct.unpack_from(
f"{endianness}LLLHH", rawmpentries, entrynum * 16
)

View File

@ -1584,7 +1584,7 @@ class TiffImageFile(ImageFile.ImageFile):
# byte order.
elif rawmode == "I;16":
rawmode = "I;16N"
elif rawmode.endswith(";16B") or rawmode.endswith(";16L"):
elif rawmode.endswith((";16B", ";16L")):
rawmode = rawmode[:-1] + "N"
# Offset in the tile tuple is 0, we go from 0,0 to