Skip to content

Commit

Permalink
Added type hints to Image.__init__()
Browse files Browse the repository at this point in the history
  • Loading branch information
radarhere committed Aug 2, 2024
1 parent d8447de commit 8f1157a
Show file tree
Hide file tree
Showing 38 changed files with 232 additions and 51 deletions.
1 change: 1 addition & 0 deletions Tests/test_box_blur.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def test_imageops_box_blur() -> None:


def box_blur(image: Image.Image, radius: float = 1, n: int = 1) -> Image.Image:
assert image.im is not None
return image._new(image.im.box_blur((radius, radius), n))


Expand Down
16 changes: 16 additions & 0 deletions Tests/test_color_lut.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ def generate_identity_table(

def test_wrong_args(self) -> None:
im = Image.new("RGB", (10, 10), 0)
assert im.im is not None

with pytest.raises(ValueError, match="filter"):
im.im.color_lut_3d(
Expand Down Expand Up @@ -107,6 +108,7 @@ def test_wrong_args(self) -> None:

def test_correct_args(self) -> None:
im = Image.new("RGB", (10, 10), 0)
assert im.im is not None

im.im.color_lut_3d(
"RGB", Image.Resampling.BILINEAR, *self.generate_identity_table(3, 3)
Expand Down Expand Up @@ -143,51 +145,60 @@ def test_correct_args(self) -> None:
def test_wrong_mode(self) -> None:
with pytest.raises(ValueError, match="wrong mode"):
im = Image.new("L", (10, 10), 0)
assert im.im is not None
im.im.color_lut_3d(
"RGB", Image.Resampling.BILINEAR, *self.generate_identity_table(3, 3)
)

with pytest.raises(ValueError, match="wrong mode"):
im = Image.new("RGB", (10, 10), 0)
assert im.im is not None
im.im.color_lut_3d(
"L", Image.Resampling.BILINEAR, *self.generate_identity_table(3, 3)
)

with pytest.raises(ValueError, match="wrong mode"):
im = Image.new("L", (10, 10), 0)
assert im.im is not None
im.im.color_lut_3d(
"L", Image.Resampling.BILINEAR, *self.generate_identity_table(3, 3)
)

with pytest.raises(ValueError, match="wrong mode"):
im = Image.new("RGB", (10, 10), 0)
assert im.im is not None
im.im.color_lut_3d(
"RGBA", Image.Resampling.BILINEAR, *self.generate_identity_table(3, 3)
)

with pytest.raises(ValueError, match="wrong mode"):
im = Image.new("RGB", (10, 10), 0)
assert im.im is not None
im.im.color_lut_3d(
"RGB", Image.Resampling.BILINEAR, *self.generate_identity_table(4, 3)
)

def test_correct_mode(self) -> None:
im = Image.new("RGBA", (10, 10), 0)
assert im.im is not None
im.im.color_lut_3d(
"RGBA", Image.Resampling.BILINEAR, *self.generate_identity_table(3, 3)
)

im = Image.new("RGBA", (10, 10), 0)
assert im.im is not None
im.im.color_lut_3d(
"RGBA", Image.Resampling.BILINEAR, *self.generate_identity_table(4, 3)
)

im = Image.new("RGB", (10, 10), 0)
assert im.im is not None
im.im.color_lut_3d(
"HSV", Image.Resampling.BILINEAR, *self.generate_identity_table(3, 3)
)

im = Image.new("RGB", (10, 10), 0)
assert im.im is not None
im.im.color_lut_3d(
"RGBA", Image.Resampling.BILINEAR, *self.generate_identity_table(4, 3)
)
Expand All @@ -202,6 +213,7 @@ def test_identities(self) -> None:
g.transpose(Image.Transpose.ROTATE_180),
],
)
assert im.im is not None

# Fast test with small cubes
for size in [2, 3, 5, 7, 11, 16, 17]:
Expand Down Expand Up @@ -238,6 +250,7 @@ def test_identities_4_channels(self) -> None:
g.transpose(Image.Transpose.ROTATE_180),
],
)
assert im.im is not None

