Added type hints

This commit is contained in:
Andrew Murray 2024-07-06 19:17:23 +10:00
parent a528cd8bd3
commit 486dac7efc
9 changed files with 49 additions and 23 deletions

View File

@ -353,7 +353,7 @@ def test_palette_434(tmp_path: Path) -> None:
def roundtrip(im: Image.Image, **kwargs: bool) -> Image.Image: def roundtrip(im: Image.Image, **kwargs: bool) -> Image.Image:
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
im.copy().save(out, **kwargs) im.copy().save(out, "GIF", **kwargs)
reloaded = Image.open(out) reloaded = Image.open(out)
return reloaded return reloaded

View File

@ -92,11 +92,22 @@ class TestFileLibTiff(LibTiffTestCase):
def test_g4_non_disk_file_object(self, tmp_path: Path) -> None: def test_g4_non_disk_file_object(self, tmp_path: Path) -> None:
"""Testing loading from non-disk non-BytesIO file object""" """Testing loading from non-disk non-BytesIO file object"""
test_file = "Tests/images/hopper_g4_500.tif" test_file = "Tests/images/hopper_g4_500.tif"
s = io.BytesIO()
with open(test_file, "rb") as f: with open(test_file, "rb") as f:
s.write(f.read()) data = f.read()
s.seek(0)
r = io.BufferedReader(s) class NonBytesIO(io.RawIOBase):
def read(self, size: int = -1) -> bytes:
nonlocal data
if size == -1:
size = len(data)
result = data[:size]
data = data[size:]
return result
def readable(self) -> bool:
return True
r = io.BufferedReader(NonBytesIO())
with Image.open(r) as im: with Image.open(r) as im:
assert im.size == (500, 500) assert im.size == (500, 500)
self._assert_noerr(tmp_path, im) self._assert_noerr(tmp_path, im)
@ -1139,7 +1150,7 @@ class TestFileLibTiff(LibTiffTestCase):
arguments: dict[str, str | int] = {"compression": "tiff_adobe_deflate"} arguments: dict[str, str | int] = {"compression": "tiff_adobe_deflate"}
if argument: if argument:
arguments["strip_size"] = 2**18 arguments["strip_size"] = 2**18
im.save(out, **arguments) im.save(out, "TIFF", **arguments)
with Image.open(out) as im: with Image.open(out) as im:
assert isinstance(im, TiffImagePlugin.TiffImageFile) assert isinstance(im, TiffImagePlugin.TiffImageFile)

View File

@ -118,7 +118,7 @@ def test_dpi(params: dict[str, int | tuple[int, int]], tmp_path: Path) -> None:
im = hopper() im = hopper()
outfile = str(tmp_path / "temp.pdf") outfile = str(tmp_path / "temp.pdf")
im.save(outfile, **params) im.save(outfile, "PDF", **params)
with open(outfile, "rb") as fp: with open(outfile, "rb") as fp:
contents = fp.read() contents = fp.read()

View File

@ -78,6 +78,7 @@ class TestFileTiff:
def test_seek_after_close(self) -> None: def test_seek_after_close(self) -> None:
im = Image.open("Tests/images/multipage.tiff") im = Image.open("Tests/images/multipage.tiff")
assert isinstance(im, TiffImagePlugin.TiffImageFile)
im.close() im.close()
with pytest.raises(ValueError): with pytest.raises(ValueError):
@ -424,13 +425,13 @@ class TestFileTiff:
def test_load_float(self) -> None: def test_load_float(self) -> None:
ifd = TiffImagePlugin.ImageFileDirectory_v2() ifd = TiffImagePlugin.ImageFileDirectory_v2()
data = b"abcdabcd" data = b"abcdabcd"
ret = ifd.load_float(data, False) ret = getattr(ifd, "load_float")(data, False)
assert ret == (1.6777999408082104e22, 1.6777999408082104e22) assert ret == (1.6777999408082104e22, 1.6777999408082104e22)
def test_load_double(self) -> None: def test_load_double(self) -> None:
ifd = TiffImagePlugin.ImageFileDirectory_v2() ifd = TiffImagePlugin.ImageFileDirectory_v2()
data = b"abcdefghabcdefgh" data = b"abcdefghabcdefgh"
ret = ifd.load_double(data, False) ret = getattr(ifd, "load_double")(data, False)
assert ret == (8.540883223036124e194, 8.540883223036124e194) assert ret == (8.540883223036124e194, 8.540883223036124e194)
def test_ifd_tag_type(self) -> None: def test_ifd_tag_type(self) -> None:
@ -599,7 +600,7 @@ class TestFileTiff:
def test_with_underscores(self, tmp_path: Path) -> None: def test_with_underscores(self, tmp_path: Path) -> None:
kwargs = {"resolution_unit": "inch", "x_resolution": 72, "y_resolution": 36} kwargs = {"resolution_unit": "inch", "x_resolution": 72, "y_resolution": 36}
filename = str(tmp_path / "temp.tif") filename = str(tmp_path / "temp.tif")
hopper("RGB").save(filename, **kwargs) hopper("RGB").save(filename, "TIFF", **kwargs)
with Image.open(filename) as im: with Image.open(filename) as im:
# legacy interface # legacy interface
assert im.tag[X_RESOLUTION][0][0] == 72 assert im.tag[X_RESOLUTION][0][0] == 72
@ -624,7 +625,9 @@ class TestFileTiff:
def test_iptc(self, tmp_path: Path) -> None: def test_iptc(self, tmp_path: Path) -> None:
# Do not preserve IPTC_NAA_CHUNK by default if type is LONG # Do not preserve IPTC_NAA_CHUNK by default if type is LONG
outfile = str(tmp_path / "temp.tif") outfile = str(tmp_path / "temp.tif")
im = hopper() with Image.open("Tests/images/hopper.tif") as im:
im.load()
assert isinstance(im, TiffImagePlugin.TiffImageFile)
ifd = TiffImagePlugin.ImageFileDirectory_v2() ifd = TiffImagePlugin.ImageFileDirectory_v2()
ifd[33723] = 1 ifd[33723] = 1
ifd.tagtype[33723] = 4 ifd.tagtype[33723] = 4
@ -632,6 +635,7 @@ class TestFileTiff:
im.save(outfile) im.save(outfile)
with Image.open(outfile) as im: with Image.open(outfile) as im:
assert isinstance(im, TiffImagePlugin.TiffImageFile)
assert 33723 not in im.tag_v2 assert 33723 not in im.tag_v2
def test_rowsperstrip(self, tmp_path: Path) -> None: def test_rowsperstrip(self, tmp_path: Path) -> None:

View File

@ -704,7 +704,7 @@ class TestImage:
else: else:
assert new_image.palette is None assert new_image.palette is None
_make_new(im, im_p, ImagePalette.ImagePalette(list(range(256)) * 3)) _make_new(im, im_p, ImagePalette.ImagePalette("RGB"))
_make_new(im_p, im, None) _make_new(im_p, im, None)
_make_new(im, blank_p, ImagePalette.ImagePalette()) _make_new(im, blank_p, ImagePalette.ImagePalette())
_make_new(im, blank_pa, ImagePalette.ImagePalette()) _make_new(im, blank_pa, ImagePalette.ImagePalette())

View File

@ -60,6 +60,8 @@ class TestImageGrab:
def test_grabclipboard(self) -> None: def test_grabclipboard(self) -> None:
if sys.platform == "darwin": if sys.platform == "darwin":
subprocess.call(["screencapture", "-cx"]) subprocess.call(["screencapture", "-cx"])
ImageGrab.grabclipboard()
elif sys.platform == "win32": elif sys.platform == "win32":
p = subprocess.Popen(["powershell", "-command", "-"], stdin=subprocess.PIPE) p = subprocess.Popen(["powershell", "-command", "-"], stdin=subprocess.PIPE)
p.stdin.write( p.stdin.write(
@ -69,6 +71,8 @@ $bmp = New-Object Drawing.Bitmap 200, 200
[Windows.Forms.Clipboard]::SetImage($bmp)""" [Windows.Forms.Clipboard]::SetImage($bmp)"""
) )
p.communicate() p.communicate()
ImageGrab.grabclipboard()
else: else:
if not shutil.which("wl-paste") and not shutil.which("xclip"): if not shutil.which("wl-paste") and not shutil.which("xclip"):
with pytest.raises( with pytest.raises(
@ -77,9 +81,6 @@ $bmp = New-Object Drawing.Bitmap 200, 200
r" ImageGrab.grabclipboard\(\) on Linux", r" ImageGrab.grabclipboard\(\) on Linux",
): ):
ImageGrab.grabclipboard() ImageGrab.grabclipboard()
return
ImageGrab.grabclipboard()
@pytest.mark.skipif(sys.platform != "win32", reason="Windows only") @pytest.mark.skipif(sys.platform != "win32", reason="Windows only")
def test_grabclipboard_file(self) -> None: def test_grabclipboard_file(self) -> None:

View File

@ -155,3 +155,11 @@ follow_imports = "silent"
warn_redundant_casts = true warn_redundant_casts = true
warn_unreachable = true warn_unreachable = true
warn_unused_ignores = true warn_unused_ignores = true
exclude = [
'^Tests/oss-fuzz/fuzz_font.py$',
'^Tests/oss-fuzz/fuzz_pillow.py$',
'^Tests/test_qt_image_qapplication.py$',
'^Tests/test_font_pcf_charsets.py$',
'^Tests/test_font_pcf.py$',
'^Tests/test_file_tar.py$',
]

View File

@ -1886,7 +1886,7 @@ class Image:
def point( def point(
self, self,
lut: Sequence[float] | Callable[[int], float] | ImagePointHandler, lut: Sequence[float] | NumpyArray | Callable[[int], float] | ImagePointHandler,
mode: str | None = None, mode: str | None = None,
) -> Image: ) -> Image:
""" """
@ -1996,7 +1996,7 @@ class Image:
def putdata( def putdata(
self, self,
data: Sequence[float] | Sequence[Sequence[int]], data: Sequence[float] | Sequence[Sequence[int]] | NumpyArray,
scale: float = 1.0, scale: float = 1.0,
offset: float = 0.0, offset: float = 0.0,
) -> None: ) -> None:

View File

@ -38,9 +38,11 @@ deps =
ipython ipython
numpy numpy
packaging packaging
pytest
types-defusedxml types-defusedxml
types-olefile types-olefile
types-setuptools
extras = extras =
typing typing
commands = commands =
mypy src {posargs} mypy src Tests {posargs}