# Red channel copied to alpha
assert_image_equal(
Expand All @@ -262,6 +275,7 @@ def test_copy_alpha_channel(self) -> None:
g.transpose(Image.Transpose.ROTATE_270),
],
)
assert im.im is not None

assert_image_equal(
im,
Expand All @@ -284,6 +298,7 @@ def test_channels_order(self) -> None:
g.transpose(Image.Transpose.ROTATE_180),
],
)
assert im.im is not None

# Reverse channels by splitting and using table
# fmt: off
Expand All @@ -309,6 +324,7 @@ def test_overflow(self) -> None:
g.transpose(Image.Transpose.ROTATE_180),
],
)
assert im.im is not None

# fmt: off
transformed = im._new(im.im.color_lut_3d('RGB', Image.Resampling.BILINEAR,
Expand Down
1 change: 1 addition & 0 deletions Tests/test_file_webp.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ def test_roundtrip_rgba_palette(self, tmp_path: Path) -> None:
temp_file = str(tmp_path / "temp.webp")
im = Image.new("RGBA", (1, 1)).convert("P")
assert im.mode == "P"
assert im.palette is not None
assert im.palette.mode == "RGBA"
im.save(temp_file)

Expand Down
7 changes: 7 additions & 0 deletions Tests/test_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -695,11 +695,13 @@ def _make_new(
image: Image.Image,
palette_result: ImagePalette.ImagePalette | None = None,
) -> None:
assert image.im is not None
new_image = base_image._new(image.im)
assert new_image.mode == image.mode
assert new_image.size == image.size
assert new_image.info == base_image.info
if palette_result is not None:
assert new_image.palette is not None
assert new_image.palette.tobytes() == palette_result.tobytes()
else:
assert new_image.palette is None
Expand Down Expand Up @@ -990,12 +992,14 @@ def test_has_transparency_data(self) -> None:
# P mode with RGBA palette
im = Image.new("RGBA", (1, 1)).convert("P")
assert im.mode == "P"
assert im.palette is not None
assert im.palette.mode == "RGBA"
assert im.has_transparency_data

def test_apply_transparency(self) -> None:
im = Image.new("P", (1, 1))
im.putpalette((0, 0, 0, 1, 1, 1))
assert im.palette is not None
assert im.palette.colors == {(0, 0, 0): 0, (1, 1, 1): 1}

# Test that no transformation is applied without transparency
Expand All @@ -1013,13 +1017,16 @@ def test_apply_transparency(self) -> None:
im.putpalette((0, 0, 0, 255, 1, 1, 1, 128), "RGBA")
im.info["transparency"] = 0
im.apply_transparency()
assert im.palette is not None
assert im.palette.colors == {(0, 0, 0, 0): 0, (1, 1, 1, 128): 1}

# Test that transparency bytes are applied
with Image.open("Tests/images/pil123p.png") as im:
assert isinstance(im.info["transparency"], bytes)
assert im.palette is not None
assert im.palette.colors[(27, 35, 6)] == 24
im.apply_transparency()
assert im.palette is not None
assert im.palette.colors[(27, 35, 6, 214)] == 24

def test_constants(self) -> None:
Expand Down
2 changes: 2 additions & 0 deletions Tests/test_image_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,6 @@ def test_fromarray_palette() -> None:
out = Image.fromarray(a, "P")

# Assert that the Python and C palettes match
assert out.palette is not None
assert out.im is not None
assert len(out.palette.colors) == len(out.im.getpalette()) / 3
1 change: 1 addition & 0 deletions Tests/test_image_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ def test_trns_RGB(tmp_path: Path) -> None:
def test_l_macro_rounding(convert_mode: str) -> None:
for mode in ("P", "PA"):
im = Image.new(mode, (1, 1))
assert im.palette is not None
im.palette.getcolor((0, 1, 2))

converted_im = im.convert(convert_mode)
Expand Down
4 changes: 3 additions & 1 deletion Tests/test_image_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,9 @@ def test_builtinfilter_p() -> None:
builtin_filter = ImageFilter.BuiltinFilter()

with pytest.raises(ValueError):
builtin_filter.filter(hopper("P").im)
im = hopper("P").im
assert im is not None
builtin_filter.filter(im)


def test_kernel_not_enough_coefficients() -> None:
Expand Down
1 change: 1 addition & 0 deletions Tests/test_image_getim.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ def test_sanity() -> None:
type_repr = repr(type(im.getim()))

assert "PyCapsule" in type_repr
assert im.im is not None
assert isinstance(im.im.id, int)
1 change: 1 addition & 0 deletions Tests/test_image_putpalette.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def test_rgba_palette(mode: str, palette: tuple[int, ...]) -> None:
im = Image.new("P", (1, 1))
im.putpalette(palette, mode)
assert im.getpalette() == [1, 2, 3]
assert im.palette is not None
assert im.palette.colors == {(1, 2, 3, 4): 0}


Expand Down
4 changes: 4 additions & 0 deletions Tests/test_image_quantize.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ def test_quantize_no_dither() -> None:

converted = image.quantize(dither=Image.Dither.NONE, palette=palette)
assert converted.mode == "P"
assert converted.palette is not None
assert converted.palette.palette == palette.palette.palette


Expand All @@ -81,6 +82,7 @@ def test_quantize_no_dither2() -> None:
palette.putpalette(data)
quantized = im.quantize(dither=Image.Dither.NONE, palette=palette)

assert quantized.palette is not None
assert tuple(quantized.palette.palette) == data

px = quantized.load()
Expand Down Expand Up @@ -117,6 +119,7 @@ def test_colors() -> None:
im = hopper()
colors = 2
converted = im.quantize(colors)
assert converted.palette is not None
assert len(converted.palette.palette) == colors * len("RGB")


Expand Down Expand Up @@ -147,6 +150,7 @@ def test_palette(method: Image.Quantize, color: tuple[int, ...]) -> None:
converted = im.quantize(method=method)
converted_px = converted.load()
assert converted_px is not None
assert converted.palette is not None
assert converted_px[0, 0] == converted.palette.colors[color]


Expand Down
1 change: 1 addition & 0 deletions Tests/test_image_resample.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def test_overflow(self) -> None:
):
with pytest.raises(MemoryError):
# any resampling filter will do here
assert im.im is not None
im.im.resize((xsize, ysize), Image.Resampling.BILINEAR)

def test_invalid_size(self) -> None:
Expand Down
5 changes: 5 additions & 0 deletions Tests/test_image_resize.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def resize(
) -> Image.Image:
# Image class independent version of resize.
im.load()
assert im.im is not None
return im._new(im.im.resize(size, f))

@pytest.mark.parametrize(
Expand All @@ -37,6 +38,8 @@ def test_nearest_mode(self, mode: str) -> None:
r = self.resize(im, (15, 12), Image.Resampling.NEAREST)
assert r.mode == mode
assert r.size == (15, 12)
assert r.im is not None
assert im.im is not None
assert r.im.bands == im.im.bands

def test_convolution_modes(self) -> None:
Expand All @@ -51,6 +54,8 @@ def test_convolution_modes(self) -> None:
r = self.resize(im, (15, 12), Image.Resampling.BILINEAR)
assert r.mode == mode
assert r.size == (15, 12)
assert r.im is not None
assert im.im is not None
assert r.im.bands == im.im.bands

@pytest.mark.parametrize(
Expand Down
2 changes: 2 additions & 0 deletions Tests/test_imagemorph.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,8 @@ def test_wrong_mode() -> None:
lut = ImageMorph.LutBuilder(op_name="corner").build_lut()
imrgb = Image.new("RGB", (10, 10))
iml = Image.new("L", (10, 10))
assert imrgb.im is not None
assert iml.im is not None

with pytest.raises(RuntimeError):
_imagingmorph.apply(bytes(lut), imrgb.im.id, iml.im.id)
Expand Down
2 changes: 2 additions & 0 deletions Tests/test_imageops_usm.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,12 @@ def test_blur_accuracy(test_images: dict[str, ImageFile.ImageFile]) -> None:
(4, 3, 2),
(4, 2, 2),
]:
assert i.im is not None
assert i.im.getpixel((x, y))[c] >= 250
# Fuzzy match.

def gp(x: int, y: int) -> tuple[int, ...]:
assert i.im is not None
return i.im.getpixel((x, y))

assert 236 <= gp(7, 4)[0] <= 239
Expand Down
3 changes: 3 additions & 0 deletions Tests/test_lib_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,21 @@

def test_setmode() -> None:
im = Image.new("L", (1, 1), 255)
assert im.im is not None
im.im.setmode("1")
assert im.im.getpixel((0, 0)) == 255
im.im.setmode("L")
assert im.im.getpixel((0, 0)) == 255

im = Image.new("1", (1, 1), 1)
assert im.im is not None
im.im.setmode("L")
assert im.im.getpixel((0, 0)) == 255
im.im.setmode("1")
assert im.im.getpixel((0, 0)) == 255

im = Image.new("RGB", (1, 1), (1, 2, 3))
assert im.im is not None
im.im.setmode("RGB")
assert im.im.getpixel((0, 0)) == (1, 2, 3)
im.im.setmode("RGBA")
Expand Down
1 change: 1 addition & 0 deletions src/PIL/BlpImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
magic = b"BLP1" if im.encoderinfo.get("blp_version") == "BLP1" else b"BLP2"
fp.write(magic)

assert im.palette is not None
fp.write(struct.pack("<i", 1)) # Uncompressed or DirectX compression
fp.write(struct.pack("<b", Encoding.UNCOMPRESSED))
fp.write(struct.pack("<b", 1 if im.palette.mode == "RGBA" else 0))
Expand Down
3 changes: 3 additions & 0 deletions src/PIL/BmpImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ def _bitmap(self, header: int = 0, offset: int = 0) -> None:

# ------------------ Special case : header is reported 40, which
# ---------------------- is shorter than real size for bpp >= 16
assert isinstance(file_info["width"], int)
assert isinstance(file_info["height"], int)
self._size = file_info["width"], file_info["height"]

# ------- If color count was not found in the header, compute from bits
Expand Down Expand Up @@ -443,6 +445,7 @@ def _save(
elif im.mode == "L":
palette = b"".join(o8(i) * 4 for i in range(256))
elif im.mode == "P":
assert im.im is not None
palette = im.im.getpalette("RGB", "BGRX")
colors = len(palette) // 4
else:
Expand Down
8 changes: 4 additions & 4 deletions src/PIL/EpsImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def Ghostscript(
fp: IO[bytes],
scale: int = 1,
transparency: bool = False,
) -> Image.Image:
) -> Image.core.ImagingCore:
"""Render an image using Ghostscript"""
global gs_binary
if not has_ghostscript():
Expand Down Expand Up @@ -161,6 +161,7 @@ def Ghostscript(
except OSError:
pass

assert out_im.im is not None
im = out_im.im.copy()
out_im.close()
return im
Expand Down Expand Up @@ -190,7 +191,6 @@ def _open(self) -> None:
self.fp.seek(offset)

self._mode = "RGB"
self._size = None

byte_arr = bytearray(255)
bytes_mv = memoryview(byte_arr)
Expand Down Expand Up @@ -228,7 +228,7 @@ def _read_comment(s: str) -> bool:
if k == "BoundingBox":
if v == "(atend)":
reading_trailer_comments = True
elif not self._size or (trailer_reached and reading_trailer_comments):
elif not self.tile or (trailer_reached and reading_trailer_comments):
try:
# Note: The DSC spec says that BoundingBox
# fields should be integers, but some drivers
Expand Down Expand Up @@ -346,7 +346,7 @@ def _read_comment(s: str) -> bool:
trailer_reached = True
bytes_read = 0

if not self._size:
if not self.tile:
msg = "cannot determine EPS bounding box"
raise OSError(msg)

Expand Down
Loading

0 comments on commit 8f1157a

Please sign in to comment.