mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-10-29 23:17:49 +03:00 
			
		
		
		
	Merge branch 'main' into progress
This commit is contained in:
		
						commit
						344c300597
					
				|  | @ -1 +1 @@ | |||
| cibuildwheel==2.16.2 | ||||
| cibuildwheel==2.16.5 | ||||
|  |  | |||
							
								
								
									
										12
									
								
								.github/workflows/docs.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								.github/workflows/docs.yml
									
									
									
									
										vendored
									
									
								
							|  | @ -37,16 +37,26 @@ jobs: | |||
|       with: | ||||
|         python-version: "3.x" | ||||
|         cache: pip | ||||
|         cache-dependency-path: ".ci/*.sh" | ||||
|         cache-dependency-path: | | ||||
|           ".ci/*.sh" | ||||
|           "pyproject.toml" | ||||
| 
 | ||||
|     - name: Build system information | ||||
|       run: python3 .github/workflows/system-info.py | ||||
| 
 | ||||
|     - name: Cache libimagequant | ||||
|       uses: actions/cache@v4 | ||||
|       id: cache-libimagequant | ||||
|       with: | ||||
|         path: ~/cache-libimagequant | ||||
|         key: ${{ runner.os }}-libimagequant-${{ hashFiles('depends/install_imagequant.sh') }} | ||||
| 
 | ||||
|     - name: Install Linux dependencies | ||||
|       run: | | ||||
|         .ci/install.sh | ||||
|       env: | ||||
|         GHA_PYTHON_VERSION: "3.x" | ||||
|         GHA_LIBIMAGEQUANT_CACHE_HIT: ${{ steps.cache-libimagequant.outputs.cache-hit }} | ||||
| 
 | ||||
|     - name: Build | ||||
|       run: | | ||||
|  |  | |||
							
								
								
									
										11
									
								
								.github/workflows/macos-install.sh
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								.github/workflows/macos-install.sh
									
									
									
									
										vendored
									
									
								
							|  | @ -2,7 +2,16 @@ | |||
| 
 | ||||
| set -e | ||||
| 
 | ||||
| brew install libtiff libjpeg openjpeg libimagequant webp little-cms2 freetype libraqm | ||||
| brew install \ | ||||
|     freetype \ | ||||
|     ghostscript \ | ||||
|     libimagequant \ | ||||
|     libjpeg \ | ||||
|     libraqm \ | ||||
|     libtiff \ | ||||
|     little-cms2 \ | ||||
|     openjpeg \ | ||||
|     webp | ||||
| export PKG_CONFIG_PATH="/usr/local/opt/openblas/lib/pkgconfig" | ||||
| 
 | ||||
| # TODO Update condition when cffi supports 3.13 | ||||
|  |  | |||
							
								
								
									
										5
									
								
								.github/workflows/test-cygwin.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.github/workflows/test-cygwin.yml
									
									
									
									
										vendored
									
									
								
							|  | @ -47,7 +47,7 @@ jobs: | |||
|         uses: actions/checkout@v4 | ||||
| 
 | ||||
|       - name: Install Cygwin | ||||
|         uses: cygwin/cygwin-install-action@v4 | ||||
|         uses: egor-tensin/setup-cygwin@v4 | ||||
|         with: | ||||
|           platform: x86_64 | ||||
|           packages: > | ||||
|  | @ -69,6 +69,7 @@ jobs: | |||
|             make | ||||
|             netpbm | ||||
|             perl | ||||
|             python39=3.9.16-1 | ||||
|             python3${{ matrix.python-minor-version }}-cffi | ||||
|             python3${{ matrix.python-minor-version }}-cython | ||||
|             python3${{ matrix.python-minor-version }}-devel | ||||
|  | @ -86,7 +87,7 @@ jobs: | |||
| 
 | ||||
|       - name: Select Python version | ||||
|         run: | | ||||
|           ln -sf c:/cygwin/bin/python3.${{ matrix.python-minor-version }} c:/cygwin/bin/python3 | ||||
|           ln -sf c:/tools/cygwin/bin/python3.${{ matrix.python-minor-version }} c:/tools/cygwin/bin/python3 | ||||
| 
 | ||||
|       - name: Get latest NumPy version | ||||
|         id: latest-numpy | ||||
|  |  | |||
							
								
								
									
										34
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										34
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
								
							|  | @ -26,6 +26,9 @@ concurrency: | |||
|   group: ${{ github.workflow }}-${{ github.ref }} | ||||
|   cancel-in-progress: true | ||||
| 
 | ||||
| env: | ||||
|   FORCE_COLOR: 1 | ||||
| 
 | ||||
| jobs: | ||||
|   build: | ||||
| 
 | ||||
|  | @ -33,7 +36,7 @@ jobs: | |||
|       fail-fast: false | ||||
|       matrix: | ||||
|         os: [ | ||||
|           "macos-latest", | ||||
|           "macos-14", | ||||
|           "ubuntu-latest", | ||||
|         ] | ||||
|         python-version: [ | ||||
|  | @ -47,11 +50,21 @@ jobs: | |||
|           "3.8", | ||||
|         ] | ||||
|         include: | ||||
|         - python-version: "3.9" | ||||
|         - python-version: "3.11" | ||||
|           PYTHONOPTIMIZE: 1 | ||||
|           REVERSE: "--reverse" | ||||
|         - python-version: "3.8" | ||||
|         - python-version: "3.10" | ||||
|           PYTHONOPTIMIZE: 2 | ||||
|         # M1 only available for 3.10+ | ||||
|         - os: "macos-latest" | ||||
|           python-version: "3.9" | ||||
|         - os: "macos-latest" | ||||
|           python-version: "3.8" | ||||
|         exclude: | ||||
|         - os: "macos-14" | ||||
|           python-version: "3.9" | ||||
|         - os: "macos-14" | ||||
|           python-version: "3.8" | ||||
| 
 | ||||
|     runs-on: ${{ matrix.os }} | ||||
|     name: ${{ matrix.os }} Python ${{ matrix.python-version }} | ||||
|  | @ -65,17 +78,28 @@ jobs: | |||
|         python-version: ${{ matrix.python-version }} | ||||
|         allow-prereleases: true | ||||
|         cache: pip | ||||
|         cache-dependency-path: ".ci/*.sh" | ||||
|         cache-dependency-path: | | ||||
|           ".ci/*.sh" | ||||
|           "pyproject.toml" | ||||
| 
 | ||||
|     - name: Build system information | ||||
|       run: python3 .github/workflows/system-info.py | ||||
| 
 | ||||
|     - name: Cache libimagequant | ||||
|       if: startsWith(matrix.os, 'ubuntu') | ||||
|       uses: actions/cache@v4 | ||||
|       id: cache-libimagequant | ||||
|       with: | ||||
|         path: ~/cache-libimagequant | ||||
|         key: ${{ runner.os }}-libimagequant-${{ hashFiles('depends/install_imagequant.sh') }} | ||||
| 
 | ||||
|     - name: Install Linux dependencies | ||||
|       if: startsWith(matrix.os, 'ubuntu') | ||||
|       run: | | ||||
|         .ci/install.sh | ||||
|       env: | ||||
|         GHA_PYTHON_VERSION: ${{ matrix.python-version }} | ||||
|         GHA_LIBIMAGEQUANT_CACHE_HIT: ${{ steps.cache-libimagequant.outputs.cache-hit }} | ||||
| 
 | ||||
|     - name: Install macOS dependencies | ||||
|       if: startsWith(matrix.os, 'macOS') | ||||
|  | @ -127,7 +151,7 @@ jobs: | |||
|     - name: Upload coverage | ||||
|       uses: codecov/codecov-action@v3 | ||||
|       with: | ||||
|         flags: ${{ matrix.os == 'macos-latest' && 'GHA_macOS' || 'GHA_Ubuntu' }} | ||||
|         flags: ${{ matrix.os == 'ubuntu-latest' && 'GHA_Ubuntu' || 'GHA_macOS' }} | ||||
|         name: ${{ matrix.os }} Python ${{ matrix.python-version }} | ||||
|         gcov: true | ||||
| 
 | ||||
|  |  | |||
|  | @ -32,6 +32,7 @@ repos: | |||
|     rev: v4.5.0 | ||||
|     hooks: | ||||
|       - id: check-executables-have-shebangs | ||||
|       - id: check-shebang-scripts-are-executable | ||||
|       - id: check-merge-conflict | ||||
|       - id: check-json | ||||
|       - id: check-toml | ||||
|  |  | |||
|  | @ -5,6 +5,12 @@ Changelog (Pillow) | |||
| 10.3.0 (unreleased) | ||||
| ------------------- | ||||
| 
 | ||||
| - Do not support using test-image-results to upload images after test failures #7739 | ||||
|   [radarhere] | ||||
| 
 | ||||
| - Changed ImageMath.ops to be static #7721 | ||||
|   [radarhere] | ||||
| 
 | ||||
| - Fix APNG info after seeking backwards more than twice #7701 | ||||
|   [esoma, radarhere] | ||||
| 
 | ||||
|  |  | |||
|  | @ -9,21 +9,21 @@ from .helper import hopper | |||
| # Not running this test by default. No DOS against CI. | ||||
| 
 | ||||
| 
 | ||||
| def iterate_get(size, access): | ||||
| def iterate_get(size, access) -> None: | ||||
|     (w, h) = size | ||||
|     for x in range(w): | ||||
|         for y in range(h): | ||||
|             access[(x, y)] | ||||
| 
 | ||||
| 
 | ||||
| def iterate_set(size, access): | ||||
| def iterate_set(size, access) -> None: | ||||
|     (w, h) = size | ||||
|     for x in range(w): | ||||
|         for y in range(h): | ||||
|             access[(x, y)] = (x % 256, y % 256, 0) | ||||
| 
 | ||||
| 
 | ||||
| def timer(func, label, *args): | ||||
| def timer(func, label, *args) -> None: | ||||
|     iterations = 5000 | ||||
|     starttime = time.time() | ||||
|     for x in range(iterations): | ||||
|  | @ -38,7 +38,7 @@ def timer(func, label, *args): | |||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| def test_direct(): | ||||
| def test_direct() -> None: | ||||
|     im = hopper() | ||||
|     im.load() | ||||
|     # im = Image.new("RGB", (2000, 2000), (1, 3, 2)) | ||||
|  |  | |||
|  | @ -1,4 +1,3 @@ | |||
| #!/usr/bin/env python3 | ||||
| from __future__ import annotations | ||||
| 
 | ||||
| from PIL import Image | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ from PIL import Image | |||
| TEST_FILE = "Tests/images/fli_overflow.fli" | ||||
| 
 | ||||
| 
 | ||||
| def test_fli_overflow(): | ||||
| def test_fli_overflow() -> None: | ||||
|     # this should not crash with a malloc error or access violation | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         im.load() | ||||
|  |  | |||
|  | @ -1,6 +1,8 @@ | |||
| #!/usr/bin/env python3 | ||||
| from __future__ import annotations | ||||
| 
 | ||||
| from typing import Any, Callable | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
| from PIL import Image | ||||
|  | @ -13,31 +15,34 @@ max_iterations = 10000 | |||
| pytestmark = pytest.mark.skipif(is_win32(), reason="requires Unix or macOS") | ||||
| 
 | ||||
| 
 | ||||
| def _get_mem_usage(): | ||||
| def _get_mem_usage() -> float: | ||||
|     from resource import RUSAGE_SELF, getpagesize, getrusage | ||||
| 
 | ||||
|     mem = getrusage(RUSAGE_SELF).ru_maxrss | ||||
|     return mem * getpagesize() / 1024 / 1024 | ||||
| 
 | ||||
| 
 | ||||
| def _test_leak(min_iterations, max_iterations, fn, *args, **kwargs): | ||||
| def _test_leak( | ||||
|     min_iterations: int, max_iterations: int, fn: Callable[..., None], *args: Any | ||||
| ) -> None: | ||||
|     mem_limit = None | ||||
|     for i in range(max_iterations): | ||||
|         fn(*args, **kwargs) | ||||
|         fn(*args) | ||||
|         mem = _get_mem_usage() | ||||
|         if i < min_iterations: | ||||
|             mem_limit = mem + 1 | ||||
|             continue | ||||
|         msg = f"memory usage limit exceeded after {i + 1} iterations" | ||||
|         assert mem_limit is not None | ||||
|         assert mem <= mem_limit, msg | ||||
| 
 | ||||
| 
 | ||||
| def test_leak_putdata(): | ||||
| def test_leak_putdata() -> None: | ||||
|     im = Image.new("RGB", (25, 25)) | ||||
|     _test_leak(min_iterations, max_iterations, im.putdata, im.getdata()) | ||||
| 
 | ||||
| 
 | ||||
| def test_leak_getlist(): | ||||
| def test_leak_getlist() -> None: | ||||
|     im = Image.new("P", (25, 25)) | ||||
|     _test_leak( | ||||
|         min_iterations, | ||||
|  |  | |||
|  | @ -20,7 +20,7 @@ pytestmark = [ | |||
| ] | ||||
| 
 | ||||
| 
 | ||||
| def test_leak_load(): | ||||
| def test_leak_load() -> None: | ||||
|     from resource import RLIMIT_AS, RLIMIT_STACK, setrlimit | ||||
| 
 | ||||
|     setrlimit(RLIMIT_STACK, (stack_size, stack_size)) | ||||
|  | @ -30,7 +30,7 @@ def test_leak_load(): | |||
|             im.load() | ||||
| 
 | ||||
| 
 | ||||
| def test_leak_save(): | ||||
| def test_leak_save() -> None: | ||||
|     from resource import RLIMIT_AS, RLIMIT_STACK, setrlimit | ||||
| 
 | ||||
|     setrlimit(RLIMIT_STACK, (stack_size, stack_size)) | ||||
|  |  | |||
|  | @ -1,11 +1,13 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
| from PIL import Image | ||||
| 
 | ||||
| 
 | ||||
| def test_j2k_overflow(tmp_path): | ||||
| def test_j2k_overflow(tmp_path: Path) -> None: | ||||
|     im = Image.new("RGBA", (1024, 131584)) | ||||
|     target = str(tmp_path / "temp.jpc") | ||||
|     with pytest.raises(OSError): | ||||
|  |  | |||
							
								
								
									
										2
									
								
								Tests/check_jp2_overflow.py
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										2
									
								
								Tests/check_jp2_overflow.py
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							|  | @ -1,5 +1,3 @@ | |||
| #!/usr/bin/env python3 | ||||
| 
 | ||||
| # Reproductions/tests for OOB read errors in FliDecode.c | ||||
| 
 | ||||
| # When run in python, all of these images should fail for | ||||
|  |  | |||
|  | @ -111,14 +111,14 @@ standard_chrominance_qtable = ( | |||
|         [standard_l_qtable, standard_chrominance_qtable], | ||||
|     ), | ||||
| ) | ||||
| def test_qtables_leak(qtables): | ||||
| def test_qtables_leak(qtables: tuple[tuple[int, ...]] | list[tuple[int, ...]]) -> None: | ||||
|     im = hopper("RGB") | ||||
|     for _ in range(iterations): | ||||
|         test_output = BytesIO() | ||||
|         im.save(test_output, "JPEG", qtables=qtables) | ||||
| 
 | ||||
| 
 | ||||
| def test_exif_leak(): | ||||
| def test_exif_leak() -> None: | ||||
|     """ | ||||
|     pre patch: | ||||
| 
 | ||||
|  | @ -181,7 +181,7 @@ def test_exif_leak(): | |||
|         im.save(test_output, "JPEG", exif=exif) | ||||
| 
 | ||||
| 
 | ||||
| def test_base_save(): | ||||
| def test_base_save() -> None: | ||||
|     """ | ||||
|     base case: | ||||
|         MB | ||||
|  |  | |||
|  | @ -1,6 +1,8 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| import sys | ||||
| from pathlib import Path | ||||
| from types import ModuleType | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -16,6 +18,7 @@ from PIL import Image | |||
| # 2.7 and 3.2. | ||||
| 
 | ||||
| 
 | ||||
| numpy: ModuleType | None | ||||
| try: | ||||
|     import numpy | ||||
| except ImportError: | ||||
|  | @ -28,23 +31,24 @@ XDIM = 48000 | |||
| pytestmark = pytest.mark.skipif(sys.maxsize <= 2**32, reason="requires 64-bit system") | ||||
| 
 | ||||
| 
 | ||||
| def _write_png(tmp_path, xdim, ydim): | ||||
| def _write_png(tmp_path: Path, xdim: int, ydim: int) -> None: | ||||
|     f = str(tmp_path / "temp.png") | ||||
|     im = Image.new("L", (xdim, ydim), 0) | ||||
|     im.save(f) | ||||
| 
 | ||||
| 
 | ||||
| def test_large(tmp_path): | ||||
| def test_large(tmp_path: Path) -> None: | ||||
|     """succeeded prepatch""" | ||||
|     _write_png(tmp_path, XDIM, YDIM) | ||||
| 
 | ||||
| 
 | ||||
| def test_2gpx(tmp_path): | ||||
| def test_2gpx(tmp_path: Path) -> None: | ||||
|     """failed prepatch""" | ||||
|     _write_png(tmp_path, XDIM, XDIM) | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.skipif(numpy is None, reason="Numpy is not installed") | ||||
| def test_size_greater_than_int(): | ||||
| def test_size_greater_than_int() -> None: | ||||
|     assert numpy is not None | ||||
|     arr = numpy.ndarray(shape=(16394, 16394)) | ||||
|     Image.fromarray(arr) | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| import sys | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -24,7 +25,7 @@ XDIM = 48000 | |||
| pytestmark = pytest.mark.skipif(sys.maxsize <= 2**32, reason="requires 64-bit system") | ||||
| 
 | ||||
| 
 | ||||
| def _write_png(tmp_path, xdim, ydim): | ||||
| def _write_png(tmp_path: Path, xdim: int, ydim: int) -> None: | ||||
|     dtype = np.uint8 | ||||
|     a = np.zeros((xdim, ydim), dtype=dtype) | ||||
|     f = str(tmp_path / "temp.png") | ||||
|  | @ -32,11 +33,11 @@ def _write_png(tmp_path, xdim, ydim): | |||
|     im.save(f) | ||||
| 
 | ||||
| 
 | ||||
| def test_large(tmp_path): | ||||
| def test_large(tmp_path: Path) -> None: | ||||
|     """succeeded prepatch""" | ||||
|     _write_png(tmp_path, XDIM, YDIM) | ||||
| 
 | ||||
| 
 | ||||
| def test_2gpx(tmp_path): | ||||
| def test_2gpx(tmp_path: Path) -> None: | ||||
|     """failed prepatch""" | ||||
|     _write_png(tmp_path, XDIM, XDIM) | ||||
|  |  | |||
|  | @ -7,7 +7,7 @@ from PIL import Image | |||
| TEST_FILE = "Tests/images/libtiff_segfault.tif" | ||||
| 
 | ||||
| 
 | ||||
| def test_libtiff_segfault(): | ||||
| def test_libtiff_segfault() -> None: | ||||
|     """This test should not segfault. It will on Pillow <= 3.1.0 and | ||||
|     libtiff >= 4.0.0 | ||||
|     """ | ||||
|  |  | |||
|  | @ -8,7 +8,7 @@ from PIL import Image, ImageFile, PngImagePlugin | |||
| TEST_FILE = "Tests/images/png_decompression_dos.png" | ||||
| 
 | ||||
| 
 | ||||
| def test_ignore_dos_text(): | ||||
| def test_ignore_dos_text() -> None: | ||||
|     ImageFile.LOAD_TRUNCATED_IMAGES = True | ||||
| 
 | ||||
|     try: | ||||
|  | @ -24,7 +24,7 @@ def test_ignore_dos_text(): | |||
|         assert len(s) < 1024 * 1024, "Text chunk larger than 1M" | ||||
| 
 | ||||
| 
 | ||||
| def test_dos_text(): | ||||
| def test_dos_text() -> None: | ||||
|     try: | ||||
|         im = Image.open(TEST_FILE) | ||||
|         im.load() | ||||
|  | @ -36,7 +36,7 @@ def test_dos_text(): | |||
|         assert len(s) < 1024 * 1024, "Text chunk larger than 1M" | ||||
| 
 | ||||
| 
 | ||||
| def test_dos_total_memory(): | ||||
| def test_dos_total_memory() -> None: | ||||
|     im = Image.new("L", (1, 1)) | ||||
|     compressed_data = zlib.compress(b"a" * 1024 * 1023) | ||||
| 
 | ||||
|  | @ -53,7 +53,7 @@ def test_dos_total_memory(): | |||
|     try: | ||||
|         im2 = Image.open(b) | ||||
|     except ValueError as msg: | ||||
|         assert "Too much memory" in msg | ||||
|         assert "Too much memory" in str(msg) | ||||
|         return | ||||
| 
 | ||||
|     total_len = 0 | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ import sys | |||
| from PIL import features | ||||
| 
 | ||||
| 
 | ||||
| def test_wheel_modules(): | ||||
| def test_wheel_modules() -> None: | ||||
|     expected_modules = {"pil", "tkinter", "freetype2", "littlecms2", "webp"} | ||||
| 
 | ||||
|     # tkinter is not available in cibuildwheel installed CPython on Windows | ||||
|  | @ -19,13 +19,13 @@ def test_wheel_modules(): | |||
|     assert set(features.get_supported_modules()) == expected_modules | ||||
| 
 | ||||
| 
 | ||||
| def test_wheel_codecs(): | ||||
| def test_wheel_codecs() -> None: | ||||
|     expected_codecs = {"jpg", "jpg_2000", "zlib", "libtiff"} | ||||
| 
 | ||||
|     assert set(features.get_supported_codecs()) == expected_codecs | ||||
| 
 | ||||
| 
 | ||||
| def test_wheel_features(): | ||||
| def test_wheel_features() -> None: | ||||
|     expected_features = { | ||||
|         "webp_anim", | ||||
|         "webp_mux", | ||||
|  |  | |||
|  | @ -2,8 +2,10 @@ from __future__ import annotations | |||
| 
 | ||||
| import io | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
| def pytest_report_header(config): | ||||
| 
 | ||||
| def pytest_report_header(config: pytest.Config) -> str: | ||||
|     try: | ||||
|         from PIL import features | ||||
| 
 | ||||
|  | @ -14,7 +16,7 @@ def pytest_report_header(config): | |||
|         return f"pytest_report_header failed: {e}" | ||||
| 
 | ||||
| 
 | ||||
| def pytest_configure(config): | ||||
| def pytest_configure(config: pytest.Config) -> None: | ||||
|     config.addinivalue_line( | ||||
|         "markers", | ||||
|         "pil_noop_mark: A conditional mark where nothing special happens", | ||||
|  |  | |||
|  | @ -25,13 +25,6 @@ if os.environ.get("SHOW_ERRORS"): | |||
|     uploader = "show" | ||||
| elif "GITHUB_ACTIONS" in os.environ: | ||||
|     uploader = "github_actions" | ||||
| else: | ||||
|     try: | ||||
|         import test_image_results | ||||
| 
 | ||||
|         uploader = "aws" | ||||
|     except ImportError: | ||||
|         pass | ||||
| 
 | ||||
| 
 | ||||
| def upload(a: Image.Image, b: Image.Image) -> str | None: | ||||
|  | @ -46,8 +39,6 @@ def upload(a: Image.Image, b: Image.Image) -> str | None: | |||
|         a.save(os.path.join(tmpdir, "a.png")) | ||||
|         b.save(os.path.join(tmpdir, "b.png")) | ||||
|         return tmpdir | ||||
|     elif uploader == "aws": | ||||
|         return test_image_results.upload(a, b) | ||||
|     return None | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,3 @@ | |||
| #!/usr/bin/gnuplot | ||||
| 
 | ||||
| #This is the script that was used to create our sample EPS files | ||||
| #We used the following version of the gnuplot program | ||||
| #G N U P L O T | ||||
|  |  | |||
|  | @ -1,5 +1,3 @@ | |||
| #!/usr/bin/python3 | ||||
| 
 | ||||
| # Copyright 2020 Google LLC | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ from __future__ import annotations | |||
| from PIL import Image | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(): | ||||
| def test_sanity() -> None: | ||||
|     # Make sure we have the binary extension | ||||
|     Image.core.new("L", (100, 100)) | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,12 +3,12 @@ from __future__ import annotations | |||
| from PIL import _binary | ||||
| 
 | ||||
| 
 | ||||
| def test_standard(): | ||||
| def test_standard() -> None: | ||||
|     assert _binary.i8(b"*") == 42 | ||||
|     assert _binary.o8(42) == b"*" | ||||
| 
 | ||||
| 
 | ||||
| def test_little_endian(): | ||||
| def test_little_endian() -> None: | ||||
|     assert _binary.i16le(b"\xff\xff\x00\x00") == 65535 | ||||
|     assert _binary.i32le(b"\xff\xff\x00\x00") == 65535 | ||||
| 
 | ||||
|  | @ -16,7 +16,7 @@ def test_little_endian(): | |||
|     assert _binary.o32le(65535) == b"\xff\xff\x00\x00" | ||||
| 
 | ||||
| 
 | ||||
| def test_big_endian(): | ||||
| def test_big_endian() -> None: | ||||
|     assert _binary.i16be(b"\x00\x00\xff\xff") == 0 | ||||
|     assert _binary.i32be(b"\x00\x00\xff\xff") == 65535 | ||||
| 
 | ||||
|  |  | |||
|  | @ -10,13 +10,13 @@ from .helper import assert_image_similar | |||
| base = os.path.join("Tests", "images", "bmp") | ||||
| 
 | ||||
| 
 | ||||
| def get_files(d, ext=".bmp"): | ||||
| def get_files(d, ext: str = ".bmp"): | ||||
|     return [ | ||||
|         os.path.join(base, d, f) for f in os.listdir(os.path.join(base, d)) if ext in f | ||||
|     ] | ||||
| 
 | ||||
| 
 | ||||
| def test_bad(): | ||||
| def test_bad() -> None: | ||||
|     """These shouldn't crash/dos, but they shouldn't return anything | ||||
|     either""" | ||||
|     for f in get_files("b"): | ||||
|  | @ -56,7 +56,7 @@ def test_questionable(): | |||
|                 raise | ||||
| 
 | ||||
| 
 | ||||
| def test_good(): | ||||
| def test_good() -> None: | ||||
|     """These should all work. There's a set of target files in the | ||||
|     html directory that we can compare against.""" | ||||
| 
 | ||||
|  |  | |||
|  | @ -16,18 +16,18 @@ sample.putdata(sum([ | |||
| # fmt: on | ||||
| 
 | ||||
| 
 | ||||
| def test_imageops_box_blur(): | ||||
| def test_imageops_box_blur() -> None: | ||||
|     i = sample.filter(ImageFilter.BoxBlur(1)) | ||||
|     assert i.mode == sample.mode | ||||
|     assert i.size == sample.size | ||||
|     assert isinstance(i, Image.Image) | ||||
| 
 | ||||
| 
 | ||||
| def box_blur(image, radius=1, n=1): | ||||
| def box_blur(image, radius: int = 1, n: int = 1): | ||||
|     return image._new(image.im.box_blur((radius, radius), n)) | ||||
| 
 | ||||
| 
 | ||||
| def assert_image(im, data, delta=0): | ||||
| def assert_image(im, data, delta: int = 0) -> None: | ||||
|     it = iter(im.getdata()) | ||||
|     for data_row in data: | ||||
|         im_row = [next(it) for _ in range(im.size[0])] | ||||
|  | @ -37,7 +37,7 @@ def assert_image(im, data, delta=0): | |||
|         next(it) | ||||
| 
 | ||||
| 
 | ||||
| def assert_blur(im, radius, data, passes=1, delta=0): | ||||
| def assert_blur(im, radius, data, passes: int = 1, delta: int = 0) -> None: | ||||
|     # check grayscale image | ||||
|     assert_image(box_blur(im, radius, passes), data, delta) | ||||
|     rgba = Image.merge("RGBA", (im, im, im, im)) | ||||
|  | @ -45,7 +45,7 @@ def assert_blur(im, radius, data, passes=1, delta=0): | |||
|         assert_image(band, data, delta) | ||||
| 
 | ||||
| 
 | ||||
| def test_color_modes(): | ||||
| def test_color_modes() -> None: | ||||
|     with pytest.raises(ValueError): | ||||
|         box_blur(sample.convert("1")) | ||||
|     with pytest.raises(ValueError): | ||||
|  | @ -65,7 +65,7 @@ def test_color_modes(): | |||
|         box_blur(sample.convert("YCbCr")) | ||||
| 
 | ||||
| 
 | ||||
| def test_radius_0(): | ||||
| def test_radius_0() -> None: | ||||
|     assert_blur( | ||||
|         sample, | ||||
|         0, | ||||
|  | @ -81,7 +81,7 @@ def test_radius_0(): | |||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| def test_radius_0_02(): | ||||
| def test_radius_0_02() -> None: | ||||
|     assert_blur( | ||||
|         sample, | ||||
|         0.02, | ||||
|  | @ -98,7 +98,7 @@ def test_radius_0_02(): | |||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| def test_radius_0_05(): | ||||
| def test_radius_0_05() -> None: | ||||
|     assert_blur( | ||||
|         sample, | ||||
|         0.05, | ||||
|  | @ -115,7 +115,7 @@ def test_radius_0_05(): | |||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| def test_radius_0_1(): | ||||
| def test_radius_0_1() -> None: | ||||
|     assert_blur( | ||||
|         sample, | ||||
|         0.1, | ||||
|  | @ -132,7 +132,7 @@ def test_radius_0_1(): | |||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| def test_radius_0_5(): | ||||
| def test_radius_0_5() -> None: | ||||
|     assert_blur( | ||||
|         sample, | ||||
|         0.5, | ||||
|  | @ -149,7 +149,7 @@ def test_radius_0_5(): | |||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| def test_radius_1(): | ||||
| def test_radius_1() -> None: | ||||
|     assert_blur( | ||||
|         sample, | ||||
|         1, | ||||
|  | @ -166,7 +166,7 @@ def test_radius_1(): | |||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| def test_radius_1_5(): | ||||
| def test_radius_1_5() -> None: | ||||
|     assert_blur( | ||||
|         sample, | ||||
|         1.5, | ||||
|  | @ -183,7 +183,7 @@ def test_radius_1_5(): | |||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| def test_radius_bigger_then_half(): | ||||
| def test_radius_bigger_then_half() -> None: | ||||
|     assert_blur( | ||||
|         sample, | ||||
|         3, | ||||
|  | @ -200,7 +200,7 @@ def test_radius_bigger_then_half(): | |||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| def test_radius_bigger_then_width(): | ||||
| def test_radius_bigger_then_width() -> None: | ||||
|     assert_blur( | ||||
|         sample, | ||||
|         10, | ||||
|  | @ -215,7 +215,7 @@ def test_radius_bigger_then_width(): | |||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| def test_extreme_large_radius(): | ||||
| def test_extreme_large_radius() -> None: | ||||
|     assert_blur( | ||||
|         sample, | ||||
|         600, | ||||
|  | @ -230,7 +230,7 @@ def test_extreme_large_radius(): | |||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| def test_two_passes(): | ||||
| def test_two_passes() -> None: | ||||
|     assert_blur( | ||||
|         sample, | ||||
|         1, | ||||
|  | @ -248,7 +248,7 @@ def test_two_passes(): | |||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| def test_three_passes(): | ||||
| def test_three_passes() -> None: | ||||
|     assert_blur( | ||||
|         sample, | ||||
|         1, | ||||
|  |  | |||
|  | @ -41,7 +41,7 @@ class TestColorLut3DCoreAPI: | |||
|             [item for sublist in table for item in sublist], | ||||
|         ) | ||||
| 
 | ||||
|     def test_wrong_args(self): | ||||
|     def test_wrong_args(self) -> None: | ||||
|         im = Image.new("RGB", (10, 10), 0) | ||||
| 
 | ||||
|         with pytest.raises(ValueError, match="filter"): | ||||
|  | @ -101,7 +101,7 @@ class TestColorLut3DCoreAPI: | |||
|         with pytest.raises(TypeError): | ||||
|             im.im.color_lut_3d("RGB", Image.Resampling.BILINEAR, 3, 2, 2, 2, 16) | ||||
| 
 | ||||
|     def test_correct_args(self): | ||||
|     def test_correct_args(self) -> None: | ||||
|         im = Image.new("RGB", (10, 10), 0) | ||||
| 
 | ||||
|         im.im.color_lut_3d( | ||||
|  | @ -136,7 +136,7 @@ class TestColorLut3DCoreAPI: | |||
|             *self.generate_identity_table(3, (3, 3, 65)), | ||||
|         ) | ||||
| 
 | ||||
|     def test_wrong_mode(self): | ||||
|     def test_wrong_mode(self) -> None: | ||||
|         with pytest.raises(ValueError, match="wrong mode"): | ||||
|             im = Image.new("L", (10, 10), 0) | ||||
|             im.im.color_lut_3d( | ||||
|  | @ -167,7 +167,7 @@ class TestColorLut3DCoreAPI: | |||
|                 "RGB", Image.Resampling.BILINEAR, *self.generate_identity_table(4, 3) | ||||
|             ) | ||||
| 
 | ||||
|     def test_correct_mode(self): | ||||
|     def test_correct_mode(self) -> None: | ||||
|         im = Image.new("RGBA", (10, 10), 0) | ||||
|         im.im.color_lut_3d( | ||||
|             "RGBA", Image.Resampling.BILINEAR, *self.generate_identity_table(3, 3) | ||||
|  | @ -188,7 +188,7 @@ class TestColorLut3DCoreAPI: | |||
|             "RGBA", Image.Resampling.BILINEAR, *self.generate_identity_table(4, 3) | ||||
|         ) | ||||
| 
 | ||||
|     def test_identities(self): | ||||
|     def test_identities(self) -> None: | ||||
|         g = Image.linear_gradient("L") | ||||
|         im = Image.merge( | ||||
|             "RGB", | ||||
|  | @ -224,7 +224,7 @@ class TestColorLut3DCoreAPI: | |||
|             ), | ||||
|         ) | ||||
| 
 | ||||
|     def test_identities_4_channels(self): | ||||
|     def test_identities_4_channels(self) -> None: | ||||
|         g = Image.linear_gradient("L") | ||||
|         im = Image.merge( | ||||
|             "RGB", | ||||
|  | @ -247,7 +247,7 @@ class TestColorLut3DCoreAPI: | |||
|             ), | ||||
|         ) | ||||
| 
 | ||||
|     def test_copy_alpha_channel(self): | ||||
|     def test_copy_alpha_channel(self) -> None: | ||||
|         g = Image.linear_gradient("L") | ||||
|         im = Image.merge( | ||||
|             "RGBA", | ||||
|  | @ -270,7 +270,7 @@ class TestColorLut3DCoreAPI: | |||
|             ), | ||||
|         ) | ||||
| 
 | ||||
|     def test_channels_order(self): | ||||
|     def test_channels_order(self) -> None: | ||||
|         g = Image.linear_gradient("L") | ||||
|         im = Image.merge( | ||||
|             "RGB", | ||||
|  | @ -295,7 +295,7 @@ class TestColorLut3DCoreAPI: | |||
|                     ]))) | ||||
|         # fmt: on | ||||
| 
 | ||||
|     def test_overflow(self): | ||||
|     def test_overflow(self) -> None: | ||||
|         g = Image.linear_gradient("L") | ||||
|         im = Image.merge( | ||||
|             "RGB", | ||||
|  | @ -348,7 +348,7 @@ class TestColorLut3DCoreAPI: | |||
| 
 | ||||
| 
 | ||||
| class TestColorLut3DFilter: | ||||
|     def test_wrong_args(self): | ||||
|     def test_wrong_args(self) -> None: | ||||
|         with pytest.raises(ValueError, match="should be either an integer"): | ||||
|             ImageFilter.Color3DLUT("small", [1]) | ||||
| 
 | ||||
|  | @ -376,7 +376,7 @@ class TestColorLut3DFilter: | |||
|         with pytest.raises(ValueError, match="Only 3 or 4 output"): | ||||
|             ImageFilter.Color3DLUT((2, 2, 2), [[1, 1]] * 8, channels=2) | ||||
| 
 | ||||
|     def test_convert_table(self): | ||||
|     def test_convert_table(self) -> None: | ||||
|         lut = ImageFilter.Color3DLUT(2, [0, 1, 2] * 8) | ||||
|         assert tuple(lut.size) == (2, 2, 2) | ||||
|         assert lut.name == "Color 3D LUT" | ||||
|  | @ -394,7 +394,7 @@ class TestColorLut3DFilter: | |||
|         assert lut.table == list(range(4)) * 8 | ||||
| 
 | ||||
|     @pytest.mark.skipif(numpy is None, reason="NumPy not installed") | ||||
|     def test_numpy_sources(self): | ||||
|     def test_numpy_sources(self) -> None: | ||||
|         table = numpy.ones((5, 6, 7, 3), dtype=numpy.float16) | ||||
|         with pytest.raises(ValueError, match="should have either channels"): | ||||
|             lut = ImageFilter.Color3DLUT((5, 6, 7), table) | ||||
|  | @ -427,7 +427,7 @@ class TestColorLut3DFilter: | |||
|         assert lut.table[0] == 33 | ||||
| 
 | ||||
|     @pytest.mark.skipif(numpy is None, reason="NumPy not installed") | ||||
|     def test_numpy_formats(self): | ||||
|     def test_numpy_formats(self) -> None: | ||||
|         g = Image.linear_gradient("L") | ||||
|         im = Image.merge( | ||||
|             "RGB", | ||||
|  | @ -466,7 +466,7 @@ class TestColorLut3DFilter: | |||
|         lut.table = numpy.array(lut.table, dtype=numpy.int8) | ||||
|         im.filter(lut) | ||||
| 
 | ||||
|     def test_repr(self): | ||||
|     def test_repr(self) -> None: | ||||
|         lut = ImageFilter.Color3DLUT(2, [0, 1, 2] * 8) | ||||
|         assert repr(lut) == "<Color3DLUT from list size=2x2x2 channels=3>" | ||||
| 
 | ||||
|  | @ -484,7 +484,7 @@ class TestColorLut3DFilter: | |||
| 
 | ||||
| 
 | ||||
| class TestGenerateColorLut3D: | ||||
|     def test_wrong_channels_count(self): | ||||
|     def test_wrong_channels_count(self) -> None: | ||||
|         with pytest.raises(ValueError, match="3 or 4 output channels"): | ||||
|             ImageFilter.Color3DLUT.generate( | ||||
|                 5, channels=2, callback=lambda r, g, b: (r, g, b) | ||||
|  | @ -498,7 +498,7 @@ class TestGenerateColorLut3D: | |||
|                 5, channels=4, callback=lambda r, g, b: (r, g, b) | ||||
|             ) | ||||
| 
 | ||||
|     def test_3_channels(self): | ||||
|     def test_3_channels(self) -> None: | ||||
|         lut = ImageFilter.Color3DLUT.generate(5, lambda r, g, b: (r, g, b)) | ||||
|         assert tuple(lut.size) == (5, 5, 5) | ||||
|         assert lut.name == "Color 3D LUT" | ||||
|  | @ -508,7 +508,7 @@ class TestGenerateColorLut3D: | |||
|             1.0, 0.0, 0.0,  0.0, 0.25, 0.0,  0.25, 0.25, 0.0,  0.5, 0.25, 0.0] | ||||
|         # fmt: on | ||||
| 
 | ||||
|     def test_4_channels(self): | ||||
|     def test_4_channels(self) -> None: | ||||
|         lut = ImageFilter.Color3DLUT.generate( | ||||
|             5, channels=4, callback=lambda r, g, b: (b, r, g, (r + g + b) / 2) | ||||
|         ) | ||||
|  | @ -521,7 +521,7 @@ class TestGenerateColorLut3D: | |||
|         ] | ||||
|         # fmt: on | ||||
| 
 | ||||
|     def test_apply(self): | ||||
|     def test_apply(self) -> None: | ||||
|         lut = ImageFilter.Color3DLUT.generate(5, lambda r, g, b: (r, g, b)) | ||||
| 
 | ||||
|         g = Image.linear_gradient("L") | ||||
|  | @ -537,7 +537,7 @@ class TestGenerateColorLut3D: | |||
| 
 | ||||
| 
 | ||||
| class TestTransformColorLut3D: | ||||
|     def test_wrong_args(self): | ||||
|     def test_wrong_args(self) -> None: | ||||
|         source = ImageFilter.Color3DLUT.generate(5, lambda r, g, b: (r, g, b)) | ||||
| 
 | ||||
|         with pytest.raises(ValueError, match="Only 3 or 4 output"): | ||||
|  | @ -552,7 +552,7 @@ class TestTransformColorLut3D: | |||
|         with pytest.raises(TypeError): | ||||
|             source.transform(lambda r, g, b, a: (r, g, b)) | ||||
| 
 | ||||
|     def test_target_mode(self): | ||||
|     def test_target_mode(self) -> None: | ||||
|         source = ImageFilter.Color3DLUT.generate( | ||||
|             2, lambda r, g, b: (r, g, b), target_mode="HSV" | ||||
|         ) | ||||
|  | @ -563,7 +563,7 @@ class TestTransformColorLut3D: | |||
|         lut = source.transform(lambda r, g, b: (r, g, b), target_mode="RGB") | ||||
|         assert lut.mode == "RGB" | ||||
| 
 | ||||
|     def test_3_to_3_channels(self): | ||||
|     def test_3_to_3_channels(self) -> None: | ||||
|         source = ImageFilter.Color3DLUT.generate((3, 4, 5), lambda r, g, b: (r, g, b)) | ||||
|         lut = source.transform(lambda r, g, b: (r * r, g * g, b * b)) | ||||
|         assert tuple(lut.size) == tuple(source.size) | ||||
|  | @ -571,7 +571,7 @@ class TestTransformColorLut3D: | |||
|         assert lut.table != source.table | ||||
|         assert lut.table[:10] == [0.0, 0.0, 0.0, 0.25, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0] | ||||
| 
 | ||||
|     def test_3_to_4_channels(self): | ||||
|     def test_3_to_4_channels(self) -> None: | ||||
|         source = ImageFilter.Color3DLUT.generate((6, 5, 4), lambda r, g, b: (r, g, b)) | ||||
|         lut = source.transform(lambda r, g, b: (r * r, g * g, b * b, 1), channels=4) | ||||
|         assert tuple(lut.size) == tuple(source.size) | ||||
|  | @ -583,7 +583,7 @@ class TestTransformColorLut3D: | |||
|             0.4**2, 0.0, 0.0, 1,  0.6**2, 0.0, 0.0, 1] | ||||
|         # fmt: on | ||||
| 
 | ||||
|     def test_4_to_3_channels(self): | ||||
|     def test_4_to_3_channels(self) -> None: | ||||
|         source = ImageFilter.Color3DLUT.generate( | ||||
|             (3, 6, 5), lambda r, g, b: (r, g, b, 1), channels=4 | ||||
|         ) | ||||
|  | @ -599,7 +599,7 @@ class TestTransformColorLut3D: | |||
|             1.0, 0.96, 1.0,  0.75, 0.96, 1.0,  0.0, 0.96, 1.0] | ||||
|         # fmt: on | ||||
| 
 | ||||
|     def test_4_to_4_channels(self): | ||||
|     def test_4_to_4_channels(self) -> None: | ||||
|         source = ImageFilter.Color3DLUT.generate( | ||||
|             (6, 5, 4), lambda r, g, b: (r, g, b, 1), channels=4 | ||||
|         ) | ||||
|  | @ -613,7 +613,7 @@ class TestTransformColorLut3D: | |||
|             0.4**2, 0.0, 0.0, 0.5,  0.6**2, 0.0, 0.0, 0.5] | ||||
|         # fmt: on | ||||
| 
 | ||||
|     def test_with_normals_3_channels(self): | ||||
|     def test_with_normals_3_channels(self) -> None: | ||||
|         source = ImageFilter.Color3DLUT.generate( | ||||
|             (6, 5, 4), lambda r, g, b: (r * r, g * g, b * b) | ||||
|         ) | ||||
|  | @ -629,7 +629,7 @@ class TestTransformColorLut3D: | |||
|             0.24, 0.0, 0.0,  0.8 - (0.8**2), 0, 0,  0, 0, 0] | ||||
|         # fmt: on | ||||
| 
 | ||||
|     def test_with_normals_4_channels(self): | ||||
|     def test_with_normals_4_channels(self) -> None: | ||||
|         source = ImageFilter.Color3DLUT.generate( | ||||
|             (3, 6, 5), lambda r, g, b: (r * r, g * g, b * b, 1), channels=4 | ||||
|         ) | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ from PIL import Image | |||
| from .helper import is_pypy | ||||
| 
 | ||||
| 
 | ||||
| def test_get_stats(): | ||||
| def test_get_stats() -> None: | ||||
|     # Create at least one image | ||||
|     Image.new("RGB", (10, 10)) | ||||
| 
 | ||||
|  | @ -22,7 +22,7 @@ def test_get_stats(): | |||
|     assert "blocks_cached" in stats | ||||
| 
 | ||||
| 
 | ||||
| def test_reset_stats(): | ||||
| def test_reset_stats() -> None: | ||||
|     Image.core.reset_stats() | ||||
| 
 | ||||
|     stats = Image.core.get_stats() | ||||
|  | @ -35,19 +35,19 @@ def test_reset_stats(): | |||
| 
 | ||||
| 
 | ||||
| class TestCoreMemory: | ||||
|     def teardown_method(self): | ||||
|     def teardown_method(self) -> None: | ||||
|         # Restore default values | ||||
|         Image.core.set_alignment(1) | ||||
|         Image.core.set_block_size(1024 * 1024) | ||||
|         Image.core.set_blocks_max(0) | ||||
|         Image.core.clear_cache() | ||||
| 
 | ||||
|     def test_get_alignment(self): | ||||
|     def test_get_alignment(self) -> None: | ||||
|         alignment = Image.core.get_alignment() | ||||
| 
 | ||||
|         assert alignment > 0 | ||||
| 
 | ||||
|     def test_set_alignment(self): | ||||
|     def test_set_alignment(self) -> None: | ||||
|         for i in [1, 2, 4, 8, 16, 32]: | ||||
|             Image.core.set_alignment(i) | ||||
|             alignment = Image.core.get_alignment() | ||||
|  | @ -63,12 +63,12 @@ class TestCoreMemory: | |||
|         with pytest.raises(ValueError): | ||||
|             Image.core.set_alignment(3) | ||||
| 
 | ||||
|     def test_get_block_size(self): | ||||
|     def test_get_block_size(self) -> None: | ||||
|         block_size = Image.core.get_block_size() | ||||
| 
 | ||||
|         assert block_size >= 4096 | ||||
| 
 | ||||
|     def test_set_block_size(self): | ||||
|     def test_set_block_size(self) -> None: | ||||
|         for i in [4096, 2 * 4096, 3 * 4096]: | ||||
|             Image.core.set_block_size(i) | ||||
|             block_size = Image.core.get_block_size() | ||||
|  | @ -84,7 +84,7 @@ class TestCoreMemory: | |||
|         with pytest.raises(ValueError): | ||||
|             Image.core.set_block_size(4000) | ||||
| 
 | ||||
|     def test_set_block_size_stats(self): | ||||
|     def test_set_block_size_stats(self) -> None: | ||||
|         Image.core.reset_stats() | ||||
|         Image.core.set_blocks_max(0) | ||||
|         Image.core.set_block_size(4096) | ||||
|  | @ -96,12 +96,12 @@ class TestCoreMemory: | |||
|         if not is_pypy(): | ||||
|             assert stats["freed_blocks"] >= 64 | ||||
| 
 | ||||
|     def test_get_blocks_max(self): | ||||
|     def test_get_blocks_max(self) -> None: | ||||
|         blocks_max = Image.core.get_blocks_max() | ||||
| 
 | ||||
|         assert blocks_max >= 0 | ||||
| 
 | ||||
|     def test_set_blocks_max(self): | ||||
|     def test_set_blocks_max(self) -> None: | ||||
|         for i in [0, 1, 10]: | ||||
|             Image.core.set_blocks_max(i) | ||||
|             blocks_max = Image.core.get_blocks_max() | ||||
|  | @ -117,7 +117,7 @@ class TestCoreMemory: | |||
|                 Image.core.set_blocks_max(2**29) | ||||
| 
 | ||||
|     @pytest.mark.skipif(is_pypy(), reason="Images not collected") | ||||
|     def test_set_blocks_max_stats(self): | ||||
|     def test_set_blocks_max_stats(self) -> None: | ||||
|         Image.core.reset_stats() | ||||
|         Image.core.set_blocks_max(128) | ||||
|         Image.core.set_block_size(4096) | ||||
|  | @ -132,7 +132,7 @@ class TestCoreMemory: | |||
|         assert stats["blocks_cached"] == 64 | ||||
| 
 | ||||
|     @pytest.mark.skipif(is_pypy(), reason="Images not collected") | ||||
|     def test_clear_cache_stats(self): | ||||
|     def test_clear_cache_stats(self) -> None: | ||||
|         Image.core.reset_stats() | ||||
|         Image.core.clear_cache() | ||||
|         Image.core.set_blocks_max(128) | ||||
|  | @ -149,7 +149,7 @@ class TestCoreMemory: | |||
|         assert stats["freed_blocks"] >= 48 | ||||
|         assert stats["blocks_cached"] == 16 | ||||
| 
 | ||||
|     def test_large_images(self): | ||||
|     def test_large_images(self) -> None: | ||||
|         Image.core.reset_stats() | ||||
|         Image.core.set_blocks_max(0) | ||||
|         Image.core.set_block_size(4096) | ||||
|  | @ -166,14 +166,14 @@ class TestCoreMemory: | |||
| 
 | ||||
| 
 | ||||
| class TestEnvVars: | ||||
|     def teardown_method(self): | ||||
|     def teardown_method(self) -> None: | ||||
|         # Restore default values | ||||
|         Image.core.set_alignment(1) | ||||
|         Image.core.set_block_size(1024 * 1024) | ||||
|         Image.core.set_blocks_max(0) | ||||
|         Image.core.clear_cache() | ||||
| 
 | ||||
|     def test_units(self): | ||||
|     def test_units(self) -> None: | ||||
|         Image._apply_env_variables({"PILLOW_BLOCKS_MAX": "2K"}) | ||||
|         assert Image.core.get_blocks_max() == 2 * 1024 | ||||
|         Image._apply_env_variables({"PILLOW_BLOCK_SIZE": "2m"}) | ||||
|  | @ -187,6 +187,6 @@ class TestEnvVars: | |||
|             {"PILLOW_BLOCKS_MAX": "wat"}, | ||||
|         ), | ||||
|     ) | ||||
|     def test_warnings(self, var): | ||||
|     def test_warnings(self, var) -> None: | ||||
|         with pytest.warns(UserWarning): | ||||
|             Image._apply_env_variables(var) | ||||
|  |  | |||
|  | @ -12,16 +12,16 @@ ORIGINAL_LIMIT = Image.MAX_IMAGE_PIXELS | |||
| 
 | ||||
| 
 | ||||
| class TestDecompressionBomb: | ||||
|     def teardown_method(self, method): | ||||
|     def teardown_method(self, method) -> None: | ||||
|         Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT | ||||
| 
 | ||||
|     def test_no_warning_small_file(self): | ||||
|     def test_no_warning_small_file(self) -> None: | ||||
|         # Implicit assert: no warning. | ||||
|         # A warning would cause a failure. | ||||
|         with Image.open(TEST_FILE): | ||||
|             pass | ||||
| 
 | ||||
|     def test_no_warning_no_limit(self): | ||||
|     def test_no_warning_no_limit(self) -> None: | ||||
|         # Arrange | ||||
|         # Turn limit off | ||||
|         Image.MAX_IMAGE_PIXELS = None | ||||
|  | @ -33,7 +33,7 @@ class TestDecompressionBomb: | |||
|         with Image.open(TEST_FILE): | ||||
|             pass | ||||
| 
 | ||||
|     def test_warning(self): | ||||
|     def test_warning(self) -> None: | ||||
|         # Set limit to trigger warning on the test file | ||||
|         Image.MAX_IMAGE_PIXELS = 128 * 128 - 1 | ||||
|         assert Image.MAX_IMAGE_PIXELS == 128 * 128 - 1 | ||||
|  | @ -42,7 +42,7 @@ class TestDecompressionBomb: | |||
|             with Image.open(TEST_FILE): | ||||
|                 pass | ||||
| 
 | ||||
|     def test_exception(self): | ||||
|     def test_exception(self) -> None: | ||||
|         # Set limit to trigger exception on the test file | ||||
|         Image.MAX_IMAGE_PIXELS = 64 * 128 - 1 | ||||
|         assert Image.MAX_IMAGE_PIXELS == 64 * 128 - 1 | ||||
|  | @ -51,22 +51,22 @@ class TestDecompressionBomb: | |||
|             with Image.open(TEST_FILE): | ||||
|                 pass | ||||
| 
 | ||||
|     def test_exception_ico(self): | ||||
|     def test_exception_ico(self) -> None: | ||||
|         with pytest.raises(Image.DecompressionBombError): | ||||
|             with Image.open("Tests/images/decompression_bomb.ico"): | ||||
|                 pass | ||||
| 
 | ||||
|     def test_exception_gif(self): | ||||
|     def test_exception_gif(self) -> None: | ||||
|         with pytest.raises(Image.DecompressionBombError): | ||||
|             with Image.open("Tests/images/decompression_bomb.gif"): | ||||
|                 pass | ||||
| 
 | ||||
|     def test_exception_gif_extents(self): | ||||
|     def test_exception_gif_extents(self) -> None: | ||||
|         with Image.open("Tests/images/decompression_bomb_extents.gif") as im: | ||||
|             with pytest.raises(Image.DecompressionBombError): | ||||
|                 im.seek(1) | ||||
| 
 | ||||
|     def test_exception_gif_zero_width(self): | ||||
|     def test_exception_gif_zero_width(self) -> None: | ||||
|         # Set limit to trigger exception on the test file | ||||
|         Image.MAX_IMAGE_PIXELS = 4 * 64 * 128 | ||||
|         assert Image.MAX_IMAGE_PIXELS == 4 * 64 * 128 | ||||
|  | @ -75,7 +75,7 @@ class TestDecompressionBomb: | |||
|             with Image.open("Tests/images/zero_width.gif"): | ||||
|                 pass | ||||
| 
 | ||||
|     def test_exception_bmp(self): | ||||
|     def test_exception_bmp(self) -> None: | ||||
|         with pytest.raises(Image.DecompressionBombError): | ||||
|             with Image.open("Tests/images/bmp/b/reallybig.bmp"): | ||||
|                 pass | ||||
|  | @ -83,15 +83,15 @@ class TestDecompressionBomb: | |||
| 
 | ||||
| class TestDecompressionCrop: | ||||
|     @classmethod | ||||
|     def setup_class(cls): | ||||
|     def setup_class(cls) -> None: | ||||
|         width, height = 128, 128 | ||||
|         Image.MAX_IMAGE_PIXELS = height * width * 4 - 1 | ||||
| 
 | ||||
|     @classmethod | ||||
|     def teardown_class(cls): | ||||
|     def teardown_class(cls) -> None: | ||||
|         Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT | ||||
| 
 | ||||
|     def test_enlarge_crop(self): | ||||
|     def test_enlarge_crop(self) -> None: | ||||
|         # Crops can extend the extents, therefore we should have the | ||||
|         # same decompression bomb warnings on them. | ||||
|         with hopper() as src: | ||||
|  | @ -99,7 +99,7 @@ class TestDecompressionCrop: | |||
|             with pytest.warns(Image.DecompressionBombWarning): | ||||
|                 src.crop(box) | ||||
| 
 | ||||
|     def test_crop_decompression_checks(self): | ||||
|     def test_crop_decompression_checks(self) -> None: | ||||
|         im = Image.new("RGB", (100, 100)) | ||||
| 
 | ||||
|         for value in ((-9999, -9999, -9990, -9990), (-999, -999, -990, -990)): | ||||
|  |  | |||
|  | @ -20,12 +20,12 @@ from PIL import _deprecate | |||
|         ), | ||||
|     ], | ||||
| ) | ||||
| def test_version(version, expected): | ||||
| def test_version(version, expected) -> None: | ||||
|     with pytest.warns(DeprecationWarning, match=expected): | ||||
|         _deprecate.deprecate("Old thing", version, "new thing") | ||||
| 
 | ||||
| 
 | ||||
| def test_unknown_version(): | ||||
| def test_unknown_version() -> None: | ||||
|     expected = r"Unknown removal version: 12345. Update PIL\._deprecate\?" | ||||
|     with pytest.raises(ValueError, match=expected): | ||||
|         _deprecate.deprecate("Old thing", 12345, "new thing") | ||||
|  | @ -46,13 +46,13 @@ def test_unknown_version(): | |||
|         ), | ||||
|     ], | ||||
| ) | ||||
| def test_old_version(deprecated, plural, expected): | ||||
| def test_old_version(deprecated, plural, expected) -> None: | ||||
|     expected = r"" | ||||
|     with pytest.raises(RuntimeError, match=expected): | ||||
|         _deprecate.deprecate(deprecated, 1, plural=plural) | ||||
| 
 | ||||
| 
 | ||||
| def test_plural(): | ||||
| def test_plural() -> None: | ||||
|     expected = ( | ||||
|         r"Old things are deprecated and will be removed in Pillow 11 \(2024-10-15\)\. " | ||||
|         r"Use new thing instead\." | ||||
|  | @ -61,7 +61,7 @@ def test_plural(): | |||
|         _deprecate.deprecate("Old things", 11, "new thing", plural=True) | ||||
| 
 | ||||
| 
 | ||||
| def test_replacement_and_action(): | ||||
| def test_replacement_and_action() -> None: | ||||
|     expected = "Use only one of 'replacement' and 'action'" | ||||
|     with pytest.raises(ValueError, match=expected): | ||||
|         _deprecate.deprecate( | ||||
|  | @ -76,7 +76,7 @@ def test_replacement_and_action(): | |||
|         "Upgrade to new thing.", | ||||
|     ], | ||||
| ) | ||||
| def test_action(action): | ||||
| def test_action(action) -> None: | ||||
|     expected = ( | ||||
|         r"Old thing is deprecated and will be removed in Pillow 11 \(2024-10-15\)\. " | ||||
|         r"Upgrade to new thing\." | ||||
|  | @ -85,7 +85,7 @@ def test_action(action): | |||
|         _deprecate.deprecate("Old thing", 11, action=action) | ||||
| 
 | ||||
| 
 | ||||
| def test_no_replacement_or_action(): | ||||
| def test_no_replacement_or_action() -> None: | ||||
|     expected = ( | ||||
|         r"Old thing is deprecated and will be removed in Pillow 11 \(2024-10-15\)" | ||||
|     ) | ||||
|  |  | |||
|  | @ -15,7 +15,7 @@ except ImportError: | |||
|     pass | ||||
| 
 | ||||
| 
 | ||||
| def test_check(): | ||||
| def test_check() -> None: | ||||
|     # Check the correctness of the convenience function | ||||
|     for module in features.modules: | ||||
|         assert features.check_module(module) == features.check(module) | ||||
|  | @ -25,11 +25,11 @@ def test_check(): | |||
|         assert features.check_feature(feature) == features.check(feature) | ||||
| 
 | ||||
| 
 | ||||
| def test_version(): | ||||
| def test_version() -> None: | ||||
|     # Check the correctness of the convenience function | ||||
|     # and the format of version numbers | ||||
| 
 | ||||
|     def test(name, function): | ||||
|     def test(name, function) -> None: | ||||
|         version = features.version(name) | ||||
|         if not features.check(name): | ||||
|             assert version is None | ||||
|  | @ -47,56 +47,56 @@ def test_version(): | |||
| 
 | ||||
| 
 | ||||
| @skip_unless_feature("webp") | ||||
| def test_webp_transparency(): | ||||
| def test_webp_transparency() -> None: | ||||
|     assert features.check("transp_webp") != _webp.WebPDecoderBuggyAlpha() | ||||
|     assert features.check("transp_webp") == _webp.HAVE_TRANSPARENCY | ||||
| 
 | ||||
| 
 | ||||
| @skip_unless_feature("webp") | ||||
| def test_webp_mux(): | ||||
| def test_webp_mux() -> None: | ||||
|     assert features.check("webp_mux") == _webp.HAVE_WEBPMUX | ||||
| 
 | ||||
| 
 | ||||
| @skip_unless_feature("webp") | ||||
| def test_webp_anim(): | ||||
| def test_webp_anim() -> None: | ||||
|     assert features.check("webp_anim") == _webp.HAVE_WEBPANIM | ||||
| 
 | ||||
| 
 | ||||
| @skip_unless_feature("libjpeg_turbo") | ||||
| def test_libjpeg_turbo_version(): | ||||
| def test_libjpeg_turbo_version() -> None: | ||||
|     assert re.search(r"\d+\.\d+\.\d+$", features.version("libjpeg_turbo")) | ||||
| 
 | ||||
| 
 | ||||
| @skip_unless_feature("libimagequant") | ||||
| def test_libimagequant_version(): | ||||
| def test_libimagequant_version() -> None: | ||||
|     assert re.search(r"\d+\.\d+\.\d+$", features.version("libimagequant")) | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("feature", features.modules) | ||||
| def test_check_modules(feature): | ||||
| def test_check_modules(feature) -> None: | ||||
|     assert features.check_module(feature) in [True, False] | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("feature", features.codecs) | ||||
| def test_check_codecs(feature): | ||||
| def test_check_codecs(feature) -> None: | ||||
|     assert features.check_codec(feature) in [True, False] | ||||
| 
 | ||||
| 
 | ||||
| def test_check_warns_on_nonexistent(): | ||||
| def test_check_warns_on_nonexistent() -> None: | ||||
|     with pytest.warns(UserWarning) as cm: | ||||
|         has_feature = features.check("typo") | ||||
|     assert has_feature is False | ||||
|     assert str(cm[-1].message) == "Unknown feature 'typo'." | ||||
| 
 | ||||
| 
 | ||||
| def test_supported_modules(): | ||||
| def test_supported_modules() -> None: | ||||
|     assert isinstance(features.get_supported_modules(), list) | ||||
|     assert isinstance(features.get_supported_codecs(), list) | ||||
|     assert isinstance(features.get_supported_features(), list) | ||||
|     assert isinstance(features.get_supported(), list) | ||||
| 
 | ||||
| 
 | ||||
| def test_unsupported_codec(): | ||||
| def test_unsupported_codec() -> None: | ||||
|     # Arrange | ||||
|     codec = "unsupported_codec" | ||||
|     # Act / Assert | ||||
|  | @ -106,7 +106,7 @@ def test_unsupported_codec(): | |||
|         features.version_codec(codec) | ||||
| 
 | ||||
| 
 | ||||
| def test_unsupported_module(): | ||||
| def test_unsupported_module() -> None: | ||||
|     # Arrange | ||||
|     module = "unsupported_module" | ||||
|     # Act / Assert | ||||
|  | @ -116,7 +116,7 @@ def test_unsupported_module(): | |||
|         features.version_module(module) | ||||
| 
 | ||||
| 
 | ||||
| def test_pilinfo(): | ||||
| def test_pilinfo() -> None: | ||||
|     buf = io.StringIO() | ||||
|     features.pilinfo(buf) | ||||
|     out = buf.getvalue() | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| from io import BytesIO | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -10,7 +11,7 @@ from PIL import Image, ImageSequence, PngImagePlugin | |||
| # APNG browser support tests and fixtures via: | ||||
| # https://philip.html5.org/tests/apng/tests.html | ||||
| # (referenced from https://wiki.mozilla.org/APNG_Specification) | ||||
| def test_apng_basic(): | ||||
| def test_apng_basic() -> None: | ||||
|     with Image.open("Tests/images/apng/single_frame.png") as im: | ||||
|         assert not im.is_animated | ||||
|         assert im.n_frames == 1 | ||||
|  | @ -47,14 +48,14 @@ def test_apng_basic(): | |||
|     "filename", | ||||
|     ("Tests/images/apng/split_fdat.png", "Tests/images/apng/split_fdat_zero_chunk.png"), | ||||
| ) | ||||
| def test_apng_fdat(filename): | ||||
| def test_apng_fdat(filename) -> None: | ||||
|     with Image.open(filename) as im: | ||||
|         im.seek(im.n_frames - 1) | ||||
|         assert im.getpixel((0, 0)) == (0, 255, 0, 255) | ||||
|         assert im.getpixel((64, 32)) == (0, 255, 0, 255) | ||||
| 
 | ||||
| 
 | ||||
| def test_apng_dispose(): | ||||
| def test_apng_dispose() -> None: | ||||
|     with Image.open("Tests/images/apng/dispose_op_none.png") as im: | ||||
|         im.seek(im.n_frames - 1) | ||||
|         assert im.getpixel((0, 0)) == (0, 255, 0, 255) | ||||
|  | @ -86,7 +87,7 @@ def test_apng_dispose(): | |||
|         assert im.getpixel((64, 32)) == (0, 0, 0, 0) | ||||
| 
 | ||||
| 
 | ||||
| def test_apng_dispose_region(): | ||||
| def test_apng_dispose_region() -> None: | ||||
|     with Image.open("Tests/images/apng/dispose_op_none_region.png") as im: | ||||
|         im.seek(im.n_frames - 1) | ||||
|         assert im.getpixel((0, 0)) == (0, 255, 0, 255) | ||||
|  | @ -108,7 +109,7 @@ def test_apng_dispose_region(): | |||
|         assert im.getpixel((64, 32)) == (0, 255, 0, 255) | ||||
| 
 | ||||
| 
 | ||||
| def test_apng_dispose_op_previous_frame(): | ||||
| def test_apng_dispose_op_previous_frame() -> None: | ||||
|     # Test that the dispose settings being used are from the previous frame | ||||
|     # | ||||
|     # Image created with: | ||||
|  | @ -133,14 +134,14 @@ def test_apng_dispose_op_previous_frame(): | |||
|         assert im.getpixel((0, 0)) == (255, 0, 0, 255) | ||||
| 
 | ||||
| 
 | ||||
| def test_apng_dispose_op_background_p_mode(): | ||||
| def test_apng_dispose_op_background_p_mode() -> None: | ||||
|     with Image.open("Tests/images/apng/dispose_op_background_p_mode.png") as im: | ||||
|         im.seek(1) | ||||
|         im.load() | ||||
|         assert im.size == (128, 64) | ||||
| 
 | ||||
| 
 | ||||
| def test_apng_blend(): | ||||
| def test_apng_blend() -> None: | ||||
|     with Image.open("Tests/images/apng/blend_op_source_solid.png") as im: | ||||
|         im.seek(im.n_frames - 1) | ||||
|         assert im.getpixel((0, 0)) == (0, 255, 0, 255) | ||||
|  | @ -167,20 +168,20 @@ def test_apng_blend(): | |||
|         assert im.getpixel((64, 32)) == (0, 255, 0, 255) | ||||
| 
 | ||||
| 
 | ||||
| def test_apng_blend_transparency(): | ||||
| def test_apng_blend_transparency() -> None: | ||||
|     with Image.open("Tests/images/blend_transparency.png") as im: | ||||
|         im.seek(1) | ||||
|         assert im.getpixel((0, 0)) == (255, 0, 0) | ||||
| 
 | ||||
| 
 | ||||
| def test_apng_chunk_order(): | ||||
| def test_apng_chunk_order() -> None: | ||||
|     with Image.open("Tests/images/apng/fctl_actl.png") as im: | ||||
|         im.seek(im.n_frames - 1) | ||||
|         assert im.getpixel((0, 0)) == (0, 255, 0, 255) | ||||
|         assert im.getpixel((64, 32)) == (0, 255, 0, 255) | ||||
| 
 | ||||
| 
 | ||||
| def test_apng_delay(): | ||||
| def test_apng_delay() -> None: | ||||
|     with Image.open("Tests/images/apng/delay.png") as im: | ||||
|         im.seek(1) | ||||
|         assert im.info.get("duration") == 500.0 | ||||
|  | @ -220,7 +221,7 @@ def test_apng_delay(): | |||
|         assert im.info.get("duration") == 1000.0 | ||||
| 
 | ||||
| 
 | ||||
| def test_apng_num_plays(): | ||||
| def test_apng_num_plays() -> None: | ||||
|     with Image.open("Tests/images/apng/num_plays.png") as im: | ||||
|         assert im.info.get("loop") == 0 | ||||
| 
 | ||||
|  | @ -228,7 +229,7 @@ def test_apng_num_plays(): | |||
|         assert im.info.get("loop") == 1 | ||||
| 
 | ||||
| 
 | ||||
| def test_apng_mode(): | ||||
| def test_apng_mode() -> None: | ||||
|     with Image.open("Tests/images/apng/mode_16bit.png") as im: | ||||
|         assert im.mode == "RGBA" | ||||
|         im.seek(im.n_frames - 1) | ||||
|  | @ -269,7 +270,7 @@ def test_apng_mode(): | |||
|         assert im.getpixel((64, 32)) == (0, 0, 255, 128) | ||||
| 
 | ||||
| 
 | ||||
| def test_apng_chunk_errors(): | ||||
| def test_apng_chunk_errors() -> None: | ||||
|     with Image.open("Tests/images/apng/chunk_no_actl.png") as im: | ||||
|         assert not im.is_animated | ||||
| 
 | ||||
|  | @ -294,7 +295,7 @@ def test_apng_chunk_errors(): | |||
|             im.seek(im.n_frames - 1) | ||||
| 
 | ||||
| 
 | ||||
| def test_apng_syntax_errors(): | ||||
| def test_apng_syntax_errors() -> None: | ||||
|     with pytest.warns(UserWarning): | ||||
|         with Image.open("Tests/images/apng/syntax_num_frames_zero.png") as im: | ||||
|             assert not im.is_animated | ||||
|  | @ -338,14 +339,14 @@ def test_apng_syntax_errors(): | |||
|         "sequence_fdat_fctl.png", | ||||
|     ), | ||||
| ) | ||||
| def test_apng_sequence_errors(test_file): | ||||
| def test_apng_sequence_errors(test_file) -> None: | ||||
|     with pytest.raises(SyntaxError): | ||||
|         with Image.open(f"Tests/images/apng/{test_file}") as im: | ||||
|             im.seek(im.n_frames - 1) | ||||
|             im.load() | ||||
| 
 | ||||
| 
 | ||||
| def test_apng_save(tmp_path): | ||||
| def test_apng_save(tmp_path: Path) -> None: | ||||
|     with Image.open("Tests/images/apng/single_frame.png") as im: | ||||
|         test_file = str(tmp_path / "temp.png") | ||||
|         im.save(test_file, save_all=True) | ||||
|  | @ -376,7 +377,7 @@ def test_apng_save(tmp_path): | |||
|         assert im.getpixel((64, 32)) == (0, 255, 0, 255) | ||||
| 
 | ||||
| 
 | ||||
| def test_apng_save_alpha(tmp_path): | ||||
| def test_apng_save_alpha(tmp_path: Path) -> None: | ||||
|     test_file = str(tmp_path / "temp.png") | ||||
| 
 | ||||
|     im = Image.new("RGBA", (1, 1), (255, 0, 0, 255)) | ||||
|  | @ -390,7 +391,7 @@ def test_apng_save_alpha(tmp_path): | |||
|         assert reloaded.getpixel((0, 0)) == (255, 0, 0, 127) | ||||
| 
 | ||||
| 
 | ||||
| def test_apng_save_split_fdat(tmp_path): | ||||
| def test_apng_save_split_fdat(tmp_path: Path) -> None: | ||||
|     # test to make sure we do not generate sequence errors when writing | ||||
|     # frames with image data spanning multiple fdAT chunks (in this case | ||||
|     # both the default image and first animation frame will span multiple | ||||
|  | @ -414,7 +415,7 @@ def test_apng_save_split_fdat(tmp_path): | |||
|         assert exception is None | ||||
| 
 | ||||
| 
 | ||||
| def test_apng_save_duration_loop(tmp_path): | ||||
| def test_apng_save_duration_loop(tmp_path: Path) -> None: | ||||
|     test_file = str(tmp_path / "temp.png") | ||||
|     with Image.open("Tests/images/apng/delay.png") as im: | ||||
|         frames = [] | ||||
|  | @ -477,7 +478,7 @@ def test_apng_save_duration_loop(tmp_path): | |||
|         assert im.info["duration"] == 600 | ||||
| 
 | ||||
| 
 | ||||
| def test_apng_save_disposal(tmp_path): | ||||
| def test_apng_save_disposal(tmp_path: Path) -> None: | ||||
|     test_file = str(tmp_path / "temp.png") | ||||
|     size = (128, 64) | ||||
|     red = Image.new("RGBA", size, (255, 0, 0, 255)) | ||||
|  | @ -578,7 +579,7 @@ def test_apng_save_disposal(tmp_path): | |||
|         assert im.getpixel((64, 32)) == (0, 0, 0, 0) | ||||
| 
 | ||||
| 
 | ||||
| def test_apng_save_disposal_previous(tmp_path): | ||||
| def test_apng_save_disposal_previous(tmp_path: Path) -> None: | ||||
|     test_file = str(tmp_path / "temp.png") | ||||
|     size = (128, 64) | ||||
|     blue = Image.new("RGBA", size, (0, 0, 255, 255)) | ||||
|  | @ -600,7 +601,7 @@ def test_apng_save_disposal_previous(tmp_path): | |||
|         assert im.getpixel((64, 32)) == (0, 255, 0, 255) | ||||
| 
 | ||||
| 
 | ||||
| def test_apng_save_blend(tmp_path): | ||||
| def test_apng_save_blend(tmp_path: Path) -> None: | ||||
|     test_file = str(tmp_path / "temp.png") | ||||
|     size = (128, 64) | ||||
|     red = Image.new("RGBA", size, (255, 0, 0, 255)) | ||||
|  | @ -668,7 +669,7 @@ def test_apng_save_blend(tmp_path): | |||
|         assert im.getpixel((0, 0)) == (0, 255, 0, 255) | ||||
| 
 | ||||
| 
 | ||||
| def test_save_all_progress(): | ||||
| def test_save_all_progress() -> None: | ||||
|     out = BytesIO() | ||||
|     progress = [] | ||||
| 
 | ||||
|  | @ -716,7 +717,7 @@ def test_save_all_progress(): | |||
|     assert progress == expected | ||||
| 
 | ||||
| 
 | ||||
| def test_seek_after_close(): | ||||
| def test_seek_after_close() -> None: | ||||
|     im = Image.open("Tests/images/apng/delay.png") | ||||
|     im.seek(1) | ||||
|     im.close() | ||||
|  | @ -728,7 +729,9 @@ def test_seek_after_close(): | |||
| @pytest.mark.parametrize("mode", ("RGBA", "RGB", "P")) | ||||
| @pytest.mark.parametrize("default_image", (True, False)) | ||||
| @pytest.mark.parametrize("duplicate", (True, False)) | ||||
| def test_different_modes_in_later_frames(mode, default_image, duplicate, tmp_path): | ||||
| def test_different_modes_in_later_frames( | ||||
|     mode, default_image, duplicate, tmp_path: Path | ||||
| ) -> None: | ||||
|     test_file = str(tmp_path / "temp.png") | ||||
| 
 | ||||
|     im = Image.new("L", (1, 1)) | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
| from PIL import Image | ||||
|  | @ -12,7 +14,7 @@ from .helper import ( | |||
| ) | ||||
| 
 | ||||
| 
 | ||||
| def test_load_blp1(): | ||||
| def test_load_blp1() -> None: | ||||
|     with Image.open("Tests/images/blp/blp1_jpeg.blp") as im: | ||||
|         assert_image_equal_tofile(im, "Tests/images/blp/blp1_jpeg.png") | ||||
| 
 | ||||
|  | @ -20,22 +22,22 @@ def test_load_blp1(): | |||
|         im.load() | ||||
| 
 | ||||
| 
 | ||||
| def test_load_blp2_raw(): | ||||
| def test_load_blp2_raw() -> None: | ||||
|     with Image.open("Tests/images/blp/blp2_raw.blp") as im: | ||||
|         assert_image_equal_tofile(im, "Tests/images/blp/blp2_raw.png") | ||||
| 
 | ||||
| 
 | ||||
| def test_load_blp2_dxt1(): | ||||
| def test_load_blp2_dxt1() -> None: | ||||
|     with Image.open("Tests/images/blp/blp2_dxt1.blp") as im: | ||||
|         assert_image_equal_tofile(im, "Tests/images/blp/blp2_dxt1.png") | ||||
| 
 | ||||
| 
 | ||||
| def test_load_blp2_dxt1a(): | ||||
| def test_load_blp2_dxt1a() -> None: | ||||
|     with Image.open("Tests/images/blp/blp2_dxt1a.blp") as im: | ||||
|         assert_image_equal_tofile(im, "Tests/images/blp/blp2_dxt1a.png") | ||||
| 
 | ||||
| 
 | ||||
| def test_save(tmp_path): | ||||
| def test_save(tmp_path: Path) -> None: | ||||
|     f = str(tmp_path / "temp.blp") | ||||
| 
 | ||||
|     for version in ("BLP1", "BLP2"): | ||||
|  | @ -69,7 +71,7 @@ def test_save(tmp_path): | |||
|         "Tests/images/timeout-ef9112a065e7183fa7faa2e18929b03e44ee16bf.blp", | ||||
|     ], | ||||
| ) | ||||
| def test_crashes(test_file): | ||||
| def test_crashes(test_file) -> None: | ||||
|     with open(test_file, "rb") as f: | ||||
|         with Image.open(f) as im: | ||||
|             with pytest.raises(OSError): | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| import io | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -14,8 +15,8 @@ from .helper import ( | |||
| ) | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(tmp_path): | ||||
|     def roundtrip(im): | ||||
| def test_sanity(tmp_path: Path) -> None: | ||||
|     def roundtrip(im) -> None: | ||||
|         outfile = str(tmp_path / "temp.bmp") | ||||
| 
 | ||||
|         im.save(outfile, "BMP") | ||||
|  | @ -35,20 +36,20 @@ def test_sanity(tmp_path): | |||
|     roundtrip(hopper("RGB")) | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     with open("Tests/images/flower.jpg", "rb") as fp: | ||||
|         with pytest.raises(SyntaxError): | ||||
|             BmpImagePlugin.BmpImageFile(fp) | ||||
| 
 | ||||
| 
 | ||||
| def test_fallback_if_mmap_errors(): | ||||
| def test_fallback_if_mmap_errors() -> None: | ||||
|     # This image has been truncated, | ||||
|     # so that the buffer is not large enough when using mmap | ||||
|     with Image.open("Tests/images/mmap_error.bmp") as im: | ||||
|         assert_image_equal_tofile(im, "Tests/images/pal8_offset.bmp") | ||||
| 
 | ||||
| 
 | ||||
| def test_save_to_bytes(): | ||||
| def test_save_to_bytes() -> None: | ||||
|     output = io.BytesIO() | ||||
|     im = hopper() | ||||
|     im.save(output, "BMP") | ||||
|  | @ -60,7 +61,7 @@ def test_save_to_bytes(): | |||
|         assert reloaded.format == "BMP" | ||||
| 
 | ||||
| 
 | ||||
| def test_small_palette(tmp_path): | ||||
| def test_small_palette(tmp_path: Path) -> None: | ||||
|     im = Image.new("P", (1, 1)) | ||||
|     colors = [0, 0, 0, 125, 125, 125, 255, 255, 255] | ||||
|     im.putpalette(colors) | ||||
|  | @ -72,7 +73,7 @@ def test_small_palette(tmp_path): | |||
|         assert reloaded.getpalette() == colors | ||||
| 
 | ||||
| 
 | ||||
| def test_save_too_large(tmp_path): | ||||
| def test_save_too_large(tmp_path: Path) -> None: | ||||
|     outfile = str(tmp_path / "temp.bmp") | ||||
|     with Image.new("RGB", (1, 1)) as im: | ||||
|         im._size = (37838, 37838) | ||||
|  | @ -80,7 +81,7 @@ def test_save_too_large(tmp_path): | |||
|             im.save(outfile) | ||||
| 
 | ||||
| 
 | ||||
| def test_dpi(): | ||||
| def test_dpi() -> None: | ||||
|     dpi = (72, 72) | ||||
| 
 | ||||
|     output = io.BytesIO() | ||||
|  | @ -92,7 +93,7 @@ def test_dpi(): | |||
|         assert reloaded.info["dpi"] == (72.008961115161, 72.008961115161) | ||||
| 
 | ||||
| 
 | ||||
| def test_save_bmp_with_dpi(tmp_path): | ||||
| def test_save_bmp_with_dpi(tmp_path: Path) -> None: | ||||
|     # Test for #1301 | ||||
|     # Arrange | ||||
|     outfile = str(tmp_path / "temp.jpg") | ||||
|  | @ -110,7 +111,7 @@ def test_save_bmp_with_dpi(tmp_path): | |||
|             assert reloaded.format == "JPEG" | ||||
| 
 | ||||
| 
 | ||||
| def test_save_float_dpi(tmp_path): | ||||
| def test_save_float_dpi(tmp_path: Path) -> None: | ||||
|     outfile = str(tmp_path / "temp.bmp") | ||||
|     with Image.open("Tests/images/hopper.bmp") as im: | ||||
|         im.save(outfile, dpi=(72.21216100543306, 72.21216100543306)) | ||||
|  | @ -118,7 +119,7 @@ def test_save_float_dpi(tmp_path): | |||
|             assert reloaded.info["dpi"] == (72.21216100543306, 72.21216100543306) | ||||
| 
 | ||||
| 
 | ||||
| def test_load_dib(): | ||||
| def test_load_dib() -> None: | ||||
|     # test for #1293, Imagegrab returning Unsupported Bitfields Format | ||||
|     with Image.open("Tests/images/clipboard.dib") as im: | ||||
|         assert im.format == "DIB" | ||||
|  | @ -127,7 +128,7 @@ def test_load_dib(): | |||
|         assert_image_equal_tofile(im, "Tests/images/clipboard_target.png") | ||||
| 
 | ||||
| 
 | ||||
| def test_save_dib(tmp_path): | ||||
| def test_save_dib(tmp_path: Path) -> None: | ||||
|     outfile = str(tmp_path / "temp.dib") | ||||
| 
 | ||||
|     with Image.open("Tests/images/clipboard.dib") as im: | ||||
|  | @ -139,7 +140,7 @@ def test_save_dib(tmp_path): | |||
|             assert_image_equal(im, reloaded) | ||||
| 
 | ||||
| 
 | ||||
| def test_rgba_bitfields(): | ||||
| def test_rgba_bitfields() -> None: | ||||
|     # This test image has been manually hexedited | ||||
|     # to change the bitfield compression in the header from XBGR to RGBA | ||||
|     with Image.open("Tests/images/rgb32bf-rgba.bmp") as im: | ||||
|  | @ -157,7 +158,7 @@ def test_rgba_bitfields(): | |||
|         ) | ||||
| 
 | ||||
| 
 | ||||
| def test_rle8(): | ||||
| def test_rle8() -> None: | ||||
|     with Image.open("Tests/images/hopper_rle8.bmp") as im: | ||||
|         assert_image_similar_tofile(im.convert("RGB"), "Tests/images/hopper.bmp", 12) | ||||
| 
 | ||||
|  | @ -177,7 +178,7 @@ def test_rle8(): | |||
|                 im.load() | ||||
| 
 | ||||
| 
 | ||||
| def test_rle4(): | ||||
| def test_rle4() -> None: | ||||
|     with Image.open("Tests/images/bmp/g/pal4rle.bmp") as im: | ||||
|         assert_image_similar_tofile(im, "Tests/images/bmp/g/pal4.bmp", 12) | ||||
| 
 | ||||
|  | @ -193,7 +194,7 @@ def test_rle4(): | |||
|         ("Tests/images/bmp/g/pal8rle.bmp", 1064), | ||||
|     ), | ||||
| ) | ||||
| def test_rle8_eof(file_name, length): | ||||
| def test_rle8_eof(file_name, length) -> None: | ||||
|     with open(file_name, "rb") as fp: | ||||
|         data = fp.read(length) | ||||
|         with Image.open(io.BytesIO(data)) as im: | ||||
|  | @ -201,7 +202,7 @@ def test_rle8_eof(file_name, length): | |||
|                 im.load() | ||||
| 
 | ||||
| 
 | ||||
| def test_offset(): | ||||
| def test_offset() -> None: | ||||
|     # This image has been hexedited | ||||
|     # to exclude the palette size from the pixel data offset | ||||
|     with Image.open("Tests/images/pal8_offset.bmp") as im: | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
| from PIL import BufrStubImagePlugin, Image | ||||
|  | @ -9,7 +11,7 @@ from .helper import hopper | |||
| TEST_FILE = "Tests/images/gfs.t06z.rassda.tm00.bufr_d" | ||||
| 
 | ||||
| 
 | ||||
| def test_open(): | ||||
| def test_open() -> None: | ||||
|     # Act | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         # Assert | ||||
|  | @ -20,7 +22,7 @@ def test_open(): | |||
|         assert im.size == (1, 1) | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     # Arrange | ||||
|     invalid_file = "Tests/images/flower.jpg" | ||||
| 
 | ||||
|  | @ -29,7 +31,7 @@ def test_invalid_file(): | |||
|         BufrStubImagePlugin.BufrStubImageFile(invalid_file) | ||||
| 
 | ||||
| 
 | ||||
| def test_load(): | ||||
| def test_load() -> None: | ||||
|     # Arrange | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         # Act / Assert: stub cannot load without an implemented handler | ||||
|  | @ -37,7 +39,7 @@ def test_load(): | |||
|             im.load() | ||||
| 
 | ||||
| 
 | ||||
| def test_save(tmp_path): | ||||
| def test_save(tmp_path: Path) -> None: | ||||
|     # Arrange | ||||
|     im = hopper() | ||||
|     tmpfile = str(tmp_path / "temp.bufr") | ||||
|  | @ -47,13 +49,13 @@ def test_save(tmp_path): | |||
|         im.save(tmpfile) | ||||
| 
 | ||||
| 
 | ||||
| def test_handler(tmp_path): | ||||
| def test_handler(tmp_path: Path) -> None: | ||||
|     class TestHandler: | ||||
|         opened = False | ||||
|         loaded = False | ||||
|         saved = False | ||||
| 
 | ||||
|         def open(self, im): | ||||
|         def open(self, im) -> None: | ||||
|             self.opened = True | ||||
| 
 | ||||
|         def load(self, im): | ||||
|  | @ -61,7 +63,7 @@ def test_handler(tmp_path): | |||
|             im.fp.close() | ||||
|             return Image.new("RGB", (1, 1)) | ||||
| 
 | ||||
|         def save(self, im, fp, filename): | ||||
|         def save(self, im, fp, filename) -> None: | ||||
|             self.saved = True | ||||
| 
 | ||||
|     handler = TestHandler() | ||||
|  |  | |||
|  | @ -9,19 +9,19 @@ from .helper import hopper | |||
| TEST_FILE = "Tests/images/dummy.container" | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(): | ||||
| def test_sanity() -> None: | ||||
|     dir(Image) | ||||
|     dir(ContainerIO) | ||||
| 
 | ||||
| 
 | ||||
| def test_isatty(): | ||||
| def test_isatty() -> None: | ||||
|     with hopper() as im: | ||||
|         container = ContainerIO.ContainerIO(im, 0, 0) | ||||
| 
 | ||||
|     assert container.isatty() is False | ||||
| 
 | ||||
| 
 | ||||
| def test_seek_mode_0(): | ||||
| def test_seek_mode_0() -> None: | ||||
|     # Arrange | ||||
|     mode = 0 | ||||
|     with open(TEST_FILE, "rb") as fh: | ||||
|  | @ -35,7 +35,7 @@ def test_seek_mode_0(): | |||
|         assert container.tell() == 33 | ||||
| 
 | ||||
| 
 | ||||
| def test_seek_mode_1(): | ||||
| def test_seek_mode_1() -> None: | ||||
|     # Arrange | ||||
|     mode = 1 | ||||
|     with open(TEST_FILE, "rb") as fh: | ||||
|  | @ -49,7 +49,7 @@ def test_seek_mode_1(): | |||
|         assert container.tell() == 66 | ||||
| 
 | ||||
| 
 | ||||
| def test_seek_mode_2(): | ||||
| def test_seek_mode_2() -> None: | ||||
|     # Arrange | ||||
|     mode = 2 | ||||
|     with open(TEST_FILE, "rb") as fh: | ||||
|  | @ -64,7 +64,7 @@ def test_seek_mode_2(): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("bytesmode", (True, False)) | ||||
| def test_read_n0(bytesmode): | ||||
| def test_read_n0(bytesmode) -> None: | ||||
|     # Arrange | ||||
|     with open(TEST_FILE, "rb" if bytesmode else "r") as fh: | ||||
|         container = ContainerIO.ContainerIO(fh, 22, 100) | ||||
|  | @ -80,7 +80,7 @@ def test_read_n0(bytesmode): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("bytesmode", (True, False)) | ||||
| def test_read_n(bytesmode): | ||||
| def test_read_n(bytesmode) -> None: | ||||
|     # Arrange | ||||
|     with open(TEST_FILE, "rb" if bytesmode else "r") as fh: | ||||
|         container = ContainerIO.ContainerIO(fh, 22, 100) | ||||
|  | @ -96,7 +96,7 @@ def test_read_n(bytesmode): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("bytesmode", (True, False)) | ||||
| def test_read_eof(bytesmode): | ||||
| def test_read_eof(bytesmode) -> None: | ||||
|     # Arrange | ||||
|     with open(TEST_FILE, "rb" if bytesmode else "r") as fh: | ||||
|         container = ContainerIO.ContainerIO(fh, 22, 100) | ||||
|  | @ -112,7 +112,7 @@ def test_read_eof(bytesmode): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("bytesmode", (True, False)) | ||||
| def test_readline(bytesmode): | ||||
| def test_readline(bytesmode) -> None: | ||||
|     # Arrange | ||||
|     with open(TEST_FILE, "rb" if bytesmode else "r") as fh: | ||||
|         container = ContainerIO.ContainerIO(fh, 0, 120) | ||||
|  | @ -127,7 +127,7 @@ def test_readline(bytesmode): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("bytesmode", (True, False)) | ||||
| def test_readlines(bytesmode): | ||||
| def test_readlines(bytesmode) -> None: | ||||
|     # Arrange | ||||
|     expected = [ | ||||
|         "This is line 1\n", | ||||
|  |  | |||
|  | @ -7,7 +7,7 @@ from PIL import CurImagePlugin, Image | |||
| TEST_FILE = "Tests/images/deerstalker.cur" | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(): | ||||
| def test_sanity() -> None: | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         assert im.size == (32, 32) | ||||
|         assert isinstance(im, CurImagePlugin.CurImageFile) | ||||
|  | @ -17,7 +17,7 @@ def test_sanity(): | |||
|         assert im.getpixel((16, 16)) == (84, 87, 86, 255) | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     invalid_file = "Tests/images/flower.jpg" | ||||
| 
 | ||||
|     with pytest.raises(SyntaxError): | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ from .helper import assert_image_equal, hopper, is_pypy | |||
| TEST_FILE = "Tests/images/hopper.dcx" | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(): | ||||
| def test_sanity() -> None: | ||||
|     # Arrange | ||||
| 
 | ||||
|     # Act | ||||
|  | @ -25,8 +25,8 @@ def test_sanity(): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.skipif(is_pypy(), reason="Requires CPython") | ||||
| def test_unclosed_file(): | ||||
|     def open(): | ||||
| def test_unclosed_file() -> None: | ||||
|     def open() -> None: | ||||
|         im = Image.open(TEST_FILE) | ||||
|         im.load() | ||||
| 
 | ||||
|  | @ -34,26 +34,26 @@ def test_unclosed_file(): | |||
|         open() | ||||
| 
 | ||||
| 
 | ||||
| def test_closed_file(): | ||||
| def test_closed_file() -> None: | ||||
|     with warnings.catch_warnings(): | ||||
|         im = Image.open(TEST_FILE) | ||||
|         im.load() | ||||
|         im.close() | ||||
| 
 | ||||
| 
 | ||||
| def test_context_manager(): | ||||
| def test_context_manager() -> None: | ||||
|     with warnings.catch_warnings(): | ||||
|         with Image.open(TEST_FILE) as im: | ||||
|             im.load() | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     with open("Tests/images/flower.jpg", "rb") as fp: | ||||
|         with pytest.raises(SyntaxError): | ||||
|             DcxImagePlugin.DcxImageFile(fp) | ||||
| 
 | ||||
| 
 | ||||
| def test_tell(): | ||||
| def test_tell() -> None: | ||||
|     # Arrange | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         # Act | ||||
|  | @ -63,13 +63,13 @@ def test_tell(): | |||
|         assert frame == 0 | ||||
| 
 | ||||
| 
 | ||||
| def test_n_frames(): | ||||
| def test_n_frames() -> None: | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         assert im.n_frames == 1 | ||||
|         assert not im.is_animated | ||||
| 
 | ||||
| 
 | ||||
| def test_eoferror(): | ||||
| def test_eoferror() -> None: | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         n_frames = im.n_frames | ||||
| 
 | ||||
|  | @ -82,7 +82,7 @@ def test_eoferror(): | |||
|         im.seek(n_frames - 1) | ||||
| 
 | ||||
| 
 | ||||
| def test_seek_too_far(): | ||||
| def test_seek_too_far() -> None: | ||||
|     # Arrange | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         frame = 999  # too big on purpose | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| from io import BytesIO | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -46,7 +47,7 @@ TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA = "Tests/images/uncompressed_rgb.dds" | |||
|         TEST_FILE_DX10_BC1_TYPELESS, | ||||
|     ), | ||||
| ) | ||||
| def test_sanity_dxt1_bc1(image_path): | ||||
| def test_sanity_dxt1_bc1(image_path) -> None: | ||||
|     """Check DXT1 and BC1 images can be opened""" | ||||
|     with Image.open(TEST_FILE_DXT1.replace(".dds", ".png")) as target: | ||||
|         target = target.convert("RGBA") | ||||
|  | @ -60,7 +61,7 @@ def test_sanity_dxt1_bc1(image_path): | |||
|         assert_image_equal(im, target) | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity_dxt3(): | ||||
| def test_sanity_dxt3() -> None: | ||||
|     """Check DXT3 images can be opened""" | ||||
| 
 | ||||
|     with Image.open(TEST_FILE_DXT3) as im: | ||||
|  | @ -73,7 +74,7 @@ def test_sanity_dxt3(): | |||
|         assert_image_equal_tofile(im, TEST_FILE_DXT3.replace(".dds", ".png")) | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity_dxt5(): | ||||
| def test_sanity_dxt5() -> None: | ||||
|     """Check DXT5 images can be opened""" | ||||
| 
 | ||||
|     with Image.open(TEST_FILE_DXT5) as im: | ||||
|  | @ -94,7 +95,7 @@ def test_sanity_dxt5(): | |||
|         TEST_FILE_BC4U, | ||||
|     ), | ||||
| ) | ||||
| def test_sanity_ati1_bc4u(image_path): | ||||
| def test_sanity_ati1_bc4u(image_path) -> None: | ||||
|     """Check ATI1 and BC4U images can be opened""" | ||||
| 
 | ||||
|     with Image.open(image_path) as im: | ||||
|  | @ -115,7 +116,7 @@ def test_sanity_ati1_bc4u(image_path): | |||
|         TEST_FILE_DX10_BC4_TYPELESS, | ||||
|     ), | ||||
| ) | ||||
| def test_dx10_bc4(image_path): | ||||
| def test_dx10_bc4(image_path) -> None: | ||||
|     """Check DX10 BC4 images can be opened""" | ||||
| 
 | ||||
|     with Image.open(image_path) as im: | ||||
|  | @ -136,7 +137,7 @@ def test_dx10_bc4(image_path): | |||
|         TEST_FILE_BC5U, | ||||
|     ), | ||||
| ) | ||||
| def test_sanity_ati2_bc5u(image_path): | ||||
| def test_sanity_ati2_bc5u(image_path) -> None: | ||||
|     """Check ATI2 and BC5U images can be opened""" | ||||
| 
 | ||||
|     with Image.open(image_path) as im: | ||||
|  | @ -160,7 +161,7 @@ def test_sanity_ati2_bc5u(image_path): | |||
|         (TEST_FILE_BC5S, TEST_FILE_BC5S), | ||||
|     ), | ||||
| ) | ||||
| def test_dx10_bc5(image_path, expected_path): | ||||
| def test_dx10_bc5(image_path, expected_path) -> None: | ||||
|     """Check DX10 BC5 images can be opened""" | ||||
| 
 | ||||
|     with Image.open(image_path) as im: | ||||
|  | @ -174,7 +175,7 @@ def test_dx10_bc5(image_path, expected_path): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("image_path", (TEST_FILE_BC6H, TEST_FILE_BC6HS)) | ||||
| def test_dx10_bc6h(image_path): | ||||
| def test_dx10_bc6h(image_path) -> None: | ||||
|     """Check DX10 BC6H/BC6HS images can be opened""" | ||||
| 
 | ||||
|     with Image.open(image_path) as im: | ||||
|  | @ -187,7 +188,7 @@ def test_dx10_bc6h(image_path): | |||
|         assert_image_equal_tofile(im, image_path.replace(".dds", ".png")) | ||||
| 
 | ||||
| 
 | ||||
| def test_dx10_bc7(): | ||||
| def test_dx10_bc7() -> None: | ||||
|     """Check DX10 images can be opened""" | ||||
| 
 | ||||
|     with Image.open(TEST_FILE_DX10_BC7) as im: | ||||
|  | @ -200,7 +201,7 @@ def test_dx10_bc7(): | |||
|         assert_image_equal_tofile(im, TEST_FILE_DX10_BC7.replace(".dds", ".png")) | ||||
| 
 | ||||
| 
 | ||||
| def test_dx10_bc7_unorm_srgb(): | ||||
| def test_dx10_bc7_unorm_srgb() -> None: | ||||
|     """Check DX10 unsigned normalized integer images can be opened""" | ||||
| 
 | ||||
|     with Image.open(TEST_FILE_DX10_BC7_UNORM_SRGB) as im: | ||||
|  | @ -216,7 +217,7 @@ def test_dx10_bc7_unorm_srgb(): | |||
|         ) | ||||
| 
 | ||||
| 
 | ||||
| def test_dx10_r8g8b8a8(): | ||||
| def test_dx10_r8g8b8a8() -> None: | ||||
|     """Check DX10 images can be opened""" | ||||
| 
 | ||||
|     with Image.open(TEST_FILE_DX10_R8G8B8A8) as im: | ||||
|  | @ -229,7 +230,7 @@ def test_dx10_r8g8b8a8(): | |||
|         assert_image_equal_tofile(im, TEST_FILE_DX10_R8G8B8A8.replace(".dds", ".png")) | ||||
| 
 | ||||
| 
 | ||||
| def test_dx10_r8g8b8a8_unorm_srgb(): | ||||
| def test_dx10_r8g8b8a8_unorm_srgb() -> None: | ||||
|     """Check DX10 unsigned normalized integer images can be opened""" | ||||
| 
 | ||||
|     with Image.open(TEST_FILE_DX10_R8G8B8A8_UNORM_SRGB) as im: | ||||
|  | @ -255,7 +256,7 @@ def test_dx10_r8g8b8a8_unorm_srgb(): | |||
|         ("RGBA", (800, 600), TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA), | ||||
|     ], | ||||
| ) | ||||
| def test_uncompressed(mode, size, test_file): | ||||
| def test_uncompressed(mode, size, test_file) -> None: | ||||
|     """Check uncompressed images can be opened""" | ||||
| 
 | ||||
|     with Image.open(test_file) as im: | ||||
|  | @ -266,7 +267,7 @@ def test_uncompressed(mode, size, test_file): | |||
|         assert_image_equal_tofile(im, test_file.replace(".dds", ".png")) | ||||
| 
 | ||||
| 
 | ||||
| def test__accept_true(): | ||||
| def test__accept_true() -> None: | ||||
|     """Check valid prefix""" | ||||
|     # Arrange | ||||
|     prefix = b"DDS etc" | ||||
|  | @ -278,7 +279,7 @@ def test__accept_true(): | |||
|     assert output | ||||
| 
 | ||||
| 
 | ||||
| def test__accept_false(): | ||||
| def test__accept_false() -> None: | ||||
|     """Check invalid prefix""" | ||||
|     # Arrange | ||||
|     prefix = b"something invalid" | ||||
|  | @ -290,19 +291,19 @@ def test__accept_false(): | |||
|     assert not output | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     invalid_file = "Tests/images/flower.jpg" | ||||
| 
 | ||||
|     with pytest.raises(SyntaxError): | ||||
|         DdsImagePlugin.DdsImageFile(invalid_file) | ||||
| 
 | ||||
| 
 | ||||
| def test_short_header(): | ||||
| def test_short_header() -> None: | ||||
|     """Check a short header""" | ||||
|     with open(TEST_FILE_DXT5, "rb") as f: | ||||
|         img_file = f.read() | ||||
| 
 | ||||
|     def short_header(): | ||||
|     def short_header() -> None: | ||||
|         with Image.open(BytesIO(img_file[:119])): | ||||
|             pass  # pragma: no cover | ||||
| 
 | ||||
|  | @ -310,13 +311,13 @@ def test_short_header(): | |||
|         short_header() | ||||
| 
 | ||||
| 
 | ||||
| def test_short_file(): | ||||
| def test_short_file() -> None: | ||||
|     """Check that the appropriate error is thrown for a short file""" | ||||
| 
 | ||||
|     with open(TEST_FILE_DXT5, "rb") as f: | ||||
|         img_file = f.read() | ||||
| 
 | ||||
|     def short_file(): | ||||
|     def short_file() -> None: | ||||
|         with Image.open(BytesIO(img_file[:-100])) as im: | ||||
|             im.load() | ||||
| 
 | ||||
|  | @ -324,7 +325,7 @@ def test_short_file(): | |||
|         short_file() | ||||
| 
 | ||||
| 
 | ||||
| def test_dxt5_colorblock_alpha_issue_4142(): | ||||
| def test_dxt5_colorblock_alpha_issue_4142() -> None: | ||||
|     """Check that colorblocks are decoded correctly in DXT5""" | ||||
| 
 | ||||
|     with Image.open("Tests/images/dxt5-colorblock-alpha-issue-4142.dds") as im: | ||||
|  | @ -339,12 +340,12 @@ def test_dxt5_colorblock_alpha_issue_4142(): | |||
|         assert px[2] != 0 | ||||
| 
 | ||||
| 
 | ||||
| def test_palette(): | ||||
| def test_palette() -> None: | ||||
|     with Image.open("Tests/images/palette.dds") as im: | ||||
|         assert_image_equal_tofile(im, "Tests/images/transparent.gif") | ||||
| 
 | ||||
| 
 | ||||
| def test_unsupported_bitcount(): | ||||
| def test_unsupported_bitcount() -> None: | ||||
|     with pytest.raises(OSError): | ||||
|         with Image.open("Tests/images/unsupported_bitcount.dds"): | ||||
|             pass | ||||
|  | @ -357,13 +358,13 @@ def test_unsupported_bitcount(): | |||
|         "Tests/images/unimplemented_pfflags.dds", | ||||
|     ), | ||||
| ) | ||||
| def test_not_implemented(test_file): | ||||
| def test_not_implemented(test_file) -> None: | ||||
|     with pytest.raises(NotImplementedError): | ||||
|         with Image.open(test_file): | ||||
|             pass | ||||
| 
 | ||||
| 
 | ||||
| def test_save_unsupported_mode(tmp_path): | ||||
| def test_save_unsupported_mode(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.dds") | ||||
|     im = hopper("HSV") | ||||
|     with pytest.raises(OSError): | ||||
|  | @ -379,7 +380,7 @@ def test_save_unsupported_mode(tmp_path): | |||
|         ("RGBA", "Tests/images/pil123rgba.png"), | ||||
|     ], | ||||
| ) | ||||
| def test_save(mode, test_file, tmp_path): | ||||
| def test_save(mode, test_file, tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.dds") | ||||
|     with Image.open(test_file) as im: | ||||
|         assert im.mode == mode | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| import io | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -83,7 +84,7 @@ simple_eps_file_with_long_binary_data = ( | |||
|     ("filename", "size"), ((FILE1, (460, 352)), (FILE2, (360, 252))) | ||||
| ) | ||||
| @pytest.mark.parametrize("scale", (1, 2)) | ||||
| def test_sanity(filename, size, scale): | ||||
| def test_sanity(filename, size, scale) -> None: | ||||
|     expected_size = tuple(s * scale for s in size) | ||||
|     with Image.open(filename) as image: | ||||
|         image.load(scale=scale) | ||||
|  | @ -93,7 +94,7 @@ def test_sanity(filename, size, scale): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") | ||||
| def test_load(): | ||||
| def test_load() -> None: | ||||
|     with Image.open(FILE1) as im: | ||||
|         assert im.load()[0, 0] == (255, 255, 255) | ||||
| 
 | ||||
|  | @ -101,7 +102,7 @@ def test_load(): | |||
|         assert im.load()[0, 0] == (255, 255, 255) | ||||
| 
 | ||||
| 
 | ||||
| def test_binary(): | ||||
| def test_binary() -> None: | ||||
|     if HAS_GHOSTSCRIPT: | ||||
|         assert EpsImagePlugin.gs_binary is not None | ||||
|     else: | ||||
|  | @ -115,41 +116,41 @@ def test_binary(): | |||
|         assert EpsImagePlugin.gs_windows_binary is not None | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     invalid_file = "Tests/images/flower.jpg" | ||||
|     with pytest.raises(SyntaxError): | ||||
|         EpsImagePlugin.EpsImageFile(invalid_file) | ||||
| 
 | ||||
| 
 | ||||
| def test_binary_header_only(): | ||||
| def test_binary_header_only() -> None: | ||||
|     data = io.BytesIO(simple_binary_header) | ||||
|     with pytest.raises(SyntaxError, match='EPS header missing "%!PS-Adobe" comment'): | ||||
|         EpsImagePlugin.EpsImageFile(data) | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("prefix", (b"", simple_binary_header)) | ||||
| def test_missing_version_comment(prefix): | ||||
| def test_missing_version_comment(prefix) -> None: | ||||
|     data = io.BytesIO(prefix + b"\n".join(simple_eps_file_without_version)) | ||||
|     with pytest.raises(SyntaxError): | ||||
|         EpsImagePlugin.EpsImageFile(data) | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("prefix", (b"", simple_binary_header)) | ||||
| def test_missing_boundingbox_comment(prefix): | ||||
| def test_missing_boundingbox_comment(prefix) -> None: | ||||
|     data = io.BytesIO(prefix + b"\n".join(simple_eps_file_without_boundingbox)) | ||||
|     with pytest.raises(SyntaxError, match='EPS header missing "%%BoundingBox" comment'): | ||||
|         EpsImagePlugin.EpsImageFile(data) | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("prefix", (b"", simple_binary_header)) | ||||
| def test_invalid_boundingbox_comment(prefix): | ||||
| def test_invalid_boundingbox_comment(prefix) -> None: | ||||
|     data = io.BytesIO(prefix + b"\n".join(simple_eps_file_with_invalid_boundingbox)) | ||||
|     with pytest.raises(OSError, match="cannot determine EPS bounding box"): | ||||
|         EpsImagePlugin.EpsImageFile(data) | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("prefix", (b"", simple_binary_header)) | ||||
| def test_invalid_boundingbox_comment_valid_imagedata_comment(prefix): | ||||
| def test_invalid_boundingbox_comment_valid_imagedata_comment(prefix) -> None: | ||||
|     data = io.BytesIO( | ||||
|         prefix + b"\n".join(simple_eps_file_with_invalid_boundingbox_valid_imagedata) | ||||
|     ) | ||||
|  | @ -160,21 +161,21 @@ def test_invalid_boundingbox_comment_valid_imagedata_comment(prefix): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("prefix", (b"", simple_binary_header)) | ||||
| def test_ascii_comment_too_long(prefix): | ||||
| def test_ascii_comment_too_long(prefix) -> None: | ||||
|     data = io.BytesIO(prefix + b"\n".join(simple_eps_file_with_long_ascii_comment)) | ||||
|     with pytest.raises(SyntaxError, match="not an EPS file"): | ||||
|         EpsImagePlugin.EpsImageFile(data) | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("prefix", (b"", simple_binary_header)) | ||||
| def test_long_binary_data(prefix): | ||||
| def test_long_binary_data(prefix) -> None: | ||||
|     data = io.BytesIO(prefix + b"\n".join(simple_eps_file_with_long_binary_data)) | ||||
|     EpsImagePlugin.EpsImageFile(data) | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") | ||||
| @pytest.mark.parametrize("prefix", (b"", simple_binary_header)) | ||||
| def test_load_long_binary_data(prefix): | ||||
| def test_load_long_binary_data(prefix) -> None: | ||||
|     data = io.BytesIO(prefix + b"\n".join(simple_eps_file_with_long_binary_data)) | ||||
|     with Image.open(data) as img: | ||||
|         img.load() | ||||
|  | @ -187,7 +188,7 @@ def test_load_long_binary_data(prefix): | |||
|     pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" | ||||
| ) | ||||
| @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") | ||||
| def test_cmyk(): | ||||
| def test_cmyk() -> None: | ||||
|     with Image.open("Tests/images/pil_sample_cmyk.eps") as cmyk_image: | ||||
|         assert cmyk_image.mode == "CMYK" | ||||
|         assert cmyk_image.size == (100, 100) | ||||
|  | @ -203,7 +204,7 @@ def test_cmyk(): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") | ||||
| def test_showpage(): | ||||
| def test_showpage() -> None: | ||||
|     # See https://github.com/python-pillow/Pillow/issues/2615 | ||||
|     with Image.open("Tests/images/reqd_showpage.eps") as plot_image: | ||||
|         with Image.open("Tests/images/reqd_showpage.png") as target: | ||||
|  | @ -214,7 +215,7 @@ def test_showpage(): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") | ||||
| def test_transparency(): | ||||
| def test_transparency() -> None: | ||||
|     with Image.open("Tests/images/reqd_showpage.eps") as plot_image: | ||||
|         plot_image.load(transparency=True) | ||||
|         assert plot_image.mode == "RGBA" | ||||
|  | @ -225,7 +226,7 @@ def test_transparency(): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") | ||||
| def test_file_object(tmp_path): | ||||
| def test_file_object(tmp_path: Path) -> None: | ||||
|     # issue 479 | ||||
|     with Image.open(FILE1) as image1: | ||||
|         with open(str(tmp_path / "temp.eps"), "wb") as fh: | ||||
|  | @ -233,7 +234,7 @@ def test_file_object(tmp_path): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") | ||||
| def test_bytesio_object(): | ||||
| def test_bytesio_object() -> None: | ||||
|     with open(FILE1, "rb") as f: | ||||
|         img_bytes = io.BytesIO(f.read()) | ||||
| 
 | ||||
|  | @ -246,12 +247,12 @@ def test_bytesio_object(): | |||
|         assert_image_similar(img, image1_scale1_compare, 5) | ||||
| 
 | ||||
| 
 | ||||
| def test_1_mode(): | ||||
| def test_1_mode() -> None: | ||||
|     with Image.open("Tests/images/1.eps") as im: | ||||
|         assert im.mode == "1" | ||||
| 
 | ||||
| 
 | ||||
| def test_image_mode_not_supported(tmp_path): | ||||
| def test_image_mode_not_supported(tmp_path: Path) -> None: | ||||
|     im = hopper("RGBA") | ||||
|     tmpfile = str(tmp_path / "temp.eps") | ||||
|     with pytest.raises(ValueError): | ||||
|  | @ -260,7 +261,7 @@ def test_image_mode_not_supported(tmp_path): | |||
| 
 | ||||
| @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") | ||||
| @skip_unless_feature("zlib") | ||||
| def test_render_scale1(): | ||||
| def test_render_scale1() -> None: | ||||
|     # We need png support for these render test | ||||
| 
 | ||||
|     # Zero bounding box | ||||
|  | @ -282,7 +283,7 @@ def test_render_scale1(): | |||
| 
 | ||||
| @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") | ||||
| @skip_unless_feature("zlib") | ||||
| def test_render_scale2(): | ||||
| def test_render_scale2() -> None: | ||||
|     # We need png support for these render test | ||||
| 
 | ||||
|     # Zero bounding box | ||||
|  | @ -304,7 +305,7 @@ def test_render_scale2(): | |||
| 
 | ||||
| @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") | ||||
| @pytest.mark.parametrize("filename", (FILE1, FILE2, "Tests/images/illu10_preview.eps")) | ||||
| def test_resize(filename): | ||||
| def test_resize(filename) -> None: | ||||
|     with Image.open(filename) as im: | ||||
|         new_size = (100, 100) | ||||
|         im = im.resize(new_size) | ||||
|  | @ -313,7 +314,7 @@ def test_resize(filename): | |||
| 
 | ||||
| @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") | ||||
| @pytest.mark.parametrize("filename", (FILE1, FILE2)) | ||||
| def test_thumbnail(filename): | ||||
| def test_thumbnail(filename) -> None: | ||||
|     # Issue #619 | ||||
|     with Image.open(filename) as im: | ||||
|         new_size = (100, 100) | ||||
|  | @ -321,20 +322,20 @@ def test_thumbnail(filename): | |||
|         assert max(im.size) == max(new_size) | ||||
| 
 | ||||
| 
 | ||||
| def test_read_binary_preview(): | ||||
| def test_read_binary_preview() -> None: | ||||
|     # Issue 302 | ||||
|     # open image with binary preview | ||||
|     with Image.open(FILE3): | ||||
|         pass | ||||
| 
 | ||||
| 
 | ||||
| def test_readline_psfile(tmp_path): | ||||
| def test_readline_psfile(tmp_path: Path) -> None: | ||||
|     # check all the freaking line endings possible from the spec | ||||
|     # test_string = u'something\r\nelse\n\rbaz\rbif\n' | ||||
|     line_endings = ["\r\n", "\n", "\n\r", "\r"] | ||||
|     strings = ["something", "else", "baz", "bif"] | ||||
| 
 | ||||
|     def _test_readline(t, ending): | ||||
|     def _test_readline(t, ending) -> None: | ||||
|         ending = "Failure with line ending: %s" % ( | ||||
|             "".join("%s" % ord(s) for s in ending) | ||||
|         ) | ||||
|  | @ -343,13 +344,13 @@ def test_readline_psfile(tmp_path): | |||
|         assert t.readline().strip("\r\n") == "baz", ending | ||||
|         assert t.readline().strip("\r\n") == "bif", ending | ||||
| 
 | ||||
|     def _test_readline_io_psfile(test_string, ending): | ||||
|     def _test_readline_io_psfile(test_string, ending) -> None: | ||||
|         f = io.BytesIO(test_string.encode("latin-1")) | ||||
|         with pytest.warns(DeprecationWarning): | ||||
|             t = EpsImagePlugin.PSFile(f) | ||||
|         _test_readline(t, ending) | ||||
| 
 | ||||
|     def _test_readline_file_psfile(test_string, ending): | ||||
|     def _test_readline_file_psfile(test_string, ending) -> None: | ||||
|         f = str(tmp_path / "temp.txt") | ||||
|         with open(f, "wb") as w: | ||||
|             w.write(test_string.encode("latin-1")) | ||||
|  | @ -365,7 +366,7 @@ def test_readline_psfile(tmp_path): | |||
|         _test_readline_file_psfile(s, ending) | ||||
| 
 | ||||
| 
 | ||||
| def test_psfile_deprecation(): | ||||
| def test_psfile_deprecation() -> None: | ||||
|     with pytest.warns(DeprecationWarning): | ||||
|         EpsImagePlugin.PSFile(None) | ||||
| 
 | ||||
|  | @ -375,7 +376,7 @@ def test_psfile_deprecation(): | |||
|     "line_ending", | ||||
|     (b"\r\n", b"\n", b"\n\r", b"\r"), | ||||
| ) | ||||
| def test_readline(prefix, line_ending): | ||||
| def test_readline(prefix, line_ending) -> None: | ||||
|     simple_file = prefix + line_ending.join(simple_eps_file_with_comments) | ||||
|     data = io.BytesIO(simple_file) | ||||
|     test_file = EpsImagePlugin.EpsImageFile(data) | ||||
|  | @ -393,14 +394,14 @@ def test_readline(prefix, line_ending): | |||
|         "Tests/images/illuCS6_preview.eps", | ||||
|     ), | ||||
| ) | ||||
| def test_open_eps(filename): | ||||
| def test_open_eps(filename) -> None: | ||||
|     # https://github.com/python-pillow/Pillow/issues/1104 | ||||
|     with Image.open(filename) as img: | ||||
|         assert img.mode == "RGB" | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") | ||||
| def test_emptyline(): | ||||
| def test_emptyline() -> None: | ||||
|     # Test file includes an empty line in the header data | ||||
|     emptyline_file = "Tests/images/zero_bb_emptyline.eps" | ||||
| 
 | ||||
|  | @ -416,14 +417,14 @@ def test_emptyline(): | |||
|     "test_file", | ||||
|     ["Tests/images/timeout-d675703545fee17acab56e5fec644c19979175de.eps"], | ||||
| ) | ||||
| def test_timeout(test_file): | ||||
| def test_timeout(test_file) -> None: | ||||
|     with open(test_file, "rb") as f: | ||||
|         with pytest.raises(Image.UnidentifiedImageError): | ||||
|             with Image.open(f): | ||||
|                 pass | ||||
| 
 | ||||
| 
 | ||||
| def test_bounding_box_in_trailer(): | ||||
| def test_bounding_box_in_trailer() -> None: | ||||
|     # Check bounding boxes are parsed in the same way | ||||
|     # when specified in the header and the trailer | ||||
|     with Image.open("Tests/images/zero_bb_trailer.eps") as trailer_image, Image.open( | ||||
|  | @ -432,7 +433,7 @@ def test_bounding_box_in_trailer(): | |||
|         assert trailer_image.size == header_image.size | ||||
| 
 | ||||
| 
 | ||||
| def test_eof_before_bounding_box(): | ||||
| def test_eof_before_bounding_box() -> None: | ||||
|     with pytest.raises(OSError): | ||||
|         with Image.open("Tests/images/zero_bb_eof_before_boundingbox.eps"): | ||||
|             pass | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ from .helper import assert_image_equal, hopper | |||
| TEST_FILE = "Tests/images/hopper.fits" | ||||
| 
 | ||||
| 
 | ||||
| def test_open(): | ||||
| def test_open() -> None: | ||||
|     # Act | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         # Assert | ||||
|  | @ -22,7 +22,7 @@ def test_open(): | |||
|         assert_image_equal(im, hopper("L")) | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     # Arrange | ||||
|     invalid_file = "Tests/images/flower.jpg" | ||||
| 
 | ||||
|  | @ -31,14 +31,14 @@ def test_invalid_file(): | |||
|         FitsImagePlugin.FitsImageFile(invalid_file) | ||||
| 
 | ||||
| 
 | ||||
| def test_truncated_fits(): | ||||
| def test_truncated_fits() -> None: | ||||
|     # No END to headers | ||||
|     image_data = b"SIMPLE  =                    T" + b" " * 50 + b"TRUNCATE" | ||||
|     with pytest.raises(OSError): | ||||
|         FitsImagePlugin.FitsImageFile(BytesIO(image_data)) | ||||
| 
 | ||||
| 
 | ||||
| def test_naxis_zero(): | ||||
| def test_naxis_zero() -> None: | ||||
|     # This test image has been manually hexedited | ||||
|     # to set the number of data axes to zero | ||||
|     with pytest.raises(ValueError): | ||||
|  | @ -46,7 +46,7 @@ def test_naxis_zero(): | |||
|             pass | ||||
| 
 | ||||
| 
 | ||||
| def test_comment(): | ||||
| def test_comment() -> None: | ||||
|     image_data = b"SIMPLE  =                    T / comment string" | ||||
|     with pytest.raises(OSError): | ||||
|         FitsImagePlugin.FitsImageFile(BytesIO(image_data)) | ||||
|  |  | |||
|  | @ -16,7 +16,7 @@ static_test_file = "Tests/images/hopper.fli" | |||
| animated_test_file = "Tests/images/a.fli" | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(): | ||||
| def test_sanity() -> None: | ||||
|     with Image.open(static_test_file) as im: | ||||
|         im.load() | ||||
|         assert im.mode == "P" | ||||
|  | @ -33,8 +33,8 @@ def test_sanity(): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.skipif(is_pypy(), reason="Requires CPython") | ||||
| def test_unclosed_file(): | ||||
|     def open(): | ||||
| def test_unclosed_file() -> None: | ||||
|     def open() -> None: | ||||
|         im = Image.open(static_test_file) | ||||
|         im.load() | ||||
| 
 | ||||
|  | @ -42,14 +42,14 @@ def test_unclosed_file(): | |||
|         open() | ||||
| 
 | ||||
| 
 | ||||
| def test_closed_file(): | ||||
| def test_closed_file() -> None: | ||||
|     with warnings.catch_warnings(): | ||||
|         im = Image.open(static_test_file) | ||||
|         im.load() | ||||
|         im.close() | ||||
| 
 | ||||
| 
 | ||||
| def test_seek_after_close(): | ||||
| def test_seek_after_close() -> None: | ||||
|     im = Image.open(animated_test_file) | ||||
|     im.seek(1) | ||||
|     im.close() | ||||
|  | @ -58,13 +58,13 @@ def test_seek_after_close(): | |||
|         im.seek(0) | ||||
| 
 | ||||
| 
 | ||||
| def test_context_manager(): | ||||
| def test_context_manager() -> None: | ||||
|     with warnings.catch_warnings(): | ||||
|         with Image.open(static_test_file) as im: | ||||
|             im.load() | ||||
| 
 | ||||
| 
 | ||||
| def test_tell(): | ||||
| def test_tell() -> None: | ||||
|     # Arrange | ||||
|     with Image.open(static_test_file) as im: | ||||
|         # Act | ||||
|  | @ -74,20 +74,20 @@ def test_tell(): | |||
|         assert frame == 0 | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     invalid_file = "Tests/images/flower.jpg" | ||||
| 
 | ||||
|     with pytest.raises(SyntaxError): | ||||
|         FliImagePlugin.FliImageFile(invalid_file) | ||||
| 
 | ||||
| 
 | ||||
| def test_palette_chunk_second(): | ||||
| def test_palette_chunk_second() -> None: | ||||
|     with Image.open("Tests/images/hopper_palette_chunk_second.fli") as im: | ||||
|         with Image.open(static_test_file) as expected: | ||||
|             assert_image_equal(im.convert("RGB"), expected.convert("RGB")) | ||||
| 
 | ||||
| 
 | ||||
| def test_n_frames(): | ||||
| def test_n_frames() -> None: | ||||
|     with Image.open(static_test_file) as im: | ||||
|         assert im.n_frames == 1 | ||||
|         assert not im.is_animated | ||||
|  | @ -97,7 +97,7 @@ def test_n_frames(): | |||
|         assert im.is_animated | ||||
| 
 | ||||
| 
 | ||||
| def test_eoferror(): | ||||
| def test_eoferror() -> None: | ||||
|     with Image.open(animated_test_file) as im: | ||||
|         n_frames = im.n_frames | ||||
| 
 | ||||
|  | @ -110,7 +110,7 @@ def test_eoferror(): | |||
|         im.seek(n_frames - 1) | ||||
| 
 | ||||
| 
 | ||||
| def test_seek_tell(): | ||||
| def test_seek_tell() -> None: | ||||
|     with Image.open(animated_test_file) as im: | ||||
|         layer_number = im.tell() | ||||
|         assert layer_number == 0 | ||||
|  | @ -132,7 +132,7 @@ def test_seek_tell(): | |||
|         assert layer_number == 1 | ||||
| 
 | ||||
| 
 | ||||
| def test_seek(): | ||||
| def test_seek() -> None: | ||||
|     with Image.open(animated_test_file) as im: | ||||
|         im.seek(50) | ||||
| 
 | ||||
|  | @ -147,7 +147,7 @@ def test_seek(): | |||
|     ], | ||||
| ) | ||||
| @pytest.mark.timeout(timeout=3) | ||||
| def test_timeouts(test_file): | ||||
| def test_timeouts(test_file) -> None: | ||||
|     with open(test_file, "rb") as f: | ||||
|         with Image.open(f) as im: | ||||
|             with pytest.raises(OSError): | ||||
|  | @ -160,7 +160,7 @@ def test_timeouts(test_file): | |||
|         "Tests/images/crash-5762152299364352.fli", | ||||
|     ], | ||||
| ) | ||||
| def test_crash(test_file): | ||||
| def test_crash(test_file) -> None: | ||||
|     with open(test_file, "rb") as f: | ||||
|         with Image.open(f) as im: | ||||
|             with pytest.raises(OSError): | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ FpxImagePlugin = pytest.importorskip( | |||
| ) | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(): | ||||
| def test_sanity() -> None: | ||||
|     with Image.open("Tests/images/input_bw_one_band.fpx") as im: | ||||
|         assert im.mode == "L" | ||||
|         assert im.size == (70, 46) | ||||
|  | @ -20,7 +20,7 @@ def test_sanity(): | |||
|         assert_image_equal_tofile(im, "Tests/images/input_bw_one_band.png") | ||||
| 
 | ||||
| 
 | ||||
| def test_close(): | ||||
| def test_close() -> None: | ||||
|     with Image.open("Tests/images/input_bw_one_band.fpx") as im: | ||||
|         pass | ||||
|     assert im.ole.fp.closed | ||||
|  | @ -30,7 +30,7 @@ def test_close(): | |||
|     assert im.ole.fp.closed | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     # Test an invalid OLE file | ||||
|     invalid_file = "Tests/images/flower.jpg" | ||||
|     with pytest.raises(SyntaxError): | ||||
|  | @ -42,7 +42,7 @@ def test_invalid_file(): | |||
|         FpxImagePlugin.FpxImageFile(ole_file) | ||||
| 
 | ||||
| 
 | ||||
| def test_fpx_invalid_number_of_bands(): | ||||
| def test_fpx_invalid_number_of_bands() -> None: | ||||
|     with pytest.raises(OSError, match="Invalid number of bands"): | ||||
|         with Image.open("Tests/images/input_bw_five_bands.fpx"): | ||||
|             pass | ||||
|  |  | |||
|  | @ -7,18 +7,18 @@ from PIL import FtexImagePlugin, Image | |||
| from .helper import assert_image_equal_tofile, assert_image_similar | ||||
| 
 | ||||
| 
 | ||||
| def test_load_raw(): | ||||
| def test_load_raw() -> None: | ||||
|     with Image.open("Tests/images/ftex_uncompressed.ftu") as im: | ||||
|         assert_image_equal_tofile(im, "Tests/images/ftex_uncompressed.png") | ||||
| 
 | ||||
| 
 | ||||
| def test_load_dxt1(): | ||||
| def test_load_dxt1() -> None: | ||||
|     with Image.open("Tests/images/ftex_dxt1.ftc") as im: | ||||
|         with Image.open("Tests/images/ftex_dxt1.png") as target: | ||||
|             assert_image_similar(im, target.convert("RGBA"), 15) | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     invalid_file = "Tests/images/flower.jpg" | ||||
| 
 | ||||
|     with pytest.raises(SyntaxError): | ||||
|  |  | |||
|  | @ -7,12 +7,12 @@ from PIL import GbrImagePlugin, Image | |||
| from .helper import assert_image_equal_tofile | ||||
| 
 | ||||
| 
 | ||||
| def test_gbr_file(): | ||||
| def test_gbr_file() -> None: | ||||
|     with Image.open("Tests/images/gbr.gbr") as im: | ||||
|         assert_image_equal_tofile(im, "Tests/images/gbr.png") | ||||
| 
 | ||||
| 
 | ||||
| def test_load(): | ||||
| def test_load() -> None: | ||||
|     with Image.open("Tests/images/gbr.gbr") as im: | ||||
|         assert im.load()[0, 0] == (0, 0, 0, 0) | ||||
| 
 | ||||
|  | @ -20,14 +20,14 @@ def test_load(): | |||
|         assert im.load()[0, 0] == (0, 0, 0, 0) | ||||
| 
 | ||||
| 
 | ||||
| def test_multiple_load_operations(): | ||||
| def test_multiple_load_operations() -> None: | ||||
|     with Image.open("Tests/images/gbr.gbr") as im: | ||||
|         im.load() | ||||
|         im.load() | ||||
|         assert_image_equal_tofile(im, "Tests/images/gbr.png") | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     invalid_file = "Tests/images/flower.jpg" | ||||
| 
 | ||||
|     with pytest.raises(SyntaxError): | ||||
|  |  | |||
|  | @ -7,18 +7,18 @@ from PIL import GdImageFile, UnidentifiedImageError | |||
| TEST_GD_FILE = "Tests/images/hopper.gd" | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(): | ||||
| def test_sanity() -> None: | ||||
|     with GdImageFile.open(TEST_GD_FILE) as im: | ||||
|         assert im.size == (128, 128) | ||||
|         assert im.format == "GD" | ||||
| 
 | ||||
| 
 | ||||
| def test_bad_mode(): | ||||
| def test_bad_mode() -> None: | ||||
|     with pytest.raises(ValueError): | ||||
|         GdImageFile.open(TEST_GD_FILE, "bad mode") | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     invalid_file = "Tests/images/flower.jpg" | ||||
| 
 | ||||
|     with pytest.raises(UnidentifiedImageError): | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ from __future__ import annotations | |||
| 
 | ||||
| import warnings | ||||
| from io import BytesIO | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -23,7 +24,7 @@ with open(TEST_GIF, "rb") as f: | |||
|     data = f.read() | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(): | ||||
| def test_sanity() -> None: | ||||
|     with Image.open(TEST_GIF) as im: | ||||
|         im.load() | ||||
|         assert im.mode == "P" | ||||
|  | @ -33,8 +34,8 @@ def test_sanity(): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.skipif(is_pypy(), reason="Requires CPython") | ||||
| def test_unclosed_file(): | ||||
|     def open(): | ||||
| def test_unclosed_file() -> None: | ||||
|     def open() -> None: | ||||
|         im = Image.open(TEST_GIF) | ||||
|         im.load() | ||||
| 
 | ||||
|  | @ -42,14 +43,14 @@ def test_unclosed_file(): | |||
|         open() | ||||
| 
 | ||||
| 
 | ||||
| def test_closed_file(): | ||||
| def test_closed_file() -> None: | ||||
|     with warnings.catch_warnings(): | ||||
|         im = Image.open(TEST_GIF) | ||||
|         im.load() | ||||
|         im.close() | ||||
| 
 | ||||
| 
 | ||||
| def test_seek_after_close(): | ||||
| def test_seek_after_close() -> None: | ||||
|     im = Image.open("Tests/images/iss634.gif") | ||||
|     im.load() | ||||
|     im.close() | ||||
|  | @ -62,20 +63,20 @@ def test_seek_after_close(): | |||
|         im.seek(1) | ||||
| 
 | ||||
| 
 | ||||
| def test_context_manager(): | ||||
| def test_context_manager() -> None: | ||||
|     with warnings.catch_warnings(): | ||||
|         with Image.open(TEST_GIF) as im: | ||||
|             im.load() | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     invalid_file = "Tests/images/flower.jpg" | ||||
| 
 | ||||
|     with pytest.raises(SyntaxError): | ||||
|         GifImagePlugin.GifImageFile(invalid_file) | ||||
| 
 | ||||
| 
 | ||||
| def test_l_mode_transparency(): | ||||
| def test_l_mode_transparency() -> None: | ||||
|     with Image.open("Tests/images/no_palette_with_transparency.gif") as im: | ||||
|         assert im.mode == "L" | ||||
|         assert im.load()[0, 0] == 128 | ||||
|  | @ -86,7 +87,7 @@ def test_l_mode_transparency(): | |||
|         assert im.load()[0, 0] == 128 | ||||
| 
 | ||||
| 
 | ||||
| def test_l_mode_after_rgb(): | ||||
| def test_l_mode_after_rgb() -> None: | ||||
|     with Image.open("Tests/images/no_palette_after_rgb.gif") as im: | ||||
|         im.seek(1) | ||||
|         assert im.mode == "RGB" | ||||
|  | @ -95,13 +96,13 @@ def test_l_mode_after_rgb(): | |||
|         assert im.mode == "RGB" | ||||
| 
 | ||||
| 
 | ||||
| def test_palette_not_needed_for_second_frame(): | ||||
| def test_palette_not_needed_for_second_frame() -> None: | ||||
|     with Image.open("Tests/images/palette_not_needed_for_second_frame.gif") as im: | ||||
|         im.seek(1) | ||||
|         assert_image_similar(im, hopper("L").convert("RGB"), 8) | ||||
| 
 | ||||
| 
 | ||||
| def test_strategy(): | ||||
| def test_strategy() -> None: | ||||
|     with Image.open("Tests/images/iss634.gif") as im: | ||||
|         expected_rgb_always = im.convert("RGB") | ||||
| 
 | ||||
|  | @ -142,7 +143,7 @@ def test_strategy(): | |||
|         GifImagePlugin.LOADING_STRATEGY = GifImagePlugin.LoadingStrategy.RGB_AFTER_FIRST | ||||
| 
 | ||||
| 
 | ||||
| def test_optimize(): | ||||
| def test_optimize() -> None: | ||||
|     def test_grayscale(optimize): | ||||
|         im = Image.new("L", (1, 1), 0) | ||||
|         filename = BytesIO() | ||||
|  | @ -177,7 +178,7 @@ def test_optimize(): | |||
|         (4, 513, 256), | ||||
|     ), | ||||
| ) | ||||
| def test_optimize_correctness(colors, size, expected_palette_length): | ||||
| def test_optimize_correctness(colors, size, expected_palette_length) -> None: | ||||
|     # 256 color Palette image, posterize to > 128 and < 128 levels. | ||||
|     # Size bigger and smaller than 512x512. | ||||
|     # Check the palette for number of colors allocated. | ||||
|  | @ -199,14 +200,14 @@ def test_optimize_correctness(colors, size, expected_palette_length): | |||
|         assert_image_equal(im.convert("RGB"), reloaded.convert("RGB")) | ||||
| 
 | ||||
| 
 | ||||
| def test_optimize_full_l(): | ||||
| def test_optimize_full_l() -> None: | ||||
|     im = Image.frombytes("L", (16, 16), bytes(range(256))) | ||||
|     test_file = BytesIO() | ||||
|     im.save(test_file, "GIF", optimize=True) | ||||
|     assert im.mode == "L" | ||||
| 
 | ||||
| 
 | ||||
| def test_optimize_if_palette_can_be_reduced_by_half(): | ||||
| def test_optimize_if_palette_can_be_reduced_by_half() -> None: | ||||
|     im = Image.new("P", (8, 1)) | ||||
|     im.palette = ImagePalette.raw("RGB", bytes((0, 0, 0) * 150)) | ||||
|     for i in range(8): | ||||
|  | @ -219,7 +220,7 @@ def test_optimize_if_palette_can_be_reduced_by_half(): | |||
|             assert len(reloaded.palette.palette) // 3 == colors | ||||
| 
 | ||||
| 
 | ||||
| def test_full_palette_second_frame(tmp_path): | ||||
| def test_full_palette_second_frame(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.gif") | ||||
|     im = Image.new("P", (1, 256)) | ||||
| 
 | ||||
|  | @ -240,7 +241,7 @@ def test_full_palette_second_frame(tmp_path): | |||
|             reloaded.getpixel((0, i)) == i | ||||
| 
 | ||||
| 
 | ||||
| def test_roundtrip(tmp_path): | ||||
| def test_roundtrip(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.gif") | ||||
|     im = hopper() | ||||
|     im.save(out) | ||||
|  | @ -248,7 +249,7 @@ def test_roundtrip(tmp_path): | |||
|         assert_image_similar(reread.convert("RGB"), im, 50) | ||||
| 
 | ||||
| 
 | ||||
| def test_roundtrip2(tmp_path): | ||||
| def test_roundtrip2(tmp_path: Path) -> None: | ||||
|     # see https://github.com/python-pillow/Pillow/issues/403 | ||||
|     out = str(tmp_path / "temp.gif") | ||||
|     with Image.open(TEST_GIF) as im: | ||||
|  | @ -258,7 +259,7 @@ def test_roundtrip2(tmp_path): | |||
|         assert_image_similar(reread.convert("RGB"), hopper(), 50) | ||||
| 
 | ||||
| 
 | ||||
| def test_roundtrip_save_all(tmp_path): | ||||
| def test_roundtrip_save_all(tmp_path: Path) -> None: | ||||
|     # Single frame image | ||||
|     out = str(tmp_path / "temp.gif") | ||||
|     im = hopper() | ||||
|  | @ -275,7 +276,7 @@ def test_roundtrip_save_all(tmp_path): | |||
|         assert reread.n_frames == 5 | ||||
| 
 | ||||
| 
 | ||||
| def test_roundtrip_save_all_1(tmp_path): | ||||
| def test_roundtrip_save_all_1(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.gif") | ||||
|     im = Image.new("1", (1, 1)) | ||||
|     im2 = Image.new("1", (1, 1), 1) | ||||
|  | @ -340,7 +341,7 @@ def test_save_all_progress(): | |||
|         ("Tests/images/dispose_bgnd_rgba.gif", "RGBA"), | ||||
|     ), | ||||
| ) | ||||
| def test_loading_multiple_palettes(path, mode): | ||||
| def test_loading_multiple_palettes(path, mode) -> None: | ||||
|     with Image.open(path) as im: | ||||
|         assert im.mode == "P" | ||||
|         first_frame_colors = im.palette.colors.keys() | ||||
|  | @ -358,7 +359,7 @@ def test_loading_multiple_palettes(path, mode): | |||
|         assert im.load()[24, 24] not in first_frame_colors | ||||
| 
 | ||||
| 
 | ||||
| def test_headers_saving_for_animated_gifs(tmp_path): | ||||
| def test_headers_saving_for_animated_gifs(tmp_path: Path) -> None: | ||||
|     important_headers = ["background", "version", "duration", "loop"] | ||||
|     # Multiframe image | ||||
|     with Image.open("Tests/images/dispose_bgnd.gif") as im: | ||||
|  | @ -371,7 +372,7 @@ def test_headers_saving_for_animated_gifs(tmp_path): | |||
|             assert info[header] == reread.info[header] | ||||
| 
 | ||||
| 
 | ||||
| def test_palette_handling(tmp_path): | ||||
| def test_palette_handling(tmp_path: Path) -> None: | ||||
|     # see https://github.com/python-pillow/Pillow/issues/513 | ||||
| 
 | ||||
|     with Image.open(TEST_GIF) as im: | ||||
|  | @ -387,7 +388,7 @@ def test_palette_handling(tmp_path): | |||
|         assert_image_similar(im, reloaded.convert("RGB"), 10) | ||||
| 
 | ||||
| 
 | ||||
| def test_palette_434(tmp_path): | ||||
| def test_palette_434(tmp_path: Path) -> None: | ||||
|     # see https://github.com/python-pillow/Pillow/issues/434 | ||||
| 
 | ||||
|     def roundtrip(im, *args, **kwargs): | ||||
|  | @ -412,7 +413,7 @@ def test_palette_434(tmp_path): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.skipif(not netpbm_available(), reason="Netpbm not available") | ||||
| def test_save_netpbm_bmp_mode(tmp_path): | ||||
| def test_save_netpbm_bmp_mode(tmp_path: Path) -> None: | ||||
|     with Image.open(TEST_GIF) as img: | ||||
|         img = img.convert("RGB") | ||||
| 
 | ||||
|  | @ -423,7 +424,7 @@ def test_save_netpbm_bmp_mode(tmp_path): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.skipif(not netpbm_available(), reason="Netpbm not available") | ||||
| def test_save_netpbm_l_mode(tmp_path): | ||||
| def test_save_netpbm_l_mode(tmp_path: Path) -> None: | ||||
|     with Image.open(TEST_GIF) as img: | ||||
|         img = img.convert("L") | ||||
| 
 | ||||
|  | @ -433,7 +434,7 @@ def test_save_netpbm_l_mode(tmp_path): | |||
|             assert_image_similar(img, reloaded.convert("L"), 0) | ||||
| 
 | ||||
| 
 | ||||
| def test_seek(): | ||||
| def test_seek() -> None: | ||||
|     with Image.open("Tests/images/dispose_none.gif") as img: | ||||
|         frame_count = 0 | ||||
|         try: | ||||
|  | @ -444,7 +445,7 @@ def test_seek(): | |||
|             assert frame_count == 5 | ||||
| 
 | ||||
| 
 | ||||
| def test_seek_info(): | ||||
| def test_seek_info() -> None: | ||||
|     with Image.open("Tests/images/iss634.gif") as im: | ||||
|         info = im.info.copy() | ||||
| 
 | ||||
|  | @ -454,7 +455,7 @@ def test_seek_info(): | |||
|         assert im.info == info | ||||
| 
 | ||||
| 
 | ||||
| def test_seek_rewind(): | ||||
| def test_seek_rewind() -> None: | ||||
|     with Image.open("Tests/images/iss634.gif") as im: | ||||
|         im.seek(2) | ||||
|         im.seek(1) | ||||
|  | @ -472,7 +473,7 @@ def test_seek_rewind(): | |||
|         ("Tests/images/iss634.gif", 42), | ||||
|     ), | ||||
| ) | ||||
| def test_n_frames(path, n_frames): | ||||
| def test_n_frames(path, n_frames) -> None: | ||||
|     # Test is_animated before n_frames | ||||
|     with Image.open(path) as im: | ||||
|         assert im.is_animated == (n_frames != 1) | ||||
|  | @ -483,7 +484,7 @@ def test_n_frames(path, n_frames): | |||
|         assert im.is_animated == (n_frames != 1) | ||||
| 
 | ||||
| 
 | ||||
| def test_no_change(): | ||||
| def test_no_change() -> None: | ||||
|     # Test n_frames does not change the image | ||||
|     with Image.open("Tests/images/dispose_bgnd.gif") as im: | ||||
|         im.seek(1) | ||||
|  | @ -504,7 +505,7 @@ def test_no_change(): | |||
|         assert_image_equal(im, expected) | ||||
| 
 | ||||
| 
 | ||||
| def test_eoferror(): | ||||
| def test_eoferror() -> None: | ||||
|     with Image.open(TEST_GIF) as im: | ||||
|         n_frames = im.n_frames | ||||
| 
 | ||||
|  | @ -517,13 +518,13 @@ def test_eoferror(): | |||
|         im.seek(n_frames - 1) | ||||
| 
 | ||||
| 
 | ||||
| def test_first_frame_transparency(): | ||||
| def test_first_frame_transparency() -> None: | ||||
|     with Image.open("Tests/images/first_frame_transparency.gif") as im: | ||||
|         px = im.load() | ||||
|         assert px[0, 0] == im.info["transparency"] | ||||
| 
 | ||||
| 
 | ||||
| def test_dispose_none(): | ||||
| def test_dispose_none() -> None: | ||||
|     with Image.open("Tests/images/dispose_none.gif") as img: | ||||
|         try: | ||||
|             while True: | ||||
|  | @ -533,7 +534,7 @@ def test_dispose_none(): | |||
|             pass | ||||
| 
 | ||||
| 
 | ||||
| def test_dispose_none_load_end(): | ||||
| def test_dispose_none_load_end() -> None: | ||||
|     # Test image created with: | ||||
|     # | ||||
|     # im = Image.open("transparent.gif") | ||||
|  | @ -546,7 +547,7 @@ def test_dispose_none_load_end(): | |||
|         assert_image_equal_tofile(img, "Tests/images/dispose_none_load_end_second.png") | ||||
| 
 | ||||
| 
 | ||||
| def test_dispose_background(): | ||||
| def test_dispose_background() -> None: | ||||
|     with Image.open("Tests/images/dispose_bgnd.gif") as img: | ||||
|         try: | ||||
|             while True: | ||||
|  | @ -556,7 +557,7 @@ def test_dispose_background(): | |||
|             pass | ||||
| 
 | ||||
| 
 | ||||
| def test_dispose_background_transparency(): | ||||
| def test_dispose_background_transparency() -> None: | ||||
|     with Image.open("Tests/images/dispose_bgnd_transparency.gif") as img: | ||||
|         img.seek(2) | ||||
|         px = img.load() | ||||
|  | @ -584,7 +585,7 @@ def test_dispose_background_transparency(): | |||
|         ), | ||||
|     ), | ||||
| ) | ||||
| def test_transparent_dispose(loading_strategy, expected_colors): | ||||
| def test_transparent_dispose(loading_strategy, expected_colors) -> None: | ||||
|     GifImagePlugin.LOADING_STRATEGY = loading_strategy | ||||
|     try: | ||||
|         with Image.open("Tests/images/transparent_dispose.gif") as img: | ||||
|  | @ -597,7 +598,7 @@ def test_transparent_dispose(loading_strategy, expected_colors): | |||
|         GifImagePlugin.LOADING_STRATEGY = GifImagePlugin.LoadingStrategy.RGB_AFTER_FIRST | ||||
| 
 | ||||
| 
 | ||||
| def test_dispose_previous(): | ||||
| def test_dispose_previous() -> None: | ||||
|     with Image.open("Tests/images/dispose_prev.gif") as img: | ||||
|         try: | ||||
|             while True: | ||||
|  | @ -607,7 +608,7 @@ def test_dispose_previous(): | |||
|             pass | ||||
| 
 | ||||
| 
 | ||||
| def test_dispose_previous_first_frame(): | ||||
| def test_dispose_previous_first_frame() -> None: | ||||
|     with Image.open("Tests/images/dispose_prev_first_frame.gif") as im: | ||||
|         im.seek(1) | ||||
|         assert_image_equal_tofile( | ||||
|  | @ -615,7 +616,7 @@ def test_dispose_previous_first_frame(): | |||
|         ) | ||||
| 
 | ||||
| 
 | ||||
| def test_previous_frame_loaded(): | ||||
| def test_previous_frame_loaded() -> None: | ||||
|     with Image.open("Tests/images/dispose_none.gif") as img: | ||||
|         img.load() | ||||
|         img.seek(1) | ||||
|  | @ -626,7 +627,7 @@ def test_previous_frame_loaded(): | |||
|             assert_image_equal(img_skipped, img) | ||||
| 
 | ||||
| 
 | ||||
| def test_save_dispose(tmp_path): | ||||
| def test_save_dispose(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.gif") | ||||
|     im_list = [ | ||||
|         Image.new("L", (100, 100), "#000"), | ||||
|  | @ -654,7 +655,7 @@ def test_save_dispose(tmp_path): | |||
|             assert img.disposal_method == i + 1 | ||||
| 
 | ||||
| 
 | ||||
| def test_dispose2_palette(tmp_path): | ||||
| def test_dispose2_palette(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.gif") | ||||
| 
 | ||||
|     # Four colors: white, gray, black, red | ||||
|  | @ -685,7 +686,7 @@ def test_dispose2_palette(tmp_path): | |||
|             assert rgb_img.getpixel((50, 50)) == circle | ||||
| 
 | ||||
| 
 | ||||
| def test_dispose2_diff(tmp_path): | ||||
| def test_dispose2_diff(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.gif") | ||||
| 
 | ||||
|     # 4 frames: red/blue, red/red, blue/blue, red/blue | ||||
|  | @ -727,7 +728,7 @@ def test_dispose2_diff(tmp_path): | |||
|             assert rgb_img.getpixel((1, 1)) == (255, 255, 255, 0) | ||||
| 
 | ||||
| 
 | ||||
| def test_dispose2_background(tmp_path): | ||||
| def test_dispose2_background(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.gif") | ||||
| 
 | ||||
|     im_list = [] | ||||
|  | @ -753,7 +754,7 @@ def test_dispose2_background(tmp_path): | |||
|         assert im.getpixel((0, 0)) == (255, 0, 0) | ||||
| 
 | ||||
| 
 | ||||
| def test_dispose2_background_frame(tmp_path): | ||||
| def test_dispose2_background_frame(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.gif") | ||||
| 
 | ||||
|     im_list = [Image.new("RGBA", (1, 20))] | ||||
|  | @ -771,7 +772,7 @@ def test_dispose2_background_frame(tmp_path): | |||
|         assert im.n_frames == 3 | ||||
| 
 | ||||
| 
 | ||||
| def test_transparency_in_second_frame(tmp_path): | ||||
| def test_transparency_in_second_frame(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.gif") | ||||
|     with Image.open("Tests/images/different_transparency.gif") as im: | ||||
|         assert im.info["transparency"] == 0 | ||||
|  | @ -791,7 +792,7 @@ def test_transparency_in_second_frame(tmp_path): | |||
|         ) | ||||
| 
 | ||||
| 
 | ||||
| def test_no_transparency_in_second_frame(): | ||||
| def test_no_transparency_in_second_frame() -> None: | ||||
|     with Image.open("Tests/images/iss634.gif") as img: | ||||
|         # Seek to the second frame | ||||
|         img.seek(img.tell() + 1) | ||||
|  | @ -801,7 +802,7 @@ def test_no_transparency_in_second_frame(): | |||
|         assert img.histogram()[255] == 0 | ||||
| 
 | ||||
| 
 | ||||
| def test_remapped_transparency(tmp_path): | ||||
| def test_remapped_transparency(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.gif") | ||||
| 
 | ||||
|     im = Image.new("P", (1, 2)) | ||||
|  | @ -817,7 +818,7 @@ def test_remapped_transparency(tmp_path): | |||
|         assert reloaded.info["transparency"] == reloaded.getpixel((0, 1)) | ||||
| 
 | ||||
| 
 | ||||
| def test_duration(tmp_path): | ||||
| def test_duration(tmp_path: Path) -> None: | ||||
|     duration = 1000 | ||||
| 
 | ||||
|     out = str(tmp_path / "temp.gif") | ||||
|  | @ -831,7 +832,7 @@ def test_duration(tmp_path): | |||
|         assert reread.info["duration"] == duration | ||||
| 
 | ||||
| 
 | ||||
| def test_multiple_duration(tmp_path): | ||||
| def test_multiple_duration(tmp_path: Path) -> None: | ||||
|     duration_list = [1000, 2000, 3000] | ||||
| 
 | ||||
|     out = str(tmp_path / "temp.gif") | ||||
|  | @ -866,7 +867,7 @@ def test_multiple_duration(tmp_path): | |||
|                 pass | ||||
| 
 | ||||
| 
 | ||||
| def test_roundtrip_info_duration(tmp_path): | ||||
| def test_roundtrip_info_duration(tmp_path: Path) -> None: | ||||
|     duration_list = [100, 500, 500] | ||||
| 
 | ||||
|     out = str(tmp_path / "temp.gif") | ||||
|  | @ -883,7 +884,7 @@ def test_roundtrip_info_duration(tmp_path): | |||
|         ] == duration_list | ||||
| 
 | ||||
| 
 | ||||
| def test_roundtrip_info_duration_combined(tmp_path): | ||||
| def test_roundtrip_info_duration_combined(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.gif") | ||||
|     with Image.open("Tests/images/duplicate_frame.gif") as im: | ||||
|         assert [frame.info["duration"] for frame in ImageSequence.Iterator(im)] == [ | ||||
|  | @ -899,7 +900,7 @@ def test_roundtrip_info_duration_combined(tmp_path): | |||
|         ] == [1000, 2000] | ||||
| 
 | ||||
| 
 | ||||
| def test_identical_frames(tmp_path): | ||||
| def test_identical_frames(tmp_path: Path) -> None: | ||||
|     duration_list = [1000, 1500, 2000, 4000] | ||||
| 
 | ||||
|     out = str(tmp_path / "temp.gif") | ||||
|  | @ -932,7 +933,7 @@ def test_identical_frames(tmp_path): | |||
|         1500, | ||||
|     ), | ||||
| ) | ||||
| def test_identical_frames_to_single_frame(duration, tmp_path): | ||||
| def test_identical_frames_to_single_frame(duration, tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.gif") | ||||
|     im_list = [ | ||||
|         Image.new("L", (100, 100), "#000"), | ||||
|  | @ -949,7 +950,7 @@ def test_identical_frames_to_single_frame(duration, tmp_path): | |||
|         assert reread.info["duration"] == 4500 | ||||
| 
 | ||||
| 
 | ||||
| def test_loop_none(tmp_path): | ||||
| def test_loop_none(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.gif") | ||||
|     im = Image.new("L", (100, 100), "#000") | ||||
|     im.save(out, loop=None) | ||||
|  | @ -957,7 +958,7 @@ def test_loop_none(tmp_path): | |||
|         assert "loop" not in reread.info | ||||
| 
 | ||||
| 
 | ||||
| def test_number_of_loops(tmp_path): | ||||
| def test_number_of_loops(tmp_path: Path) -> None: | ||||
|     number_of_loops = 2 | ||||
| 
 | ||||
|     out = str(tmp_path / "temp.gif") | ||||
|  | @ -975,7 +976,7 @@ def test_number_of_loops(tmp_path): | |||
|         assert im.info["loop"] == 2 | ||||
| 
 | ||||
| 
 | ||||
| def test_background(tmp_path): | ||||
| def test_background(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.gif") | ||||
|     im = Image.new("L", (100, 100), "#000") | ||||
|     im.info["background"] = 1 | ||||
|  | @ -984,7 +985,7 @@ def test_background(tmp_path): | |||
|         assert reread.info["background"] == im.info["background"] | ||||
| 
 | ||||
| 
 | ||||
| def test_webp_background(tmp_path): | ||||
| def test_webp_background(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.gif") | ||||
| 
 | ||||
|     # Test opaque WebP background | ||||
|  | @ -999,7 +1000,7 @@ def test_webp_background(tmp_path): | |||
|     im.save(out) | ||||
| 
 | ||||
| 
 | ||||
| def test_comment(tmp_path): | ||||
| def test_comment(tmp_path: Path) -> None: | ||||
|     with Image.open(TEST_GIF) as im: | ||||
|         assert im.info["comment"] == b"File written by Adobe Photoshop\xa8 4.0" | ||||
| 
 | ||||
|  | @ -1019,7 +1020,7 @@ def test_comment(tmp_path): | |||
|         assert reread.info["version"] == b"GIF89a" | ||||
| 
 | ||||
| 
 | ||||
| def test_comment_over_255(tmp_path): | ||||
| def test_comment_over_255(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.gif") | ||||
|     im = Image.new("L", (100, 100), "#000") | ||||
|     comment = b"Test comment text" | ||||
|  | @ -1034,18 +1035,18 @@ def test_comment_over_255(tmp_path): | |||
|         assert reread.info["version"] == b"GIF89a" | ||||
| 
 | ||||
| 
 | ||||
| def test_zero_comment_subblocks(): | ||||
| def test_zero_comment_subblocks() -> None: | ||||
|     with Image.open("Tests/images/hopper_zero_comment_subblocks.gif") as im: | ||||
|         assert_image_equal_tofile(im, TEST_GIF) | ||||
| 
 | ||||
| 
 | ||||
| def test_read_multiple_comment_blocks(): | ||||
| def test_read_multiple_comment_blocks() -> None: | ||||
|     with Image.open("Tests/images/multiple_comments.gif") as im: | ||||
|         # Multiple comment blocks in a frame are separated not concatenated | ||||
|         assert im.info["comment"] == b"Test comment 1\nTest comment 2" | ||||
| 
 | ||||
| 
 | ||||
| def test_empty_string_comment(tmp_path): | ||||
| def test_empty_string_comment(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.gif") | ||||
|     with Image.open("Tests/images/chi.gif") as im: | ||||
|         assert "comment" in im.info | ||||
|  | @ -1058,7 +1059,7 @@ def test_empty_string_comment(tmp_path): | |||
|             assert "comment" not in frame.info | ||||
| 
 | ||||
| 
 | ||||
| def test_retain_comment_in_subsequent_frames(tmp_path): | ||||
| def test_retain_comment_in_subsequent_frames(tmp_path: Path) -> None: | ||||
|     # Test that a comment block at the beginning is kept | ||||
|     with Image.open("Tests/images/chi.gif") as im: | ||||
|         for frame in ImageSequence.Iterator(im): | ||||
|  | @ -1089,10 +1090,10 @@ def test_retain_comment_in_subsequent_frames(tmp_path): | |||
|             assert frame.info["comment"] == b"Test" | ||||
| 
 | ||||
| 
 | ||||
| def test_version(tmp_path): | ||||
| def test_version(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.gif") | ||||
| 
 | ||||
|     def assert_version_after_save(im, version): | ||||
|     def assert_version_after_save(im, version) -> None: | ||||
|         im.save(out) | ||||
|         with Image.open(out) as reread: | ||||
|             assert reread.info["version"] == version | ||||
|  | @ -1119,7 +1120,7 @@ def test_version(tmp_path): | |||
|         assert_version_after_save(im, b"GIF87a") | ||||
| 
 | ||||
| 
 | ||||
| def test_append_images(tmp_path): | ||||
| def test_append_images(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.gif") | ||||
| 
 | ||||
|     # Test appending single frame images | ||||
|  | @ -1148,7 +1149,7 @@ def test_append_images(tmp_path): | |||
|         assert reread.n_frames == 10 | ||||
| 
 | ||||
| 
 | ||||
| def test_transparent_optimize(tmp_path): | ||||
| def test_transparent_optimize(tmp_path: Path) -> None: | ||||
|     # From issue #2195, if the transparent color is incorrectly optimized out, GIF loses | ||||
|     # transparency. | ||||
|     # Need a palette that isn't using the 0 color, | ||||
|  | @ -1168,7 +1169,7 @@ def test_transparent_optimize(tmp_path): | |||
|         assert reloaded.info["transparency"] == reloaded.getpixel((252, 0)) | ||||
| 
 | ||||
| 
 | ||||
| def test_removed_transparency(tmp_path): | ||||
| def test_removed_transparency(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.gif") | ||||
|     im = Image.new("RGB", (256, 1)) | ||||
| 
 | ||||
|  | @ -1183,7 +1184,7 @@ def test_removed_transparency(tmp_path): | |||
|         assert "transparency" not in reloaded.info | ||||
| 
 | ||||
| 
 | ||||
| def test_rgb_transparency(tmp_path): | ||||
| def test_rgb_transparency(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.gif") | ||||
| 
 | ||||
|     # Single frame | ||||
|  | @ -1205,7 +1206,7 @@ def test_rgb_transparency(tmp_path): | |||
|         assert "transparency" not in reloaded.info | ||||
| 
 | ||||
| 
 | ||||
| def test_rgba_transparency(tmp_path): | ||||
| def test_rgba_transparency(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.gif") | ||||
| 
 | ||||
|     im = hopper("P") | ||||
|  | @ -1216,13 +1217,13 @@ def test_rgba_transparency(tmp_path): | |||
|         assert_image_equal(hopper("P").convert("RGB"), reloaded) | ||||
| 
 | ||||
| 
 | ||||
| def test_background_outside_palettte(tmp_path): | ||||
| def test_background_outside_palettte(tmp_path: Path) -> None: | ||||
|     with Image.open("Tests/images/background_outside_palette.gif") as im: | ||||
|         im.seek(1) | ||||
|         assert im.info["background"] == 255 | ||||
| 
 | ||||
| 
 | ||||
| def test_bbox(tmp_path): | ||||
| def test_bbox(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.gif") | ||||
| 
 | ||||
|     im = Image.new("RGB", (100, 100), "#fff") | ||||
|  | @ -1233,7 +1234,7 @@ def test_bbox(tmp_path): | |||
|         assert reread.n_frames == 2 | ||||
| 
 | ||||
| 
 | ||||
| def test_bbox_alpha(tmp_path): | ||||
| def test_bbox_alpha(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.gif") | ||||
| 
 | ||||
|     im = Image.new("RGBA", (1, 2), (255, 0, 0, 255)) | ||||
|  | @ -1245,7 +1246,7 @@ def test_bbox_alpha(tmp_path): | |||
|         assert reread.n_frames == 2 | ||||
| 
 | ||||
| 
 | ||||
| def test_palette_save_L(tmp_path): | ||||
| def test_palette_save_L(tmp_path: Path) -> None: | ||||
|     # Generate an L mode image with a separate palette | ||||
| 
 | ||||
|     im = hopper("P") | ||||
|  | @ -1259,7 +1260,7 @@ def test_palette_save_L(tmp_path): | |||
|         assert_image_equal(reloaded.convert("RGB"), im.convert("RGB")) | ||||
| 
 | ||||
| 
 | ||||
| def test_palette_save_P(tmp_path): | ||||
| def test_palette_save_P(tmp_path: Path) -> None: | ||||
|     im = Image.new("P", (1, 2)) | ||||
|     im.putpixel((0, 1), 1) | ||||
| 
 | ||||
|  | @ -1273,7 +1274,7 @@ def test_palette_save_P(tmp_path): | |||
|         assert reloaded_rgb.getpixel((0, 1)) == (4, 5, 6) | ||||
| 
 | ||||
| 
 | ||||
| def test_palette_save_duplicate_entries(tmp_path): | ||||
| def test_palette_save_duplicate_entries(tmp_path: Path) -> None: | ||||
|     im = Image.new("P", (1, 2)) | ||||
|     im.putpixel((0, 1), 1) | ||||
| 
 | ||||
|  | @ -1286,7 +1287,7 @@ def test_palette_save_duplicate_entries(tmp_path): | |||
|         assert reloaded.convert("RGB").getpixel((0, 1)) == (0, 0, 0) | ||||
| 
 | ||||
| 
 | ||||
| def test_palette_save_all_P(tmp_path): | ||||
| def test_palette_save_all_P(tmp_path: Path) -> None: | ||||
|     frames = [] | ||||
|     colors = ((255, 0, 0), (0, 255, 0)) | ||||
|     for color in colors: | ||||
|  | @ -1309,7 +1310,7 @@ def test_palette_save_all_P(tmp_path): | |||
|         assert im.palette.palette == im.global_palette.palette | ||||
| 
 | ||||
| 
 | ||||
| def test_palette_save_ImagePalette(tmp_path): | ||||
| def test_palette_save_ImagePalette(tmp_path: Path) -> None: | ||||
|     # Pass in a different palette, as an ImagePalette.ImagePalette | ||||
|     # effectively the same as test_palette_save_P | ||||
| 
 | ||||
|  | @ -1324,7 +1325,7 @@ def test_palette_save_ImagePalette(tmp_path): | |||
|         assert_image_equal(reloaded.convert("RGB"), im.convert("RGB")) | ||||
| 
 | ||||
| 
 | ||||
| def test_save_I(tmp_path): | ||||
| def test_save_I(tmp_path: Path) -> None: | ||||
|     # Test saving something that would trigger the auto-convert to 'L' | ||||
| 
 | ||||
|     im = hopper("I") | ||||
|  | @ -1336,7 +1337,7 @@ def test_save_I(tmp_path): | |||
|         assert_image_equal(reloaded.convert("L"), im.convert("L")) | ||||
| 
 | ||||
| 
 | ||||
| def test_getdata(): | ||||
| def test_getdata() -> None: | ||||
|     # Test getheader/getdata against legacy values. | ||||
|     # Create a 'P' image with holes in the palette. | ||||
|     im = Image._wedge().resize((16, 16), Image.Resampling.NEAREST) | ||||
|  | @ -1364,7 +1365,7 @@ def test_getdata(): | |||
|         GifImagePlugin._FORCE_OPTIMIZE = False | ||||
| 
 | ||||
| 
 | ||||
| def test_lzw_bits(): | ||||
| def test_lzw_bits() -> None: | ||||
|     # see https://github.com/python-pillow/Pillow/issues/2811 | ||||
|     with Image.open("Tests/images/issue_2811.gif") as im: | ||||
|         assert im.tile[0][3][0] == 11  # LZW bits | ||||
|  | @ -1372,7 +1373,7 @@ def test_lzw_bits(): | |||
|         im.load() | ||||
| 
 | ||||
| 
 | ||||
| def test_extents(): | ||||
| def test_extents() -> None: | ||||
|     with Image.open("Tests/images/test_extents.gif") as im: | ||||
|         assert im.size == (100, 100) | ||||
| 
 | ||||
|  | @ -1384,7 +1385,7 @@ def test_extents(): | |||
|         assert im.size == (150, 150) | ||||
| 
 | ||||
| 
 | ||||
| def test_missing_background(): | ||||
| def test_missing_background() -> None: | ||||
|     # The Global Color Table Flag isn't set, so there is no background color index, | ||||
|     # but the disposal method is "Restore to background color" | ||||
|     with Image.open("Tests/images/missing_background.gif") as im: | ||||
|  | @ -1392,7 +1393,7 @@ def test_missing_background(): | |||
|         assert_image_equal_tofile(im, "Tests/images/missing_background_first_frame.png") | ||||
| 
 | ||||
| 
 | ||||
| def test_saving_rgba(tmp_path): | ||||
| def test_saving_rgba(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.gif") | ||||
|     with Image.open("Tests/images/transparent.png") as im: | ||||
|         im.save(out) | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ from __future__ import annotations | |||
| from PIL import GimpGradientFile, ImagePalette | ||||
| 
 | ||||
| 
 | ||||
| def test_linear_pos_le_middle(): | ||||
| def test_linear_pos_le_middle() -> None: | ||||
|     # Arrange | ||||
|     middle = 0.5 | ||||
|     pos = 0.25 | ||||
|  | @ -15,7 +15,7 @@ def test_linear_pos_le_middle(): | |||
|     assert ret == 0.25 | ||||
| 
 | ||||
| 
 | ||||
| def test_linear_pos_le_small_middle(): | ||||
| def test_linear_pos_le_small_middle() -> None: | ||||
|     # Arrange | ||||
|     middle = 1e-11 | ||||
|     pos = 1e-12 | ||||
|  | @ -27,7 +27,7 @@ def test_linear_pos_le_small_middle(): | |||
|     assert ret == 0.0 | ||||
| 
 | ||||
| 
 | ||||
| def test_linear_pos_gt_middle(): | ||||
| def test_linear_pos_gt_middle() -> None: | ||||
|     # Arrange | ||||
|     middle = 0.5 | ||||
|     pos = 0.75 | ||||
|  | @ -39,7 +39,7 @@ def test_linear_pos_gt_middle(): | |||
|     assert ret == 0.75 | ||||
| 
 | ||||
| 
 | ||||
| def test_linear_pos_gt_small_middle(): | ||||
| def test_linear_pos_gt_small_middle() -> None: | ||||
|     # Arrange | ||||
|     middle = 1 - 1e-11 | ||||
|     pos = 1 - 1e-12 | ||||
|  | @ -51,7 +51,7 @@ def test_linear_pos_gt_small_middle(): | |||
|     assert ret == 1.0 | ||||
| 
 | ||||
| 
 | ||||
| def test_curved(): | ||||
| def test_curved() -> None: | ||||
|     # Arrange | ||||
|     middle = 0.5 | ||||
|     pos = 0.75 | ||||
|  | @ -63,7 +63,7 @@ def test_curved(): | |||
|     assert ret == 0.75 | ||||
| 
 | ||||
| 
 | ||||
| def test_sine(): | ||||
| def test_sine() -> None: | ||||
|     # Arrange | ||||
|     middle = 0.5 | ||||
|     pos = 0.75 | ||||
|  | @ -75,7 +75,7 @@ def test_sine(): | |||
|     assert ret == 0.8535533905932737 | ||||
| 
 | ||||
| 
 | ||||
| def test_sphere_increasing(): | ||||
| def test_sphere_increasing() -> None: | ||||
|     # Arrange | ||||
|     middle = 0.5 | ||||
|     pos = 0.75 | ||||
|  | @ -87,7 +87,7 @@ def test_sphere_increasing(): | |||
|     assert round(abs(ret - 0.9682458365518543), 7) == 0 | ||||
| 
 | ||||
| 
 | ||||
| def test_sphere_decreasing(): | ||||
| def test_sphere_decreasing() -> None: | ||||
|     # Arrange | ||||
|     middle = 0.5 | ||||
|     pos = 0.75 | ||||
|  | @ -99,7 +99,7 @@ def test_sphere_decreasing(): | |||
|     assert ret == 0.3385621722338523 | ||||
| 
 | ||||
| 
 | ||||
| def test_load_via_imagepalette(): | ||||
| def test_load_via_imagepalette() -> None: | ||||
|     # Arrange | ||||
|     test_file = "Tests/images/gimp_gradient.ggr" | ||||
| 
 | ||||
|  | @ -112,7 +112,7 @@ def test_load_via_imagepalette(): | |||
|     assert palette[1] == "RGBA" | ||||
| 
 | ||||
| 
 | ||||
| def test_load_1_3_via_imagepalette(): | ||||
| def test_load_1_3_via_imagepalette() -> None: | ||||
|     # Arrange | ||||
|     # GIMP 1.3 gradient files contain a name field | ||||
|     test_file = "Tests/images/gimp_gradient_with_name.ggr" | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ import pytest | |||
| from PIL.GimpPaletteFile import GimpPaletteFile | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(): | ||||
| def test_sanity() -> None: | ||||
|     with open("Tests/images/test.gpl", "rb") as fp: | ||||
|         GimpPaletteFile(fp) | ||||
| 
 | ||||
|  | @ -22,7 +22,7 @@ def test_sanity(): | |||
|             GimpPaletteFile(fp) | ||||
| 
 | ||||
| 
 | ||||
| def test_get_palette(): | ||||
| def test_get_palette() -> None: | ||||
|     # Arrange | ||||
|     with open("Tests/images/custom_gimp_palette.gpl", "rb") as fp: | ||||
|         palette_file = GimpPaletteFile(fp) | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
| from PIL import GribStubImagePlugin, Image | ||||
|  | @ -9,7 +11,7 @@ from .helper import hopper | |||
| TEST_FILE = "Tests/images/WAlaska.wind.7days.grb" | ||||
| 
 | ||||
| 
 | ||||
| def test_open(): | ||||
| def test_open() -> None: | ||||
|     # Act | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         # Assert | ||||
|  | @ -20,7 +22,7 @@ def test_open(): | |||
|         assert im.size == (1, 1) | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     # Arrange | ||||
|     invalid_file = "Tests/images/flower.jpg" | ||||
| 
 | ||||
|  | @ -29,7 +31,7 @@ def test_invalid_file(): | |||
|         GribStubImagePlugin.GribStubImageFile(invalid_file) | ||||
| 
 | ||||
| 
 | ||||
| def test_load(): | ||||
| def test_load() -> None: | ||||
|     # Arrange | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         # Act / Assert: stub cannot load without an implemented handler | ||||
|  | @ -37,7 +39,7 @@ def test_load(): | |||
|             im.load() | ||||
| 
 | ||||
| 
 | ||||
| def test_save(tmp_path): | ||||
| def test_save(tmp_path: Path) -> None: | ||||
|     # Arrange | ||||
|     im = hopper() | ||||
|     tmpfile = str(tmp_path / "temp.grib") | ||||
|  | @ -47,13 +49,13 @@ def test_save(tmp_path): | |||
|         im.save(tmpfile) | ||||
| 
 | ||||
| 
 | ||||
| def test_handler(tmp_path): | ||||
| def test_handler(tmp_path: Path) -> None: | ||||
|     class TestHandler: | ||||
|         opened = False | ||||
|         loaded = False | ||||
|         saved = False | ||||
| 
 | ||||
|         def open(self, im): | ||||
|         def open(self, im) -> None: | ||||
|             self.opened = True | ||||
| 
 | ||||
|         def load(self, im): | ||||
|  | @ -61,7 +63,7 @@ def test_handler(tmp_path): | |||
|             im.fp.close() | ||||
|             return Image.new("RGB", (1, 1)) | ||||
| 
 | ||||
|         def save(self, im, fp, filename): | ||||
|         def save(self, im, fp, filename) -> None: | ||||
|             self.saved = True | ||||
| 
 | ||||
|     handler = TestHandler() | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
| from PIL import Hdf5StubImagePlugin, Image | ||||
|  | @ -7,7 +9,7 @@ from PIL import Hdf5StubImagePlugin, Image | |||
| TEST_FILE = "Tests/images/hdf5.h5" | ||||
| 
 | ||||
| 
 | ||||
| def test_open(): | ||||
| def test_open() -> None: | ||||
|     # Act | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         # Assert | ||||
|  | @ -18,7 +20,7 @@ def test_open(): | |||
|         assert im.size == (1, 1) | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     # Arrange | ||||
|     invalid_file = "Tests/images/flower.jpg" | ||||
| 
 | ||||
|  | @ -27,7 +29,7 @@ def test_invalid_file(): | |||
|         Hdf5StubImagePlugin.HDF5StubImageFile(invalid_file) | ||||
| 
 | ||||
| 
 | ||||
| def test_load(): | ||||
| def test_load() -> None: | ||||
|     # Arrange | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         # Act / Assert: stub cannot load without an implemented handler | ||||
|  | @ -35,7 +37,7 @@ def test_load(): | |||
|             im.load() | ||||
| 
 | ||||
| 
 | ||||
| def test_save(): | ||||
| def test_save() -> None: | ||||
|     # Arrange | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         dummy_fp = None | ||||
|  | @ -48,13 +50,13 @@ def test_save(): | |||
|             Hdf5StubImagePlugin._save(im, dummy_fp, dummy_filename) | ||||
| 
 | ||||
| 
 | ||||
| def test_handler(tmp_path): | ||||
| def test_handler(tmp_path: Path) -> None: | ||||
|     class TestHandler: | ||||
|         opened = False | ||||
|         loaded = False | ||||
|         saved = False | ||||
| 
 | ||||
|         def open(self, im): | ||||
|         def open(self, im) -> None: | ||||
|             self.opened = True | ||||
| 
 | ||||
|         def load(self, im): | ||||
|  | @ -62,7 +64,7 @@ def test_handler(tmp_path): | |||
|             im.fp.close() | ||||
|             return Image.new("RGB", (1, 1)) | ||||
| 
 | ||||
|         def save(self, im, fp, filename): | ||||
|         def save(self, im, fp, filename) -> None: | ||||
|             self.saved = True | ||||
| 
 | ||||
|     handler = TestHandler() | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ from __future__ import annotations | |||
| import io | ||||
| import os | ||||
| import warnings | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -14,7 +15,7 @@ from .helper import assert_image_equal, assert_image_similar_tofile, skip_unless | |||
| TEST_FILE = "Tests/images/pillow.icns" | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(): | ||||
| def test_sanity() -> None: | ||||
|     # Loading this icon by default should result in the largest size | ||||
|     # (512x512@2x) being loaded | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|  | @ -27,7 +28,7 @@ def test_sanity(): | |||
|         assert im.format == "ICNS" | ||||
| 
 | ||||
| 
 | ||||
| def test_load(): | ||||
| def test_load() -> None: | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         assert im.load()[0, 0] == (0, 0, 0, 0) | ||||
| 
 | ||||
|  | @ -35,7 +36,7 @@ def test_load(): | |||
|         assert im.load()[0, 0] == (0, 0, 0, 0) | ||||
| 
 | ||||
| 
 | ||||
| def test_save(tmp_path): | ||||
| def test_save(tmp_path: Path) -> None: | ||||
|     temp_file = str(tmp_path / "temp.icns") | ||||
| 
 | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|  | @ -52,7 +53,7 @@ def test_save(tmp_path): | |||
|         assert _binary.i32be(fp.read(4)) == file_length | ||||
| 
 | ||||
| 
 | ||||
| def test_save_append_images(tmp_path): | ||||
| def test_save_append_images(tmp_path: Path) -> None: | ||||
|     temp_file = str(tmp_path / "temp.icns") | ||||
|     provided_im = Image.new("RGBA", (32, 32), (255, 0, 0, 128)) | ||||
| 
 | ||||
|  | @ -67,7 +68,7 @@ def test_save_append_images(tmp_path): | |||
|             assert_image_equal(reread, provided_im) | ||||
| 
 | ||||
| 
 | ||||
| def test_save_fp(): | ||||
| def test_save_fp() -> None: | ||||
|     fp = io.BytesIO() | ||||
| 
 | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|  | @ -79,7 +80,7 @@ def test_save_fp(): | |||
|         assert reread.format == "ICNS" | ||||
| 
 | ||||
| 
 | ||||
| def test_sizes(): | ||||
| def test_sizes() -> None: | ||||
|     # Check that we can load all of the sizes, and that the final pixel | ||||
|     # dimensions are as expected | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|  | @ -96,7 +97,7 @@ def test_sizes(): | |||
|             im.size = (1, 1) | ||||
| 
 | ||||
| 
 | ||||
| def test_older_icon(): | ||||
| def test_older_icon() -> None: | ||||
|     # This icon was made with Icon Composer rather than iconutil; it still | ||||
|     # uses PNG rather than JP2, however (since it was made on 10.9). | ||||
|     with Image.open("Tests/images/pillow2.icns") as im: | ||||
|  | @ -111,7 +112,7 @@ def test_older_icon(): | |||
| 
 | ||||
| 
 | ||||
| @skip_unless_feature("jpg_2000") | ||||
| def test_jp2_icon(): | ||||
| def test_jp2_icon() -> None: | ||||
|     # This icon uses JPEG 2000 images instead of the PNG images. | ||||
|     # The advantage of doing this is that OS X 10.5 supports JPEG 2000 | ||||
|     # but not PNG; some commercial software therefore does just this. | ||||
|  | @ -127,7 +128,7 @@ def test_jp2_icon(): | |||
|                 assert im2.size == (wr, hr) | ||||
| 
 | ||||
| 
 | ||||
| def test_getimage(): | ||||
| def test_getimage() -> None: | ||||
|     with open(TEST_FILE, "rb") as fp: | ||||
|         icns_file = IcnsImagePlugin.IcnsFile(fp) | ||||
| 
 | ||||
|  | @ -140,14 +141,14 @@ def test_getimage(): | |||
|         assert im.size == (512, 512) | ||||
| 
 | ||||
| 
 | ||||
| def test_not_an_icns_file(): | ||||
| def test_not_an_icns_file() -> None: | ||||
|     with io.BytesIO(b"invalid\n") as fp: | ||||
|         with pytest.raises(SyntaxError): | ||||
|             IcnsImagePlugin.IcnsFile(fp) | ||||
| 
 | ||||
| 
 | ||||
| @skip_unless_feature("jpg_2000") | ||||
| def test_icns_decompression_bomb(): | ||||
| def test_icns_decompression_bomb() -> None: | ||||
|     with Image.open( | ||||
|         "Tests/images/oom-8ed3316a4109213ca96fb8a256a0bfefdece1461.icns" | ||||
|     ) as im: | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ from __future__ import annotations | |||
| 
 | ||||
| import io | ||||
| import os | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -12,7 +13,7 @@ from .helper import assert_image_equal, assert_image_equal_tofile, hopper | |||
| TEST_ICO_FILE = "Tests/images/hopper.ico" | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(): | ||||
| def test_sanity() -> None: | ||||
|     with Image.open(TEST_ICO_FILE) as im: | ||||
|         im.load() | ||||
|     assert im.mode == "RGBA" | ||||
|  | @ -21,29 +22,29 @@ def test_sanity(): | |||
|     assert im.get_format_mimetype() == "image/x-icon" | ||||
| 
 | ||||
| 
 | ||||
| def test_load(): | ||||
| def test_load() -> None: | ||||
|     with Image.open(TEST_ICO_FILE) as im: | ||||
|         assert im.load()[0, 0] == (1, 1, 9, 255) | ||||
| 
 | ||||
| 
 | ||||
| def test_mask(): | ||||
| def test_mask() -> None: | ||||
|     with Image.open("Tests/images/hopper_mask.ico") as im: | ||||
|         assert_image_equal_tofile(im, "Tests/images/hopper_mask.png") | ||||
| 
 | ||||
| 
 | ||||
| def test_black_and_white(): | ||||
| def test_black_and_white() -> None: | ||||
|     with Image.open("Tests/images/black_and_white.ico") as im: | ||||
|         assert im.mode == "RGBA" | ||||
|         assert im.size == (16, 16) | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     with open("Tests/images/flower.jpg", "rb") as fp: | ||||
|         with pytest.raises(SyntaxError): | ||||
|             IcoImagePlugin.IcoImageFile(fp) | ||||
| 
 | ||||
| 
 | ||||
| def test_save_to_bytes(): | ||||
| def test_save_to_bytes() -> None: | ||||
|     output = io.BytesIO() | ||||
|     im = hopper() | ||||
|     im.save(output, "ico", sizes=[(32, 32), (64, 64)]) | ||||
|  | @ -73,7 +74,7 @@ def test_save_to_bytes(): | |||
|         ) | ||||
| 
 | ||||
| 
 | ||||
| def test_getpixel(tmp_path): | ||||
| def test_getpixel(tmp_path: Path) -> None: | ||||
|     temp_file = str(tmp_path / "temp.ico") | ||||
| 
 | ||||
|     im = hopper() | ||||
|  | @ -86,7 +87,7 @@ def test_getpixel(tmp_path): | |||
|         assert reloaded.getpixel((0, 0)) == (18, 20, 62) | ||||
| 
 | ||||
| 
 | ||||
| def test_no_duplicates(tmp_path): | ||||
| def test_no_duplicates(tmp_path: Path) -> None: | ||||
|     temp_file = str(tmp_path / "temp.ico") | ||||
|     temp_file2 = str(tmp_path / "temp2.ico") | ||||
| 
 | ||||
|  | @ -100,7 +101,7 @@ def test_no_duplicates(tmp_path): | |||
|     assert os.path.getsize(temp_file) == os.path.getsize(temp_file2) | ||||
| 
 | ||||
| 
 | ||||
| def test_different_bit_depths(tmp_path): | ||||
| def test_different_bit_depths(tmp_path: Path) -> None: | ||||
|     temp_file = str(tmp_path / "temp.ico") | ||||
|     temp_file2 = str(tmp_path / "temp2.ico") | ||||
| 
 | ||||
|  | @ -134,7 +135,7 @@ def test_different_bit_depths(tmp_path): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("mode", ("1", "L", "P", "RGB", "RGBA")) | ||||
| def test_save_to_bytes_bmp(mode): | ||||
| def test_save_to_bytes_bmp(mode) -> None: | ||||
|     output = io.BytesIO() | ||||
|     im = hopper(mode) | ||||
|     im.save(output, "ico", bitmap_format="bmp", sizes=[(32, 32), (64, 64)]) | ||||
|  | @ -162,13 +163,13 @@ def test_save_to_bytes_bmp(mode): | |||
|         assert_image_equal(reloaded, im) | ||||
| 
 | ||||
| 
 | ||||
| def test_incorrect_size(): | ||||
| def test_incorrect_size() -> None: | ||||
|     with Image.open(TEST_ICO_FILE) as im: | ||||
|         with pytest.raises(ValueError): | ||||
|             im.size = (1, 1) | ||||
| 
 | ||||
| 
 | ||||
| def test_save_256x256(tmp_path): | ||||
| def test_save_256x256(tmp_path: Path) -> None: | ||||
|     """Issue #2264 https://github.com/python-pillow/Pillow/issues/2264""" | ||||
|     # Arrange | ||||
|     with Image.open("Tests/images/hopper_256x256.ico") as im: | ||||
|  | @ -181,7 +182,7 @@ def test_save_256x256(tmp_path): | |||
|         assert im_saved.size == (256, 256) | ||||
| 
 | ||||
| 
 | ||||
| def test_only_save_relevant_sizes(tmp_path): | ||||
| def test_only_save_relevant_sizes(tmp_path: Path) -> None: | ||||
|     """Issue #2266 https://github.com/python-pillow/Pillow/issues/2266 | ||||
|     Should save in 16x16, 24x24, 32x32, 48x48 sizes | ||||
|     and not in 16x16, 24x24, 32x32, 48x48, 48x48, 48x48, 48x48 sizes | ||||
|  | @ -197,7 +198,7 @@ def test_only_save_relevant_sizes(tmp_path): | |||
|         assert im_saved.info["sizes"] == {(16, 16), (24, 24), (32, 32), (48, 48)} | ||||
| 
 | ||||
| 
 | ||||
| def test_save_append_images(tmp_path): | ||||
| def test_save_append_images(tmp_path: Path) -> None: | ||||
|     # append_images should be used for scaled down versions of the image | ||||
|     im = hopper("RGBA") | ||||
|     provided_im = Image.new("RGBA", (32, 32), (255, 0, 0)) | ||||
|  | @ -211,7 +212,7 @@ def test_save_append_images(tmp_path): | |||
|         assert_image_equal(reread, provided_im) | ||||
| 
 | ||||
| 
 | ||||
| def test_unexpected_size(): | ||||
| def test_unexpected_size() -> None: | ||||
|     # This image has been manually hexedited to state that it is 16x32 | ||||
|     # while the image within is still 16x16 | ||||
|     with pytest.warns(UserWarning): | ||||
|  | @ -219,7 +220,7 @@ def test_unexpected_size(): | |||
|             assert im.size == (16, 16) | ||||
| 
 | ||||
| 
 | ||||
| def test_draw_reloaded(tmp_path): | ||||
| def test_draw_reloaded(tmp_path: Path) -> None: | ||||
|     with Image.open(TEST_ICO_FILE) as im: | ||||
|         outfile = str(tmp_path / "temp_saved_hopper_draw.ico") | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ from __future__ import annotations | |||
| 
 | ||||
| import filecmp | ||||
| import warnings | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -13,7 +14,7 @@ from .helper import assert_image_equal_tofile, hopper, is_pypy | |||
| TEST_IM = "Tests/images/hopper.im" | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(): | ||||
| def test_sanity() -> None: | ||||
|     with Image.open(TEST_IM) as im: | ||||
|         im.load() | ||||
|         assert im.mode == "RGB" | ||||
|  | @ -21,7 +22,7 @@ def test_sanity(): | |||
|         assert im.format == "IM" | ||||
| 
 | ||||
| 
 | ||||
| def test_name_limit(tmp_path): | ||||
| def test_name_limit(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / ("name_limit_test" * 7 + ".im")) | ||||
|     with Image.open(TEST_IM) as im: | ||||
|         im.save(out) | ||||
|  | @ -29,8 +30,8 @@ def test_name_limit(tmp_path): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.skipif(is_pypy(), reason="Requires CPython") | ||||
| def test_unclosed_file(): | ||||
|     def open(): | ||||
| def test_unclosed_file() -> None: | ||||
|     def open() -> None: | ||||
|         im = Image.open(TEST_IM) | ||||
|         im.load() | ||||
| 
 | ||||
|  | @ -38,20 +39,20 @@ def test_unclosed_file(): | |||
|         open() | ||||
| 
 | ||||
| 
 | ||||
| def test_closed_file(): | ||||
| def test_closed_file() -> None: | ||||
|     with warnings.catch_warnings(): | ||||
|         im = Image.open(TEST_IM) | ||||
|         im.load() | ||||
|         im.close() | ||||
| 
 | ||||
| 
 | ||||
| def test_context_manager(): | ||||
| def test_context_manager() -> None: | ||||
|     with warnings.catch_warnings(): | ||||
|         with Image.open(TEST_IM) as im: | ||||
|             im.load() | ||||
| 
 | ||||
| 
 | ||||
| def test_tell(): | ||||
| def test_tell() -> None: | ||||
|     # Arrange | ||||
|     with Image.open(TEST_IM) as im: | ||||
|         # Act | ||||
|  | @ -61,13 +62,13 @@ def test_tell(): | |||
|     assert frame == 0 | ||||
| 
 | ||||
| 
 | ||||
| def test_n_frames(): | ||||
| def test_n_frames() -> None: | ||||
|     with Image.open(TEST_IM) as im: | ||||
|         assert im.n_frames == 1 | ||||
|         assert not im.is_animated | ||||
| 
 | ||||
| 
 | ||||
| def test_eoferror(): | ||||
| def test_eoferror() -> None: | ||||
|     with Image.open(TEST_IM) as im: | ||||
|         n_frames = im.n_frames | ||||
| 
 | ||||
|  | @ -81,14 +82,14 @@ def test_eoferror(): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("mode", ("RGB", "P", "PA")) | ||||
| def test_roundtrip(mode, tmp_path): | ||||
| def test_roundtrip(mode, tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.im") | ||||
|     im = hopper(mode) | ||||
|     im.save(out) | ||||
|     assert_image_equal_tofile(im, out) | ||||
| 
 | ||||
| 
 | ||||
| def test_small_palette(tmp_path): | ||||
| def test_small_palette(tmp_path: Path) -> None: | ||||
|     im = Image.new("P", (1, 1)) | ||||
|     colors = [0, 1, 2] | ||||
|     im.putpalette(colors) | ||||
|  | @ -100,19 +101,19 @@ def test_small_palette(tmp_path): | |||
|         assert reloaded.getpalette() == colors + [0] * 765 | ||||
| 
 | ||||
| 
 | ||||
| def test_save_unsupported_mode(tmp_path): | ||||
| def test_save_unsupported_mode(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.im") | ||||
|     im = hopper("HSV") | ||||
|     with pytest.raises(ValueError): | ||||
|         im.save(out) | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     invalid_file = "Tests/images/flower.jpg" | ||||
| 
 | ||||
|     with pytest.raises(SyntaxError): | ||||
|         ImImagePlugin.ImImageFile(invalid_file) | ||||
| 
 | ||||
| 
 | ||||
| def test_number(): | ||||
| def test_number() -> None: | ||||
|     assert ImImagePlugin.number("1.2") == 1.2 | ||||
|  |  | |||
|  | @ -9,13 +9,13 @@ from PIL import Image, ImtImagePlugin | |||
| from .helper import assert_image_equal_tofile | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(): | ||||
| def test_sanity() -> None: | ||||
|     with Image.open("Tests/images/bw_gradient.imt") as im: | ||||
|         assert_image_equal_tofile(im, "Tests/images/bw_gradient.png") | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("data", (b"\n", b"\n-", b"width 1\n")) | ||||
| def test_invalid_file(data): | ||||
| def test_invalid_file(data: bytes) -> None: | ||||
|     with io.BytesIO(data) as fp: | ||||
|         with pytest.raises(SyntaxError): | ||||
|             ImtImagePlugin.ImtImageFile(fp) | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ from .helper import assert_image_equal, hopper | |||
| TEST_FILE = "Tests/images/iptc.jpg" | ||||
| 
 | ||||
| 
 | ||||
| def test_open(): | ||||
| def test_open() -> None: | ||||
|     expected = Image.new("L", (1, 1)) | ||||
| 
 | ||||
|     f = BytesIO( | ||||
|  | @ -24,7 +24,7 @@ def test_open(): | |||
|         assert_image_equal(im, expected) | ||||
| 
 | ||||
| 
 | ||||
| def test_getiptcinfo_jpg_none(): | ||||
| def test_getiptcinfo_jpg_none() -> None: | ||||
|     # Arrange | ||||
|     with hopper() as im: | ||||
|         # Act | ||||
|  | @ -34,7 +34,7 @@ def test_getiptcinfo_jpg_none(): | |||
|     assert iptc is None | ||||
| 
 | ||||
| 
 | ||||
| def test_getiptcinfo_jpg_found(): | ||||
| def test_getiptcinfo_jpg_found() -> None: | ||||
|     # Arrange | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         # Act | ||||
|  | @ -46,7 +46,7 @@ def test_getiptcinfo_jpg_found(): | |||
|     assert iptc[(2, 101)] == b"Hungary" | ||||
| 
 | ||||
| 
 | ||||
| def test_getiptcinfo_fotostation(): | ||||
| def test_getiptcinfo_fotostation() -> None: | ||||
|     # Arrange | ||||
|     with open(TEST_FILE, "rb") as fp: | ||||
|         data = bytearray(fp.read()) | ||||
|  | @ -63,7 +63,7 @@ def test_getiptcinfo_fotostation(): | |||
|     pytest.fail("FotoStation tag not found") | ||||
| 
 | ||||
| 
 | ||||
| def test_getiptcinfo_zero_padding(): | ||||
| def test_getiptcinfo_zero_padding() -> None: | ||||
|     # Arrange | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         im.info["photoshop"][0x0404] += b"\x00\x00\x00" | ||||
|  | @ -76,7 +76,7 @@ def test_getiptcinfo_zero_padding(): | |||
|     assert len(iptc) == 3 | ||||
| 
 | ||||
| 
 | ||||
| def test_getiptcinfo_tiff_none(): | ||||
| def test_getiptcinfo_tiff_none() -> None: | ||||
|     # Arrange | ||||
|     with Image.open("Tests/images/hopper.tif") as im: | ||||
|         # Act | ||||
|  | @ -86,7 +86,7 @@ def test_getiptcinfo_tiff_none(): | |||
|     assert iptc is None | ||||
| 
 | ||||
| 
 | ||||
| def test_i(): | ||||
| def test_i() -> None: | ||||
|     # Arrange | ||||
|     c = b"a" | ||||
| 
 | ||||
|  | @ -98,7 +98,7 @@ def test_i(): | |||
|     assert ret == 97 | ||||
| 
 | ||||
| 
 | ||||
| def test_dump(monkeypatch): | ||||
| def test_dump(monkeypatch) -> None: | ||||
|     # Arrange | ||||
|     c = b"abc" | ||||
|     # Temporarily redirect stdout | ||||
|  | @ -113,6 +113,6 @@ def test_dump(monkeypatch): | |||
|     assert mystdout.getvalue() == "61 62 63 \n" | ||||
| 
 | ||||
| 
 | ||||
| def test_pad_deprecation(): | ||||
| def test_pad_deprecation() -> None: | ||||
|     with pytest.warns(DeprecationWarning): | ||||
|         assert IptcImagePlugin.PAD == b"\0\0\0\0" | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ import os | |||
| import re | ||||
| import warnings | ||||
| from io import BytesIO | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -50,7 +51,7 @@ class TestFileJpeg: | |||
|         im.bytes = test_bytes  # for testing only | ||||
|         return im | ||||
| 
 | ||||
|     def gen_random_image(self, size, mode="RGB"): | ||||
|     def gen_random_image(self, size, mode: str = "RGB"): | ||||
|         """Generates a very hard to compress file | ||||
|         :param size: tuple | ||||
|         :param mode: optional image mode | ||||
|  | @ -58,7 +59,7 @@ class TestFileJpeg: | |||
|         """ | ||||
|         return Image.frombytes(mode, size, os.urandom(size[0] * size[1] * len(mode))) | ||||
| 
 | ||||
|     def test_sanity(self): | ||||
|     def test_sanity(self) -> None: | ||||
|         # internal version number | ||||
|         assert re.search(r"\d+\.\d+$", features.version_codec("jpg")) | ||||
| 
 | ||||
|  | @ -70,13 +71,13 @@ class TestFileJpeg: | |||
|             assert im.get_format_mimetype() == "image/jpeg" | ||||
| 
 | ||||
|     @pytest.mark.parametrize("size", ((1, 0), (0, 1), (0, 0))) | ||||
|     def test_zero(self, size, tmp_path): | ||||
|     def test_zero(self, size, tmp_path: Path) -> None: | ||||
|         f = str(tmp_path / "temp.jpg") | ||||
|         im = Image.new("RGB", size) | ||||
|         with pytest.raises(ValueError): | ||||
|             im.save(f) | ||||
| 
 | ||||
|     def test_app(self): | ||||
|     def test_app(self) -> None: | ||||
|         # Test APP/COM reader (@PIL135) | ||||
|         with Image.open(TEST_FILE) as im: | ||||
|             assert im.applist[0] == ("APP0", b"JFIF\x00\x01\x01\x01\x00`\x00`\x00\x00") | ||||
|  | @ -89,7 +90,7 @@ class TestFileJpeg: | |||
|             assert im.info["comment"] == b"File written by Adobe Photoshop\xa8 4.0\x00" | ||||
|             assert im.app["COM"] == im.info["comment"] | ||||
| 
 | ||||
|     def test_comment_write(self): | ||||
|     def test_comment_write(self) -> None: | ||||
|         with Image.open(TEST_FILE) as im: | ||||
|             assert im.info["comment"] == b"File written by Adobe Photoshop\xa8 4.0\x00" | ||||
| 
 | ||||
|  | @ -115,7 +116,7 @@ class TestFileJpeg: | |||
|                         comment = comment.encode() | ||||
|                     assert reloaded.info["comment"] == comment | ||||
| 
 | ||||
|     def test_cmyk(self): | ||||
|     def test_cmyk(self) -> None: | ||||
|         # Test CMYK handling.  Thanks to Tim and Charlie for test data, | ||||
|         # Michael for getting me to look one more time. | ||||
|         f = "Tests/images/pil_sample_cmyk.jpg" | ||||
|  | @ -143,7 +144,7 @@ class TestFileJpeg: | |||
|             ) | ||||
|             assert k > 0.9 | ||||
| 
 | ||||
|     def test_rgb(self): | ||||
|     def test_rgb(self) -> None: | ||||
|         def getchannels(im): | ||||
|             return tuple(v[0] for v in im.layer) | ||||
| 
 | ||||
|  | @ -160,7 +161,7 @@ class TestFileJpeg: | |||
|         "test_image_path", | ||||
|         [TEST_FILE, "Tests/images/pil_sample_cmyk.jpg"], | ||||
|     ) | ||||
|     def test_dpi(self, test_image_path): | ||||
|     def test_dpi(self, test_image_path) -> None: | ||||
|         def test(xdpi, ydpi=None): | ||||
|             with Image.open(test_image_path) as im: | ||||
|                 im = self.roundtrip(im, dpi=(xdpi, ydpi or xdpi)) | ||||
|  | @ -174,7 +175,7 @@ class TestFileJpeg: | |||
|     @mark_if_feature_version( | ||||
|         pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" | ||||
|     ) | ||||
|     def test_icc(self, tmp_path): | ||||
|     def test_icc(self, tmp_path: Path) -> None: | ||||
|         # Test ICC support | ||||
|         with Image.open("Tests/images/rgb.jpg") as im1: | ||||
|             icc_profile = im1.info["icc_profile"] | ||||
|  | @ -206,7 +207,7 @@ class TestFileJpeg: | |||
|             ImageFile.MAXBLOCK * 4 + 3,  # large block | ||||
|         ), | ||||
|     ) | ||||
|     def test_icc_big(self, n): | ||||
|     def test_icc_big(self, n) -> None: | ||||
|         # Make sure that the "extra" support handles large blocks | ||||
|         # The ICC APP marker can store 65519 bytes per marker, so | ||||
|         # using a 4-byte test code should allow us to detect out of | ||||
|  | @ -219,7 +220,7 @@ class TestFileJpeg: | |||
|     @mark_if_feature_version( | ||||
|         pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" | ||||
|     ) | ||||
|     def test_large_icc_meta(self, tmp_path): | ||||
|     def test_large_icc_meta(self, tmp_path: Path) -> None: | ||||
|         # https://github.com/python-pillow/Pillow/issues/148 | ||||
|         # Sometimes the meta data on the icc_profile block is bigger than | ||||
|         # Image.MAXBLOCK or the image size. | ||||
|  | @ -243,7 +244,7 @@ class TestFileJpeg: | |||
|             f = str(tmp_path / "temp3.jpg") | ||||
|             im.save(f, progressive=True, quality=94, exif=b" " * 43668) | ||||
| 
 | ||||
|     def test_optimize(self): | ||||
|     def test_optimize(self) -> None: | ||||
|         im1 = self.roundtrip(hopper()) | ||||
|         im2 = self.roundtrip(hopper(), optimize=0) | ||||
|         im3 = self.roundtrip(hopper(), optimize=1) | ||||
|  | @ -252,14 +253,14 @@ class TestFileJpeg: | |||
|         assert im1.bytes >= im2.bytes | ||||
|         assert im1.bytes >= im3.bytes | ||||
| 
 | ||||
|     def test_optimize_large_buffer(self, tmp_path): | ||||
|     def test_optimize_large_buffer(self, tmp_path: Path) -> None: | ||||
|         # https://github.com/python-pillow/Pillow/issues/148 | ||||
|         f = str(tmp_path / "temp.jpg") | ||||
|         # this requires ~ 1.5x Image.MAXBLOCK | ||||
|         im = Image.new("RGB", (4096, 4096), 0xFF3333) | ||||
|         im.save(f, format="JPEG", optimize=True) | ||||
| 
 | ||||
|     def test_progressive(self): | ||||
|     def test_progressive(self) -> None: | ||||
|         im1 = self.roundtrip(hopper()) | ||||
|         im2 = self.roundtrip(hopper(), progressive=False) | ||||
|         im3 = self.roundtrip(hopper(), progressive=True) | ||||
|  | @ -270,25 +271,25 @@ class TestFileJpeg: | |||
|         assert_image_equal(im1, im3) | ||||
|         assert im1.bytes >= im3.bytes | ||||
| 
 | ||||
|     def test_progressive_large_buffer(self, tmp_path): | ||||
|     def test_progressive_large_buffer(self, tmp_path: Path) -> None: | ||||
|         f = str(tmp_path / "temp.jpg") | ||||
|         # this requires ~ 1.5x Image.MAXBLOCK | ||||
|         im = Image.new("RGB", (4096, 4096), 0xFF3333) | ||||
|         im.save(f, format="JPEG", progressive=True) | ||||
| 
 | ||||
|     def test_progressive_large_buffer_highest_quality(self, tmp_path): | ||||
|     def test_progressive_large_buffer_highest_quality(self, tmp_path: Path) -> None: | ||||
|         f = str(tmp_path / "temp.jpg") | ||||
|         im = self.gen_random_image((255, 255)) | ||||
|         # this requires more bytes than pixels in the image | ||||
|         im.save(f, format="JPEG", progressive=True, quality=100) | ||||
| 
 | ||||
|     def test_progressive_cmyk_buffer(self): | ||||
|     def test_progressive_cmyk_buffer(self) -> None: | ||||
|         # Issue 2272, quality 90 cmyk image is tripping the large buffer bug. | ||||
|         f = BytesIO() | ||||
|         im = self.gen_random_image((256, 256), "CMYK") | ||||
|         im.save(f, format="JPEG", progressive=True, quality=94) | ||||
| 
 | ||||
|     def test_large_exif(self, tmp_path): | ||||
|     def test_large_exif(self, tmp_path: Path) -> None: | ||||
|         # https://github.com/python-pillow/Pillow/issues/148 | ||||
|         f = str(tmp_path / "temp.jpg") | ||||
|         im = hopper() | ||||
|  | @ -297,12 +298,12 @@ class TestFileJpeg: | |||
|         with pytest.raises(ValueError): | ||||
|             im.save(f, "JPEG", quality=90, exif=b"1" * 65534) | ||||
| 
 | ||||
|     def test_exif_typeerror(self): | ||||
|     def test_exif_typeerror(self) -> None: | ||||
|         with Image.open("Tests/images/exif_typeerror.jpg") as im: | ||||
|             # Should not raise a TypeError | ||||
|             im._getexif() | ||||
| 
 | ||||
|     def test_exif_gps(self, tmp_path): | ||||
|     def test_exif_gps(self, tmp_path: Path) -> None: | ||||
|         expected_exif_gps = { | ||||
|             0: b"\x00\x00\x00\x01", | ||||
|             2: 4294967295, | ||||
|  | @ -327,7 +328,7 @@ class TestFileJpeg: | |||
|             exif = reloaded._getexif() | ||||
|             assert exif[gps_index] == expected_exif_gps | ||||
| 
 | ||||
|     def test_empty_exif_gps(self): | ||||
|     def test_empty_exif_gps(self) -> None: | ||||
|         with Image.open("Tests/images/empty_gps_ifd.jpg") as im: | ||||
|             exif = im.getexif() | ||||
|             del exif[0x8769] | ||||
|  | @ -345,7 +346,7 @@ class TestFileJpeg: | |||
|         # Assert that it was transposed | ||||
|         assert 0x0112 not in exif | ||||
| 
 | ||||
|     def test_exif_equality(self): | ||||
|     def test_exif_equality(self) -> None: | ||||
|         # In 7.2.0, Exif rationals were changed to be read as | ||||
|         # TiffImagePlugin.IFDRational. This class had a bug in __eq__, | ||||
|         # breaking the self-equality of Exif data | ||||
|  | @ -355,7 +356,7 @@ class TestFileJpeg: | |||
|                 exifs.append(im._getexif()) | ||||
|         assert exifs[0] == exifs[1] | ||||
| 
 | ||||
|     def test_exif_rollback(self): | ||||
|     def test_exif_rollback(self) -> None: | ||||
|         # rolling back exif support in 3.1 to pre-3.0 formatting. | ||||
|         # expected from 2.9, with b/u qualifiers switched for 3.2 compatibility | ||||
|         # this test passes on 2.9 and 3.1, but not 3.0 | ||||
|  | @ -390,12 +391,12 @@ class TestFileJpeg: | |||
|         for tag, value in expected_exif.items(): | ||||
|             assert value == exif[tag] | ||||
| 
 | ||||
|     def test_exif_gps_typeerror(self): | ||||
|     def test_exif_gps_typeerror(self) -> None: | ||||
|         with Image.open("Tests/images/exif_gps_typeerror.jpg") as im: | ||||
|             # Should not raise a TypeError | ||||
|             im._getexif() | ||||
| 
 | ||||
|     def test_progressive_compat(self): | ||||
|     def test_progressive_compat(self) -> None: | ||||
|         im1 = self.roundtrip(hopper()) | ||||
|         assert not im1.info.get("progressive") | ||||
|         assert not im1.info.get("progression") | ||||
|  | @ -416,7 +417,7 @@ class TestFileJpeg: | |||
|         assert im3.info.get("progressive") | ||||
|         assert im3.info.get("progression") | ||||
| 
 | ||||
|     def test_quality(self): | ||||
|     def test_quality(self) -> None: | ||||
|         im1 = self.roundtrip(hopper()) | ||||
|         im2 = self.roundtrip(hopper(), quality=50) | ||||
|         assert_image(im1, im2.mode, im2.size) | ||||
|  | @ -426,12 +427,12 @@ class TestFileJpeg: | |||
|         assert_image(im1, im3.mode, im3.size) | ||||
|         assert im2.bytes > im3.bytes | ||||
| 
 | ||||
|     def test_smooth(self): | ||||
|     def test_smooth(self) -> None: | ||||
|         im1 = self.roundtrip(hopper()) | ||||
|         im2 = self.roundtrip(hopper(), smooth=100) | ||||
|         assert_image(im1, im2.mode, im2.size) | ||||
| 
 | ||||
|     def test_subsampling(self): | ||||
|     def test_subsampling(self) -> None: | ||||
|         def getsampling(im): | ||||
|             layer = im.layer | ||||
|             return layer[0][1:3] + layer[1][1:3] + layer[2][1:3] | ||||
|  | @ -463,23 +464,23 @@ class TestFileJpeg: | |||
|         with pytest.raises(TypeError): | ||||
|             self.roundtrip(hopper(), subsampling="1:1:1") | ||||
| 
 | ||||
|     def test_exif(self): | ||||
|     def test_exif(self) -> None: | ||||
|         with Image.open("Tests/images/pil_sample_rgb.jpg") as im: | ||||
|             info = im._getexif() | ||||
|             assert info[305] == "Adobe Photoshop CS Macintosh" | ||||
| 
 | ||||
|     def test_get_child_images(self): | ||||
|     def test_get_child_images(self) -> None: | ||||
|         with Image.open("Tests/images/flower.jpg") as im: | ||||
|             ims = im.get_child_images() | ||||
| 
 | ||||
|         assert len(ims) == 1 | ||||
|         assert_image_similar_tofile(ims[0], "Tests/images/flower_thumbnail.png", 2.1) | ||||
| 
 | ||||
|     def test_mp(self): | ||||
|     def test_mp(self) -> None: | ||||
|         with Image.open("Tests/images/pil_sample_rgb.jpg") as im: | ||||
|             assert im._getmp() is None | ||||
| 
 | ||||
|     def test_quality_keep(self, tmp_path): | ||||
|     def test_quality_keep(self, tmp_path: Path) -> None: | ||||
|         # RGB | ||||
|         with Image.open("Tests/images/hopper.jpg") as im: | ||||
|             f = str(tmp_path / "temp.jpg") | ||||
|  | @ -493,13 +494,13 @@ class TestFileJpeg: | |||
|             f = str(tmp_path / "temp.jpg") | ||||
|             im.save(f, quality="keep") | ||||
| 
 | ||||
|     def test_junk_jpeg_header(self): | ||||
|     def test_junk_jpeg_header(self) -> None: | ||||
|         # https://github.com/python-pillow/Pillow/issues/630 | ||||
|         filename = "Tests/images/junk_jpeg_header.jpg" | ||||
|         with Image.open(filename): | ||||
|             pass | ||||
| 
 | ||||
|     def test_ff00_jpeg_header(self): | ||||
|     def test_ff00_jpeg_header(self) -> None: | ||||
|         filename = "Tests/images/jpeg_ff00_header.jpg" | ||||
|         with Image.open(filename): | ||||
|             pass | ||||
|  | @ -507,7 +508,7 @@ class TestFileJpeg: | |||
|     @mark_if_feature_version( | ||||
|         pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" | ||||
|     ) | ||||
|     def test_truncated_jpeg_should_read_all_the_data(self): | ||||
|     def test_truncated_jpeg_should_read_all_the_data(self) -> None: | ||||
|         filename = "Tests/images/truncated_jpeg.jpg" | ||||
|         ImageFile.LOAD_TRUNCATED_IMAGES = True | ||||
|         with Image.open(filename) as im: | ||||
|  | @ -515,7 +516,7 @@ class TestFileJpeg: | |||
|             ImageFile.LOAD_TRUNCATED_IMAGES = False | ||||
|             assert im.getbbox() is not None | ||||
| 
 | ||||
|     def test_truncated_jpeg_throws_oserror(self): | ||||
|     def test_truncated_jpeg_throws_oserror(self) -> None: | ||||
|         filename = "Tests/images/truncated_jpeg.jpg" | ||||
|         with Image.open(filename) as im: | ||||
|             with pytest.raises(OSError): | ||||
|  | @ -528,8 +529,8 @@ class TestFileJpeg: | |||
|     @mark_if_feature_version( | ||||
|         pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" | ||||
|     ) | ||||
|     def test_qtables(self, tmp_path): | ||||
|         def _n_qtables_helper(n, test_file): | ||||
|     def test_qtables(self, tmp_path: Path) -> None: | ||||
|         def _n_qtables_helper(n, test_file) -> None: | ||||
|             with Image.open(test_file) as im: | ||||
|                 f = str(tmp_path / "temp.jpg") | ||||
|                 im.save(f, qtables=[[n] * 64] * n) | ||||
|  | @ -637,24 +638,24 @@ class TestFileJpeg: | |||
|             with pytest.raises(ValueError): | ||||
|                 self.roundtrip(im, qtables=[[1, 2, 3, 4]]) | ||||
| 
 | ||||
|     def test_load_16bit_qtables(self): | ||||
|     def test_load_16bit_qtables(self) -> None: | ||||
|         with Image.open("Tests/images/hopper_16bit_qtables.jpg") as im: | ||||
|             assert len(im.quantization) == 2 | ||||
|             assert len(im.quantization[0]) == 64 | ||||
|             assert max(im.quantization[0]) > 255 | ||||
| 
 | ||||
|     def test_save_multiple_16bit_qtables(self): | ||||
|     def test_save_multiple_16bit_qtables(self) -> None: | ||||
|         with Image.open("Tests/images/hopper_16bit_qtables.jpg") as im: | ||||
|             im2 = self.roundtrip(im, qtables="keep") | ||||
|             assert im.quantization == im2.quantization | ||||
| 
 | ||||
|     def test_save_single_16bit_qtable(self): | ||||
|     def test_save_single_16bit_qtable(self) -> None: | ||||
|         with Image.open("Tests/images/hopper_16bit_qtables.jpg") as im: | ||||
|             im2 = self.roundtrip(im, qtables={0: im.quantization[0]}) | ||||
|             assert len(im2.quantization) == 1 | ||||
|             assert im2.quantization[0] == im.quantization[0] | ||||
| 
 | ||||
|     def test_save_low_quality_baseline_qtables(self): | ||||
|     def test_save_low_quality_baseline_qtables(self) -> None: | ||||
|         with Image.open(TEST_FILE) as im: | ||||
|             im2 = self.roundtrip(im, quality=10) | ||||
|             assert len(im2.quantization) == 2 | ||||
|  | @ -665,7 +666,7 @@ class TestFileJpeg: | |||
|         "blocks, rows, markers", | ||||
|         ((0, 0, 0), (1, 0, 15), (3, 0, 5), (8, 0, 1), (0, 1, 3), (0, 2, 1)), | ||||
|     ) | ||||
|     def test_restart_markers(self, blocks, rows, markers): | ||||
|     def test_restart_markers(self, blocks, rows, markers) -> None: | ||||
|         im = Image.new("RGB", (32, 32))  # 16 MCUs | ||||
|         out = BytesIO() | ||||
|         im.save( | ||||
|  | @ -679,20 +680,20 @@ class TestFileJpeg: | |||
|         assert len(re.findall(b"\xff[\xd0-\xd7]", out.getvalue())) == markers | ||||
| 
 | ||||
|     @pytest.mark.skipif(not djpeg_available(), reason="djpeg not available") | ||||
|     def test_load_djpeg(self): | ||||
|     def test_load_djpeg(self) -> None: | ||||
|         with Image.open(TEST_FILE) as img: | ||||
|             img.load_djpeg() | ||||
|             assert_image_similar_tofile(img, TEST_FILE, 5) | ||||
| 
 | ||||
|     @pytest.mark.skipif(not cjpeg_available(), reason="cjpeg not available") | ||||
|     def test_save_cjpeg(self, tmp_path): | ||||
|     def test_save_cjpeg(self, tmp_path: Path) -> None: | ||||
|         with Image.open(TEST_FILE) as img: | ||||
|             tempfile = str(tmp_path / "temp.jpg") | ||||
|             JpegImagePlugin._save_cjpeg(img, 0, tempfile) | ||||
|             # Default save quality is 75%, so a tiny bit of difference is alright | ||||
|             assert_image_similar_tofile(img, tempfile, 17) | ||||
| 
 | ||||
|     def test_no_duplicate_0x1001_tag(self): | ||||
|     def test_no_duplicate_0x1001_tag(self) -> None: | ||||
|         # Arrange | ||||
|         tag_ids = {v: k for k, v in ExifTags.TAGS.items()} | ||||
| 
 | ||||
|  | @ -700,7 +701,7 @@ class TestFileJpeg: | |||
|         assert tag_ids["RelatedImageWidth"] == 0x1001 | ||||
|         assert tag_ids["RelatedImageLength"] == 0x1002 | ||||
| 
 | ||||
|     def test_MAXBLOCK_scaling(self, tmp_path): | ||||
|     def test_MAXBLOCK_scaling(self, tmp_path: Path) -> None: | ||||
|         im = self.gen_random_image((512, 512)) | ||||
|         f = str(tmp_path / "temp.jpeg") | ||||
|         im.save(f, quality=100, optimize=True) | ||||
|  | @ -711,7 +712,7 @@ class TestFileJpeg: | |||
|             reloaded.save(f, quality="keep", progressive=True) | ||||
|             reloaded.save(f, quality="keep", optimize=True) | ||||
| 
 | ||||
|     def test_bad_mpo_header(self): | ||||
|     def test_bad_mpo_header(self) -> None: | ||||
|         """Treat unknown MPO as JPEG""" | ||||
|         # Arrange | ||||
| 
 | ||||
|  | @ -723,20 +724,20 @@ class TestFileJpeg: | |||
|             assert im.format == "JPEG" | ||||
| 
 | ||||
|     @pytest.mark.parametrize("mode", ("1", "L", "RGB", "RGBX", "CMYK", "YCbCr")) | ||||
|     def test_save_correct_modes(self, mode): | ||||
|     def test_save_correct_modes(self, mode) -> None: | ||||
|         out = BytesIO() | ||||
|         img = Image.new(mode, (20, 20)) | ||||
|         img.save(out, "JPEG") | ||||
| 
 | ||||
|     @pytest.mark.parametrize("mode", ("LA", "La", "RGBA", "RGBa", "P")) | ||||
|     def test_save_wrong_modes(self, mode): | ||||
|     def test_save_wrong_modes(self, mode) -> None: | ||||
|         # ref https://github.com/python-pillow/Pillow/issues/2005 | ||||
|         out = BytesIO() | ||||
|         img = Image.new(mode, (20, 20)) | ||||
|         with pytest.raises(OSError): | ||||
|             img.save(out, "JPEG") | ||||
| 
 | ||||
|     def test_save_tiff_with_dpi(self, tmp_path): | ||||
|     def test_save_tiff_with_dpi(self, tmp_path: Path) -> None: | ||||
|         # Arrange | ||||
|         outfile = str(tmp_path / "temp.tif") | ||||
|         with Image.open("Tests/images/hopper.tif") as im: | ||||
|  | @ -748,7 +749,7 @@ class TestFileJpeg: | |||
|                 reloaded.load() | ||||
|                 assert im.info["dpi"] == reloaded.info["dpi"] | ||||
| 
 | ||||
|     def test_save_dpi_rounding(self, tmp_path): | ||||
|     def test_save_dpi_rounding(self, tmp_path: Path) -> None: | ||||
|         outfile = str(tmp_path / "temp.jpg") | ||||
|         with Image.open("Tests/images/hopper.jpg") as im: | ||||
|             im.save(outfile, dpi=(72.2, 72.2)) | ||||
|  | @ -761,7 +762,7 @@ class TestFileJpeg: | |||
|         with Image.open(outfile) as reloaded: | ||||
|             assert reloaded.info["dpi"] == (73, 73) | ||||
| 
 | ||||
|     def test_dpi_tuple_from_exif(self): | ||||
|     def test_dpi_tuple_from_exif(self) -> None: | ||||
|         # Arrange | ||||
|         # This Photoshop CC 2017 image has DPI in EXIF not metadata | ||||
|         # EXIF XResolution is (2000000, 10000) | ||||
|  | @ -769,7 +770,7 @@ class TestFileJpeg: | |||
|             # Act / Assert | ||||
|             assert im.info.get("dpi") == (200, 200) | ||||
| 
 | ||||
|     def test_dpi_int_from_exif(self): | ||||
|     def test_dpi_int_from_exif(self) -> None: | ||||
|         # Arrange | ||||
|         # This image has DPI in EXIF not metadata | ||||
|         # EXIF XResolution is 72 | ||||
|  | @ -777,7 +778,7 @@ class TestFileJpeg: | |||
|             # Act / Assert | ||||
|             assert im.info.get("dpi") == (72, 72) | ||||
| 
 | ||||
|     def test_dpi_from_dpcm_exif(self): | ||||
|     def test_dpi_from_dpcm_exif(self) -> None: | ||||
|         # Arrange | ||||
|         # This is photoshop-200dpi.jpg with EXIF resolution unit set to cm: | ||||
|         # exiftool -exif:ResolutionUnit=cm photoshop-200dpi.jpg | ||||
|  | @ -785,7 +786,7 @@ class TestFileJpeg: | |||
|             # Act / Assert | ||||
|             assert im.info.get("dpi") == (508, 508) | ||||
| 
 | ||||
|     def test_dpi_exif_zero_division(self): | ||||
|     def test_dpi_exif_zero_division(self) -> None: | ||||
|         # Arrange | ||||
|         # This is photoshop-200dpi.jpg with EXIF resolution set to 0/0: | ||||
|         # exiftool -XResolution=0/0 -YResolution=0/0 photoshop-200dpi.jpg | ||||
|  | @ -794,7 +795,7 @@ class TestFileJpeg: | |||
|             # This should return the default, and not raise a ZeroDivisionError | ||||
|             assert im.info.get("dpi") == (72, 72) | ||||
| 
 | ||||
|     def test_dpi_exif_string(self): | ||||
|     def test_dpi_exif_string(self) -> None: | ||||
|         # Arrange | ||||
|         # 0x011A tag in this exif contains string '300300\x02' | ||||
|         with Image.open("Tests/images/broken_exif_dpi.jpg") as im: | ||||
|  | @ -802,14 +803,14 @@ class TestFileJpeg: | |||
|             # This should return the default | ||||
|             assert im.info.get("dpi") == (72, 72) | ||||
| 
 | ||||
|     def test_dpi_exif_truncated(self): | ||||
|     def test_dpi_exif_truncated(self) -> None: | ||||
|         # Arrange | ||||
|         with Image.open("Tests/images/truncated_exif_dpi.jpg") as im: | ||||
|             # Act / Assert | ||||
|             # This should return the default | ||||
|             assert im.info.get("dpi") == (72, 72) | ||||
| 
 | ||||
|     def test_no_dpi_in_exif(self): | ||||
|     def test_no_dpi_in_exif(self) -> None: | ||||
|         # Arrange | ||||
|         # This is photoshop-200dpi.jpg with resolution removed from EXIF: | ||||
|         # exiftool "-*resolution*"= photoshop-200dpi.jpg | ||||
|  | @ -819,7 +820,7 @@ class TestFileJpeg: | |||
|             # https://exiv2.org/tags.html | ||||
|             assert im.info.get("dpi") == (72, 72) | ||||
| 
 | ||||
|     def test_invalid_exif(self): | ||||
|     def test_invalid_exif(self) -> None: | ||||
|         # This is no-dpi-in-exif with the tiff header of the exif block | ||||
|         # hexedited from MM * to FF FF FF FF | ||||
|         with Image.open("Tests/images/invalid-exif.jpg") as im: | ||||
|  | @ -830,7 +831,7 @@ class TestFileJpeg: | |||
|     @mark_if_feature_version( | ||||
|         pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" | ||||
|     ) | ||||
|     def test_exif_x_resolution(self, tmp_path): | ||||
|     def test_exif_x_resolution(self, tmp_path: Path) -> None: | ||||
|         with Image.open("Tests/images/flower.jpg") as im: | ||||
|             exif = im.getexif() | ||||
|             assert exif[282] == 180 | ||||
|  | @ -842,14 +843,14 @@ class TestFileJpeg: | |||
|         with Image.open(out) as reloaded: | ||||
|             assert reloaded.getexif()[282] == 180 | ||||
| 
 | ||||
|     def test_invalid_exif_x_resolution(self): | ||||
|     def test_invalid_exif_x_resolution(self) -> None: | ||||
|         # When no x or y resolution is defined in EXIF | ||||
|         with Image.open("Tests/images/invalid-exif-without-x-resolution.jpg") as im: | ||||
|             # This should return the default, and not a ValueError or | ||||
|             # OSError for an unidentified image. | ||||
|             assert im.info.get("dpi") == (72, 72) | ||||
| 
 | ||||
|     def test_ifd_offset_exif(self): | ||||
|     def test_ifd_offset_exif(self) -> None: | ||||
|         # Arrange | ||||
|         # This image has been manually hexedited to have an IFD offset of 10, | ||||
|         # in contrast to normal 8 | ||||
|  | @ -857,14 +858,14 @@ class TestFileJpeg: | |||
|             # Act / Assert | ||||
|             assert im._getexif()[306] == "2017:03:13 23:03:09" | ||||
| 
 | ||||
|     def test_multiple_exif(self): | ||||
|     def test_multiple_exif(self) -> None: | ||||
|         with Image.open("Tests/images/multiple_exif.jpg") as im: | ||||
|             assert im.info["exif"] == b"Exif\x00\x00firstsecond" | ||||
| 
 | ||||
|     @mark_if_feature_version( | ||||
|         pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" | ||||
|     ) | ||||
|     def test_photoshop(self): | ||||
|     def test_photoshop(self) -> None: | ||||
|         with Image.open("Tests/images/photoshop-200dpi.jpg") as im: | ||||
|             assert im.info["photoshop"][0x03ED] == { | ||||
|                 "XResolution": 200.0, | ||||
|  | @ -881,14 +882,14 @@ class TestFileJpeg: | |||
|         with Image.open("Tests/images/app13.jpg") as im: | ||||
|             assert "photoshop" not in im.info | ||||
| 
 | ||||
|     def test_photoshop_malformed_and_multiple(self): | ||||
|     def test_photoshop_malformed_and_multiple(self) -> None: | ||||
|         with Image.open("Tests/images/app13-multiple.jpg") as im: | ||||
|             assert "photoshop" in im.info | ||||
|             assert 24 == len(im.info["photoshop"]) | ||||
|             apps_13_lengths = [len(v) for k, v in im.applist if k == "APP13"] | ||||
|             assert [65504, 24] == apps_13_lengths | ||||
| 
 | ||||
|     def test_adobe_transform(self): | ||||
|     def test_adobe_transform(self) -> None: | ||||
|         with Image.open("Tests/images/pil_sample_rgb.jpg") as im: | ||||
|             assert im.info["adobe_transform"] == 1 | ||||
| 
 | ||||
|  | @ -902,11 +903,11 @@ class TestFileJpeg: | |||
|             assert "adobe" in im.info | ||||
|             assert "adobe_transform" not in im.info | ||||
| 
 | ||||
|     def test_icc_after_SOF(self): | ||||
|     def test_icc_after_SOF(self) -> None: | ||||
|         with Image.open("Tests/images/icc-after-SOF.jpg") as im: | ||||
|             assert im.info["icc_profile"] == b"profile" | ||||
| 
 | ||||
|     def test_jpeg_magic_number(self): | ||||
|     def test_jpeg_magic_number(self) -> None: | ||||
|         size = 4097 | ||||
|         buffer = BytesIO(b"\xFF" * size)  # Many xFF bytes | ||||
|         buffer.max_pos = 0 | ||||
|  | @ -925,7 +926,7 @@ class TestFileJpeg: | |||
|         # Assert the entire file has not been read | ||||
|         assert 0 < buffer.max_pos < size | ||||
| 
 | ||||
|     def test_getxmp(self): | ||||
|     def test_getxmp(self) -> None: | ||||
|         with Image.open("Tests/images/xmp_test.jpg") as im: | ||||
|             if ElementTree is None: | ||||
|                 with pytest.warns( | ||||
|  | @ -954,7 +955,7 @@ class TestFileJpeg: | |||
|             with Image.open("Tests/images/hopper.jpg") as im: | ||||
|                 assert im.getxmp() == {} | ||||
| 
 | ||||
|     def test_getxmp_no_prefix(self): | ||||
|     def test_getxmp_no_prefix(self) -> None: | ||||
|         with Image.open("Tests/images/xmp_no_prefix.jpg") as im: | ||||
|             if ElementTree is None: | ||||
|                 with pytest.warns( | ||||
|  | @ -965,7 +966,7 @@ class TestFileJpeg: | |||
|             else: | ||||
|                 assert im.getxmp() == {"xmpmeta": {"key": "value"}} | ||||
| 
 | ||||
|     def test_getxmp_padded(self): | ||||
|     def test_getxmp_padded(self) -> None: | ||||
|         with Image.open("Tests/images/xmp_padded.jpg") as im: | ||||
|             if ElementTree is None: | ||||
|                 with pytest.warns( | ||||
|  | @ -977,7 +978,7 @@ class TestFileJpeg: | |||
|                 assert im.getxmp() == {"xmpmeta": None} | ||||
| 
 | ||||
|     @pytest.mark.timeout(timeout=1) | ||||
|     def test_eof(self): | ||||
|     def test_eof(self) -> None: | ||||
|         # Even though this decoder never says that it is finished | ||||
|         # the image should still end when there is no new data | ||||
|         class InfiniteMockPyDecoder(ImageFile.PyDecoder): | ||||
|  | @ -1000,7 +1001,7 @@ class TestFileJpeg: | |||
|             im.load() | ||||
|             ImageFile.LOAD_TRUNCATED_IMAGES = False | ||||
| 
 | ||||
|     def test_separate_tables(self): | ||||
|     def test_separate_tables(self) -> None: | ||||
|         im = hopper() | ||||
|         data = []  # [interchange, tables-only, image-only] | ||||
|         for streamtype in range(3): | ||||
|  | @ -1022,14 +1023,14 @@ class TestFileJpeg: | |||
|             with Image.open(BytesIO(data[1] + data[2])) as combined_im: | ||||
|                 assert_image_equal(interchange_im, combined_im) | ||||
| 
 | ||||
|     def test_repr_jpeg(self): | ||||
|     def test_repr_jpeg(self) -> None: | ||||
|         im = hopper() | ||||
| 
 | ||||
|         with Image.open(BytesIO(im._repr_jpeg_())) as repr_jpeg: | ||||
|             assert repr_jpeg.format == "JPEG" | ||||
|             assert_image_similar(im, repr_jpeg, 17) | ||||
| 
 | ||||
|     def test_repr_jpeg_error_returns_none(self): | ||||
|     def test_repr_jpeg_error_returns_none(self) -> None: | ||||
|         im = hopper("F") | ||||
| 
 | ||||
|         assert im._repr_jpeg_() is None | ||||
|  | @ -1038,7 +1039,7 @@ class TestFileJpeg: | |||
| @pytest.mark.skipif(not is_win32(), reason="Windows only") | ||||
| @skip_unless_feature("jpg") | ||||
| class TestFileCloseW32: | ||||
|     def test_fd_leak(self, tmp_path): | ||||
|     def test_fd_leak(self, tmp_path: Path) -> None: | ||||
|         tmpfile = str(tmp_path / "temp.jpg") | ||||
| 
 | ||||
|         with Image.open("Tests/images/hopper.jpg") as im: | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ from __future__ import annotations | |||
| import os | ||||
| import re | ||||
| from io import BytesIO | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -46,7 +47,7 @@ def roundtrip(im, **options): | |||
|     return im | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(): | ||||
| def test_sanity() -> None: | ||||
|     # Internal version number | ||||
|     assert re.search(r"\d+\.\d+\.\d+$", features.version_codec("jpg_2000")) | ||||
| 
 | ||||
|  | @ -59,20 +60,20 @@ def test_sanity(): | |||
|         assert im.get_format_mimetype() == "image/jp2" | ||||
| 
 | ||||
| 
 | ||||
| def test_jpf(): | ||||
| def test_jpf() -> None: | ||||
|     with Image.open("Tests/images/balloon.jpf") as im: | ||||
|         assert im.format == "JPEG2000" | ||||
|         assert im.get_format_mimetype() == "image/jpx" | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     invalid_file = "Tests/images/flower.jpg" | ||||
| 
 | ||||
|     with pytest.raises(SyntaxError): | ||||
|         Jpeg2KImagePlugin.Jpeg2KImageFile(invalid_file) | ||||
| 
 | ||||
| 
 | ||||
| def test_bytesio(): | ||||
| def test_bytesio() -> None: | ||||
|     with open("Tests/images/test-card-lossless.jp2", "rb") as f: | ||||
|         data = BytesIO(f.read()) | ||||
|     assert_image_similar_tofile(test_card, data, 1.0e-3) | ||||
|  | @ -82,7 +83,7 @@ def test_bytesio(): | |||
| # PIL (they were made using Adobe Photoshop) | ||||
| 
 | ||||
| 
 | ||||
| def test_lossless(tmp_path): | ||||
| def test_lossless(tmp_path: Path) -> None: | ||||
|     with Image.open("Tests/images/test-card-lossless.jp2") as im: | ||||
|         im.load() | ||||
|         outfile = str(tmp_path / "temp_test-card.png") | ||||
|  | @ -90,54 +91,54 @@ def test_lossless(tmp_path): | |||
|     assert_image_similar(im, test_card, 1.0e-3) | ||||
| 
 | ||||
| 
 | ||||
| def test_lossy_tiled(): | ||||
| def test_lossy_tiled() -> None: | ||||
|     assert_image_similar_tofile( | ||||
|         test_card, "Tests/images/test-card-lossy-tiled.jp2", 2.0 | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| def test_lossless_rt(): | ||||
| def test_lossless_rt() -> None: | ||||
|     im = roundtrip(test_card) | ||||
|     assert_image_equal(im, test_card) | ||||
| 
 | ||||
| 
 | ||||
| def test_lossy_rt(): | ||||
| def test_lossy_rt() -> None: | ||||
|     im = roundtrip(test_card, quality_layers=[20]) | ||||
|     assert_image_similar(im, test_card, 2.0) | ||||
| 
 | ||||
| 
 | ||||
| def test_tiled_rt(): | ||||
| def test_tiled_rt() -> None: | ||||
|     im = roundtrip(test_card, tile_size=(128, 128)) | ||||
|     assert_image_equal(im, test_card) | ||||
| 
 | ||||
| 
 | ||||
| def test_tiled_offset_rt(): | ||||
| def test_tiled_offset_rt() -> None: | ||||
|     im = roundtrip(test_card, tile_size=(128, 128), tile_offset=(0, 0), offset=(32, 32)) | ||||
|     assert_image_equal(im, test_card) | ||||
| 
 | ||||
| 
 | ||||
| def test_tiled_offset_too_small(): | ||||
| def test_tiled_offset_too_small() -> None: | ||||
|     with pytest.raises(ValueError): | ||||
|         roundtrip(test_card, tile_size=(128, 128), tile_offset=(0, 0), offset=(128, 32)) | ||||
| 
 | ||||
| 
 | ||||
| def test_irreversible_rt(): | ||||
| def test_irreversible_rt() -> None: | ||||
|     im = roundtrip(test_card, irreversible=True, quality_layers=[20]) | ||||
|     assert_image_similar(im, test_card, 2.0) | ||||
| 
 | ||||
| 
 | ||||
| def test_prog_qual_rt(): | ||||
| def test_prog_qual_rt() -> None: | ||||
|     im = roundtrip(test_card, quality_layers=[60, 40, 20], progression="LRCP") | ||||
|     assert_image_similar(im, test_card, 2.0) | ||||
| 
 | ||||
| 
 | ||||
| def test_prog_res_rt(): | ||||
| def test_prog_res_rt() -> None: | ||||
|     im = roundtrip(test_card, num_resolutions=8, progression="RLCP") | ||||
|     assert_image_equal(im, test_card) | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("num_resolutions", range(2, 6)) | ||||
| def test_default_num_resolutions(num_resolutions): | ||||
| def test_default_num_resolutions(num_resolutions) -> None: | ||||
|     d = 1 << (num_resolutions - 1) | ||||
|     im = test_card.resize((d - 1, d - 1)) | ||||
|     with pytest.raises(OSError): | ||||
|  | @ -146,7 +147,7 @@ def test_default_num_resolutions(num_resolutions): | |||
|     assert_image_equal(im, reloaded) | ||||
| 
 | ||||
| 
 | ||||
| def test_reduce(): | ||||
| def test_reduce() -> None: | ||||
|     with Image.open("Tests/images/test-card-lossless.jp2") as im: | ||||
|         assert callable(im.reduce) | ||||
| 
 | ||||
|  | @ -160,7 +161,7 @@ def test_reduce(): | |||
|         assert im.size == (40, 30) | ||||
| 
 | ||||
| 
 | ||||
| def test_load_dpi(): | ||||
| def test_load_dpi() -> None: | ||||
|     with Image.open("Tests/images/test-card-lossless.jp2") as im: | ||||
|         assert im.info["dpi"] == (71.9836, 71.9836) | ||||
| 
 | ||||
|  | @ -168,7 +169,7 @@ def test_load_dpi(): | |||
|         assert "dpi" not in im.info | ||||
| 
 | ||||
| 
 | ||||
| def test_restricted_icc_profile(): | ||||
| def test_restricted_icc_profile() -> None: | ||||
|     ImageFile.LOAD_TRUNCATED_IMAGES = True | ||||
|     try: | ||||
|         # JPEG2000 image with a restricted ICC profile and a known colorspace | ||||
|  | @ -178,7 +179,7 @@ def test_restricted_icc_profile(): | |||
|         ImageFile.LOAD_TRUNCATED_IMAGES = False | ||||
| 
 | ||||
| 
 | ||||
| def test_header_errors(): | ||||
| def test_header_errors() -> None: | ||||
|     for path in ( | ||||
|         "Tests/images/invalid_header_length.jp2", | ||||
|         "Tests/images/not_enough_data.jp2", | ||||
|  | @ -192,7 +193,7 @@ def test_header_errors(): | |||
|             pass | ||||
| 
 | ||||
| 
 | ||||
| def test_layers_type(tmp_path): | ||||
| def test_layers_type(tmp_path: Path) -> None: | ||||
|     outfile = str(tmp_path / "temp_layers.jp2") | ||||
|     for quality_layers in [[100, 50, 10], (100, 50, 10), None]: | ||||
|         test_card.save(outfile, quality_layers=quality_layers) | ||||
|  | @ -202,7 +203,7 @@ def test_layers_type(tmp_path): | |||
|             test_card.save(outfile, quality_layers=quality_layers) | ||||
| 
 | ||||
| 
 | ||||
| def test_layers(): | ||||
| def test_layers() -> None: | ||||
|     out = BytesIO() | ||||
|     test_card.save(out, "JPEG2000", quality_layers=[100, 50, 10], progression="LRCP") | ||||
|     out.seek(0) | ||||
|  | @ -232,7 +233,7 @@ def test_layers(): | |||
|         ("foo.jp2", {"no_jp2": False}, 4, b"jP"), | ||||
|     ), | ||||
| ) | ||||
| def test_no_jp2(name, args, offset, data): | ||||
| def test_no_jp2(name, args, offset, data) -> None: | ||||
|     out = BytesIO() | ||||
|     if name: | ||||
|         out.name = name | ||||
|  | @ -241,7 +242,7 @@ def test_no_jp2(name, args, offset, data): | |||
|     assert out.read(2) == data | ||||
| 
 | ||||
| 
 | ||||
| def test_mct(): | ||||
| def test_mct() -> None: | ||||
|     # Three component | ||||
|     for val in (0, 1): | ||||
|         out = BytesIO() | ||||
|  | @ -262,7 +263,7 @@ def test_mct(): | |||
|             assert_image_similar(im, jp2, 1.0e-3) | ||||
| 
 | ||||
| 
 | ||||
| def test_sgnd(tmp_path): | ||||
| def test_sgnd(tmp_path: Path) -> None: | ||||
|     outfile = str(tmp_path / "temp.jp2") | ||||
| 
 | ||||
|     im = Image.new("L", (1, 1)) | ||||
|  | @ -277,7 +278,7 @@ def test_sgnd(tmp_path): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("ext", (".j2k", ".jp2")) | ||||
| def test_rgba(ext): | ||||
| def test_rgba(ext) -> None: | ||||
|     # Arrange | ||||
|     with Image.open("Tests/images/rgb_trns_ycbc" + ext) as im: | ||||
|         # Act | ||||
|  | @ -288,47 +289,47 @@ def test_rgba(ext): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("ext", (".j2k", ".jp2")) | ||||
| def test_16bit_monochrome_has_correct_mode(ext): | ||||
| def test_16bit_monochrome_has_correct_mode(ext) -> None: | ||||
|     with Image.open("Tests/images/16bit.cropped" + ext) as im: | ||||
|         im.load() | ||||
|         assert im.mode == "I;16" | ||||
| 
 | ||||
| 
 | ||||
| def test_16bit_monochrome_jp2_like_tiff(): | ||||
| def test_16bit_monochrome_jp2_like_tiff() -> None: | ||||
|     with Image.open("Tests/images/16bit.cropped.tif") as tiff_16bit: | ||||
|         assert_image_similar_tofile(tiff_16bit, "Tests/images/16bit.cropped.jp2", 1e-3) | ||||
| 
 | ||||
| 
 | ||||
| def test_16bit_monochrome_j2k_like_tiff(): | ||||
| def test_16bit_monochrome_j2k_like_tiff() -> None: | ||||
|     with Image.open("Tests/images/16bit.cropped.tif") as tiff_16bit: | ||||
|         assert_image_similar_tofile(tiff_16bit, "Tests/images/16bit.cropped.j2k", 1e-3) | ||||
| 
 | ||||
| 
 | ||||
| def test_16bit_j2k_roundtrips(): | ||||
| def test_16bit_j2k_roundtrips() -> None: | ||||
|     with Image.open("Tests/images/16bit.cropped.j2k") as j2k: | ||||
|         im = roundtrip(j2k) | ||||
|         assert_image_equal(im, j2k) | ||||
| 
 | ||||
| 
 | ||||
| def test_16bit_jp2_roundtrips(): | ||||
| def test_16bit_jp2_roundtrips() -> None: | ||||
|     with Image.open("Tests/images/16bit.cropped.jp2") as jp2: | ||||
|         im = roundtrip(jp2) | ||||
|         assert_image_equal(im, jp2) | ||||
| 
 | ||||
| 
 | ||||
| def test_issue_6194(): | ||||
| def test_issue_6194() -> None: | ||||
|     with Image.open("Tests/images/issue_6194.j2k") as im: | ||||
|         assert im.getpixel((5, 5)) == 31 | ||||
| 
 | ||||
| 
 | ||||
| def test_unbound_local(): | ||||
| def test_unbound_local() -> None: | ||||
|     # prepatch, a malformed jp2 file could cause an UnboundLocalError exception. | ||||
|     with pytest.raises(OSError): | ||||
|         with Image.open("Tests/images/unbound_variable.jp2"): | ||||
|             pass | ||||
| 
 | ||||
| 
 | ||||
| def test_parser_feed(): | ||||
| def test_parser_feed() -> None: | ||||
|     # Arrange | ||||
|     with open("Tests/images/test-card-lossless.jp2", "rb") as f: | ||||
|         data = f.read() | ||||
|  | @ -345,7 +346,7 @@ def test_parser_feed(): | |||
|     not os.path.exists(EXTRA_DIR), reason="Extra image files not installed" | ||||
| ) | ||||
| @pytest.mark.parametrize("name", ("subsampling_1", "subsampling_2", "zoo1", "zoo2")) | ||||
| def test_subsampling_decode(name): | ||||
| def test_subsampling_decode(name) -> None: | ||||
|     test = f"{EXTRA_DIR}/{name}.jp2" | ||||
|     reference = f"{EXTRA_DIR}/{name}.ppm" | ||||
| 
 | ||||
|  | @ -361,7 +362,7 @@ def test_subsampling_decode(name): | |||
|         assert_image_similar(im, expected, epsilon) | ||||
| 
 | ||||
| 
 | ||||
| def test_comment(): | ||||
| def test_comment() -> None: | ||||
|     with Image.open("Tests/images/comment.jp2") as im: | ||||
|         assert im.info["comment"] == b"Created by OpenJPEG version 2.5.0" | ||||
| 
 | ||||
|  | @ -372,7 +373,7 @@ def test_comment(): | |||
|             pass | ||||
| 
 | ||||
| 
 | ||||
| def test_save_comment(): | ||||
| def test_save_comment() -> None: | ||||
|     for comment in ("Created by Pillow", b"Created by Pillow"): | ||||
|         out = BytesIO() | ||||
|         test_card.save(out, "JPEG2000", comment=comment) | ||||
|  | @ -399,7 +400,7 @@ def test_save_comment(): | |||
|         "Tests/images/crash-d2c93af851d3ab9a19e34503626368b2ecde9c03.j2k", | ||||
|     ], | ||||
| ) | ||||
| def test_crashes(test_file): | ||||
| def test_crashes(test_file) -> None: | ||||
|     with open(test_file, "rb") as f: | ||||
|         with Image.open(f) as im: | ||||
|             # Valgrind should not complain here | ||||
|  | @ -410,7 +411,7 @@ def test_crashes(test_file): | |||
| 
 | ||||
| 
 | ||||
| @skip_unless_feature_version("jpg_2000", "2.4.0") | ||||
| def test_plt_marker(): | ||||
| def test_plt_marker() -> None: | ||||
|     # Search the start of the codesteam for PLT | ||||
|     out = BytesIO() | ||||
|     test_card.save(out, "JPEG2000", no_jp2=True, plt=True) | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ import os | |||
| import re | ||||
| import sys | ||||
| from collections import namedtuple | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -26,7 +27,7 @@ from .helper import ( | |||
| 
 | ||||
| @skip_unless_feature("libtiff") | ||||
| class LibTiffTestCase: | ||||
|     def _assert_noerr(self, tmp_path, im): | ||||
|     def _assert_noerr(self, tmp_path: Path, im) -> None: | ||||
|         """Helper tests that assert basic sanity about the g4 tiff reading""" | ||||
|         # 1 bit | ||||
|         assert im.mode == "1" | ||||
|  | @ -50,10 +51,10 @@ class LibTiffTestCase: | |||
| 
 | ||||
| 
 | ||||
| class TestFileLibTiff(LibTiffTestCase): | ||||
|     def test_version(self): | ||||
|     def test_version(self) -> None: | ||||
|         assert re.search(r"\d+\.\d+\.\d+$", features.version_codec("libtiff")) | ||||
| 
 | ||||
|     def test_g4_tiff(self, tmp_path): | ||||
|     def test_g4_tiff(self, tmp_path: Path) -> None: | ||||
|         """Test the ordinary file path load path""" | ||||
| 
 | ||||
|         test_file = "Tests/images/hopper_g4_500.tif" | ||||
|  | @ -61,12 +62,12 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|             assert im.size == (500, 500) | ||||
|             self._assert_noerr(tmp_path, im) | ||||
| 
 | ||||
|     def test_g4_large(self, tmp_path): | ||||
|     def test_g4_large(self, tmp_path: Path) -> None: | ||||
|         test_file = "Tests/images/pport_g4.tif" | ||||
|         with Image.open(test_file) as im: | ||||
|             self._assert_noerr(tmp_path, im) | ||||
| 
 | ||||
|     def test_g4_tiff_file(self, tmp_path): | ||||
|     def test_g4_tiff_file(self, tmp_path: Path) -> None: | ||||
|         """Testing the string load path""" | ||||
| 
 | ||||
|         test_file = "Tests/images/hopper_g4_500.tif" | ||||
|  | @ -75,7 +76,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|                 assert im.size == (500, 500) | ||||
|                 self._assert_noerr(tmp_path, im) | ||||
| 
 | ||||
|     def test_g4_tiff_bytesio(self, tmp_path): | ||||
|     def test_g4_tiff_bytesio(self, tmp_path: Path) -> None: | ||||
|         """Testing the stringio loading code path""" | ||||
|         test_file = "Tests/images/hopper_g4_500.tif" | ||||
|         s = io.BytesIO() | ||||
|  | @ -86,7 +87,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|             assert im.size == (500, 500) | ||||
|             self._assert_noerr(tmp_path, im) | ||||
| 
 | ||||
|     def test_g4_non_disk_file_object(self, tmp_path): | ||||
|     def test_g4_non_disk_file_object(self, tmp_path: Path) -> None: | ||||
|         """Testing loading from non-disk non-BytesIO file object""" | ||||
|         test_file = "Tests/images/hopper_g4_500.tif" | ||||
|         s = io.BytesIO() | ||||
|  | @ -98,18 +99,18 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|             assert im.size == (500, 500) | ||||
|             self._assert_noerr(tmp_path, im) | ||||
| 
 | ||||
|     def test_g4_eq_png(self): | ||||
|     def test_g4_eq_png(self) -> None: | ||||
|         """Checking that we're actually getting the data that we expect""" | ||||
|         with Image.open("Tests/images/hopper_bw_500.png") as png: | ||||
|             assert_image_equal_tofile(png, "Tests/images/hopper_g4_500.tif") | ||||
| 
 | ||||
|     # see https://github.com/python-pillow/Pillow/issues/279 | ||||
|     def test_g4_fillorder_eq_png(self): | ||||
|     def test_g4_fillorder_eq_png(self) -> None: | ||||
|         """Checking that we're actually getting the data that we expect""" | ||||
|         with Image.open("Tests/images/g4-fillorder-test.tif") as g4: | ||||
|             assert_image_equal_tofile(g4, "Tests/images/g4-fillorder-test.png") | ||||
| 
 | ||||
|     def test_g4_write(self, tmp_path): | ||||
|     def test_g4_write(self, tmp_path: Path) -> None: | ||||
|         """Checking to see that the saved image is the same as what we wrote""" | ||||
|         test_file = "Tests/images/hopper_g4_500.tif" | ||||
|         with Image.open(test_file) as orig: | ||||
|  | @ -128,7 +129,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
| 
 | ||||
|                 assert orig.tobytes() != reread.tobytes() | ||||
| 
 | ||||
|     def test_adobe_deflate_tiff(self): | ||||
|     def test_adobe_deflate_tiff(self) -> None: | ||||
|         test_file = "Tests/images/tiff_adobe_deflate.tif" | ||||
|         with Image.open(test_file) as im: | ||||
|             assert im.mode == "RGB" | ||||
|  | @ -139,7 +140,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|             assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png") | ||||
| 
 | ||||
|     @pytest.mark.parametrize("legacy_api", (False, True)) | ||||
|     def test_write_metadata(self, legacy_api, tmp_path): | ||||
|     def test_write_metadata(self, legacy_api, tmp_path: Path) -> None: | ||||
|         """Test metadata writing through libtiff""" | ||||
|         f = str(tmp_path / "temp.tiff") | ||||
|         with Image.open("Tests/images/hopper_g4.tif") as img: | ||||
|  | @ -184,7 +185,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|             assert field in reloaded, f"{field} not in metadata" | ||||
| 
 | ||||
|     @pytest.mark.valgrind_known_error(reason="Known invalid metadata") | ||||
|     def test_additional_metadata(self, tmp_path): | ||||
|     def test_additional_metadata(self, tmp_path: Path) -> None: | ||||
|         # these should not crash. Seriously dummy data, most of it doesn't make | ||||
|         # any sense, so we're running up against limits where we're asking | ||||
|         # libtiff to do stupid things. | ||||
|  | @ -241,7 +242,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
| 
 | ||||
|         TiffImagePlugin.WRITE_LIBTIFF = False | ||||
| 
 | ||||
|     def test_custom_metadata(self, tmp_path): | ||||
|     def test_custom_metadata(self, tmp_path: Path) -> None: | ||||
|         tc = namedtuple("test_case", "value,type,supported_by_default") | ||||
|         custom = { | ||||
|             37000 + k: v | ||||
|  | @ -283,7 +284,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|         for libtiff in libtiffs: | ||||
|             TiffImagePlugin.WRITE_LIBTIFF = libtiff | ||||
| 
 | ||||
|             def check_tags(tiffinfo): | ||||
|             def check_tags(tiffinfo) -> None: | ||||
|                 im = hopper() | ||||
| 
 | ||||
|                 out = str(tmp_path / "temp.tif") | ||||
|  | @ -322,7 +323,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|             ) | ||||
|         TiffImagePlugin.WRITE_LIBTIFF = False | ||||
| 
 | ||||
|     def test_subifd(self, tmp_path): | ||||
|     def test_subifd(self, tmp_path: Path) -> None: | ||||
|         outfile = str(tmp_path / "temp.tif") | ||||
|         with Image.open("Tests/images/g4_orientation_6.tif") as im: | ||||
|             im.tag_v2[SUBIFD] = 10000 | ||||
|  | @ -330,7 +331,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|             # Should not segfault | ||||
|             im.save(outfile) | ||||
| 
 | ||||
|     def test_xmlpacket_tag(self, tmp_path): | ||||
|     def test_xmlpacket_tag(self, tmp_path: Path) -> None: | ||||
|         TiffImagePlugin.WRITE_LIBTIFF = True | ||||
| 
 | ||||
|         out = str(tmp_path / "temp.tif") | ||||
|  | @ -341,7 +342,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|             if 700 in reloaded.tag_v2: | ||||
|                 assert reloaded.tag_v2[700] == b"xmlpacket tag" | ||||
| 
 | ||||
|     def test_int_dpi(self, tmp_path): | ||||
|     def test_int_dpi(self, tmp_path: Path) -> None: | ||||
|         # issue #1765 | ||||
|         im = hopper("RGB") | ||||
|         out = str(tmp_path / "temp.tif") | ||||
|  | @ -351,7 +352,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|         with Image.open(out) as reloaded: | ||||
|             assert reloaded.info["dpi"] == (72.0, 72.0) | ||||
| 
 | ||||
|     def test_g3_compression(self, tmp_path): | ||||
|     def test_g3_compression(self, tmp_path: Path) -> None: | ||||
|         with Image.open("Tests/images/hopper_g4_500.tif") as i: | ||||
|             out = str(tmp_path / "temp.tif") | ||||
|             i.save(out, compression="group3") | ||||
|  | @ -360,7 +361,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|                 assert reread.info["compression"] == "group3" | ||||
|                 assert_image_equal(reread, i) | ||||
| 
 | ||||
|     def test_little_endian(self, tmp_path): | ||||
|     def test_little_endian(self, tmp_path: Path) -> None: | ||||
|         with Image.open("Tests/images/16bit.deflate.tif") as im: | ||||
|             assert im.getpixel((0, 0)) == 480 | ||||
|             assert im.mode == "I;16" | ||||
|  | @ -379,7 +380,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|         # UNDONE - libtiff defaults to writing in native endian, so | ||||
|         # on big endian, we'll get back mode = 'I;16B' here. | ||||
| 
 | ||||
|     def test_big_endian(self, tmp_path): | ||||
|     def test_big_endian(self, tmp_path: Path) -> None: | ||||
|         with Image.open("Tests/images/16bit.MM.deflate.tif") as im: | ||||
|             assert im.getpixel((0, 0)) == 480 | ||||
|             assert im.mode == "I;16B" | ||||
|  | @ -396,7 +397,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|                 assert reread.info["compression"] == im.info["compression"] | ||||
|                 assert reread.getpixel((0, 0)) == 480 | ||||
| 
 | ||||
|     def test_g4_string_info(self, tmp_path): | ||||
|     def test_g4_string_info(self, tmp_path: Path) -> None: | ||||
|         """Tests String data in info directory""" | ||||
|         test_file = "Tests/images/hopper_g4_500.tif" | ||||
|         with Image.open(test_file) as orig: | ||||
|  | @ -409,7 +410,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|             assert "temp.tif" == reread.tag_v2[269] | ||||
|             assert "temp.tif" == reread.tag[269][0] | ||||
| 
 | ||||
|     def test_12bit_rawmode(self): | ||||
|     def test_12bit_rawmode(self) -> None: | ||||
|         """Are we generating the same interpretation | ||||
|         of the image as Imagemagick is?""" | ||||
|         TiffImagePlugin.READ_LIBTIFF = True | ||||
|  | @ -424,7 +425,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
| 
 | ||||
|             assert_image_equal_tofile(im, "Tests/images/12in16bit.tif") | ||||
| 
 | ||||
|     def test_blur(self, tmp_path): | ||||
|     def test_blur(self, tmp_path: Path) -> None: | ||||
|         # test case from irc, how to do blur on b/w image | ||||
|         # and save to compressed tif. | ||||
|         out = str(tmp_path / "temp.tif") | ||||
|  | @ -436,7 +437,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
| 
 | ||||
|         assert_image_equal_tofile(im, out) | ||||
| 
 | ||||
|     def test_compressions(self, tmp_path): | ||||
|     def test_compressions(self, tmp_path: Path) -> None: | ||||
|         # Test various tiff compressions and assert similar image content but reduced | ||||
|         # file sizes. | ||||
|         im = hopper("RGB") | ||||
|  | @ -462,7 +463,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|         assert size_compressed > size_jpeg | ||||
|         assert size_jpeg > size_jpeg_30 | ||||
| 
 | ||||
|     def test_tiff_jpeg_compression(self, tmp_path): | ||||
|     def test_tiff_jpeg_compression(self, tmp_path: Path) -> None: | ||||
|         im = hopper("RGB") | ||||
|         out = str(tmp_path / "temp.tif") | ||||
|         im.save(out, compression="tiff_jpeg") | ||||
|  | @ -470,7 +471,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|         with Image.open(out) as reloaded: | ||||
|             assert reloaded.info["compression"] == "jpeg" | ||||
| 
 | ||||
|     def test_tiff_deflate_compression(self, tmp_path): | ||||
|     def test_tiff_deflate_compression(self, tmp_path: Path) -> None: | ||||
|         im = hopper("RGB") | ||||
|         out = str(tmp_path / "temp.tif") | ||||
|         im.save(out, compression="tiff_deflate") | ||||
|  | @ -478,7 +479,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|         with Image.open(out) as reloaded: | ||||
|             assert reloaded.info["compression"] == "tiff_adobe_deflate" | ||||
| 
 | ||||
|     def test_quality(self, tmp_path): | ||||
|     def test_quality(self, tmp_path: Path) -> None: | ||||
|         im = hopper("RGB") | ||||
|         out = str(tmp_path / "temp.tif") | ||||
| 
 | ||||
|  | @ -493,7 +494,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|         im.save(out, compression="jpeg", quality=0) | ||||
|         im.save(out, compression="jpeg", quality=100) | ||||
| 
 | ||||
|     def test_cmyk_save(self, tmp_path): | ||||
|     def test_cmyk_save(self, tmp_path: Path) -> None: | ||||
|         im = hopper("CMYK") | ||||
|         out = str(tmp_path / "temp.tif") | ||||
| 
 | ||||
|  | @ -501,7 +502,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|         assert_image_equal_tofile(im, out) | ||||
| 
 | ||||
|     @pytest.mark.parametrize("im", (hopper("P"), Image.new("P", (1, 1), "#000"))) | ||||
|     def test_palette_save(self, im, tmp_path): | ||||
|     def test_palette_save(self, im, tmp_path: Path) -> None: | ||||
|         out = str(tmp_path / "temp.tif") | ||||
| 
 | ||||
|         TiffImagePlugin.WRITE_LIBTIFF = True | ||||
|  | @ -513,14 +514,14 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|             assert len(reloaded.tag_v2[320]) == 768 | ||||
| 
 | ||||
|     @pytest.mark.parametrize("compression", ("tiff_ccitt", "group3", "group4")) | ||||
|     def test_bw_compression_w_rgb(self, compression, tmp_path): | ||||
|     def test_bw_compression_w_rgb(self, compression, tmp_path: Path) -> None: | ||||
|         im = hopper("RGB") | ||||
|         out = str(tmp_path / "temp.tif") | ||||
| 
 | ||||
|         with pytest.raises(OSError): | ||||
|             im.save(out, compression=compression) | ||||
| 
 | ||||
|     def test_fp_leak(self): | ||||
|     def test_fp_leak(self) -> None: | ||||
|         im = Image.open("Tests/images/hopper_g4_500.tif") | ||||
|         fn = im.fp.fileno() | ||||
| 
 | ||||
|  | @ -534,7 +535,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|         with pytest.raises(OSError): | ||||
|             os.close(fn) | ||||
| 
 | ||||
|     def test_multipage(self): | ||||
|     def test_multipage(self) -> None: | ||||
|         # issue #862 | ||||
|         TiffImagePlugin.READ_LIBTIFF = True | ||||
|         with Image.open("Tests/images/multipage.tiff") as im: | ||||
|  | @ -557,7 +558,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
| 
 | ||||
|         TiffImagePlugin.READ_LIBTIFF = False | ||||
| 
 | ||||
|     def test_multipage_nframes(self): | ||||
|     def test_multipage_nframes(self) -> None: | ||||
|         # issue #862 | ||||
|         TiffImagePlugin.READ_LIBTIFF = True | ||||
|         with Image.open("Tests/images/multipage.tiff") as im: | ||||
|  | @ -570,7 +571,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
| 
 | ||||
|         TiffImagePlugin.READ_LIBTIFF = False | ||||
| 
 | ||||
|     def test_multipage_seek_backwards(self): | ||||
|     def test_multipage_seek_backwards(self) -> None: | ||||
|         TiffImagePlugin.READ_LIBTIFF = True | ||||
|         with Image.open("Tests/images/multipage.tiff") as im: | ||||
|             im.seek(1) | ||||
|  | @ -581,14 +582,14 @@ class TestFileLibTiff(LibTiffTestCase): | |||
| 
 | ||||
|         TiffImagePlugin.READ_LIBTIFF = False | ||||
| 
 | ||||
|     def test__next(self): | ||||
|     def test__next(self) -> None: | ||||
|         TiffImagePlugin.READ_LIBTIFF = True | ||||
|         with Image.open("Tests/images/hopper.tif") as im: | ||||
|             assert not im.tag.next | ||||
|             im.load() | ||||
|             assert not im.tag.next | ||||
| 
 | ||||
|     def test_4bit(self): | ||||
|     def test_4bit(self) -> None: | ||||
|         # Arrange | ||||
|         test_file = "Tests/images/hopper_gray_4bpp.tif" | ||||
|         original = hopper("L") | ||||
|  | @ -603,7 +604,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|             assert im.mode == "L" | ||||
|             assert_image_similar(im, original, 7.3) | ||||
| 
 | ||||
|     def test_gray_semibyte_per_pixel(self): | ||||
|     def test_gray_semibyte_per_pixel(self) -> None: | ||||
|         test_files = ( | ||||
|             ( | ||||
|                 24.8,  # epsilon | ||||
|  | @ -636,7 +637,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|                     assert im2.mode == "L" | ||||
|                     assert_image_equal(im, im2) | ||||
| 
 | ||||
|     def test_save_bytesio(self): | ||||
|     def test_save_bytesio(self) -> None: | ||||
|         # PR 1011 | ||||
|         # Test TIFF saving to io.BytesIO() object. | ||||
| 
 | ||||
|  | @ -646,7 +647,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|         # Generate test image | ||||
|         pilim = hopper() | ||||
| 
 | ||||
|         def save_bytesio(compression=None): | ||||
|         def save_bytesio(compression=None) -> None: | ||||
|             buffer_io = io.BytesIO() | ||||
|             pilim.save(buffer_io, format="tiff", compression=compression) | ||||
|             buffer_io.seek(0) | ||||
|  | @ -661,7 +662,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|         TiffImagePlugin.WRITE_LIBTIFF = False | ||||
|         TiffImagePlugin.READ_LIBTIFF = False | ||||
| 
 | ||||
|     def test_save_ycbcr(self, tmp_path): | ||||
|     def test_save_ycbcr(self, tmp_path: Path) -> None: | ||||
|         im = hopper("YCbCr") | ||||
|         outfile = str(tmp_path / "temp.tif") | ||||
|         im.save(outfile, compression="jpeg") | ||||
|  | @ -670,7 +671,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|             assert reloaded.tag_v2[530] == (1, 1) | ||||
|             assert reloaded.tag_v2[532] == (0, 255, 128, 255, 128, 255) | ||||
| 
 | ||||
|     def test_exif_ifd(self, tmp_path): | ||||
|     def test_exif_ifd(self, tmp_path: Path) -> None: | ||||
|         outfile = str(tmp_path / "temp.tif") | ||||
|         with Image.open("Tests/images/tiff_adobe_deflate.tif") as im: | ||||
|             assert im.tag_v2[34665] == 125456 | ||||
|  | @ -680,7 +681,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|             if Image.core.libtiff_support_custom_tags: | ||||
|                 assert reloaded.tag_v2[34665] == 125456 | ||||
| 
 | ||||
|     def test_crashing_metadata(self, tmp_path): | ||||
|     def test_crashing_metadata(self, tmp_path: Path) -> None: | ||||
|         # issue 1597 | ||||
|         with Image.open("Tests/images/rdf.tif") as im: | ||||
|             out = str(tmp_path / "temp.tif") | ||||
|  | @ -690,7 +691,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|             im.save(out, format="TIFF") | ||||
|         TiffImagePlugin.WRITE_LIBTIFF = False | ||||
| 
 | ||||
|     def test_page_number_x_0(self, tmp_path): | ||||
|     def test_page_number_x_0(self, tmp_path: Path) -> None: | ||||
|         # Issue 973 | ||||
|         # Test TIFF with tag 297 (Page Number) having value of 0 0. | ||||
|         # The first number is the current page number. | ||||
|  | @ -704,7 +705,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|             # Should not divide by zero | ||||
|             im.save(outfile) | ||||
| 
 | ||||
|     def test_fd_duplication(self, tmp_path): | ||||
|     def test_fd_duplication(self, tmp_path: Path) -> None: | ||||
|         # https://github.com/python-pillow/Pillow/issues/1651 | ||||
| 
 | ||||
|         tmpfile = str(tmp_path / "temp.tif") | ||||
|  | @ -718,7 +719,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|         # Should not raise PermissionError. | ||||
|         os.remove(tmpfile) | ||||
| 
 | ||||
|     def test_read_icc(self): | ||||
|     def test_read_icc(self) -> None: | ||||
|         with Image.open("Tests/images/hopper.iccprofile.tif") as img: | ||||
|             icc = img.info.get("icc_profile") | ||||
|             assert icc is not None | ||||
|  | @ -729,8 +730,8 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|         TiffImagePlugin.READ_LIBTIFF = False | ||||
|         assert icc == icc_libtiff | ||||
| 
 | ||||
|     def test_write_icc(self, tmp_path): | ||||
|         def check_write(libtiff): | ||||
|     def test_write_icc(self, tmp_path: Path) -> None: | ||||
|         def check_write(libtiff) -> None: | ||||
|             TiffImagePlugin.WRITE_LIBTIFF = libtiff | ||||
| 
 | ||||
|             with Image.open("Tests/images/hopper.iccprofile.tif") as img: | ||||
|  | @ -749,7 +750,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|         for libtiff in libtiffs: | ||||
|             check_write(libtiff) | ||||
| 
 | ||||
|     def test_multipage_compression(self): | ||||
|     def test_multipage_compression(self) -> None: | ||||
|         with Image.open("Tests/images/compression.tif") as im: | ||||
|             im.seek(0) | ||||
|             assert im._compression == "tiff_ccitt" | ||||
|  | @ -765,7 +766,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|             assert im.size == (10, 10) | ||||
|             im.load() | ||||
| 
 | ||||
|     def test_save_tiff_with_jpegtables(self, tmp_path): | ||||
|     def test_save_tiff_with_jpegtables(self, tmp_path: Path) -> None: | ||||
|         # Arrange | ||||
|         outfile = str(tmp_path / "temp.tif") | ||||
| 
 | ||||
|  | @ -777,7 +778,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|             # Should not raise UnicodeDecodeError or anything else | ||||
|             im.save(outfile) | ||||
| 
 | ||||
|     def test_16bit_RGB_tiff(self): | ||||
|     def test_16bit_RGB_tiff(self) -> None: | ||||
|         with Image.open("Tests/images/tiff_16bit_RGB.tiff") as im: | ||||
|             assert im.mode == "RGB" | ||||
|             assert im.size == (100, 40) | ||||
|  | @ -793,7 +794,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
| 
 | ||||
|             assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGB_target.png") | ||||
| 
 | ||||
|     def test_16bit_RGBa_tiff(self): | ||||
|     def test_16bit_RGBa_tiff(self) -> None: | ||||
|         with Image.open("Tests/images/tiff_16bit_RGBa.tiff") as im: | ||||
|             assert im.mode == "RGBA" | ||||
|             assert im.size == (100, 40) | ||||
|  | @ -805,7 +806,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|             assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGBa_target.png") | ||||
| 
 | ||||
|     @skip_unless_feature("jpg") | ||||
|     def test_gimp_tiff(self): | ||||
|     def test_gimp_tiff(self) -> None: | ||||
|         # Read TIFF JPEG images from GIMP [@PIL168] | ||||
|         filename = "Tests/images/pil168.tif" | ||||
|         with Image.open(filename) as im: | ||||
|  | @ -818,14 +819,14 @@ class TestFileLibTiff(LibTiffTestCase): | |||
| 
 | ||||
|             assert_image_equal_tofile(im, "Tests/images/pil168.png") | ||||
| 
 | ||||
|     def test_sampleformat(self): | ||||
|     def test_sampleformat(self) -> None: | ||||
|         # https://github.com/python-pillow/Pillow/issues/1466 | ||||
|         with Image.open("Tests/images/copyleft.tiff") as im: | ||||
|             assert im.mode == "RGB" | ||||
| 
 | ||||
|             assert_image_equal_tofile(im, "Tests/images/copyleft.png", mode="RGB") | ||||
| 
 | ||||
|     def test_sampleformat_write(self, tmp_path): | ||||
|     def test_sampleformat_write(self, tmp_path: Path) -> None: | ||||
|         im = Image.new("F", (1, 1)) | ||||
|         out = str(tmp_path / "temp.tif") | ||||
|         TiffImagePlugin.WRITE_LIBTIFF = True | ||||
|  | @ -874,7 +875,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|             sys.stderr.write(captured.err) | ||||
|             raise | ||||
| 
 | ||||
|     def test_lzw(self): | ||||
|     def test_lzw(self) -> None: | ||||
|         with Image.open("Tests/images/hopper_lzw.tif") as im: | ||||
|             assert im.mode == "RGB" | ||||
|             assert im.size == (128, 128) | ||||
|  | @ -882,12 +883,12 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|             im2 = hopper() | ||||
|             assert_image_similar(im, im2, 5) | ||||
| 
 | ||||
|     def test_strip_cmyk_jpeg(self): | ||||
|     def test_strip_cmyk_jpeg(self) -> None: | ||||
|         infile = "Tests/images/tiff_strip_cmyk_jpeg.tif" | ||||
|         with Image.open(infile) as im: | ||||
|             assert_image_similar_tofile(im, "Tests/images/pil_sample_cmyk.jpg", 0.5) | ||||
| 
 | ||||
|     def test_strip_cmyk_16l_jpeg(self): | ||||
|     def test_strip_cmyk_16l_jpeg(self) -> None: | ||||
|         infile = "Tests/images/tiff_strip_cmyk_16l_jpeg.tif" | ||||
|         with Image.open(infile) as im: | ||||
|             assert_image_similar_tofile(im, "Tests/images/pil_sample_cmyk.jpg", 0.5) | ||||
|  | @ -895,7 +896,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|     @mark_if_feature_version( | ||||
|         pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" | ||||
|     ) | ||||
|     def test_strip_ycbcr_jpeg_2x2_sampling(self): | ||||
|     def test_strip_ycbcr_jpeg_2x2_sampling(self) -> None: | ||||
|         infile = "Tests/images/tiff_strip_ycbcr_jpeg_2x2_sampling.tif" | ||||
|         with Image.open(infile) as im: | ||||
|             assert_image_similar_tofile(im, "Tests/images/flower.jpg", 1.2) | ||||
|  | @ -903,12 +904,12 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|     @mark_if_feature_version( | ||||
|         pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" | ||||
|     ) | ||||
|     def test_strip_ycbcr_jpeg_1x1_sampling(self): | ||||
|     def test_strip_ycbcr_jpeg_1x1_sampling(self) -> None: | ||||
|         infile = "Tests/images/tiff_strip_ycbcr_jpeg_1x1_sampling.tif" | ||||
|         with Image.open(infile) as im: | ||||
|             assert_image_similar_tofile(im, "Tests/images/flower2.jpg", 0.01) | ||||
| 
 | ||||
|     def test_tiled_cmyk_jpeg(self): | ||||
|     def test_tiled_cmyk_jpeg(self) -> None: | ||||
|         infile = "Tests/images/tiff_tiled_cmyk_jpeg.tif" | ||||
|         with Image.open(infile) as im: | ||||
|             assert_image_similar_tofile(im, "Tests/images/pil_sample_cmyk.jpg", 0.5) | ||||
|  | @ -916,7 +917,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|     @mark_if_feature_version( | ||||
|         pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" | ||||
|     ) | ||||
|     def test_tiled_ycbcr_jpeg_1x1_sampling(self): | ||||
|     def test_tiled_ycbcr_jpeg_1x1_sampling(self) -> None: | ||||
|         infile = "Tests/images/tiff_tiled_ycbcr_jpeg_1x1_sampling.tif" | ||||
|         with Image.open(infile) as im: | ||||
|             assert_image_similar_tofile(im, "Tests/images/flower2.jpg", 0.01) | ||||
|  | @ -924,45 +925,45 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|     @mark_if_feature_version( | ||||
|         pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" | ||||
|     ) | ||||
|     def test_tiled_ycbcr_jpeg_2x2_sampling(self): | ||||
|     def test_tiled_ycbcr_jpeg_2x2_sampling(self) -> None: | ||||
|         infile = "Tests/images/tiff_tiled_ycbcr_jpeg_2x2_sampling.tif" | ||||
|         with Image.open(infile) as im: | ||||
|             assert_image_similar_tofile(im, "Tests/images/flower.jpg", 1.5) | ||||
| 
 | ||||
|     def test_strip_planar_rgb(self): | ||||
|     def test_strip_planar_rgb(self) -> None: | ||||
|         # gdal_translate -co TILED=no -co INTERLEAVE=BAND -co COMPRESS=LZW \ | ||||
|         # tiff_strip_raw.tif tiff_strip_planar_lzw.tiff | ||||
|         infile = "Tests/images/tiff_strip_planar_lzw.tiff" | ||||
|         with Image.open(infile) as im: | ||||
|             assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png") | ||||
| 
 | ||||
|     def test_tiled_planar_rgb(self): | ||||
|     def test_tiled_planar_rgb(self) -> None: | ||||
|         # gdal_translate -co TILED=yes -co INTERLEAVE=BAND -co COMPRESS=LZW \ | ||||
|         # tiff_tiled_raw.tif tiff_tiled_planar_lzw.tiff | ||||
|         infile = "Tests/images/tiff_tiled_planar_lzw.tiff" | ||||
|         with Image.open(infile) as im: | ||||
|             assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png") | ||||
| 
 | ||||
|     def test_tiled_planar_16bit_RGB(self): | ||||
|     def test_tiled_planar_16bit_RGB(self) -> None: | ||||
|         # gdal_translate -co TILED=yes -co INTERLEAVE=BAND -co COMPRESS=LZW \ | ||||
|         # tiff_16bit_RGB.tiff tiff_tiled_planar_16bit_RGB.tiff | ||||
|         with Image.open("Tests/images/tiff_tiled_planar_16bit_RGB.tiff") as im: | ||||
|             assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGB_target.png") | ||||
| 
 | ||||
|     def test_strip_planar_16bit_RGB(self): | ||||
|     def test_strip_planar_16bit_RGB(self) -> None: | ||||
|         # gdal_translate -co TILED=no -co INTERLEAVE=BAND -co COMPRESS=LZW \ | ||||
|         # tiff_16bit_RGB.tiff tiff_strip_planar_16bit_RGB.tiff | ||||
|         with Image.open("Tests/images/tiff_strip_planar_16bit_RGB.tiff") as im: | ||||
|             assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGB_target.png") | ||||
| 
 | ||||
|     def test_tiled_planar_16bit_RGBa(self): | ||||
|     def test_tiled_planar_16bit_RGBa(self) -> None: | ||||
|         # gdal_translate -co TILED=yes \ | ||||
|         # -co INTERLEAVE=BAND -co COMPRESS=LZW -co ALPHA=PREMULTIPLIED \ | ||||
|         # tiff_16bit_RGBa.tiff tiff_tiled_planar_16bit_RGBa.tiff | ||||
|         with Image.open("Tests/images/tiff_tiled_planar_16bit_RGBa.tiff") as im: | ||||
|             assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGBa_target.png") | ||||
| 
 | ||||
|     def test_strip_planar_16bit_RGBa(self): | ||||
|     def test_strip_planar_16bit_RGBa(self) -> None: | ||||
|         # gdal_translate -co TILED=no \ | ||||
|         # -co INTERLEAVE=BAND -co COMPRESS=LZW -co ALPHA=PREMULTIPLIED \ | ||||
|         # tiff_16bit_RGBa.tiff tiff_strip_planar_16bit_RGBa.tiff | ||||
|  | @ -970,7 +971,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|             assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGBa_target.png") | ||||
| 
 | ||||
|     @pytest.mark.parametrize("compression", (None, "jpeg")) | ||||
|     def test_block_tile_tags(self, compression, tmp_path): | ||||
|     def test_block_tile_tags(self, compression, tmp_path: Path) -> None: | ||||
|         im = hopper() | ||||
|         out = str(tmp_path / "temp.tif") | ||||
| 
 | ||||
|  | @ -986,11 +987,11 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|             for tag in tags: | ||||
|                 assert tag not in reloaded.getexif() | ||||
| 
 | ||||
|     def test_old_style_jpeg(self): | ||||
|     def test_old_style_jpeg(self) -> None: | ||||
|         with Image.open("Tests/images/old-style-jpeg-compression.tif") as im: | ||||
|             assert_image_equal_tofile(im, "Tests/images/old-style-jpeg-compression.png") | ||||
| 
 | ||||
|     def test_open_missing_samplesperpixel(self): | ||||
|     def test_open_missing_samplesperpixel(self) -> None: | ||||
|         with Image.open( | ||||
|             "Tests/images/old-style-jpeg-compression-no-samplesperpixel.tif" | ||||
|         ) as im: | ||||
|  | @ -1019,21 +1020,21 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|             ), | ||||
|         ], | ||||
|     ) | ||||
|     def test_wrong_bits_per_sample(self, file_name, mode, size, tile): | ||||
|     def test_wrong_bits_per_sample(self, file_name, mode, size, tile) -> None: | ||||
|         with Image.open("Tests/images/" + file_name) as im: | ||||
|             assert im.mode == mode | ||||
|             assert im.size == size | ||||
|             assert im.tile == tile | ||||
|             im.load() | ||||
| 
 | ||||
|     def test_no_rows_per_strip(self): | ||||
|     def test_no_rows_per_strip(self) -> None: | ||||
|         # This image does not have a RowsPerStrip TIFF tag | ||||
|         infile = "Tests/images/no_rows_per_strip.tif" | ||||
|         with Image.open(infile) as im: | ||||
|             im.load() | ||||
|         assert im.size == (950, 975) | ||||
| 
 | ||||
|     def test_orientation(self): | ||||
|     def test_orientation(self) -> None: | ||||
|         with Image.open("Tests/images/g4_orientation_1.tif") as base_im: | ||||
|             for i in range(2, 9): | ||||
|                 with Image.open("Tests/images/g4_orientation_" + str(i) + ".tif") as im: | ||||
|  | @ -1044,7 +1045,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
| 
 | ||||
|                     assert_image_similar(base_im, im, 0.7) | ||||
| 
 | ||||
|     def test_exif_transpose(self): | ||||
|     def test_exif_transpose(self) -> None: | ||||
|         with Image.open("Tests/images/g4_orientation_1.tif") as base_im: | ||||
|             for i in range(2, 9): | ||||
|                 with Image.open("Tests/images/g4_orientation_" + str(i) + ".tif") as im: | ||||
|  | @ -1053,7 +1054,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|                     assert_image_similar(base_im, im, 0.7) | ||||
| 
 | ||||
|     @pytest.mark.valgrind_known_error(reason="Backtrace in Python Core") | ||||
|     def test_sampleformat_not_corrupted(self): | ||||
|     def test_sampleformat_not_corrupted(self) -> None: | ||||
|         # Assert that a TIFF image with SampleFormat=UINT tag is not corrupted | ||||
|         # when saving to a new file. | ||||
|         # Pillow 6.0 fails with "OSError: cannot identify image file". | ||||
|  | @ -1074,7 +1075,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|         with Image.open(out) as im: | ||||
|             im.load() | ||||
| 
 | ||||
|     def test_realloc_overflow(self): | ||||
|     def test_realloc_overflow(self) -> None: | ||||
|         TiffImagePlugin.READ_LIBTIFF = True | ||||
|         with Image.open("Tests/images/tiff_overflow_rows_per_strip.tif") as im: | ||||
|             with pytest.raises(OSError) as e: | ||||
|  | @ -1085,7 +1086,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|         TiffImagePlugin.READ_LIBTIFF = False | ||||
| 
 | ||||
|     @pytest.mark.parametrize("compression", ("tiff_adobe_deflate", "jpeg")) | ||||
|     def test_save_multistrip(self, compression, tmp_path): | ||||
|     def test_save_multistrip(self, compression, tmp_path: Path) -> None: | ||||
|         im = hopper("RGB").resize((256, 256)) | ||||
|         out = str(tmp_path / "temp.tif") | ||||
|         im.save(out, compression=compression) | ||||
|  | @ -1095,7 +1096,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|             assert len(im.tag_v2[STRIPOFFSETS]) > 1 | ||||
| 
 | ||||
|     @pytest.mark.parametrize("argument", (True, False)) | ||||
|     def test_save_single_strip(self, argument, tmp_path): | ||||
|     def test_save_single_strip(self, argument, tmp_path: Path) -> None: | ||||
|         im = hopper("RGB").resize((256, 256)) | ||||
|         out = str(tmp_path / "temp.tif") | ||||
| 
 | ||||
|  | @ -1113,13 +1114,13 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|             TiffImagePlugin.STRIP_SIZE = 65536 | ||||
| 
 | ||||
|     @pytest.mark.parametrize("compression", ("tiff_adobe_deflate", None)) | ||||
|     def test_save_zero(self, compression, tmp_path): | ||||
|     def test_save_zero(self, compression, tmp_path: Path) -> None: | ||||
|         im = Image.new("RGB", (0, 0)) | ||||
|         out = str(tmp_path / "temp.tif") | ||||
|         with pytest.raises(SystemError): | ||||
|             im.save(out, compression=compression) | ||||
| 
 | ||||
|     def test_save_many_compressed(self, tmp_path): | ||||
|     def test_save_many_compressed(self, tmp_path: Path) -> None: | ||||
|         im = hopper() | ||||
|         out = str(tmp_path / "temp.tif") | ||||
|         for _ in range(10000): | ||||
|  | @ -1133,7 +1134,7 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|             ("Tests/images/child_ifd_jpeg.tiff", (20,)), | ||||
|         ), | ||||
|     ) | ||||
|     def test_get_child_images(self, path, sizes): | ||||
|     def test_get_child_images(self, path, sizes) -> None: | ||||
|         with Image.open(path) as im: | ||||
|             ims = im.get_child_images() | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| from io import BytesIO | ||||
| from pathlib import Path | ||||
| 
 | ||||
| from PIL import Image | ||||
| 
 | ||||
|  | @ -17,7 +18,7 @@ class TestFileLibTiffSmall(LibTiffTestCase): | |||
|     file just before reading in libtiff. These tests remain | ||||
|     to ensure that it stays fixed.""" | ||||
| 
 | ||||
|     def test_g4_hopper_file(self, tmp_path): | ||||
|     def test_g4_hopper_file(self, tmp_path: Path) -> None: | ||||
|         """Testing the open file load path""" | ||||
| 
 | ||||
|         test_file = "Tests/images/hopper_g4.tif" | ||||
|  | @ -26,7 +27,7 @@ class TestFileLibTiffSmall(LibTiffTestCase): | |||
|                 assert im.size == (128, 128) | ||||
|                 self._assert_noerr(tmp_path, im) | ||||
| 
 | ||||
|     def test_g4_hopper_bytesio(self, tmp_path): | ||||
|     def test_g4_hopper_bytesio(self, tmp_path: Path) -> None: | ||||
|         """Testing the bytesio loading code path""" | ||||
|         test_file = "Tests/images/hopper_g4.tif" | ||||
|         s = BytesIO() | ||||
|  | @ -37,7 +38,7 @@ class TestFileLibTiffSmall(LibTiffTestCase): | |||
|             assert im.size == (128, 128) | ||||
|             self._assert_noerr(tmp_path, im) | ||||
| 
 | ||||
|     def test_g4_hopper(self, tmp_path): | ||||
|     def test_g4_hopper(self, tmp_path: Path) -> None: | ||||
|         """The 128x128 lena image failed for some reason.""" | ||||
| 
 | ||||
|         test_file = "Tests/images/hopper_g4.tif" | ||||
|  |  | |||
|  | @ -7,14 +7,14 @@ from PIL import Image, McIdasImagePlugin | |||
| from .helper import assert_image_equal_tofile | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     invalid_file = "Tests/images/flower.jpg" | ||||
| 
 | ||||
|     with pytest.raises(SyntaxError): | ||||
|         McIdasImagePlugin.McIdasImageFile(invalid_file) | ||||
| 
 | ||||
| 
 | ||||
| def test_valid_file(): | ||||
| def test_valid_file() -> None: | ||||
|     # Arrange | ||||
|     # https://ghrc.nsstc.nasa.gov/hydro/details/cmx3g8 | ||||
|     # https://ghrc.nsstc.nasa.gov/pub/fieldCampaigns/camex3/cmx3g8/browse/ | ||||
|  |  | |||
|  | @ -13,7 +13,7 @@ pytestmark = skip_unless_feature("libtiff") | |||
| TEST_FILE = "Tests/images/hopper.mic" | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(): | ||||
| def test_sanity() -> None: | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         im.load() | ||||
|         assert im.mode == "RGBA" | ||||
|  | @ -28,22 +28,22 @@ def test_sanity(): | |||
|         assert_image_similar(im, im2, 10) | ||||
| 
 | ||||
| 
 | ||||
| def test_n_frames(): | ||||
| def test_n_frames() -> None: | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         assert im.n_frames == 1 | ||||
| 
 | ||||
| 
 | ||||
| def test_is_animated(): | ||||
| def test_is_animated() -> None: | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         assert not im.is_animated | ||||
| 
 | ||||
| 
 | ||||
| def test_tell(): | ||||
| def test_tell() -> None: | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         assert im.tell() == 0 | ||||
| 
 | ||||
| 
 | ||||
| def test_seek(): | ||||
| def test_seek() -> None: | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         im.seek(0) | ||||
|         assert im.tell() == 0 | ||||
|  | @ -53,7 +53,7 @@ def test_seek(): | |||
|         assert im.tell() == 0 | ||||
| 
 | ||||
| 
 | ||||
| def test_close(): | ||||
| def test_close() -> None: | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         pass | ||||
|     assert im.ole.fp.closed | ||||
|  | @ -63,7 +63,7 @@ def test_close(): | |||
|     assert im.ole.fp.closed | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     # Test an invalid OLE file | ||||
|     invalid_file = "Tests/images/flower.jpg" | ||||
|     with pytest.raises(SyntaxError): | ||||
|  |  | |||
|  | @ -30,7 +30,7 @@ def roundtrip(im, **options): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("test_file", test_files) | ||||
| def test_sanity(test_file): | ||||
| def test_sanity(test_file) -> None: | ||||
|     with Image.open(test_file) as im: | ||||
|         im.load() | ||||
|         assert im.mode == "RGB" | ||||
|  | @ -39,8 +39,8 @@ def test_sanity(test_file): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.skipif(is_pypy(), reason="Requires CPython") | ||||
| def test_unclosed_file(): | ||||
|     def open(): | ||||
| def test_unclosed_file() -> None: | ||||
|     def open() -> None: | ||||
|         im = Image.open(test_files[0]) | ||||
|         im.load() | ||||
| 
 | ||||
|  | @ -48,14 +48,14 @@ def test_unclosed_file(): | |||
|         open() | ||||
| 
 | ||||
| 
 | ||||
| def test_closed_file(): | ||||
| def test_closed_file() -> None: | ||||
|     with warnings.catch_warnings(): | ||||
|         im = Image.open(test_files[0]) | ||||
|         im.load() | ||||
|         im.close() | ||||
| 
 | ||||
| 
 | ||||
| def test_seek_after_close(): | ||||
| def test_seek_after_close() -> None: | ||||
|     im = Image.open(test_files[0]) | ||||
|     im.close() | ||||
| 
 | ||||
|  | @ -63,14 +63,14 @@ def test_seek_after_close(): | |||
|         im.seek(1) | ||||
| 
 | ||||
| 
 | ||||
| def test_context_manager(): | ||||
| def test_context_manager() -> None: | ||||
|     with warnings.catch_warnings(): | ||||
|         with Image.open(test_files[0]) as im: | ||||
|             im.load() | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("test_file", test_files) | ||||
| def test_app(test_file): | ||||
| def test_app(test_file) -> None: | ||||
|     # Test APP/COM reader (@PIL135) | ||||
|     with Image.open(test_file) as im: | ||||
|         assert im.applist[0][0] == "APP1" | ||||
|  | @ -82,7 +82,7 @@ def test_app(test_file): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("test_file", test_files) | ||||
| def test_exif(test_file): | ||||
| def test_exif(test_file) -> None: | ||||
|     with Image.open(test_file) as im_original: | ||||
|         im_reloaded = roundtrip(im_original, save_all=True, exif=im_original.getexif()) | ||||
| 
 | ||||
|  | @ -93,7 +93,7 @@ def test_exif(test_file): | |||
|         assert info[34665] == 188 | ||||
| 
 | ||||
| 
 | ||||
| def test_frame_size(): | ||||
| def test_frame_size() -> None: | ||||
|     # This image has been hexedited to contain a different size | ||||
|     # in the EXIF data of the second frame | ||||
|     with Image.open("Tests/images/sugarshack_frame_size.mpo") as im: | ||||
|  | @ -106,7 +106,7 @@ def test_frame_size(): | |||
|         assert im.size == (640, 480) | ||||
| 
 | ||||
| 
 | ||||
| def test_ignore_frame_size(): | ||||
| def test_ignore_frame_size() -> None: | ||||
|     # Ignore the different size of the second frame | ||||
|     # since this is not a "Large Thumbnail" image | ||||
|     with Image.open("Tests/images/ignore_frame_size.mpo") as im: | ||||
|  | @ -120,7 +120,7 @@ def test_ignore_frame_size(): | |||
|         assert im.size == (64, 64) | ||||
| 
 | ||||
| 
 | ||||
| def test_parallax(): | ||||
| def test_parallax() -> None: | ||||
|     # Nintendo | ||||
|     with Image.open("Tests/images/sugarshack.mpo") as im: | ||||
|         exif = im.getexif() | ||||
|  | @ -133,7 +133,7 @@ def test_parallax(): | |||
|         assert exif.get_ifd(0x927C)[0xB211] == -3.125 | ||||
| 
 | ||||
| 
 | ||||
| def test_reload_exif_after_seek(): | ||||
| def test_reload_exif_after_seek() -> None: | ||||
|     with Image.open("Tests/images/sugarshack.mpo") as im: | ||||
|         exif = im.getexif() | ||||
|         del exif[296] | ||||
|  | @ -143,14 +143,14 @@ def test_reload_exif_after_seek(): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("test_file", test_files) | ||||
| def test_mp(test_file): | ||||
| def test_mp(test_file) -> None: | ||||
|     with Image.open(test_file) as im: | ||||
|         mpinfo = im._getmp() | ||||
|         assert mpinfo[45056] == b"0100" | ||||
|         assert mpinfo[45057] == 2 | ||||
| 
 | ||||
| 
 | ||||
| def test_mp_offset(): | ||||
| def test_mp_offset() -> None: | ||||
|     # This image has been manually hexedited to have an IFD offset of 10 | ||||
|     # in APP2 data, in contrast to normal 8 | ||||
|     with Image.open("Tests/images/sugarshack_ifd_offset.mpo") as im: | ||||
|  | @ -159,7 +159,7 @@ def test_mp_offset(): | |||
|         assert mpinfo[45057] == 2 | ||||
| 
 | ||||
| 
 | ||||
| def test_mp_no_data(): | ||||
| def test_mp_no_data() -> None: | ||||
|     # This image has been manually hexedited to have the second frame | ||||
|     # beyond the end of the file | ||||
|     with Image.open("Tests/images/sugarshack_no_data.mpo") as im: | ||||
|  | @ -168,7 +168,7 @@ def test_mp_no_data(): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("test_file", test_files) | ||||
| def test_mp_attribute(test_file): | ||||
| def test_mp_attribute(test_file) -> None: | ||||
|     with Image.open(test_file) as im: | ||||
|         mpinfo = im._getmp() | ||||
|     for frame_number, mpentry in enumerate(mpinfo[0xB002]): | ||||
|  | @ -185,7 +185,7 @@ def test_mp_attribute(test_file): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("test_file", test_files) | ||||
| def test_seek(test_file): | ||||
| def test_seek(test_file) -> None: | ||||
|     with Image.open(test_file) as im: | ||||
|         assert im.tell() == 0 | ||||
|         # prior to first image raises an error, both blatant and borderline | ||||
|  | @ -209,13 +209,13 @@ def test_seek(test_file): | |||
|         assert im.tell() == 0 | ||||
| 
 | ||||
| 
 | ||||
| def test_n_frames(): | ||||
| def test_n_frames() -> None: | ||||
|     with Image.open("Tests/images/sugarshack.mpo") as im: | ||||
|         assert im.n_frames == 2 | ||||
|         assert im.is_animated | ||||
| 
 | ||||
| 
 | ||||
| def test_eoferror(): | ||||
| def test_eoferror() -> None: | ||||
|     with Image.open("Tests/images/sugarshack.mpo") as im: | ||||
|         n_frames = im.n_frames | ||||
| 
 | ||||
|  | @ -229,7 +229,7 @@ def test_eoferror(): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("test_file", test_files) | ||||
| def test_image_grab(test_file): | ||||
| def test_image_grab(test_file) -> None: | ||||
|     with Image.open(test_file) as im: | ||||
|         assert im.tell() == 0 | ||||
|         im0 = im.tobytes() | ||||
|  | @ -244,7 +244,7 @@ def test_image_grab(test_file): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("test_file", test_files) | ||||
| def test_save(test_file): | ||||
| def test_save(test_file) -> None: | ||||
|     with Image.open(test_file) as im: | ||||
|         assert im.tell() == 0 | ||||
|         jpg0 = roundtrip(im) | ||||
|  | @ -255,7 +255,7 @@ def test_save(test_file): | |||
|         assert_image_similar(im, jpg1, 30) | ||||
| 
 | ||||
| 
 | ||||
| def test_save_all(): | ||||
| def test_save_all() -> None: | ||||
|     for test_file in test_files: | ||||
|         with Image.open(test_file) as im: | ||||
|             im_reloaded = roundtrip(im, save_all=True) | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| import os | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -13,7 +14,7 @@ EXTRA_DIR = "Tests/images/picins" | |||
| YA_EXTRA_DIR = "Tests/images/msp" | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(tmp_path): | ||||
| def test_sanity(tmp_path: Path) -> None: | ||||
|     test_file = str(tmp_path / "temp.msp") | ||||
| 
 | ||||
|     hopper("1").save(test_file) | ||||
|  | @ -25,14 +26,14 @@ def test_sanity(tmp_path): | |||
|         assert im.format == "MSP" | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     invalid_file = "Tests/images/flower.jpg" | ||||
| 
 | ||||
|     with pytest.raises(SyntaxError): | ||||
|         MspImagePlugin.MspImageFile(invalid_file) | ||||
| 
 | ||||
| 
 | ||||
| def test_bad_checksum(): | ||||
| def test_bad_checksum() -> None: | ||||
|     # Arrange | ||||
|     # This was created by forcing Pillow to save with checksum=0 | ||||
|     bad_checksum = "Tests/images/hopper_bad_checksum.msp" | ||||
|  | @ -42,7 +43,7 @@ def test_bad_checksum(): | |||
|         MspImagePlugin.MspImageFile(bad_checksum) | ||||
| 
 | ||||
| 
 | ||||
| def test_open_windows_v1(): | ||||
| def test_open_windows_v1() -> None: | ||||
|     # Arrange | ||||
|     # Act | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|  | @ -51,7 +52,7 @@ def test_open_windows_v1(): | |||
|         assert isinstance(im, MspImagePlugin.MspImageFile) | ||||
| 
 | ||||
| 
 | ||||
| def _assert_file_image_equal(source_path, target_path): | ||||
| def _assert_file_image_equal(source_path, target_path) -> None: | ||||
|     with Image.open(source_path) as im: | ||||
|         assert_image_equal_tofile(im, target_path) | ||||
| 
 | ||||
|  | @ -59,7 +60,7 @@ def _assert_file_image_equal(source_path, target_path): | |||
| @pytest.mark.skipif( | ||||
|     not os.path.exists(EXTRA_DIR), reason="Extra image files not installed" | ||||
| ) | ||||
| def test_open_windows_v2(): | ||||
| def test_open_windows_v2() -> None: | ||||
|     files = ( | ||||
|         os.path.join(EXTRA_DIR, f) | ||||
|         for f in os.listdir(EXTRA_DIR) | ||||
|  | @ -72,7 +73,7 @@ def test_open_windows_v2(): | |||
| @pytest.mark.skipif( | ||||
|     not os.path.exists(YA_EXTRA_DIR), reason="Even More Extra image files not installed" | ||||
| ) | ||||
| def test_msp_v2(): | ||||
| def test_msp_v2() -> None: | ||||
|     for f in os.listdir(YA_EXTRA_DIR): | ||||
|         if ".MSP" not in f: | ||||
|             continue | ||||
|  | @ -80,7 +81,7 @@ def test_msp_v2(): | |||
|         _assert_file_image_equal(path, path.replace(".MSP", ".png")) | ||||
| 
 | ||||
| 
 | ||||
| def test_cannot_save_wrong_mode(tmp_path): | ||||
| def test_cannot_save_wrong_mode(tmp_path: Path) -> None: | ||||
|     # Arrange | ||||
|     im = hopper() | ||||
|     filename = str(tmp_path / "temp.msp") | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ from __future__ import annotations | |||
| 
 | ||||
| import os.path | ||||
| import subprocess | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -10,7 +11,7 @@ from PIL import Image | |||
| from .helper import assert_image_equal, hopper, magick_command | ||||
| 
 | ||||
| 
 | ||||
| def helper_save_as_palm(tmp_path, mode): | ||||
| def helper_save_as_palm(tmp_path: Path, mode) -> None: | ||||
|     # Arrange | ||||
|     im = hopper(mode) | ||||
|     outfile = str(tmp_path / ("temp_" + mode + ".palm")) | ||||
|  | @ -23,7 +24,7 @@ def helper_save_as_palm(tmp_path, mode): | |||
|     assert os.path.getsize(outfile) > 0 | ||||
| 
 | ||||
| 
 | ||||
| def open_with_magick(magick, tmp_path, f): | ||||
| def open_with_magick(magick, tmp_path: Path, f): | ||||
|     outfile = str(tmp_path / "temp.png") | ||||
|     rc = subprocess.call( | ||||
|         magick + [f, outfile], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT | ||||
|  | @ -32,7 +33,7 @@ def open_with_magick(magick, tmp_path, f): | |||
|     return Image.open(outfile) | ||||
| 
 | ||||
| 
 | ||||
| def roundtrip(tmp_path, mode): | ||||
| def roundtrip(tmp_path: Path, mode) -> None: | ||||
|     magick = magick_command() | ||||
|     if not magick: | ||||
|         return | ||||
|  | @ -45,7 +46,7 @@ def roundtrip(tmp_path, mode): | |||
|     assert_image_equal(converted, im) | ||||
| 
 | ||||
| 
 | ||||
| def test_monochrome(tmp_path): | ||||
| def test_monochrome(tmp_path: Path) -> None: | ||||
|     # Arrange | ||||
|     mode = "1" | ||||
| 
 | ||||
|  | @ -55,7 +56,7 @@ def test_monochrome(tmp_path): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.xfail(reason="Palm P image is wrong") | ||||
| def test_p_mode(tmp_path): | ||||
| def test_p_mode(tmp_path: Path) -> None: | ||||
|     # Arrange | ||||
|     mode = "P" | ||||
| 
 | ||||
|  | @ -65,6 +66,6 @@ def test_p_mode(tmp_path): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("mode", ("L", "RGB")) | ||||
| def test_oserror(tmp_path, mode): | ||||
| def test_oserror(tmp_path: Path, mode) -> None: | ||||
|     with pytest.raises(OSError): | ||||
|         helper_save_as_palm(tmp_path, mode) | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ from __future__ import annotations | |||
| from PIL import Image | ||||
| 
 | ||||
| 
 | ||||
| def test_load_raw(): | ||||
| def test_load_raw() -> None: | ||||
|     with Image.open("Tests/images/hopper.pcd") as im: | ||||
|         im.load()  # should not segfault. | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
| from PIL import Image, ImageFile, PcxImagePlugin | ||||
|  | @ -7,7 +9,7 @@ from PIL import Image, ImageFile, PcxImagePlugin | |||
| from .helper import assert_image_equal, hopper | ||||
| 
 | ||||
| 
 | ||||
| def _roundtrip(tmp_path, im): | ||||
| def _roundtrip(tmp_path: Path, im) -> None: | ||||
|     f = str(tmp_path / "temp.pcx") | ||||
|     im.save(f) | ||||
|     with Image.open(f) as im2: | ||||
|  | @ -18,7 +20,7 @@ def _roundtrip(tmp_path, im): | |||
|         assert_image_equal(im2, im) | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(tmp_path): | ||||
| def test_sanity(tmp_path: Path) -> None: | ||||
|     for mode in ("1", "L", "P", "RGB"): | ||||
|         _roundtrip(tmp_path, hopper(mode)) | ||||
| 
 | ||||
|  | @ -34,7 +36,7 @@ def test_sanity(tmp_path): | |||
|         im.save(f) | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     invalid_file = "Tests/images/flower.jpg" | ||||
| 
 | ||||
|     with pytest.raises(SyntaxError): | ||||
|  | @ -42,7 +44,7 @@ def test_invalid_file(): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("mode", ("1", "L", "P", "RGB")) | ||||
| def test_odd(tmp_path, mode): | ||||
| def test_odd(tmp_path: Path, mode) -> None: | ||||
|     # See issue #523, odd sized images should have a stride that's even. | ||||
|     # Not that ImageMagick or GIMP write PCX that way. | ||||
|     # We were not handling properly. | ||||
|  | @ -51,7 +53,7 @@ def test_odd(tmp_path, mode): | |||
|     _roundtrip(tmp_path, hopper(mode).resize((511, 511))) | ||||
| 
 | ||||
| 
 | ||||
| def test_odd_read(): | ||||
| def test_odd_read() -> None: | ||||
|     # Reading an image with an odd stride, making it malformed | ||||
|     with Image.open("Tests/images/odd_stride.pcx") as im: | ||||
|         im.load() | ||||
|  | @ -59,7 +61,7 @@ def test_odd_read(): | |||
|         assert im.size == (371, 150) | ||||
| 
 | ||||
| 
 | ||||
| def test_pil184(): | ||||
| def test_pil184() -> None: | ||||
|     # Check reading of files where xmin/xmax is not zero. | ||||
| 
 | ||||
|     test_file = "Tests/images/pil184.pcx" | ||||
|  | @ -71,7 +73,7 @@ def test_pil184(): | |||
|         assert im.histogram()[0] + im.histogram()[255] == 447 * 144 | ||||
| 
 | ||||
| 
 | ||||
| def test_1px_width(tmp_path): | ||||
| def test_1px_width(tmp_path: Path) -> None: | ||||
|     im = Image.new("L", (1, 256)) | ||||
|     px = im.load() | ||||
|     for y in range(256): | ||||
|  | @ -79,7 +81,7 @@ def test_1px_width(tmp_path): | |||
|     _roundtrip(tmp_path, im) | ||||
| 
 | ||||
| 
 | ||||
| def test_large_count(tmp_path): | ||||
| def test_large_count(tmp_path: Path) -> None: | ||||
|     im = Image.new("L", (256, 1)) | ||||
|     px = im.load() | ||||
|     for x in range(256): | ||||
|  | @ -87,7 +89,7 @@ def test_large_count(tmp_path): | |||
|     _roundtrip(tmp_path, im) | ||||
| 
 | ||||
| 
 | ||||
| def _test_buffer_overflow(tmp_path, im, size=1024): | ||||
| def _test_buffer_overflow(tmp_path: Path, im, size: int = 1024) -> None: | ||||
|     _last = ImageFile.MAXBLOCK | ||||
|     ImageFile.MAXBLOCK = size | ||||
|     try: | ||||
|  | @ -96,7 +98,7 @@ def _test_buffer_overflow(tmp_path, im, size=1024): | |||
|         ImageFile.MAXBLOCK = _last | ||||
| 
 | ||||
| 
 | ||||
| def test_break_in_count_overflow(tmp_path): | ||||
| def test_break_in_count_overflow(tmp_path: Path) -> None: | ||||
|     im = Image.new("L", (256, 5)) | ||||
|     px = im.load() | ||||
|     for y in range(4): | ||||
|  | @ -105,7 +107,7 @@ def test_break_in_count_overflow(tmp_path): | |||
|     _test_buffer_overflow(tmp_path, im) | ||||
| 
 | ||||
| 
 | ||||
| def test_break_one_in_loop(tmp_path): | ||||
| def test_break_one_in_loop(tmp_path: Path) -> None: | ||||
|     im = Image.new("L", (256, 5)) | ||||
|     px = im.load() | ||||
|     for y in range(5): | ||||
|  | @ -114,7 +116,7 @@ def test_break_one_in_loop(tmp_path): | |||
|     _test_buffer_overflow(tmp_path, im) | ||||
| 
 | ||||
| 
 | ||||
| def test_break_many_in_loop(tmp_path): | ||||
| def test_break_many_in_loop(tmp_path: Path) -> None: | ||||
|     im = Image.new("L", (256, 5)) | ||||
|     px = im.load() | ||||
|     for y in range(4): | ||||
|  | @ -125,7 +127,7 @@ def test_break_many_in_loop(tmp_path): | |||
|     _test_buffer_overflow(tmp_path, im) | ||||
| 
 | ||||
| 
 | ||||
| def test_break_one_at_end(tmp_path): | ||||
| def test_break_one_at_end(tmp_path: Path) -> None: | ||||
|     im = Image.new("L", (256, 5)) | ||||
|     px = im.load() | ||||
|     for y in range(5): | ||||
|  | @ -135,7 +137,7 @@ def test_break_one_at_end(tmp_path): | |||
|     _test_buffer_overflow(tmp_path, im) | ||||
| 
 | ||||
| 
 | ||||
| def test_break_many_at_end(tmp_path): | ||||
| def test_break_many_at_end(tmp_path: Path) -> None: | ||||
|     im = Image.new("L", (256, 5)) | ||||
|     px = im.load() | ||||
|     for y in range(5): | ||||
|  | @ -147,7 +149,7 @@ def test_break_many_at_end(tmp_path): | |||
|     _test_buffer_overflow(tmp_path, im) | ||||
| 
 | ||||
| 
 | ||||
| def test_break_padding(tmp_path): | ||||
| def test_break_padding(tmp_path: Path) -> None: | ||||
|     im = Image.new("L", (257, 5)) | ||||
|     px = im.load() | ||||
|     for y in range(5): | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ import os.path | |||
| import tempfile | ||||
| import time | ||||
| from io import BytesIO | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -13,7 +14,7 @@ from PIL import Image, PdfParser, features | |||
| from .helper import hopper, mark_if_feature_version, skip_unless_feature | ||||
| 
 | ||||
| 
 | ||||
| def helper_save_as_pdf(tmp_path, mode, **kwargs): | ||||
| def helper_save_as_pdf(tmp_path: Path, mode, **kwargs): | ||||
|     # Arrange | ||||
|     im = hopper(mode) | ||||
|     outfile = str(tmp_path / ("temp_" + mode + ".pdf")) | ||||
|  | @ -40,17 +41,17 @@ def helper_save_as_pdf(tmp_path, mode, **kwargs): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("mode", ("L", "P", "RGB", "CMYK")) | ||||
| def test_save(tmp_path, mode): | ||||
| def test_save(tmp_path: Path, mode) -> None: | ||||
|     helper_save_as_pdf(tmp_path, mode) | ||||
| 
 | ||||
| 
 | ||||
| @skip_unless_feature("jpg_2000") | ||||
| @pytest.mark.parametrize("mode", ("LA", "RGBA")) | ||||
| def test_save_alpha(tmp_path, mode): | ||||
| def test_save_alpha(tmp_path: Path, mode) -> None: | ||||
|     helper_save_as_pdf(tmp_path, mode) | ||||
| 
 | ||||
| 
 | ||||
| def test_p_alpha(tmp_path): | ||||
| def test_p_alpha(tmp_path: Path) -> None: | ||||
|     # Arrange | ||||
|     outfile = str(tmp_path / "temp.pdf") | ||||
|     with Image.open("Tests/images/pil123p.png") as im: | ||||
|  | @ -66,7 +67,7 @@ def test_p_alpha(tmp_path): | |||
|     assert b"\n/SMask " in contents | ||||
| 
 | ||||
| 
 | ||||
| def test_monochrome(tmp_path): | ||||
| def test_monochrome(tmp_path: Path) -> None: | ||||
|     # Arrange | ||||
|     mode = "1" | ||||
| 
 | ||||
|  | @ -75,7 +76,7 @@ def test_monochrome(tmp_path): | |||
|     assert os.path.getsize(outfile) < (5000 if features.check("libtiff") else 15000) | ||||
| 
 | ||||
| 
 | ||||
| def test_unsupported_mode(tmp_path): | ||||
| def test_unsupported_mode(tmp_path: Path) -> None: | ||||
|     im = hopper("PA") | ||||
|     outfile = str(tmp_path / "temp_PA.pdf") | ||||
| 
 | ||||
|  | @ -83,7 +84,7 @@ def test_unsupported_mode(tmp_path): | |||
|         im.save(outfile) | ||||
| 
 | ||||
| 
 | ||||
| def test_resolution(tmp_path): | ||||
| def test_resolution(tmp_path: Path) -> None: | ||||
|     im = hopper() | ||||
| 
 | ||||
|     outfile = str(tmp_path / "temp.pdf") | ||||
|  | @ -111,7 +112,7 @@ def test_resolution(tmp_path): | |||
|         {"dpi": (75, 150), "resolution": 200}, | ||||
|     ), | ||||
| ) | ||||
| def test_dpi(params, tmp_path): | ||||
| def test_dpi(params, tmp_path: Path) -> None: | ||||
|     im = hopper() | ||||
| 
 | ||||
|     outfile = str(tmp_path / "temp.pdf") | ||||
|  | @ -135,7 +136,7 @@ def test_dpi(params, tmp_path): | |||
| @mark_if_feature_version( | ||||
|     pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" | ||||
| ) | ||||
| def test_save_all(tmp_path): | ||||
| def test_save_all(tmp_path: Path) -> None: | ||||
|     # Single frame image | ||||
|     helper_save_as_pdf(tmp_path, "RGB", save_all=True) | ||||
| 
 | ||||
|  | @ -171,7 +172,7 @@ def test_save_all(tmp_path): | |||
|     assert os.path.getsize(outfile) > 0 | ||||
| 
 | ||||
| 
 | ||||
| def test_save_all_progress(): | ||||
| def test_save_all_progress() -> None: | ||||
|     out = BytesIO() | ||||
|     progress = [] | ||||
| 
 | ||||
|  | @ -211,7 +212,7 @@ def test_save_all_progress(): | |||
|     assert progress == expected | ||||
| 
 | ||||
| 
 | ||||
| def test_multiframe_normal_save(tmp_path): | ||||
| def test_multiframe_normal_save(tmp_path: Path) -> None: | ||||
|     # Test saving a multiframe image without save_all | ||||
|     with Image.open("Tests/images/dispose_bgnd.gif") as im: | ||||
|         outfile = str(tmp_path / "temp.pdf") | ||||
|  | @ -221,7 +222,7 @@ def test_multiframe_normal_save(tmp_path): | |||
|     assert os.path.getsize(outfile) > 0 | ||||
| 
 | ||||
| 
 | ||||
| def test_pdf_open(tmp_path): | ||||
| def test_pdf_open(tmp_path: Path) -> None: | ||||
|     # fail on a buffer full of null bytes | ||||
|     with pytest.raises(PdfParser.PdfFormatError): | ||||
|         PdfParser.PdfParser(buf=bytearray(65536)) | ||||
|  | @ -258,14 +259,14 @@ def test_pdf_open(tmp_path): | |||
|             assert not hopper_pdf.should_close_file | ||||
| 
 | ||||
| 
 | ||||
| def test_pdf_append_fails_on_nonexistent_file(): | ||||
| def test_pdf_append_fails_on_nonexistent_file() -> None: | ||||
|     im = hopper("RGB") | ||||
|     with tempfile.TemporaryDirectory() as temp_dir: | ||||
|         with pytest.raises(OSError): | ||||
|             im.save(os.path.join(temp_dir, "nonexistent.pdf"), append=True) | ||||
| 
 | ||||
| 
 | ||||
| def check_pdf_pages_consistency(pdf): | ||||
| def check_pdf_pages_consistency(pdf) -> None: | ||||
|     pages_info = pdf.read_indirect(pdf.pages_ref) | ||||
|     assert b"Parent" not in pages_info | ||||
|     assert b"Kids" in pages_info | ||||
|  | @ -283,7 +284,7 @@ def check_pdf_pages_consistency(pdf): | |||
|     assert kids_not_used == [] | ||||
| 
 | ||||
| 
 | ||||
| def test_pdf_append(tmp_path): | ||||
| def test_pdf_append(tmp_path: Path) -> None: | ||||
|     # make a PDF file | ||||
|     pdf_filename = helper_save_as_pdf(tmp_path, "RGB", producer="PdfParser") | ||||
| 
 | ||||
|  | @ -334,7 +335,7 @@ def test_pdf_append(tmp_path): | |||
|         check_pdf_pages_consistency(pdf) | ||||
| 
 | ||||
| 
 | ||||
| def test_pdf_info(tmp_path): | ||||
| def test_pdf_info(tmp_path: Path) -> None: | ||||
|     # make a PDF file | ||||
|     pdf_filename = helper_save_as_pdf( | ||||
|         tmp_path, | ||||
|  | @ -363,7 +364,7 @@ def test_pdf_info(tmp_path): | |||
|         check_pdf_pages_consistency(pdf) | ||||
| 
 | ||||
| 
 | ||||
| def test_pdf_append_to_bytesio(): | ||||
| def test_pdf_append_to_bytesio() -> None: | ||||
|     im = hopper("RGB") | ||||
|     f = BytesIO() | ||||
|     im.save(f, format="PDF") | ||||
|  | @ -378,7 +379,7 @@ def test_pdf_append_to_bytesio(): | |||
| @pytest.mark.timeout(1) | ||||
| @pytest.mark.skipif("PILLOW_VALGRIND_TEST" in os.environ, reason="Valgrind is slower") | ||||
| @pytest.mark.parametrize("newline", (b"\r", b"\n")) | ||||
| def test_redos(newline): | ||||
| def test_redos(newline) -> None: | ||||
|     malicious = b" trailer<<>>" + newline * 3456 | ||||
| 
 | ||||
|     # This particular exception isn't relevant here. | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ from .helper import assert_image_similar, hopper | |||
| TEST_FILE = "Tests/images/hopper.pxr" | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(): | ||||
| def test_sanity() -> None: | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         im.load() | ||||
|         assert im.mode == "RGB" | ||||
|  | @ -21,7 +21,7 @@ def test_sanity(): | |||
|         assert_image_similar(im, im2, 4.8) | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     invalid_file = "Tests/images/flower.jpg" | ||||
| 
 | ||||
|     with pytest.raises(SyntaxError): | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ import sys | |||
| import warnings | ||||
| import zlib | ||||
| from io import BytesIO | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -79,7 +80,7 @@ class TestFilePng: | |||
|                     png.crc(cid, s) | ||||
|         return chunks | ||||
| 
 | ||||
|     def test_sanity(self, tmp_path): | ||||
|     def test_sanity(self, tmp_path: Path) -> None: | ||||
|         # internal version number | ||||
|         assert re.search(r"\d+(\.\d+){1,3}$", features.version_codec("zlib")) | ||||
| 
 | ||||
|  | @ -102,13 +103,13 @@ class TestFilePng: | |||
|                     reloaded = reloaded.convert(mode) | ||||
|                 assert_image_equal(reloaded, im) | ||||
| 
 | ||||
|     def test_invalid_file(self): | ||||
|     def test_invalid_file(self) -> None: | ||||
|         invalid_file = "Tests/images/flower.jpg" | ||||
| 
 | ||||
|         with pytest.raises(SyntaxError): | ||||
|             PngImagePlugin.PngImageFile(invalid_file) | ||||
| 
 | ||||
|     def test_broken(self): | ||||
|     def test_broken(self) -> None: | ||||
|         # Check reading of totally broken files.  In this case, the test | ||||
|         # file was checked into Subversion as a text file. | ||||
| 
 | ||||
|  | @ -117,7 +118,7 @@ class TestFilePng: | |||
|             with Image.open(test_file): | ||||
|                 pass | ||||
| 
 | ||||
|     def test_bad_text(self): | ||||
|     def test_bad_text(self) -> None: | ||||
|         # Make sure PIL can read malformed tEXt chunks (@PIL152) | ||||
| 
 | ||||
|         im = load(HEAD + chunk(b"tEXt") + TAIL) | ||||
|  | @ -135,7 +136,7 @@ class TestFilePng: | |||
|         im = load(HEAD + chunk(b"tEXt", b"spam\0egg\0") + TAIL) | ||||
|         assert im.info == {"spam": "egg\x00"} | ||||
| 
 | ||||
|     def test_bad_ztxt(self): | ||||
|     def test_bad_ztxt(self) -> None: | ||||
|         # Test reading malformed zTXt chunks (python-pillow/Pillow#318) | ||||
| 
 | ||||
|         im = load(HEAD + chunk(b"zTXt") + TAIL) | ||||
|  | @ -156,7 +157,7 @@ class TestFilePng: | |||
|         im = load(HEAD + chunk(b"zTXt", b"spam\0\0" + zlib.compress(b"egg")) + TAIL) | ||||
|         assert im.info == {"spam": "egg"} | ||||
| 
 | ||||
|     def test_bad_itxt(self): | ||||
|     def test_bad_itxt(self) -> None: | ||||
|         im = load(HEAD + chunk(b"iTXt") + TAIL) | ||||
|         assert im.info == {} | ||||
| 
 | ||||
|  | @ -200,7 +201,7 @@ class TestFilePng: | |||
|         assert im.info["spam"].lang == "en" | ||||
|         assert im.info["spam"].tkey == "Spam" | ||||
| 
 | ||||
|     def test_interlace(self): | ||||
|     def test_interlace(self) -> None: | ||||
|         test_file = "Tests/images/pil123p.png" | ||||
|         with Image.open(test_file) as im: | ||||
|             assert_image(im, "P", (162, 150)) | ||||
|  | @ -215,7 +216,7 @@ class TestFilePng: | |||
| 
 | ||||
|             im.load() | ||||
| 
 | ||||
|     def test_load_transparent_p(self): | ||||
|     def test_load_transparent_p(self) -> None: | ||||
|         test_file = "Tests/images/pil123p.png" | ||||
|         with Image.open(test_file) as im: | ||||
|             assert_image(im, "P", (162, 150)) | ||||
|  | @ -225,7 +226,7 @@ class TestFilePng: | |||
|         # image has 124 unique alpha values | ||||
|         assert len(im.getchannel("A").getcolors()) == 124 | ||||
| 
 | ||||
|     def test_load_transparent_rgb(self): | ||||
|     def test_load_transparent_rgb(self) -> None: | ||||
|         test_file = "Tests/images/rgb_trns.png" | ||||
|         with Image.open(test_file) as im: | ||||
|             assert im.info["transparency"] == (0, 255, 52) | ||||
|  | @ -237,7 +238,7 @@ class TestFilePng: | |||
|         # image has 876 transparent pixels | ||||
|         assert im.getchannel("A").getcolors()[0][0] == 876 | ||||
| 
 | ||||
|     def test_save_p_transparent_palette(self, tmp_path): | ||||
|     def test_save_p_transparent_palette(self, tmp_path: Path) -> None: | ||||
|         in_file = "Tests/images/pil123p.png" | ||||
|         with Image.open(in_file) as im: | ||||
|             # 'transparency' contains a byte string with the opacity for | ||||
|  | @ -258,7 +259,7 @@ class TestFilePng: | |||
|         # image has 124 unique alpha values | ||||
|         assert len(im.getchannel("A").getcolors()) == 124 | ||||
| 
 | ||||
|     def test_save_p_single_transparency(self, tmp_path): | ||||
|     def test_save_p_single_transparency(self, tmp_path: Path) -> None: | ||||
|         in_file = "Tests/images/p_trns_single.png" | ||||
|         with Image.open(in_file) as im: | ||||
|             # pixel value 164 is full transparent | ||||
|  | @ -281,7 +282,7 @@ class TestFilePng: | |||
|         # image has 876 transparent pixels | ||||
|         assert im.getchannel("A").getcolors()[0][0] == 876 | ||||
| 
 | ||||
|     def test_save_p_transparent_black(self, tmp_path): | ||||
|     def test_save_p_transparent_black(self, tmp_path: Path) -> None: | ||||
|         # check if solid black image with full transparency | ||||
|         # is supported (check for #1838) | ||||
|         im = Image.new("RGBA", (10, 10), (0, 0, 0, 0)) | ||||
|  | @ -299,7 +300,7 @@ class TestFilePng: | |||
|         assert_image(im, "RGBA", (10, 10)) | ||||
|         assert im.getcolors() == [(100, (0, 0, 0, 0))] | ||||
| 
 | ||||
|     def test_save_grayscale_transparency(self, tmp_path): | ||||
|     def test_save_grayscale_transparency(self, tmp_path: Path) -> None: | ||||
|         for mode, num_transparent in {"1": 1994, "L": 559, "I": 559}.items(): | ||||
|             in_file = "Tests/images/" + mode.lower() + "_trns.png" | ||||
|             with Image.open(in_file) as im: | ||||
|  | @ -320,13 +321,13 @@ class TestFilePng: | |||
|             test_im_rgba = test_im.convert("RGBA") | ||||
|             assert test_im_rgba.getchannel("A").getcolors()[0][0] == num_transparent | ||||
| 
 | ||||
|     def test_save_rgb_single_transparency(self, tmp_path): | ||||
|     def test_save_rgb_single_transparency(self, tmp_path: Path) -> None: | ||||
|         in_file = "Tests/images/caption_6_33_22.png" | ||||
|         with Image.open(in_file) as im: | ||||
|             test_file = str(tmp_path / "temp.png") | ||||
|             im.save(test_file) | ||||
| 
 | ||||
|     def test_load_verify(self): | ||||
|     def test_load_verify(self) -> None: | ||||
|         # Check open/load/verify exception (@PIL150) | ||||
| 
 | ||||
|         with Image.open(TEST_PNG_FILE) as im: | ||||
|  | @ -339,7 +340,7 @@ class TestFilePng: | |||
|             with pytest.raises(RuntimeError): | ||||
|                 im.verify() | ||||
| 
 | ||||
|     def test_verify_struct_error(self): | ||||
|     def test_verify_struct_error(self) -> None: | ||||
|         # Check open/load/verify exception (#1755) | ||||
| 
 | ||||
|         # offsets to test, -10: breaks in i32() in read. (OSError) | ||||
|  | @ -355,7 +356,7 @@ class TestFilePng: | |||
|                 with pytest.raises((OSError, SyntaxError)): | ||||
|                     im.verify() | ||||
| 
 | ||||
|     def test_verify_ignores_crc_error(self): | ||||
|     def test_verify_ignores_crc_error(self) -> None: | ||||
|         # check ignores crc errors in ancillary chunks | ||||
| 
 | ||||
|         chunk_data = chunk(b"tEXt", b"spam") | ||||
|  | @ -372,7 +373,7 @@ class TestFilePng: | |||
|         finally: | ||||
|             ImageFile.LOAD_TRUNCATED_IMAGES = False | ||||
| 
 | ||||
|     def test_verify_not_ignores_crc_error_in_required_chunk(self): | ||||
|     def test_verify_not_ignores_crc_error_in_required_chunk(self) -> None: | ||||
|         # check does not ignore crc errors in required chunks | ||||
| 
 | ||||
|         image_data = MAGIC + IHDR[:-1] + b"q" + TAIL | ||||
|  | @ -384,18 +385,18 @@ class TestFilePng: | |||
|         finally: | ||||
|             ImageFile.LOAD_TRUNCATED_IMAGES = False | ||||
| 
 | ||||
|     def test_roundtrip_dpi(self): | ||||
|     def test_roundtrip_dpi(self) -> None: | ||||
|         # Check dpi roundtripping | ||||
| 
 | ||||
|         with Image.open(TEST_PNG_FILE) as im: | ||||
|             im = roundtrip(im, dpi=(100.33, 100.33)) | ||||
|         assert im.info["dpi"] == (100.33, 100.33) | ||||
| 
 | ||||
|     def test_load_float_dpi(self): | ||||
|     def test_load_float_dpi(self) -> None: | ||||
|         with Image.open(TEST_PNG_FILE) as im: | ||||
|             assert im.info["dpi"] == (95.9866, 95.9866) | ||||
| 
 | ||||
|     def test_roundtrip_text(self): | ||||
|     def test_roundtrip_text(self) -> None: | ||||
|         # Check text roundtripping | ||||
| 
 | ||||
|         with Image.open(TEST_PNG_FILE) as im: | ||||
|  | @ -407,7 +408,7 @@ class TestFilePng: | |||
|         assert im.info == {"TXT": "VALUE", "ZIP": "VALUE"} | ||||
|         assert im.text == {"TXT": "VALUE", "ZIP": "VALUE"} | ||||
| 
 | ||||
|     def test_roundtrip_itxt(self): | ||||
|     def test_roundtrip_itxt(self) -> None: | ||||
|         # Check iTXt roundtripping | ||||
| 
 | ||||
|         im = Image.new("RGB", (32, 32)) | ||||
|  | @ -423,7 +424,7 @@ class TestFilePng: | |||
|         assert im.text["eggs"].lang == "en" | ||||
|         assert im.text["eggs"].tkey == "Eggs" | ||||
| 
 | ||||
|     def test_nonunicode_text(self): | ||||
|     def test_nonunicode_text(self) -> None: | ||||
|         # Check so that non-Unicode text is saved as a tEXt rather than iTXt | ||||
| 
 | ||||
|         im = Image.new("RGB", (32, 32)) | ||||
|  | @ -432,10 +433,10 @@ class TestFilePng: | |||
|         im = roundtrip(im, pnginfo=info) | ||||
|         assert isinstance(im.info["Text"], str) | ||||
| 
 | ||||
|     def test_unicode_text(self): | ||||
|     def test_unicode_text(self) -> None: | ||||
|         # Check preservation of non-ASCII characters | ||||
| 
 | ||||
|         def rt_text(value): | ||||
|         def rt_text(value) -> None: | ||||
|             im = Image.new("RGB", (32, 32)) | ||||
|             info = PngImagePlugin.PngInfo() | ||||
|             info.add_text("Text", value) | ||||
|  | @ -448,7 +449,7 @@ class TestFilePng: | |||
|         rt_text(chr(0x4E00) + chr(0x66F0) + chr(0x9FBA) + chr(0x3042) + chr(0xAC00)) | ||||
|         rt_text("A" + chr(0xC4) + chr(0x472) + chr(0x3042))  # Combined | ||||
| 
 | ||||
|     def test_scary(self): | ||||
|     def test_scary(self) -> None: | ||||
|         # Check reading of evil PNG file.  For information, see: | ||||
|         # http://scary.beasts.org/security/CESA-2004-001.txt | ||||
|         # The first byte is removed from pngtest_bad.png | ||||
|  | @ -462,7 +463,7 @@ class TestFilePng: | |||
|             with Image.open(pngfile): | ||||
|                 pass | ||||
| 
 | ||||
|     def test_trns_rgb(self): | ||||
|     def test_trns_rgb(self) -> None: | ||||
|         # Check writing and reading of tRNS chunks for RGB images. | ||||
|         # Independent file sample provided by Sebastian Spaeth. | ||||
| 
 | ||||
|  | @ -477,7 +478,7 @@ class TestFilePng: | |||
|         im = roundtrip(im, transparency=(0, 1, 2)) | ||||
|         assert im.info["transparency"] == (0, 1, 2) | ||||
| 
 | ||||
|     def test_trns_p(self, tmp_path): | ||||
|     def test_trns_p(self, tmp_path: Path) -> None: | ||||
|         # Check writing a transparency of 0, issue #528 | ||||
|         im = hopper("P") | ||||
|         im.info["transparency"] = 0 | ||||
|  | @ -490,13 +491,13 @@ class TestFilePng: | |||
| 
 | ||||
|             assert_image_equal(im2.convert("RGBA"), im.convert("RGBA")) | ||||
| 
 | ||||
|     def test_trns_null(self): | ||||
|     def test_trns_null(self) -> None: | ||||
|         # Check reading images with null tRNS value, issue #1239 | ||||
|         test_file = "Tests/images/tRNS_null_1x1.png" | ||||
|         with Image.open(test_file) as im: | ||||
|             assert im.info["transparency"] == 0 | ||||
| 
 | ||||
|     def test_save_icc_profile(self): | ||||
|     def test_save_icc_profile(self) -> None: | ||||
|         with Image.open("Tests/images/icc_profile_none.png") as im: | ||||
|             assert im.info["icc_profile"] is None | ||||
| 
 | ||||
|  | @ -506,40 +507,40 @@ class TestFilePng: | |||
|                 im = roundtrip(im, icc_profile=expected_icc) | ||||
|                 assert im.info["icc_profile"] == expected_icc | ||||
| 
 | ||||
|     def test_discard_icc_profile(self): | ||||
|     def test_discard_icc_profile(self) -> None: | ||||
|         with Image.open("Tests/images/icc_profile.png") as im: | ||||
|             assert "icc_profile" in im.info | ||||
| 
 | ||||
|             im = roundtrip(im, icc_profile=None) | ||||
|         assert "icc_profile" not in im.info | ||||
| 
 | ||||
|     def test_roundtrip_icc_profile(self): | ||||
|     def test_roundtrip_icc_profile(self) -> None: | ||||
|         with Image.open("Tests/images/icc_profile.png") as im: | ||||
|             expected_icc = im.info["icc_profile"] | ||||
| 
 | ||||
|             im = roundtrip(im) | ||||
|         assert im.info["icc_profile"] == expected_icc | ||||
| 
 | ||||
|     def test_roundtrip_no_icc_profile(self): | ||||
|     def test_roundtrip_no_icc_profile(self) -> None: | ||||
|         with Image.open("Tests/images/icc_profile_none.png") as im: | ||||
|             assert im.info["icc_profile"] is None | ||||
| 
 | ||||
|             im = roundtrip(im) | ||||
|         assert "icc_profile" not in im.info | ||||
| 
 | ||||
|     def test_repr_png(self): | ||||
|     def test_repr_png(self) -> None: | ||||
|         im = hopper() | ||||
| 
 | ||||
|         with Image.open(BytesIO(im._repr_png_())) as repr_png: | ||||
|             assert repr_png.format == "PNG" | ||||
|             assert_image_equal(im, repr_png) | ||||
| 
 | ||||
|     def test_repr_png_error_returns_none(self): | ||||
|     def test_repr_png_error_returns_none(self) -> None: | ||||
|         im = hopper("F") | ||||
| 
 | ||||
|         assert im._repr_png_() is None | ||||
| 
 | ||||
|     def test_chunk_order(self, tmp_path): | ||||
|     def test_chunk_order(self, tmp_path: Path) -> None: | ||||
|         with Image.open("Tests/images/icc_profile.png") as im: | ||||
|             test_file = str(tmp_path / "temp.png") | ||||
|             im.convert("P").save(test_file, dpi=(100, 100)) | ||||
|  | @ -560,17 +561,17 @@ class TestFilePng: | |||
|         # pHYs - before IDAT | ||||
|         assert chunks.index(b"pHYs") < chunks.index(b"IDAT") | ||||
| 
 | ||||
|     def test_getchunks(self): | ||||
|     def test_getchunks(self) -> None: | ||||
|         im = hopper() | ||||
| 
 | ||||
|         chunks = PngImagePlugin.getchunks(im) | ||||
|         assert len(chunks) == 3 | ||||
| 
 | ||||
|     def test_read_private_chunks(self): | ||||
|     def test_read_private_chunks(self) -> None: | ||||
|         with Image.open("Tests/images/exif.png") as im: | ||||
|             assert im.private_chunks == [(b"orNT", b"\x01")] | ||||
| 
 | ||||
|     def test_roundtrip_private_chunk(self): | ||||
|     def test_roundtrip_private_chunk(self) -> None: | ||||
|         # Check private chunk roundtripping | ||||
| 
 | ||||
|         with Image.open(TEST_PNG_FILE) as im: | ||||
|  | @ -588,7 +589,7 @@ class TestFilePng: | |||
|             (b"prIV", b"VALUE3", True), | ||||
|         ] | ||||
| 
 | ||||
|     def test_textual_chunks_after_idat(self): | ||||
|     def test_textual_chunks_after_idat(self) -> None: | ||||
|         with Image.open("Tests/images/hopper.png") as im: | ||||
|             assert "comment" in im.text | ||||
|             for k, v in { | ||||
|  | @ -615,7 +616,7 @@ class TestFilePng: | |||
|         with Image.open("Tests/images/hopper_idat_after_image_end.png") as im: | ||||
|             assert im.text == {"TXT": "VALUE", "ZIP": "VALUE"} | ||||
| 
 | ||||
|     def test_padded_idat(self): | ||||
|     def test_padded_idat(self) -> None: | ||||
|         # This image has been manually hexedited | ||||
|         # so that the IDAT chunk has padding at the end | ||||
|         # Set MAXBLOCK to the length of the actual data | ||||
|  | @ -635,7 +636,7 @@ class TestFilePng: | |||
|     @pytest.mark.parametrize( | ||||
|         "cid", (b"IHDR", b"sRGB", b"pHYs", b"acTL", b"fcTL", b"fdAT") | ||||
|     ) | ||||
|     def test_truncated_chunks(self, cid): | ||||
|     def test_truncated_chunks(self, cid) -> None: | ||||
|         fp = BytesIO() | ||||
|         with PngImagePlugin.PngStream(fp) as png: | ||||
|             with pytest.raises(ValueError): | ||||
|  | @ -645,7 +646,7 @@ class TestFilePng: | |||
|             png.call(cid, 0, 0) | ||||
|             ImageFile.LOAD_TRUNCATED_IMAGES = False | ||||
| 
 | ||||
|     def test_specify_bits(self, tmp_path): | ||||
|     def test_specify_bits(self, tmp_path: Path) -> None: | ||||
|         im = hopper("P") | ||||
| 
 | ||||
|         out = str(tmp_path / "temp.png") | ||||
|  | @ -654,7 +655,7 @@ class TestFilePng: | |||
|         with Image.open(out) as reloaded: | ||||
|             assert len(reloaded.png.im_palette[1]) == 48 | ||||
| 
 | ||||
|     def test_plte_length(self, tmp_path): | ||||
|     def test_plte_length(self, tmp_path: Path) -> None: | ||||
|         im = Image.new("P", (1, 1)) | ||||
|         im.putpalette((1, 1, 1)) | ||||
| 
 | ||||
|  | @ -664,7 +665,7 @@ class TestFilePng: | |||
|         with Image.open(out) as reloaded: | ||||
|             assert len(reloaded.png.im_palette[1]) == 3 | ||||
| 
 | ||||
|     def test_getxmp(self): | ||||
|     def test_getxmp(self) -> None: | ||||
|         with Image.open("Tests/images/color_snakes.png") as im: | ||||
|             if ElementTree is None: | ||||
|                 with pytest.warns( | ||||
|  | @ -679,7 +680,7 @@ class TestFilePng: | |||
|                 assert description["PixelXDimension"] == "10" | ||||
|                 assert description["subject"]["Seq"] is None | ||||
| 
 | ||||
|     def test_exif(self): | ||||
|     def test_exif(self) -> None: | ||||
|         # With an EXIF chunk | ||||
|         with Image.open("Tests/images/exif.png") as im: | ||||
|             exif = im._getexif() | ||||
|  | @ -705,7 +706,7 @@ class TestFilePng: | |||
|             exif = im.getexif() | ||||
|         assert exif[274] == 3 | ||||
| 
 | ||||
|     def test_exif_save(self, tmp_path): | ||||
|     def test_exif_save(self, tmp_path: Path) -> None: | ||||
|         # Test exif is not saved from info | ||||
|         test_file = str(tmp_path / "temp.png") | ||||
|         with Image.open("Tests/images/exif.png") as im: | ||||
|  | @ -725,7 +726,7 @@ class TestFilePng: | |||
|     @mark_if_feature_version( | ||||
|         pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" | ||||
|     ) | ||||
|     def test_exif_from_jpg(self, tmp_path): | ||||
|     def test_exif_from_jpg(self, tmp_path: Path) -> None: | ||||
|         with Image.open("Tests/images/pil_sample_rgb.jpg") as im: | ||||
|             test_file = str(tmp_path / "temp.png") | ||||
|             im.save(test_file, exif=im.getexif()) | ||||
|  | @ -734,7 +735,7 @@ class TestFilePng: | |||
|             exif = reloaded._getexif() | ||||
|         assert exif[305] == "Adobe Photoshop CS Macintosh" | ||||
| 
 | ||||
|     def test_exif_argument(self, tmp_path): | ||||
|     def test_exif_argument(self, tmp_path: Path) -> None: | ||||
|         with Image.open(TEST_PNG_FILE) as im: | ||||
|             test_file = str(tmp_path / "temp.png") | ||||
|             im.save(test_file, exif=b"exifstring") | ||||
|  | @ -742,11 +743,11 @@ class TestFilePng: | |||
|         with Image.open(test_file) as reloaded: | ||||
|             assert reloaded.info["exif"] == b"Exif\x00\x00exifstring" | ||||
| 
 | ||||
|     def test_tell(self): | ||||
|     def test_tell(self) -> None: | ||||
|         with Image.open(TEST_PNG_FILE) as im: | ||||
|             assert im.tell() == 0 | ||||
| 
 | ||||
|     def test_seek(self): | ||||
|     def test_seek(self) -> None: | ||||
|         with Image.open(TEST_PNG_FILE) as im: | ||||
|             im.seek(0) | ||||
| 
 | ||||
|  | @ -754,7 +755,7 @@ class TestFilePng: | |||
|                 im.seek(1) | ||||
| 
 | ||||
|     @pytest.mark.parametrize("buffer", (True, False)) | ||||
|     def test_save_stdout(self, buffer): | ||||
|     def test_save_stdout(self, buffer) -> None: | ||||
|         old_stdout = sys.stdout | ||||
| 
 | ||||
|         if buffer: | ||||
|  | @ -786,7 +787,7 @@ class TestTruncatedPngPLeaks(PillowLeakTestCase): | |||
|     mem_limit = 2 * 1024  # max increase in K | ||||
|     iterations = 100  # Leak is 56k/iteration, this will leak 5.6megs | ||||
| 
 | ||||
|     def test_leak_load(self): | ||||
|     def test_leak_load(self) -> None: | ||||
|         with open("Tests/images/hopper.png", "rb") as f: | ||||
|             DATA = BytesIO(f.read(16 * 1024)) | ||||
| 
 | ||||
|  | @ -794,7 +795,7 @@ class TestTruncatedPngPLeaks(PillowLeakTestCase): | |||
|         with Image.open(DATA) as im: | ||||
|             im.load() | ||||
| 
 | ||||
|         def core(): | ||||
|         def core() -> None: | ||||
|             with Image.open(DATA) as im: | ||||
|                 im.load() | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ from __future__ import annotations | |||
| 
 | ||||
| import sys | ||||
| from io import BytesIO | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -18,7 +19,7 @@ from .helper import ( | |||
| TEST_FILE = "Tests/images/hopper.ppm" | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(): | ||||
| def test_sanity() -> None: | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         assert im.mode == "RGB" | ||||
|         assert im.size == (128, 128) | ||||
|  | @ -69,7 +70,7 @@ def test_sanity(): | |||
|         ), | ||||
|     ), | ||||
| ) | ||||
| def test_arbitrary_maxval(data, mode, pixels): | ||||
| def test_arbitrary_maxval(data, mode, pixels) -> None: | ||||
|     fp = BytesIO(data) | ||||
|     with Image.open(fp) as im: | ||||
|         assert im.size == (3, 1) | ||||
|  | @ -79,7 +80,7 @@ def test_arbitrary_maxval(data, mode, pixels): | |||
|         assert tuple(px[x, 0] for x in range(3)) == pixels | ||||
| 
 | ||||
| 
 | ||||
| def test_16bit_pgm(): | ||||
| def test_16bit_pgm() -> None: | ||||
|     with Image.open("Tests/images/16_bit_binary.pgm") as im: | ||||
|         assert im.mode == "I" | ||||
|         assert im.size == (20, 100) | ||||
|  | @ -88,7 +89,7 @@ def test_16bit_pgm(): | |||
|         assert_image_equal_tofile(im, "Tests/images/16_bit_binary_pgm.png") | ||||
| 
 | ||||
| 
 | ||||
| def test_16bit_pgm_write(tmp_path): | ||||
| def test_16bit_pgm_write(tmp_path: Path) -> None: | ||||
|     with Image.open("Tests/images/16_bit_binary.pgm") as im: | ||||
|         filename = str(tmp_path / "temp.pgm") | ||||
|         im.save(filename, "PPM") | ||||
|  | @ -96,7 +97,7 @@ def test_16bit_pgm_write(tmp_path): | |||
|         assert_image_equal_tofile(im, filename) | ||||
| 
 | ||||
| 
 | ||||
| def test_pnm(tmp_path): | ||||
| def test_pnm(tmp_path: Path) -> None: | ||||
|     with Image.open("Tests/images/hopper.pnm") as im: | ||||
|         assert_image_similar(im, hopper(), 0.0001) | ||||
| 
 | ||||
|  | @ -106,7 +107,7 @@ def test_pnm(tmp_path): | |||
|         assert_image_equal_tofile(im, filename) | ||||
| 
 | ||||
| 
 | ||||
| def test_pfm(tmp_path): | ||||
| def test_pfm(tmp_path: Path) -> None: | ||||
|     with Image.open("Tests/images/hopper.pfm") as im: | ||||
|         assert im.info["scale"] == 1.0 | ||||
|         assert_image_equal(im, hopper("F")) | ||||
|  | @ -117,7 +118,7 @@ def test_pfm(tmp_path): | |||
|         assert_image_equal_tofile(im, filename) | ||||
| 
 | ||||
| 
 | ||||
| def test_pfm_big_endian(tmp_path): | ||||
| def test_pfm_big_endian(tmp_path: Path) -> None: | ||||
|     with Image.open("Tests/images/hopper_be.pfm") as im: | ||||
|         assert im.info["scale"] == 2.5 | ||||
|         assert_image_equal(im, hopper("F")) | ||||
|  | @ -138,7 +139,7 @@ def test_pfm_big_endian(tmp_path): | |||
|         b"Pf 1 1 -0.0 \0\0\0\0", | ||||
|     ], | ||||
| ) | ||||
| def test_pfm_invalid(data): | ||||
| def test_pfm_invalid(data) -> None: | ||||
|     with pytest.raises(ValueError): | ||||
|         with Image.open(BytesIO(data)): | ||||
|             pass | ||||
|  | @ -161,12 +162,12 @@ def test_pfm_invalid(data): | |||
|         ), | ||||
|     ), | ||||
| ) | ||||
| def test_plain(plain_path, raw_path): | ||||
| def test_plain(plain_path, raw_path) -> None: | ||||
|     with Image.open(plain_path) as im: | ||||
|         assert_image_equal_tofile(im, raw_path) | ||||
| 
 | ||||
| 
 | ||||
| def test_16bit_plain_pgm(): | ||||
| def test_16bit_plain_pgm() -> None: | ||||
|     # P2 with maxval 2 ** 16 - 1 | ||||
|     with Image.open("Tests/images/hopper_16bit_plain.pgm") as im: | ||||
|         assert im.mode == "I" | ||||
|  | @ -185,7 +186,7 @@ def test_16bit_plain_pgm(): | |||
|         (b"P3\n2 2\n255", b"0 0 0 001 1 1 2 2 2 255 255 255", 10**6), | ||||
|     ), | ||||
| ) | ||||
| def test_plain_data_with_comment(tmp_path, header, data, comment_count): | ||||
| def test_plain_data_with_comment(tmp_path: Path, header, data, comment_count) -> None: | ||||
|     path1 = str(tmp_path / "temp1.ppm") | ||||
|     path2 = str(tmp_path / "temp2.ppm") | ||||
|     comment = b"# comment" * comment_count | ||||
|  | @ -198,7 +199,7 @@ def test_plain_data_with_comment(tmp_path, header, data, comment_count): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("data", (b"P1\n128 128\n", b"P3\n128 128\n255\n")) | ||||
| def test_plain_truncated_data(tmp_path, data): | ||||
| def test_plain_truncated_data(tmp_path: Path, data) -> None: | ||||
|     path = str(tmp_path / "temp.ppm") | ||||
|     with open(path, "wb") as f: | ||||
|         f.write(data) | ||||
|  | @ -209,7 +210,7 @@ def test_plain_truncated_data(tmp_path, data): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("data", (b"P1\n128 128\n1009", b"P3\n128 128\n255\n100A")) | ||||
| def test_plain_invalid_data(tmp_path, data): | ||||
| def test_plain_invalid_data(tmp_path: Path, data) -> None: | ||||
|     path = str(tmp_path / "temp.ppm") | ||||
|     with open(path, "wb") as f: | ||||
|         f.write(data) | ||||
|  | @ -226,7 +227,7 @@ def test_plain_invalid_data(tmp_path, data): | |||
|         b"P3\n128 128\n255\n012345678910 0",  # token too long | ||||
|     ), | ||||
| ) | ||||
| def test_plain_ppm_token_too_long(tmp_path, data): | ||||
| def test_plain_ppm_token_too_long(tmp_path: Path, data) -> None: | ||||
|     path = str(tmp_path / "temp.ppm") | ||||
|     with open(path, "wb") as f: | ||||
|         f.write(data) | ||||
|  | @ -236,7 +237,7 @@ def test_plain_ppm_token_too_long(tmp_path, data): | |||
|             im.load() | ||||
| 
 | ||||
| 
 | ||||
| def test_plain_ppm_value_too_large(tmp_path): | ||||
| def test_plain_ppm_value_too_large(tmp_path: Path) -> None: | ||||
|     path = str(tmp_path / "temp.ppm") | ||||
|     with open(path, "wb") as f: | ||||
|         f.write(b"P3\n128 128\n255\n256") | ||||
|  | @ -246,12 +247,12 @@ def test_plain_ppm_value_too_large(tmp_path): | |||
|             im.load() | ||||
| 
 | ||||
| 
 | ||||
| def test_magic(): | ||||
| def test_magic() -> None: | ||||
|     with pytest.raises(SyntaxError): | ||||
|         PpmImagePlugin.PpmImageFile(fp=BytesIO(b"PyInvalid")) | ||||
| 
 | ||||
| 
 | ||||
| def test_header_with_comments(tmp_path): | ||||
| def test_header_with_comments(tmp_path: Path) -> None: | ||||
|     path = str(tmp_path / "temp.ppm") | ||||
|     with open(path, "wb") as f: | ||||
|         f.write(b"P6 #comment\n#comment\r12#comment\r8\n128 #comment\n255\n") | ||||
|  | @ -260,7 +261,7 @@ def test_header_with_comments(tmp_path): | |||
|         assert im.size == (128, 128) | ||||
| 
 | ||||
| 
 | ||||
| def test_non_integer_token(tmp_path): | ||||
| def test_non_integer_token(tmp_path: Path) -> None: | ||||
|     path = str(tmp_path / "temp.ppm") | ||||
|     with open(path, "wb") as f: | ||||
|         f.write(b"P6\nTEST") | ||||
|  | @ -270,7 +271,7 @@ def test_non_integer_token(tmp_path): | |||
|             pass | ||||
| 
 | ||||
| 
 | ||||
| def test_header_token_too_long(tmp_path): | ||||
| def test_header_token_too_long(tmp_path: Path) -> None: | ||||
|     path = str(tmp_path / "temp.ppm") | ||||
|     with open(path, "wb") as f: | ||||
|         f.write(b"P6\n 01234567890") | ||||
|  | @ -282,7 +283,7 @@ def test_header_token_too_long(tmp_path): | |||
|     assert str(e.value) == "Token too long in file header: 01234567890" | ||||
| 
 | ||||
| 
 | ||||
| def test_truncated_file(tmp_path): | ||||
| def test_truncated_file(tmp_path: Path) -> None: | ||||
|     # Test EOF in header | ||||
|     path = str(tmp_path / "temp.pgm") | ||||
|     with open(path, "wb") as f: | ||||
|  | @ -301,7 +302,7 @@ def test_truncated_file(tmp_path): | |||
|             im.load() | ||||
| 
 | ||||
| 
 | ||||
| def test_not_enough_image_data(tmp_path): | ||||
| def test_not_enough_image_data(tmp_path: Path) -> None: | ||||
|     path = str(tmp_path / "temp.ppm") | ||||
|     with open(path, "wb") as f: | ||||
|         f.write(b"P2 1 2 255 255") | ||||
|  | @ -312,7 +313,7 @@ def test_not_enough_image_data(tmp_path): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("maxval", (b"0", b"65536")) | ||||
| def test_invalid_maxval(maxval, tmp_path): | ||||
| def test_invalid_maxval(maxval, tmp_path: Path) -> None: | ||||
|     path = str(tmp_path / "temp.ppm") | ||||
|     with open(path, "wb") as f: | ||||
|         f.write(b"P6\n3 1 " + maxval) | ||||
|  | @ -324,7 +325,7 @@ def test_invalid_maxval(maxval, tmp_path): | |||
|     assert str(e.value) == "maxval must be greater than 0 and less than 65536" | ||||
| 
 | ||||
| 
 | ||||
| def test_neg_ppm(): | ||||
| def test_neg_ppm() -> None: | ||||
|     # Storage.c accepted negative values for xsize, ysize.  the | ||||
|     # internal open_ppm function didn't check for sanity but it | ||||
|     # has been removed. The default opener doesn't accept negative | ||||
|  | @ -335,7 +336,7 @@ def test_neg_ppm(): | |||
|             pass | ||||
| 
 | ||||
| 
 | ||||
| def test_mimetypes(tmp_path): | ||||
| def test_mimetypes(tmp_path: Path) -> None: | ||||
|     path = str(tmp_path / "temp.pgm") | ||||
| 
 | ||||
|     with open(path, "wb") as f: | ||||
|  | @ -350,7 +351,7 @@ def test_mimetypes(tmp_path): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("buffer", (True, False)) | ||||
| def test_save_stdout(buffer): | ||||
| def test_save_stdout(buffer) -> None: | ||||
|     old_stdout = sys.stdout | ||||
| 
 | ||||
|     if buffer: | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ from .helper import assert_image_equal_tofile, assert_image_similar, hopper, is_ | |||
| test_file = "Tests/images/hopper.psd" | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(): | ||||
| def test_sanity() -> None: | ||||
|     with Image.open(test_file) as im: | ||||
|         im.load() | ||||
|         assert im.mode == "RGB" | ||||
|  | @ -24,8 +24,8 @@ def test_sanity(): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.skipif(is_pypy(), reason="Requires CPython") | ||||
| def test_unclosed_file(): | ||||
|     def open(): | ||||
| def test_unclosed_file() -> None: | ||||
|     def open() -> None: | ||||
|         im = Image.open(test_file) | ||||
|         im.load() | ||||
| 
 | ||||
|  | @ -33,27 +33,27 @@ def test_unclosed_file(): | |||
|         open() | ||||
| 
 | ||||
| 
 | ||||
| def test_closed_file(): | ||||
| def test_closed_file() -> None: | ||||
|     with warnings.catch_warnings(): | ||||
|         im = Image.open(test_file) | ||||
|         im.load() | ||||
|         im.close() | ||||
| 
 | ||||
| 
 | ||||
| def test_context_manager(): | ||||
| def test_context_manager() -> None: | ||||
|     with warnings.catch_warnings(): | ||||
|         with Image.open(test_file) as im: | ||||
|             im.load() | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     invalid_file = "Tests/images/flower.jpg" | ||||
| 
 | ||||
|     with pytest.raises(SyntaxError): | ||||
|         PsdImagePlugin.PsdImageFile(invalid_file) | ||||
| 
 | ||||
| 
 | ||||
| def test_n_frames(): | ||||
| def test_n_frames() -> None: | ||||
|     with Image.open("Tests/images/hopper_merged.psd") as im: | ||||
|         assert im.n_frames == 1 | ||||
|         assert not im.is_animated | ||||
|  | @ -64,7 +64,7 @@ def test_n_frames(): | |||
|             assert im.is_animated | ||||
| 
 | ||||
| 
 | ||||
| def test_eoferror(): | ||||
| def test_eoferror() -> None: | ||||
|     with Image.open(test_file) as im: | ||||
|         # PSD seek index starts at 1 rather than 0 | ||||
|         n_frames = im.n_frames + 1 | ||||
|  | @ -78,7 +78,7 @@ def test_eoferror(): | |||
|         im.seek(n_frames - 1) | ||||
| 
 | ||||
| 
 | ||||
| def test_seek_tell(): | ||||
| def test_seek_tell() -> None: | ||||
|     with Image.open(test_file) as im: | ||||
|         layer_number = im.tell() | ||||
|         assert layer_number == 1 | ||||
|  | @ -95,30 +95,30 @@ def test_seek_tell(): | |||
|         assert layer_number == 2 | ||||
| 
 | ||||
| 
 | ||||
| def test_seek_eoferror(): | ||||
| def test_seek_eoferror() -> None: | ||||
|     with Image.open(test_file) as im: | ||||
|         with pytest.raises(EOFError): | ||||
|             im.seek(-1) | ||||
| 
 | ||||
| 
 | ||||
| def test_open_after_exclusive_load(): | ||||
| def test_open_after_exclusive_load() -> None: | ||||
|     with Image.open(test_file) as im: | ||||
|         im.load() | ||||
|         im.seek(im.tell() + 1) | ||||
|         im.load() | ||||
| 
 | ||||
| 
 | ||||
| def test_rgba(): | ||||
| def test_rgba() -> None: | ||||
|     with Image.open("Tests/images/rgba.psd") as im: | ||||
|         assert_image_equal_tofile(im, "Tests/images/imagedraw_square.png") | ||||
| 
 | ||||
| 
 | ||||
| def test_layer_skip(): | ||||
| def test_layer_skip() -> None: | ||||
|     with Image.open("Tests/images/five_channels.psd") as im: | ||||
|         assert im.n_frames == 1 | ||||
| 
 | ||||
| 
 | ||||
| def test_icc_profile(): | ||||
| def test_icc_profile() -> None: | ||||
|     with Image.open(test_file) as im: | ||||
|         assert "icc_profile" in im.info | ||||
| 
 | ||||
|  | @ -126,12 +126,12 @@ def test_icc_profile(): | |||
|         assert len(icc_profile) == 3144 | ||||
| 
 | ||||
| 
 | ||||
| def test_no_icc_profile(): | ||||
| def test_no_icc_profile() -> None: | ||||
|     with Image.open("Tests/images/hopper_merged.psd") as im: | ||||
|         assert "icc_profile" not in im.info | ||||
| 
 | ||||
| 
 | ||||
| def test_combined_larger_than_size(): | ||||
| def test_combined_larger_than_size() -> None: | ||||
|     # The combined size of the individual parts is larger than the | ||||
|     # declared 'size' of the extra data field, resulting in a backwards seek. | ||||
| 
 | ||||
|  | @ -157,7 +157,7 @@ def test_combined_larger_than_size(): | |||
|         ("Tests/images/timeout-dedc7a4ebd856d79b4359bbcc79e8ef231ce38f6.psd", OSError), | ||||
|     ], | ||||
| ) | ||||
| def test_crashes(test_file, raises): | ||||
| def test_crashes(test_file, raises) -> None: | ||||
|     with open(test_file, "rb") as f: | ||||
|         with pytest.raises(raises): | ||||
|             with Image.open(f): | ||||
|  |  | |||
|  | @ -7,7 +7,7 @@ from PIL import Image, QoiImagePlugin | |||
| from .helper import assert_image_equal_tofile | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(): | ||||
| def test_sanity() -> None: | ||||
|     with Image.open("Tests/images/hopper.qoi") as im: | ||||
|         assert im.mode == "RGB" | ||||
|         assert im.size == (128, 128) | ||||
|  | @ -23,7 +23,7 @@ def test_sanity(): | |||
|         assert_image_equal_tofile(im, "Tests/images/pil123rgba.png") | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     invalid_file = "Tests/images/flower.jpg" | ||||
| 
 | ||||
|     with pytest.raises(SyntaxError): | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
| from PIL import Image, SgiImagePlugin | ||||
|  | @ -12,7 +14,7 @@ from .helper import ( | |||
| ) | ||||
| 
 | ||||
| 
 | ||||
| def test_rgb(): | ||||
| def test_rgb() -> None: | ||||
|     # Created with ImageMagick then renamed: | ||||
|     # convert hopper.ppm -compress None sgi:hopper.rgb | ||||
|     test_file = "Tests/images/hopper.rgb" | ||||
|  | @ -22,11 +24,11 @@ def test_rgb(): | |||
|         assert im.get_format_mimetype() == "image/rgb" | ||||
| 
 | ||||
| 
 | ||||
| def test_rgb16(): | ||||
| def test_rgb16() -> None: | ||||
|     assert_image_equal_tofile(hopper(), "Tests/images/hopper16.rgb") | ||||
| 
 | ||||
| 
 | ||||
| def test_l(): | ||||
| def test_l() -> None: | ||||
|     # Created with ImageMagick | ||||
|     # convert hopper.ppm -monochrome -compress None sgi:hopper.bw | ||||
|     test_file = "Tests/images/hopper.bw" | ||||
|  | @ -36,7 +38,7 @@ def test_l(): | |||
|         assert im.get_format_mimetype() == "image/sgi" | ||||
| 
 | ||||
| 
 | ||||
| def test_rgba(): | ||||
| def test_rgba() -> None: | ||||
|     # Created with ImageMagick: | ||||
|     # convert transparent.png -compress None transparent.sgi | ||||
|     test_file = "Tests/images/transparent.sgi" | ||||
|  | @ -46,7 +48,7 @@ def test_rgba(): | |||
|         assert im.get_format_mimetype() == "image/sgi" | ||||
| 
 | ||||
| 
 | ||||
| def test_rle(): | ||||
| def test_rle() -> None: | ||||
|     # Created with ImageMagick: | ||||
|     # convert hopper.ppm  hopper.sgi | ||||
|     test_file = "Tests/images/hopper.sgi" | ||||
|  | @ -55,22 +57,22 @@ def test_rle(): | |||
|         assert_image_equal_tofile(im, "Tests/images/hopper.rgb") | ||||
| 
 | ||||
| 
 | ||||
| def test_rle16(): | ||||
| def test_rle16() -> None: | ||||
|     test_file = "Tests/images/tv16.sgi" | ||||
| 
 | ||||
|     with Image.open(test_file) as im: | ||||
|         assert_image_equal_tofile(im, "Tests/images/tv.rgb") | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     invalid_file = "Tests/images/flower.jpg" | ||||
| 
 | ||||
|     with pytest.raises(ValueError): | ||||
|         SgiImagePlugin.SgiImageFile(invalid_file) | ||||
| 
 | ||||
| 
 | ||||
| def test_write(tmp_path): | ||||
|     def roundtrip(img): | ||||
| def test_write(tmp_path: Path) -> None: | ||||
|     def roundtrip(img) -> None: | ||||
|         out = str(tmp_path / "temp.sgi") | ||||
|         img.save(out, format="sgi") | ||||
|         assert_image_equal_tofile(img, out) | ||||
|  | @ -89,7 +91,7 @@ def test_write(tmp_path): | |||
|     roundtrip(Image.new("L", (10, 1))) | ||||
| 
 | ||||
| 
 | ||||
| def test_write16(tmp_path): | ||||
| def test_write16(tmp_path: Path) -> None: | ||||
|     test_file = "Tests/images/hopper16.rgb" | ||||
| 
 | ||||
|     with Image.open(test_file) as im: | ||||
|  | @ -99,7 +101,7 @@ def test_write16(tmp_path): | |||
|         assert_image_equal_tofile(im, out) | ||||
| 
 | ||||
| 
 | ||||
| def test_unsupported_mode(tmp_path): | ||||
| def test_unsupported_mode(tmp_path: Path) -> None: | ||||
|     im = hopper("LA") | ||||
|     out = str(tmp_path / "temp.sgi") | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ from __future__ import annotations | |||
| import tempfile | ||||
| import warnings | ||||
| from io import BytesIO | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -13,7 +14,7 @@ from .helper import assert_image_equal_tofile, hopper, is_pypy | |||
| TEST_FILE = "Tests/images/hopper.spider" | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(): | ||||
| def test_sanity() -> None: | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         im.load() | ||||
|         assert im.mode == "F" | ||||
|  | @ -22,8 +23,8 @@ def test_sanity(): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.skipif(is_pypy(), reason="Requires CPython") | ||||
| def test_unclosed_file(): | ||||
|     def open(): | ||||
| def test_unclosed_file() -> None: | ||||
|     def open() -> None: | ||||
|         im = Image.open(TEST_FILE) | ||||
|         im.load() | ||||
| 
 | ||||
|  | @ -31,20 +32,20 @@ def test_unclosed_file(): | |||
|         open() | ||||
| 
 | ||||
| 
 | ||||
| def test_closed_file(): | ||||
| def test_closed_file() -> None: | ||||
|     with warnings.catch_warnings(): | ||||
|         im = Image.open(TEST_FILE) | ||||
|         im.load() | ||||
|         im.close() | ||||
| 
 | ||||
| 
 | ||||
| def test_context_manager(): | ||||
| def test_context_manager() -> None: | ||||
|     with warnings.catch_warnings(): | ||||
|         with Image.open(TEST_FILE) as im: | ||||
|             im.load() | ||||
| 
 | ||||
| 
 | ||||
| def test_save(tmp_path): | ||||
| def test_save(tmp_path: Path) -> None: | ||||
|     # Arrange | ||||
|     temp = str(tmp_path / "temp.spider") | ||||
|     im = hopper() | ||||
|  | @ -59,7 +60,7 @@ def test_save(tmp_path): | |||
|         assert im2.format == "SPIDER" | ||||
| 
 | ||||
| 
 | ||||
| def test_tempfile(): | ||||
| def test_tempfile() -> None: | ||||
|     # Arrange | ||||
|     im = hopper() | ||||
| 
 | ||||
|  | @ -75,11 +76,11 @@ def test_tempfile(): | |||
|             assert reloaded.format == "SPIDER" | ||||
| 
 | ||||
| 
 | ||||
| def test_is_spider_image(): | ||||
| def test_is_spider_image() -> None: | ||||
|     assert SpiderImagePlugin.isSpiderImage(TEST_FILE) | ||||
| 
 | ||||
| 
 | ||||
| def test_tell(): | ||||
| def test_tell() -> None: | ||||
|     # Arrange | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         # Act | ||||
|  | @ -89,13 +90,13 @@ def test_tell(): | |||
|         assert index == 0 | ||||
| 
 | ||||
| 
 | ||||
| def test_n_frames(): | ||||
| def test_n_frames() -> None: | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         assert im.n_frames == 1 | ||||
|         assert not im.is_animated | ||||
| 
 | ||||
| 
 | ||||
| def test_load_image_series(): | ||||
| def test_load_image_series() -> None: | ||||
|     # Arrange | ||||
|     not_spider_file = "Tests/images/hopper.ppm" | ||||
|     file_list = [TEST_FILE, not_spider_file, "path/not_found.ext"] | ||||
|  | @ -109,7 +110,7 @@ def test_load_image_series(): | |||
|     assert img_list[0].size == (128, 128) | ||||
| 
 | ||||
| 
 | ||||
| def test_load_image_series_no_input(): | ||||
| def test_load_image_series_no_input() -> None: | ||||
|     # Arrange | ||||
|     file_list = None | ||||
| 
 | ||||
|  | @ -120,7 +121,7 @@ def test_load_image_series_no_input(): | |||
|     assert img_list is None | ||||
| 
 | ||||
| 
 | ||||
| def test_is_int_not_a_number(): | ||||
| def test_is_int_not_a_number() -> None: | ||||
|     # Arrange | ||||
|     not_a_number = "a" | ||||
| 
 | ||||
|  | @ -131,7 +132,7 @@ def test_is_int_not_a_number(): | |||
|     assert ret == 0 | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     invalid_file = "Tests/images/invalid.spider" | ||||
| 
 | ||||
|     with pytest.raises(OSError): | ||||
|  | @ -139,20 +140,20 @@ def test_invalid_file(): | |||
|             pass | ||||
| 
 | ||||
| 
 | ||||
| def test_nonstack_file(): | ||||
| def test_nonstack_file() -> None: | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         with pytest.raises(EOFError): | ||||
|             im.seek(0) | ||||
| 
 | ||||
| 
 | ||||
| def test_nonstack_dos(): | ||||
| def test_nonstack_dos() -> None: | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         for i, frame in enumerate(ImageSequence.Iterator(im)): | ||||
|             assert i <= 1, "Non-stack DOS file test failed" | ||||
| 
 | ||||
| 
 | ||||
| # for issue #4093 | ||||
| def test_odd_size(): | ||||
| def test_odd_size() -> None: | ||||
|     data = BytesIO() | ||||
|     width = 100 | ||||
|     im = Image.new("F", (width, 64)) | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ from .helper import assert_image_equal_tofile, assert_image_similar, hopper | |||
| EXTRA_DIR = "Tests/images/sunraster" | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(): | ||||
| def test_sanity() -> None: | ||||
|     # Arrange | ||||
|     # Created with ImageMagick: convert hopper.jpg hopper.ras | ||||
|     test_file = "Tests/images/hopper.ras" | ||||
|  | @ -28,7 +28,7 @@ def test_sanity(): | |||
|         SunImagePlugin.SunImageFile(invalid_file) | ||||
| 
 | ||||
| 
 | ||||
| def test_im1(): | ||||
| def test_im1() -> None: | ||||
|     with Image.open("Tests/images/sunraster.im1") as im: | ||||
|         assert_image_equal_tofile(im, "Tests/images/sunraster.im1.png") | ||||
| 
 | ||||
|  | @ -36,7 +36,7 @@ def test_im1(): | |||
| @pytest.mark.skipif( | ||||
|     not os.path.exists(EXTRA_DIR), reason="Extra image files not installed" | ||||
| ) | ||||
| def test_others(): | ||||
| def test_others() -> None: | ||||
|     files = ( | ||||
|         os.path.join(EXTRA_DIR, f) | ||||
|         for f in os.listdir(EXTRA_DIR) | ||||
|  |  | |||
|  | @ -19,7 +19,7 @@ TEST_TAR_FILE = "Tests/images/hopper.tar" | |||
|         ("jpg", "hopper.jpg", "JPEG"), | ||||
|     ), | ||||
| ) | ||||
| def test_sanity(codec, test_path, format): | ||||
| def test_sanity(codec, test_path, format) -> None: | ||||
|     if features.check(codec): | ||||
|         with TarIO.TarIO(TEST_TAR_FILE, test_path) as tar: | ||||
|             with Image.open(tar) as im: | ||||
|  | @ -30,18 +30,18 @@ def test_sanity(codec, test_path, format): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.skipif(is_pypy(), reason="Requires CPython") | ||||
| def test_unclosed_file(): | ||||
| def test_unclosed_file() -> None: | ||||
|     with pytest.warns(ResourceWarning): | ||||
|         TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg") | ||||
| 
 | ||||
| 
 | ||||
| def test_close(): | ||||
| def test_close() -> None: | ||||
|     with warnings.catch_warnings(): | ||||
|         tar = TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg") | ||||
|         tar.close() | ||||
| 
 | ||||
| 
 | ||||
| def test_contextmanager(): | ||||
| def test_contextmanager() -> None: | ||||
|     with warnings.catch_warnings(): | ||||
|         with TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg"): | ||||
|             pass | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ from __future__ import annotations | |||
| import os | ||||
| from glob import glob | ||||
| from itertools import product | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -21,8 +22,8 @@ _ORIGIN_TO_ORIENTATION = {"tl": 1, "bl": -1} | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("mode", _MODES) | ||||
| def test_sanity(mode, tmp_path): | ||||
|     def roundtrip(original_im): | ||||
| def test_sanity(mode, tmp_path: Path) -> None: | ||||
|     def roundtrip(original_im) -> None: | ||||
|         out = str(tmp_path / "temp.tga") | ||||
| 
 | ||||
|         original_im.save(out, rle=rle) | ||||
|  | @ -64,7 +65,7 @@ def test_sanity(mode, tmp_path): | |||
|                     roundtrip(original_im) | ||||
| 
 | ||||
| 
 | ||||
| def test_palette_depth_16(tmp_path): | ||||
| def test_palette_depth_16(tmp_path: Path) -> None: | ||||
|     with Image.open("Tests/images/p_16.tga") as im: | ||||
|         assert_image_equal_tofile(im.convert("RGB"), "Tests/images/p_16.png") | ||||
| 
 | ||||
|  | @ -74,7 +75,7 @@ def test_palette_depth_16(tmp_path): | |||
|             assert_image_equal_tofile(reloaded.convert("RGB"), "Tests/images/p_16.png") | ||||
| 
 | ||||
| 
 | ||||
| def test_id_field(): | ||||
| def test_id_field() -> None: | ||||
|     # tga file with id field | ||||
|     test_file = "Tests/images/tga_id_field.tga" | ||||
| 
 | ||||
|  | @ -84,7 +85,7 @@ def test_id_field(): | |||
|         assert im.size == (100, 100) | ||||
| 
 | ||||
| 
 | ||||
| def test_id_field_rle(): | ||||
| def test_id_field_rle() -> None: | ||||
|     # tga file with id field | ||||
|     test_file = "Tests/images/rgb32rle.tga" | ||||
| 
 | ||||
|  | @ -94,7 +95,7 @@ def test_id_field_rle(): | |||
|         assert im.size == (199, 199) | ||||
| 
 | ||||
| 
 | ||||
| def test_cross_scan_line(): | ||||
| def test_cross_scan_line() -> None: | ||||
|     with Image.open("Tests/images/cross_scan_line.tga") as im: | ||||
|         assert_image_equal_tofile(im, "Tests/images/cross_scan_line.png") | ||||
| 
 | ||||
|  | @ -103,7 +104,7 @@ def test_cross_scan_line(): | |||
|             im.load() | ||||
| 
 | ||||
| 
 | ||||
| def test_save(tmp_path): | ||||
| def test_save(tmp_path: Path) -> None: | ||||
|     test_file = "Tests/images/tga_id_field.tga" | ||||
|     with Image.open(test_file) as im: | ||||
|         out = str(tmp_path / "temp.tga") | ||||
|  | @ -120,7 +121,7 @@ def test_save(tmp_path): | |||
|         assert test_im.size == (100, 100) | ||||
| 
 | ||||
| 
 | ||||
| def test_small_palette(tmp_path): | ||||
| def test_small_palette(tmp_path: Path) -> None: | ||||
|     im = Image.new("P", (1, 1)) | ||||
|     colors = [0, 0, 0] | ||||
|     im.putpalette(colors) | ||||
|  | @ -132,7 +133,7 @@ def test_small_palette(tmp_path): | |||
|         assert reloaded.getpalette() == colors | ||||
| 
 | ||||
| 
 | ||||
| def test_save_wrong_mode(tmp_path): | ||||
| def test_save_wrong_mode(tmp_path: Path) -> None: | ||||
|     im = hopper("PA") | ||||
|     out = str(tmp_path / "temp.tga") | ||||
| 
 | ||||
|  | @ -140,7 +141,7 @@ def test_save_wrong_mode(tmp_path): | |||
|         im.save(out) | ||||
| 
 | ||||
| 
 | ||||
| def test_save_mapdepth(): | ||||
| def test_save_mapdepth() -> None: | ||||
|     # This image has been manually hexedited from 200x32_p_bl_raw.tga | ||||
|     # to include an origin | ||||
|     test_file = "Tests/images/200x32_p_bl_raw_origin.tga" | ||||
|  | @ -148,7 +149,7 @@ def test_save_mapdepth(): | |||
|         assert_image_equal_tofile(im, "Tests/images/tga/common/200x32_p.png") | ||||
| 
 | ||||
| 
 | ||||
| def test_save_id_section(tmp_path): | ||||
| def test_save_id_section(tmp_path: Path) -> None: | ||||
|     test_file = "Tests/images/rgb32rle.tga" | ||||
|     with Image.open(test_file) as im: | ||||
|         out = str(tmp_path / "temp.tga") | ||||
|  | @ -179,7 +180,7 @@ def test_save_id_section(tmp_path): | |||
|         assert "id_section" not in test_im.info | ||||
| 
 | ||||
| 
 | ||||
| def test_save_orientation(tmp_path): | ||||
| def test_save_orientation(tmp_path: Path) -> None: | ||||
|     test_file = "Tests/images/rgb32rle.tga" | ||||
|     out = str(tmp_path / "temp.tga") | ||||
|     with Image.open(test_file) as im: | ||||
|  | @ -190,7 +191,7 @@ def test_save_orientation(tmp_path): | |||
|         assert test_im.info["orientation"] == 1 | ||||
| 
 | ||||
| 
 | ||||
| def test_horizontal_orientations(): | ||||
| def test_horizontal_orientations() -> None: | ||||
|     # These images have been manually hexedited to have the relevant orientations | ||||
|     with Image.open("Tests/images/rgb32rle_top_right.tga") as im: | ||||
|         assert im.load()[90, 90][:3] == (0, 0, 0) | ||||
|  | @ -199,7 +200,7 @@ def test_horizontal_orientations(): | |||
|         assert im.load()[90, 90][:3] == (0, 255, 0) | ||||
| 
 | ||||
| 
 | ||||
| def test_save_rle(tmp_path): | ||||
| def test_save_rle(tmp_path: Path) -> None: | ||||
|     test_file = "Tests/images/rgb32rle.tga" | ||||
|     with Image.open(test_file) as im: | ||||
|         assert im.info["compression"] == "tga_rle" | ||||
|  | @ -232,7 +233,7 @@ def test_save_rle(tmp_path): | |||
|         assert test_im.info["compression"] == "tga_rle" | ||||
| 
 | ||||
| 
 | ||||
| def test_save_l_transparency(tmp_path): | ||||
| def test_save_l_transparency(tmp_path: Path) -> None: | ||||
|     # There are 559 transparent pixels in la.tga. | ||||
|     num_transparent = 559 | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ from __future__ import annotations | |||
| import os | ||||
| import warnings | ||||
| from io import BytesIO | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -26,7 +27,7 @@ except ImportError: | |||
| 
 | ||||
| 
 | ||||
| class TestFileTiff: | ||||
|     def test_sanity(self, tmp_path): | ||||
|     def test_sanity(self, tmp_path: Path) -> None: | ||||
|         filename = str(tmp_path / "temp.tif") | ||||
| 
 | ||||
|         hopper("RGB").save(filename) | ||||
|  | @ -58,21 +59,21 @@ class TestFileTiff: | |||
|             pass | ||||
| 
 | ||||
|     @pytest.mark.skipif(is_pypy(), reason="Requires CPython") | ||||
|     def test_unclosed_file(self): | ||||
|         def open(): | ||||
|     def test_unclosed_file(self) -> None: | ||||
|         def open() -> None: | ||||
|             im = Image.open("Tests/images/multipage.tiff") | ||||
|             im.load() | ||||
| 
 | ||||
|         with pytest.warns(ResourceWarning): | ||||
|             open() | ||||
| 
 | ||||
|     def test_closed_file(self): | ||||
|     def test_closed_file(self) -> None: | ||||
|         with warnings.catch_warnings(): | ||||
|             im = Image.open("Tests/images/multipage.tiff") | ||||
|             im.load() | ||||
|             im.close() | ||||
| 
 | ||||
|     def test_seek_after_close(self): | ||||
|     def test_seek_after_close(self) -> None: | ||||
|         im = Image.open("Tests/images/multipage.tiff") | ||||
|         im.close() | ||||
| 
 | ||||
|  | @ -81,12 +82,12 @@ class TestFileTiff: | |||
|         with pytest.raises(ValueError): | ||||
|             im.seek(1) | ||||
| 
 | ||||
|     def test_context_manager(self): | ||||
|     def test_context_manager(self) -> None: | ||||
|         with warnings.catch_warnings(): | ||||
|             with Image.open("Tests/images/multipage.tiff") as im: | ||||
|                 im.load() | ||||
| 
 | ||||
|     def test_mac_tiff(self): | ||||
|     def test_mac_tiff(self) -> None: | ||||
|         # Read RGBa images from macOS [@PIL136] | ||||
| 
 | ||||
|         filename = "Tests/images/pil136.tiff" | ||||
|  | @ -98,7 +99,7 @@ class TestFileTiff: | |||
| 
 | ||||
|             assert_image_similar_tofile(im, "Tests/images/pil136.png", 1) | ||||
| 
 | ||||
|     def test_bigtiff(self, tmp_path): | ||||
|     def test_bigtiff(self, tmp_path: Path) -> None: | ||||
|         with Image.open("Tests/images/hopper_bigtiff.tif") as im: | ||||
|             assert_image_equal_tofile(im, "Tests/images/hopper.tif") | ||||
| 
 | ||||
|  | @ -109,13 +110,13 @@ class TestFileTiff: | |||
|             outfile = str(tmp_path / "temp.tif") | ||||
|             im.save(outfile, save_all=True, append_images=[im], tiffinfo=im.tag_v2) | ||||
| 
 | ||||
|     def test_set_legacy_api(self): | ||||
|     def test_set_legacy_api(self) -> None: | ||||
|         ifd = TiffImagePlugin.ImageFileDirectory_v2() | ||||
|         with pytest.raises(Exception) as e: | ||||
|             ifd.legacy_api = None | ||||
|         assert str(e.value) == "Not allowing setting of legacy api" | ||||
| 
 | ||||
|     def test_xyres_tiff(self): | ||||
|     def test_xyres_tiff(self) -> None: | ||||
|         filename = "Tests/images/pil168.tif" | ||||
|         with Image.open(filename) as im: | ||||
|             # legacy api | ||||
|  | @ -128,7 +129,7 @@ class TestFileTiff: | |||
| 
 | ||||
|             assert im.info["dpi"] == (72.0, 72.0) | ||||
| 
 | ||||
|     def test_xyres_fallback_tiff(self): | ||||
|     def test_xyres_fallback_tiff(self) -> None: | ||||
|         filename = "Tests/images/compression.tif" | ||||
|         with Image.open(filename) as im: | ||||
|             # v2 api | ||||
|  | @ -142,7 +143,7 @@ class TestFileTiff: | |||
|             # Fallback "inch". | ||||
|             assert im.info["dpi"] == (100.0, 100.0) | ||||
| 
 | ||||
|     def test_int_resolution(self): | ||||
|     def test_int_resolution(self) -> None: | ||||
|         filename = "Tests/images/pil168.tif" | ||||
|         with Image.open(filename) as im: | ||||
|             # Try to read a file where X,Y_RESOLUTION are ints | ||||
|  | @ -155,14 +156,14 @@ class TestFileTiff: | |||
|         "resolution_unit, dpi", | ||||
|         [(None, 72.8), (2, 72.8), (3, 184.912)], | ||||
|     ) | ||||
|     def test_load_float_dpi(self, resolution_unit, dpi): | ||||
|     def test_load_float_dpi(self, resolution_unit, dpi) -> None: | ||||
|         with Image.open( | ||||
|             "Tests/images/hopper_float_dpi_" + str(resolution_unit) + ".tif" | ||||
|         ) as im: | ||||
|             assert im.tag_v2.get(RESOLUTION_UNIT) == resolution_unit | ||||
|             assert im.info["dpi"] == (dpi, dpi) | ||||
| 
 | ||||
|     def test_save_float_dpi(self, tmp_path): | ||||
|     def test_save_float_dpi(self, tmp_path: Path) -> None: | ||||
|         outfile = str(tmp_path / "temp.tif") | ||||
|         with Image.open("Tests/images/hopper.tif") as im: | ||||
|             dpi = (72.2, 72.2) | ||||
|  | @ -171,7 +172,7 @@ class TestFileTiff: | |||
|             with Image.open(outfile) as reloaded: | ||||
|                 assert reloaded.info["dpi"] == dpi | ||||
| 
 | ||||
|     def test_save_setting_missing_resolution(self): | ||||
|     def test_save_setting_missing_resolution(self) -> None: | ||||
|         b = BytesIO() | ||||
|         with Image.open("Tests/images/10ct_32bit_128.tiff") as im: | ||||
|             im.save(b, format="tiff", resolution=123.45) | ||||
|  | @ -179,7 +180,7 @@ class TestFileTiff: | |||
|             assert im.tag_v2[X_RESOLUTION] == 123.45 | ||||
|             assert im.tag_v2[Y_RESOLUTION] == 123.45 | ||||
| 
 | ||||
|     def test_invalid_file(self): | ||||
|     def test_invalid_file(self) -> None: | ||||
|         invalid_file = "Tests/images/flower.jpg" | ||||
| 
 | ||||
|         with pytest.raises(SyntaxError): | ||||
|  | @ -190,30 +191,30 @@ class TestFileTiff: | |||
|             TiffImagePlugin.TiffImageFile(invalid_file) | ||||
|         TiffImagePlugin.PREFIXES.pop() | ||||
| 
 | ||||
|     def test_bad_exif(self): | ||||
|     def test_bad_exif(self) -> None: | ||||
|         with Image.open("Tests/images/hopper_bad_exif.jpg") as i: | ||||
|             # Should not raise struct.error. | ||||
|             with pytest.warns(UserWarning): | ||||
|                 i._getexif() | ||||
| 
 | ||||
|     def test_save_rgba(self, tmp_path): | ||||
|     def test_save_rgba(self, tmp_path: Path) -> None: | ||||
|         im = hopper("RGBA") | ||||
|         outfile = str(tmp_path / "temp.tif") | ||||
|         im.save(outfile) | ||||
| 
 | ||||
|     def test_save_unsupported_mode(self, tmp_path): | ||||
|     def test_save_unsupported_mode(self, tmp_path: Path) -> None: | ||||
|         im = hopper("HSV") | ||||
|         outfile = str(tmp_path / "temp.tif") | ||||
|         with pytest.raises(OSError): | ||||
|             im.save(outfile) | ||||
| 
 | ||||
|     def test_8bit_s(self): | ||||
|     def test_8bit_s(self) -> None: | ||||
|         with Image.open("Tests/images/8bit.s.tif") as im: | ||||
|             im.load() | ||||
|             assert im.mode == "L" | ||||
|             assert im.getpixel((50, 50)) == 184 | ||||
| 
 | ||||
|     def test_little_endian(self): | ||||
|     def test_little_endian(self) -> None: | ||||
|         with Image.open("Tests/images/16bit.cropped.tif") as im: | ||||
|             assert im.getpixel((0, 0)) == 480 | ||||
|             assert im.mode == "I;16" | ||||
|  | @ -223,7 +224,7 @@ class TestFileTiff: | |||
|         assert b[0] == ord(b"\xe0") | ||||
|         assert b[1] == ord(b"\x01") | ||||
| 
 | ||||
|     def test_big_endian(self): | ||||
|     def test_big_endian(self) -> None: | ||||
|         with Image.open("Tests/images/16bit.MM.cropped.tif") as im: | ||||
|             assert im.getpixel((0, 0)) == 480 | ||||
|             assert im.mode == "I;16B" | ||||
|  | @ -233,7 +234,7 @@ class TestFileTiff: | |||
|         assert b[0] == ord(b"\x01") | ||||
|         assert b[1] == ord(b"\xe0") | ||||
| 
 | ||||
|     def test_16bit_r(self): | ||||
|     def test_16bit_r(self) -> None: | ||||
|         with Image.open("Tests/images/16bit.r.tif") as im: | ||||
|             assert im.getpixel((0, 0)) == 480 | ||||
|             assert im.mode == "I;16" | ||||
|  | @ -242,14 +243,14 @@ class TestFileTiff: | |||
|         assert b[0] == ord(b"\xe0") | ||||
|         assert b[1] == ord(b"\x01") | ||||
| 
 | ||||
|     def test_16bit_s(self): | ||||
|     def test_16bit_s(self) -> None: | ||||
|         with Image.open("Tests/images/16bit.s.tif") as im: | ||||
|             im.load() | ||||
|             assert im.mode == "I" | ||||
|             assert im.getpixel((0, 0)) == 32767 | ||||
|             assert im.getpixel((0, 1)) == 0 | ||||
| 
 | ||||
|     def test_12bit_rawmode(self): | ||||
|     def test_12bit_rawmode(self) -> None: | ||||
|         """Are we generating the same interpretation | ||||
|         of the image as Imagemagick is?""" | ||||
| 
 | ||||
|  | @ -262,7 +263,7 @@ class TestFileTiff: | |||
| 
 | ||||
|             assert_image_equal_tofile(im, "Tests/images/12in16bit.tif") | ||||
| 
 | ||||
|     def test_32bit_float(self): | ||||
|     def test_32bit_float(self) -> None: | ||||
|         # Issue 614, specific 32-bit float format | ||||
|         path = "Tests/images/10ct_32bit_128.tiff" | ||||
|         with Image.open(path) as im: | ||||
|  | @ -271,7 +272,7 @@ class TestFileTiff: | |||
|             assert im.getpixel((0, 0)) == -0.4526388943195343 | ||||
|             assert im.getextrema() == (-3.140936851501465, 3.140684127807617) | ||||
| 
 | ||||
|     def test_unknown_pixel_mode(self): | ||||
|     def test_unknown_pixel_mode(self) -> None: | ||||
|         with pytest.raises(OSError): | ||||
|             with Image.open("Tests/images/hopper_unknown_pixel_mode.tif"): | ||||
|                 pass | ||||
|  | @ -283,12 +284,12 @@ class TestFileTiff: | |||
|             ("Tests/images/multipage.tiff", 3), | ||||
|         ), | ||||
|     ) | ||||
|     def test_n_frames(self, path, n_frames): | ||||
|     def test_n_frames(self, path, n_frames) -> None: | ||||
|         with Image.open(path) as im: | ||||
|             assert im.n_frames == n_frames | ||||
|             assert im.is_animated == (n_frames != 1) | ||||
| 
 | ||||
|     def test_eoferror(self): | ||||
|     def test_eoferror(self) -> None: | ||||
|         with Image.open("Tests/images/multipage-lastframe.tif") as im: | ||||
|             n_frames = im.n_frames | ||||
| 
 | ||||
|  | @ -300,7 +301,7 @@ class TestFileTiff: | |||
|             # Test that seeking to the last frame does not raise an error | ||||
|             im.seek(n_frames - 1) | ||||
| 
 | ||||
|     def test_multipage(self): | ||||
|     def test_multipage(self) -> None: | ||||
|         # issue #862 | ||||
|         with Image.open("Tests/images/multipage.tiff") as im: | ||||
|             # file is a multipage tiff: 10x10 green, 10x10 red, 20x20 blue | ||||
|  | @ -324,13 +325,13 @@ class TestFileTiff: | |||
|             assert im.size == (20, 20) | ||||
|             assert im.convert("RGB").getpixel((0, 0)) == (0, 0, 255) | ||||
| 
 | ||||
|     def test_multipage_last_frame(self): | ||||
|     def test_multipage_last_frame(self) -> None: | ||||
|         with Image.open("Tests/images/multipage-lastframe.tif") as im: | ||||
|             im.load() | ||||
|             assert im.size == (20, 20) | ||||
|             assert im.convert("RGB").getpixel((0, 0)) == (0, 0, 255) | ||||
| 
 | ||||
|     def test_frame_order(self): | ||||
|     def test_frame_order(self) -> None: | ||||
|         # A frame can't progress to itself after reading | ||||
|         with Image.open("Tests/images/multipage_single_frame_loop.tiff") as im: | ||||
|             assert im.n_frames == 1 | ||||
|  | @ -343,7 +344,7 @@ class TestFileTiff: | |||
|         with Image.open("Tests/images/multipage_out_of_order.tiff") as im: | ||||
|             assert im.n_frames == 3 | ||||
| 
 | ||||
|     def test___str__(self): | ||||
|     def test___str__(self) -> None: | ||||
|         filename = "Tests/images/pil136.tiff" | ||||
|         with Image.open(filename) as im: | ||||
|             # Act | ||||
|  | @ -352,7 +353,7 @@ class TestFileTiff: | |||
|             # Assert | ||||
|             assert isinstance(ret, str) | ||||
| 
 | ||||
|     def test_dict(self): | ||||
|     def test_dict(self) -> None: | ||||
|         # Arrange | ||||
|         filename = "Tests/images/pil136.tiff" | ||||
|         with Image.open(filename) as im: | ||||
|  | @ -392,7 +393,7 @@ class TestFileTiff: | |||
|             } | ||||
|             assert dict(im.tag) == legacy_tags | ||||
| 
 | ||||
|     def test__delitem__(self): | ||||
|     def test__delitem__(self) -> None: | ||||
|         filename = "Tests/images/pil136.tiff" | ||||
|         with Image.open(filename) as im: | ||||
|             len_before = len(dict(im.ifd)) | ||||
|  | @ -401,36 +402,36 @@ class TestFileTiff: | |||
|             assert len_before == len_after + 1 | ||||
| 
 | ||||
|     @pytest.mark.parametrize("legacy_api", (False, True)) | ||||
|     def test_load_byte(self, legacy_api): | ||||
|     def test_load_byte(self, legacy_api) -> None: | ||||
|         ifd = TiffImagePlugin.ImageFileDirectory_v2() | ||||
|         data = b"abc" | ||||
|         ret = ifd.load_byte(data, legacy_api) | ||||
|         assert ret == b"abc" | ||||
| 
 | ||||
|     def test_load_string(self): | ||||
|     def test_load_string(self) -> None: | ||||
|         ifd = TiffImagePlugin.ImageFileDirectory_v2() | ||||
|         data = b"abc\0" | ||||
|         ret = ifd.load_string(data, False) | ||||
|         assert ret == "abc" | ||||
| 
 | ||||
|     def test_load_float(self): | ||||
|     def test_load_float(self) -> None: | ||||
|         ifd = TiffImagePlugin.ImageFileDirectory_v2() | ||||
|         data = b"abcdabcd" | ||||
|         ret = ifd.load_float(data, False) | ||||
|         assert ret == (1.6777999408082104e22, 1.6777999408082104e22) | ||||
| 
 | ||||
|     def test_load_double(self): | ||||
|     def test_load_double(self) -> None: | ||||
|         ifd = TiffImagePlugin.ImageFileDirectory_v2() | ||||
|         data = b"abcdefghabcdefgh" | ||||
|         ret = ifd.load_double(data, False) | ||||
|         assert ret == (8.540883223036124e194, 8.540883223036124e194) | ||||
| 
 | ||||
|     def test_ifd_tag_type(self): | ||||
|     def test_ifd_tag_type(self) -> None: | ||||
|         with Image.open("Tests/images/ifd_tag_type.tiff") as im: | ||||
|             assert 0x8825 in im.tag_v2 | ||||
| 
 | ||||
|     def test_exif(self, tmp_path): | ||||
|         def check_exif(exif): | ||||
|     def test_exif(self, tmp_path: Path) -> None: | ||||
|         def check_exif(exif) -> None: | ||||
|             assert sorted(exif.keys()) == [ | ||||
|                 256, | ||||
|                 257, | ||||
|  | @ -481,7 +482,7 @@ class TestFileTiff: | |||
|             exif = im.getexif() | ||||
|             check_exif(exif) | ||||
| 
 | ||||
|     def test_modify_exif(self, tmp_path): | ||||
|     def test_modify_exif(self, tmp_path: Path) -> None: | ||||
|         outfile = str(tmp_path / "temp.tif") | ||||
|         with Image.open("Tests/images/ifd_tag_type.tiff") as im: | ||||
|             exif = im.getexif() | ||||
|  | @ -493,7 +494,7 @@ class TestFileTiff: | |||
|             exif = im.getexif() | ||||
|             assert exif[264] == 100 | ||||
| 
 | ||||
|     def test_reload_exif_after_seek(self): | ||||
|     def test_reload_exif_after_seek(self) -> None: | ||||
|         with Image.open("Tests/images/multipage.tiff") as im: | ||||
|             exif = im.getexif() | ||||
|             del exif[256] | ||||
|  | @ -501,7 +502,7 @@ class TestFileTiff: | |||
| 
 | ||||
|             assert 256 in exif | ||||
| 
 | ||||
|     def test_exif_frames(self): | ||||
|     def test_exif_frames(self) -> None: | ||||
|         # Test that EXIF data can change across frames | ||||
|         with Image.open("Tests/images/g4-multi.tiff") as im: | ||||
|             assert im.getexif()[273] == (328, 815) | ||||
|  | @ -510,7 +511,7 @@ class TestFileTiff: | |||
|             assert im.getexif()[273] == (1408, 1907) | ||||
| 
 | ||||
|     @pytest.mark.parametrize("mode", ("1", "L")) | ||||
|     def test_photometric(self, mode, tmp_path): | ||||
|     def test_photometric(self, mode, tmp_path: Path) -> None: | ||||
|         filename = str(tmp_path / "temp.tif") | ||||
|         im = hopper(mode) | ||||
|         im.save(filename, tiffinfo={262: 0}) | ||||
|  | @ -518,13 +519,13 @@ class TestFileTiff: | |||
|             assert reloaded.tag_v2[262] == 0 | ||||
|             assert_image_equal(im, reloaded) | ||||
| 
 | ||||
|     def test_seek(self): | ||||
|     def test_seek(self) -> None: | ||||
|         filename = "Tests/images/pil136.tiff" | ||||
|         with Image.open(filename) as im: | ||||
|             im.seek(0) | ||||
|             assert im.tell() == 0 | ||||
| 
 | ||||
|     def test_seek_eof(self): | ||||
|     def test_seek_eof(self) -> None: | ||||
|         filename = "Tests/images/pil136.tiff" | ||||
|         with Image.open(filename) as im: | ||||
|             assert im.tell() == 0 | ||||
|  | @ -533,21 +534,21 @@ class TestFileTiff: | |||
|             with pytest.raises(EOFError): | ||||
|                 im.seek(1) | ||||
| 
 | ||||
|     def test__limit_rational_int(self): | ||||
|     def test__limit_rational_int(self) -> None: | ||||
|         from PIL.TiffImagePlugin import _limit_rational | ||||
| 
 | ||||
|         value = 34 | ||||
|         ret = _limit_rational(value, 65536) | ||||
|         assert ret == (34, 1) | ||||
| 
 | ||||
|     def test__limit_rational_float(self): | ||||
|     def test__limit_rational_float(self) -> None: | ||||
|         from PIL.TiffImagePlugin import _limit_rational | ||||
| 
 | ||||
|         value = 22.3 | ||||
|         ret = _limit_rational(value, 65536) | ||||
|         assert ret == (223, 10) | ||||
| 
 | ||||
|     def test_4bit(self): | ||||
|     def test_4bit(self) -> None: | ||||
|         test_file = "Tests/images/hopper_gray_4bpp.tif" | ||||
|         original = hopper("L") | ||||
|         with Image.open(test_file) as im: | ||||
|  | @ -555,7 +556,7 @@ class TestFileTiff: | |||
|             assert im.mode == "L" | ||||
|             assert_image_similar(im, original, 7.3) | ||||
| 
 | ||||
|     def test_gray_semibyte_per_pixel(self): | ||||
|     def test_gray_semibyte_per_pixel(self) -> None: | ||||
|         test_files = ( | ||||
|             ( | ||||
|                 24.8,  # epsilon | ||||
|  | @ -588,7 +589,7 @@ class TestFileTiff: | |||
|                         assert im2.mode == "L" | ||||
|                         assert_image_equal(im, im2) | ||||
| 
 | ||||
|     def test_with_underscores(self, tmp_path): | ||||
|     def test_with_underscores(self, tmp_path: Path) -> None: | ||||
|         kwargs = {"resolution_unit": "inch", "x_resolution": 72, "y_resolution": 36} | ||||
|         filename = str(tmp_path / "temp.tif") | ||||
|         hopper("RGB").save(filename, **kwargs) | ||||
|  | @ -601,7 +602,7 @@ class TestFileTiff: | |||
|             assert im.tag_v2[X_RESOLUTION] == 72 | ||||
|             assert im.tag_v2[Y_RESOLUTION] == 36 | ||||
| 
 | ||||
|     def test_roundtrip_tiff_uint16(self, tmp_path): | ||||
|     def test_roundtrip_tiff_uint16(self, tmp_path: Path) -> None: | ||||
|         # Test an image of all '0' values | ||||
|         pixel_value = 0x1234 | ||||
|         infile = "Tests/images/uint16_1_4660.tif" | ||||
|  | @ -613,7 +614,7 @@ class TestFileTiff: | |||
| 
 | ||||
|             assert_image_equal_tofile(im, tmpfile) | ||||
| 
 | ||||
|     def test_rowsperstrip(self, tmp_path): | ||||
|     def test_rowsperstrip(self, tmp_path: Path) -> None: | ||||
|         outfile = str(tmp_path / "temp.tif") | ||||
|         im = hopper() | ||||
|         im.save(outfile, tiffinfo={278: 256}) | ||||
|  | @ -621,25 +622,25 @@ class TestFileTiff: | |||
|         with Image.open(outfile) as im: | ||||
|             assert im.tag_v2[278] == 256 | ||||
| 
 | ||||
|     def test_strip_raw(self): | ||||
|     def test_strip_raw(self) -> None: | ||||
|         infile = "Tests/images/tiff_strip_raw.tif" | ||||
|         with Image.open(infile) as im: | ||||
|             assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png") | ||||
| 
 | ||||
|     def test_strip_planar_raw(self): | ||||
|     def test_strip_planar_raw(self) -> None: | ||||
|         # gdal_translate -of GTiff -co INTERLEAVE=BAND \ | ||||
|         # tiff_strip_raw.tif tiff_strip_planar_raw.tiff | ||||
|         infile = "Tests/images/tiff_strip_planar_raw.tif" | ||||
|         with Image.open(infile) as im: | ||||
|             assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png") | ||||
| 
 | ||||
|     def test_strip_planar_raw_with_overviews(self): | ||||
|     def test_strip_planar_raw_with_overviews(self) -> None: | ||||
|         # gdaladdo tiff_strip_planar_raw2.tif 2 4 8 16 | ||||
|         infile = "Tests/images/tiff_strip_planar_raw_with_overviews.tif" | ||||
|         with Image.open(infile) as im: | ||||
|             assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png") | ||||
| 
 | ||||
|     def test_tiled_planar_raw(self): | ||||
|     def test_tiled_planar_raw(self) -> None: | ||||
|         # gdal_translate -of GTiff -co TILED=YES -co BLOCKXSIZE=32 \ | ||||
|         # -co BLOCKYSIZE=32 -co INTERLEAVE=BAND \ | ||||
|         # tiff_tiled_raw.tif tiff_tiled_planar_raw.tiff | ||||
|  | @ -647,7 +648,7 @@ class TestFileTiff: | |||
|         with Image.open(infile) as im: | ||||
|             assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png") | ||||
| 
 | ||||
|     def test_planar_configuration_save(self, tmp_path): | ||||
|     def test_planar_configuration_save(self, tmp_path: Path) -> None: | ||||
|         infile = "Tests/images/tiff_tiled_planar_raw.tif" | ||||
|         with Image.open(infile) as im: | ||||
|             assert im._planar_configuration == 2 | ||||
|  | @ -659,7 +660,7 @@ class TestFileTiff: | |||
|                 assert_image_equal_tofile(reloaded, infile) | ||||
| 
 | ||||
|     @pytest.mark.parametrize("mode", ("P", "PA")) | ||||
|     def test_palette(self, mode, tmp_path): | ||||
|     def test_palette(self, mode, tmp_path: Path) -> None: | ||||
|         outfile = str(tmp_path / "temp.tif") | ||||
| 
 | ||||
|         im = hopper(mode) | ||||
|  | @ -668,7 +669,7 @@ class TestFileTiff: | |||
|         with Image.open(outfile) as reloaded: | ||||
|             assert_image_equal(im.convert("RGB"), reloaded.convert("RGB")) | ||||
| 
 | ||||
|     def test_save_all(self): | ||||
|     def test_save_all(self) -> None: | ||||
|         mp = BytesIO() | ||||
|         with Image.open("Tests/images/multipage.tiff") as im: | ||||
|             im.save(mp, format="tiff", save_all=True) | ||||
|  | @ -698,7 +699,7 @@ class TestFileTiff: | |||
|         with Image.open(mp) as reread: | ||||
|             assert reread.n_frames == 3 | ||||
| 
 | ||||
|     def test_save_all_progress(self): | ||||
|     def test_save_all_progress(self) -> None: | ||||
|         out = BytesIO() | ||||
|         progress = [] | ||||
| 
 | ||||
|  | @ -743,7 +744,7 @@ class TestFileTiff: | |||
|             ) | ||||
|         assert progress == expected | ||||
| 
 | ||||
|     def test_saving_icc_profile(self, tmp_path): | ||||
|     def test_saving_icc_profile(self, tmp_path: Path) -> None: | ||||
|         # Tests saving TIFF with icc_profile set. | ||||
|         # At the time of writing this will only work for non-compressed tiffs | ||||
|         # as libtiff does not support embedded ICC profiles, | ||||
|  | @ -757,7 +758,7 @@ class TestFileTiff: | |||
|         with Image.open(tmpfile) as reloaded: | ||||
|             assert b"Dummy value" == reloaded.info["icc_profile"] | ||||
| 
 | ||||
|     def test_save_icc_profile(self, tmp_path): | ||||
|     def test_save_icc_profile(self, tmp_path: Path) -> None: | ||||
|         im = hopper() | ||||
|         assert "icc_profile" not in im.info | ||||
| 
 | ||||
|  | @ -768,14 +769,14 @@ class TestFileTiff: | |||
|         with Image.open(outfile) as reloaded: | ||||
|             assert reloaded.info["icc_profile"] == icc_profile | ||||
| 
 | ||||
|     def test_save_bmp_compression(self, tmp_path): | ||||
|     def test_save_bmp_compression(self, tmp_path: Path) -> None: | ||||
|         with Image.open("Tests/images/hopper.bmp") as im: | ||||
|             assert im.info["compression"] == 0 | ||||
| 
 | ||||
|             outfile = str(tmp_path / "temp.tif") | ||||
|             im.save(outfile) | ||||
| 
 | ||||
|     def test_discard_icc_profile(self, tmp_path): | ||||
|     def test_discard_icc_profile(self, tmp_path: Path) -> None: | ||||
|         outfile = str(tmp_path / "temp.tif") | ||||
| 
 | ||||
|         with Image.open("Tests/images/icc_profile.png") as im: | ||||
|  | @ -786,7 +787,7 @@ class TestFileTiff: | |||
|         with Image.open(outfile) as reloaded: | ||||
|             assert "icc_profile" not in reloaded.info | ||||
| 
 | ||||
|     def test_getxmp(self): | ||||
|     def test_getxmp(self) -> None: | ||||
|         with Image.open("Tests/images/lab.tif") as im: | ||||
|             if ElementTree is None: | ||||
|                 with pytest.warns( | ||||
|  | @ -801,7 +802,7 @@ class TestFileTiff: | |||
|                 assert description[0]["format"] == "image/tiff" | ||||
|                 assert description[3]["BitsPerSample"]["Seq"]["li"] == ["8", "8", "8"] | ||||
| 
 | ||||
|     def test_get_photoshop_blocks(self): | ||||
|     def test_get_photoshop_blocks(self) -> None: | ||||
|         with Image.open("Tests/images/lab.tif") as im: | ||||
|             assert list(im.get_photoshop_blocks().keys()) == [ | ||||
|                 1061, | ||||
|  | @ -827,7 +828,7 @@ class TestFileTiff: | |||
|                 4001, | ||||
|             ] | ||||
| 
 | ||||
|     def test_tiff_chunks(self, tmp_path): | ||||
|     def test_tiff_chunks(self, tmp_path: Path) -> None: | ||||
|         tmpfile = str(tmp_path / "temp.tif") | ||||
| 
 | ||||
|         im = hopper() | ||||
|  | @ -848,7 +849,7 @@ class TestFileTiff: | |||
| 
 | ||||
|         assert_image_equal_tofile(im, tmpfile) | ||||
| 
 | ||||
|     def test_close_on_load_exclusive(self, tmp_path): | ||||
|     def test_close_on_load_exclusive(self, tmp_path: Path) -> None: | ||||
|         # similar to test_fd_leak, but runs on unixlike os | ||||
|         tmpfile = str(tmp_path / "temp.tif") | ||||
| 
 | ||||
|  | @ -861,7 +862,7 @@ class TestFileTiff: | |||
|         im.load() | ||||
|         assert fp.closed | ||||
| 
 | ||||
|     def test_close_on_load_nonexclusive(self, tmp_path): | ||||
|     def test_close_on_load_nonexclusive(self, tmp_path: Path) -> None: | ||||
|         tmpfile = str(tmp_path / "temp.tif") | ||||
| 
 | ||||
|         with Image.open("Tests/images/uint16_1_4660.tif") as im: | ||||
|  | @ -883,7 +884,7 @@ class TestFileTiff: | |||
|         not os.path.exists("Tests/images/string_dimension.tiff"), | ||||
|         reason="Extra image files not installed", | ||||
|     ) | ||||
|     def test_string_dimension(self): | ||||
|     def test_string_dimension(self) -> None: | ||||
|         # Assert that an error is raised if one of the dimensions is a string | ||||
|         with Image.open("Tests/images/string_dimension.tiff") as im: | ||||
|             with pytest.raises(OSError): | ||||
|  | @ -891,7 +892,7 @@ class TestFileTiff: | |||
| 
 | ||||
|     @pytest.mark.timeout(6) | ||||
|     @pytest.mark.filterwarnings("ignore:Truncated File Read") | ||||
|     def test_timeout(self): | ||||
|     def test_timeout(self) -> None: | ||||
|         with Image.open("Tests/images/timeout-6646305047838720") as im: | ||||
|             ImageFile.LOAD_TRUNCATED_IMAGES = True | ||||
|             im.load() | ||||
|  | @ -904,7 +905,7 @@ class TestFileTiff: | |||
|         ], | ||||
|     ) | ||||
|     @pytest.mark.timeout(2) | ||||
|     def test_oom(self, test_file): | ||||
|     def test_oom(self, test_file) -> None: | ||||
|         with pytest.raises(UnidentifiedImageError): | ||||
|             with pytest.warns(UserWarning): | ||||
|                 with Image.open(test_file): | ||||
|  | @ -913,7 +914,7 @@ class TestFileTiff: | |||
| 
 | ||||
| @pytest.mark.skipif(not is_win32(), reason="Windows only") | ||||
| class TestFileTiffW32: | ||||
|     def test_fd_leak(self, tmp_path): | ||||
|     def test_fd_leak(self, tmp_path: Path) -> None: | ||||
|         tmpfile = str(tmp_path / "temp.tif") | ||||
| 
 | ||||
|         # this is an mmaped file. | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ from __future__ import annotations | |||
| 
 | ||||
| import io | ||||
| import struct | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -13,7 +14,7 @@ from .helper import assert_deep_equal, hopper | |||
| TAG_IDS = {info.name: info.value for info in TiffTags.TAGS_V2.values()} | ||||
| 
 | ||||
| 
 | ||||
| def test_rt_metadata(tmp_path): | ||||
| def test_rt_metadata(tmp_path: Path) -> None: | ||||
|     """Test writing arbitrary metadata into the tiff image directory | ||||
|     Use case is ImageJ private tags, one numeric, one arbitrary | ||||
|     data.  https://github.com/python-pillow/Pillow/issues/291 | ||||
|  | @ -79,7 +80,7 @@ def test_rt_metadata(tmp_path): | |||
|         assert loaded.tag_v2[ImageJMetaDataByteCounts] == (8, len(bin_data) - 8) | ||||
| 
 | ||||
| 
 | ||||
| def test_read_metadata(): | ||||
| def test_read_metadata() -> None: | ||||
|     with Image.open("Tests/images/hopper_g4.tif") as img: | ||||
|         assert { | ||||
|             "YResolution": IFDRational(4294967295, 113653537), | ||||
|  | @ -120,7 +121,7 @@ def test_read_metadata(): | |||
|         } == img.tag.named() | ||||
| 
 | ||||
| 
 | ||||
| def test_write_metadata(tmp_path): | ||||
| def test_write_metadata(tmp_path: Path) -> None: | ||||
|     """Test metadata writing through the python code""" | ||||
|     with Image.open("Tests/images/hopper.tif") as img: | ||||
|         f = str(tmp_path / "temp.tiff") | ||||
|  | @ -157,7 +158,7 @@ def test_write_metadata(tmp_path): | |||
|             assert value == reloaded[tag], f"{tag} didn't roundtrip" | ||||
| 
 | ||||
| 
 | ||||
| def test_change_stripbytecounts_tag_type(tmp_path): | ||||
| def test_change_stripbytecounts_tag_type(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.tiff") | ||||
|     with Image.open("Tests/images/hopper.tif") as im: | ||||
|         info = im.tag_v2 | ||||
|  | @ -176,19 +177,19 @@ def test_change_stripbytecounts_tag_type(tmp_path): | |||
|         assert reloaded.tag_v2.tagtype[TiffImagePlugin.STRIPBYTECOUNTS] == TiffTags.LONG | ||||
| 
 | ||||
| 
 | ||||
| def test_no_duplicate_50741_tag(): | ||||
| def test_no_duplicate_50741_tag() -> None: | ||||
|     assert TAG_IDS["MakerNoteSafety"] == 50741 | ||||
|     assert TAG_IDS["BestQualityScale"] == 50780 | ||||
| 
 | ||||
| 
 | ||||
| def test_iptc(tmp_path): | ||||
| def test_iptc(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.tiff") | ||||
|     with Image.open("Tests/images/hopper.Lab.tif") as im: | ||||
|         im.save(out) | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("value, expected", ((b"test", "test"), (1, "1"))) | ||||
| def test_writing_other_types_to_ascii(value, expected, tmp_path): | ||||
| def test_writing_other_types_to_ascii(value, expected, tmp_path: Path) -> None: | ||||
|     info = TiffImagePlugin.ImageFileDirectory_v2() | ||||
| 
 | ||||
|     tag = TiffTags.TAGS_V2[271] | ||||
|  | @ -205,7 +206,7 @@ def test_writing_other_types_to_ascii(value, expected, tmp_path): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("value", (1, IFDRational(1))) | ||||
| def test_writing_other_types_to_bytes(value, tmp_path): | ||||
| def test_writing_other_types_to_bytes(value, tmp_path: Path) -> None: | ||||
|     im = hopper() | ||||
|     info = TiffImagePlugin.ImageFileDirectory_v2() | ||||
| 
 | ||||
|  | @ -221,7 +222,7 @@ def test_writing_other_types_to_bytes(value, tmp_path): | |||
|         assert reloaded.tag_v2[700] == b"\x01" | ||||
| 
 | ||||
| 
 | ||||
| def test_writing_other_types_to_undefined(tmp_path): | ||||
| def test_writing_other_types_to_undefined(tmp_path: Path) -> None: | ||||
|     im = hopper() | ||||
|     info = TiffImagePlugin.ImageFileDirectory_v2() | ||||
| 
 | ||||
|  | @ -237,7 +238,7 @@ def test_writing_other_types_to_undefined(tmp_path): | |||
|         assert reloaded.tag_v2[33723] == b"1" | ||||
| 
 | ||||
| 
 | ||||
| def test_undefined_zero(tmp_path): | ||||
| def test_undefined_zero(tmp_path: Path) -> None: | ||||
|     # Check that the tag has not been changed since this test was created | ||||
|     tag = TiffTags.TAGS_V2[45059] | ||||
|     assert tag.type == TiffTags.UNDEFINED | ||||
|  | @ -252,7 +253,7 @@ def test_undefined_zero(tmp_path): | |||
|     assert info[45059] == original | ||||
| 
 | ||||
| 
 | ||||
| def test_empty_metadata(): | ||||
| def test_empty_metadata() -> None: | ||||
|     f = io.BytesIO(b"II*\x00\x08\x00\x00\x00") | ||||
|     head = f.read(8) | ||||
|     info = TiffImagePlugin.ImageFileDirectory(head) | ||||
|  | @ -261,7 +262,7 @@ def test_empty_metadata(): | |||
|         info.load(f) | ||||
| 
 | ||||
| 
 | ||||
| def test_iccprofile(tmp_path): | ||||
| def test_iccprofile(tmp_path: Path) -> None: | ||||
|     # https://github.com/python-pillow/Pillow/issues/1462 | ||||
|     out = str(tmp_path / "temp.tiff") | ||||
|     with Image.open("Tests/images/hopper.iccprofile.tif") as im: | ||||
|  | @ -272,7 +273,7 @@ def test_iccprofile(tmp_path): | |||
|         assert im.info["icc_profile"] == reloaded.info["icc_profile"] | ||||
| 
 | ||||
| 
 | ||||
| def test_iccprofile_binary(): | ||||
| def test_iccprofile_binary() -> None: | ||||
|     # https://github.com/python-pillow/Pillow/issues/1526 | ||||
|     # We should be able to load this, | ||||
|     # but probably won't be able to save it. | ||||
|  | @ -282,19 +283,19 @@ def test_iccprofile_binary(): | |||
|         assert im.info["icc_profile"] | ||||
| 
 | ||||
| 
 | ||||
| def test_iccprofile_save_png(tmp_path): | ||||
| def test_iccprofile_save_png(tmp_path: Path) -> None: | ||||
|     with Image.open("Tests/images/hopper.iccprofile.tif") as im: | ||||
|         outfile = str(tmp_path / "temp.png") | ||||
|         im.save(outfile) | ||||
| 
 | ||||
| 
 | ||||
| def test_iccprofile_binary_save_png(tmp_path): | ||||
| def test_iccprofile_binary_save_png(tmp_path: Path) -> None: | ||||
|     with Image.open("Tests/images/hopper.iccprofile_binary.tif") as im: | ||||
|         outfile = str(tmp_path / "temp.png") | ||||
|         im.save(outfile) | ||||
| 
 | ||||
| 
 | ||||
| def test_exif_div_zero(tmp_path): | ||||
| def test_exif_div_zero(tmp_path: Path) -> None: | ||||
|     im = hopper() | ||||
|     info = TiffImagePlugin.ImageFileDirectory_v2() | ||||
|     info[41988] = TiffImagePlugin.IFDRational(0, 0) | ||||
|  | @ -307,7 +308,7 @@ def test_exif_div_zero(tmp_path): | |||
|         assert 0 == reloaded.tag_v2[41988].denominator | ||||
| 
 | ||||
| 
 | ||||
| def test_ifd_unsigned_rational(tmp_path): | ||||
| def test_ifd_unsigned_rational(tmp_path: Path) -> None: | ||||
|     im = hopper() | ||||
|     info = TiffImagePlugin.ImageFileDirectory_v2() | ||||
| 
 | ||||
|  | @ -338,7 +339,7 @@ def test_ifd_unsigned_rational(tmp_path): | |||
|         assert 1 == reloaded.tag_v2[41493].denominator | ||||
| 
 | ||||
| 
 | ||||
| def test_ifd_signed_rational(tmp_path): | ||||
| def test_ifd_signed_rational(tmp_path: Path) -> None: | ||||
|     im = hopper() | ||||
|     info = TiffImagePlugin.ImageFileDirectory_v2() | ||||
| 
 | ||||
|  | @ -381,7 +382,7 @@ def test_ifd_signed_rational(tmp_path): | |||
|         assert -1 == reloaded.tag_v2[37380].denominator | ||||
| 
 | ||||
| 
 | ||||
| def test_ifd_signed_long(tmp_path): | ||||
| def test_ifd_signed_long(tmp_path: Path) -> None: | ||||
|     im = hopper() | ||||
|     info = TiffImagePlugin.ImageFileDirectory_v2() | ||||
| 
 | ||||
|  | @ -394,7 +395,7 @@ def test_ifd_signed_long(tmp_path): | |||
|         assert reloaded.tag_v2[37000] == -60000 | ||||
| 
 | ||||
| 
 | ||||
| def test_empty_values(): | ||||
| def test_empty_values() -> None: | ||||
|     data = io.BytesIO( | ||||
|         b"II*\x00\x08\x00\x00\x00\x03\x00\x1a\x01\x05\x00\x00\x00\x00\x00" | ||||
|         b"\x00\x00\x00\x00\x1b\x01\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00" | ||||
|  | @ -409,7 +410,7 @@ def test_empty_values(): | |||
|     assert 33432 in info | ||||
| 
 | ||||
| 
 | ||||
| def test_photoshop_info(tmp_path): | ||||
| def test_photoshop_info(tmp_path: Path) -> None: | ||||
|     with Image.open("Tests/images/issue_2278.tif") as im: | ||||
|         assert len(im.tag_v2[34377]) == 70 | ||||
|         assert isinstance(im.tag_v2[34377], bytes) | ||||
|  | @ -420,7 +421,7 @@ def test_photoshop_info(tmp_path): | |||
|         assert isinstance(reloaded.tag_v2[34377], bytes) | ||||
| 
 | ||||
| 
 | ||||
| def test_too_many_entries(): | ||||
| def test_too_many_entries() -> None: | ||||
|     ifd = TiffImagePlugin.ImageFileDirectory_v2() | ||||
| 
 | ||||
|     #    277: ("SamplesPerPixel", SHORT, 1), | ||||
|  | @ -432,7 +433,7 @@ def test_too_many_entries(): | |||
|         assert ifd[277] == 4 | ||||
| 
 | ||||
| 
 | ||||
| def test_tag_group_data(): | ||||
| def test_tag_group_data() -> None: | ||||
|     base_ifd = TiffImagePlugin.ImageFileDirectory_v2() | ||||
|     interop_ifd = TiffImagePlugin.ImageFileDirectory_v2(group=40965) | ||||
|     for ifd in (base_ifd, interop_ifd): | ||||
|  | @ -446,7 +447,7 @@ def test_tag_group_data(): | |||
|     assert base_ifd.tagtype[2] != interop_ifd.tagtype[256] | ||||
| 
 | ||||
| 
 | ||||
| def test_empty_subifd(tmp_path): | ||||
| def test_empty_subifd(tmp_path: Path) -> None: | ||||
|     out = str(tmp_path / "temp.jpg") | ||||
| 
 | ||||
|     im = hopper() | ||||
|  |  | |||
|  | @ -7,7 +7,7 @@ from .helper import assert_image_equal_tofile | |||
| TEST_FILE = "Tests/images/hopper.wal" | ||||
| 
 | ||||
| 
 | ||||
| def test_open(): | ||||
| def test_open() -> None: | ||||
|     with WalImageFile.open(TEST_FILE) as im: | ||||
|         assert im.format == "WAL" | ||||
|         assert im.format_description == "Quake2 Texture" | ||||
|  | @ -19,7 +19,7 @@ def test_open(): | |||
|         assert_image_equal_tofile(im, "Tests/images/hopper_wal.png") | ||||
| 
 | ||||
| 
 | ||||
| def test_load(): | ||||
| def test_load() -> None: | ||||
|     with WalImageFile.open(TEST_FILE) as im: | ||||
|         assert im.load()[0, 0] == 122 | ||||
| 
 | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ import re | |||
| import sys | ||||
| import warnings | ||||
| from io import BytesIO | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -26,7 +27,7 @@ except ImportError: | |||
| 
 | ||||
| 
 | ||||
| class TestUnsupportedWebp: | ||||
|     def test_unsupported(self): | ||||
|     def test_unsupported(self) -> None: | ||||
|         if HAVE_WEBP: | ||||
|             WebPImagePlugin.SUPPORTED = False | ||||
| 
 | ||||
|  | @ -42,15 +43,15 @@ class TestUnsupportedWebp: | |||
| 
 | ||||
| @skip_unless_feature("webp") | ||||
| class TestFileWebp: | ||||
|     def setup_method(self): | ||||
|     def setup_method(self) -> None: | ||||
|         self.rgb_mode = "RGB" | ||||
| 
 | ||||
|     def test_version(self): | ||||
|     def test_version(self) -> None: | ||||
|         _webp.WebPDecoderVersion() | ||||
|         _webp.WebPDecoderBuggyAlpha() | ||||
|         assert re.search(r"\d+\.\d+\.\d+$", features.version_module("webp")) | ||||
| 
 | ||||
|     def test_read_rgb(self): | ||||
|     def test_read_rgb(self) -> None: | ||||
|         """ | ||||
|         Can we read a RGB mode WebP file without error? | ||||
|         Does it have the bits we expect? | ||||
|  | @ -67,7 +68,7 @@ class TestFileWebp: | |||
|             # dwebp -ppm ../../Tests/images/hopper.webp -o hopper_webp_bits.ppm | ||||
|             assert_image_similar_tofile(image, "Tests/images/hopper_webp_bits.ppm", 1.0) | ||||
| 
 | ||||
|     def _roundtrip(self, tmp_path, mode, epsilon, args={}): | ||||
|     def _roundtrip(self, tmp_path: Path, mode, epsilon, args={}) -> None: | ||||
|         temp_file = str(tmp_path / "temp.webp") | ||||
| 
 | ||||
|         hopper(mode).save(temp_file, **args) | ||||
|  | @ -93,7 +94,7 @@ class TestFileWebp: | |||
|                 target = target.convert(self.rgb_mode) | ||||
|             assert_image_similar(image, target, epsilon) | ||||
| 
 | ||||
|     def test_write_rgb(self, tmp_path): | ||||
|     def test_write_rgb(self, tmp_path: Path) -> None: | ||||
|         """ | ||||
|         Can we write a RGB mode file to webp without error? | ||||
|         Does it have the bits we expect? | ||||
|  | @ -101,7 +102,7 @@ class TestFileWebp: | |||
| 
 | ||||
|         self._roundtrip(tmp_path, self.rgb_mode, 12.5) | ||||
| 
 | ||||
|     def test_write_method(self, tmp_path): | ||||
|     def test_write_method(self, tmp_path: Path) -> None: | ||||
|         self._roundtrip(tmp_path, self.rgb_mode, 12.0, {"method": 6}) | ||||
| 
 | ||||
|         buffer_no_args = BytesIO() | ||||
|  | @ -112,7 +113,7 @@ class TestFileWebp: | |||
|         assert buffer_no_args.getbuffer() != buffer_method.getbuffer() | ||||
| 
 | ||||
|     @skip_unless_feature("webp_anim") | ||||
|     def test_save_all(self, tmp_path): | ||||
|     def test_save_all(self, tmp_path: Path) -> None: | ||||
|         temp_file = str(tmp_path / "temp.webp") | ||||
|         im = Image.new("RGB", (1, 1)) | ||||
|         im2 = Image.new("RGB", (1, 1), "#f00") | ||||
|  | @ -125,7 +126,7 @@ class TestFileWebp: | |||
|             assert_image_similar(im2, reloaded, 1) | ||||
| 
 | ||||
|     @skip_unless_feature("webp_anim") | ||||
|     def test_save_all_progress(self): | ||||
|     def test_save_all_progress(self) -> None: | ||||
|         out = BytesIO() | ||||
|         progress = [] | ||||
| 
 | ||||
|  | @ -169,14 +170,14 @@ class TestFileWebp: | |||
|         ) | ||||
|         assert progress == expected | ||||
| 
 | ||||
|     def test_icc_profile(self, tmp_path): | ||||
|     def test_icc_profile(self, tmp_path: Path) -> None: | ||||
|         self._roundtrip(tmp_path, self.rgb_mode, 12.5, {"icc_profile": None}) | ||||
|         if _webp.HAVE_WEBPANIM: | ||||
|             self._roundtrip( | ||||
|                 tmp_path, self.rgb_mode, 12.5, {"icc_profile": None, "save_all": True} | ||||
|             ) | ||||
| 
 | ||||
|     def test_write_unsupported_mode_L(self, tmp_path): | ||||
|     def test_write_unsupported_mode_L(self, tmp_path: Path) -> None: | ||||
|         """ | ||||
|         Saving a black-and-white file to WebP format should work, and be | ||||
|         similar to the original file. | ||||
|  | @ -184,7 +185,7 @@ class TestFileWebp: | |||
| 
 | ||||
|         self._roundtrip(tmp_path, "L", 10.0) | ||||
| 
 | ||||
|     def test_write_unsupported_mode_P(self, tmp_path): | ||||
|     def test_write_unsupported_mode_P(self, tmp_path: Path) -> None: | ||||
|         """ | ||||
|         Saving a palette-based file to WebP format should work, and be | ||||
|         similar to the original file. | ||||
|  | @ -193,14 +194,14 @@ class TestFileWebp: | |||
|         self._roundtrip(tmp_path, "P", 50.0) | ||||
| 
 | ||||
|     @pytest.mark.skipif(sys.maxsize <= 2**32, reason="Requires 64-bit system") | ||||
|     def test_write_encoding_error_message(self, tmp_path): | ||||
|     def test_write_encoding_error_message(self, tmp_path: Path) -> None: | ||||
|         temp_file = str(tmp_path / "temp.webp") | ||||
|         im = Image.new("RGB", (15000, 15000)) | ||||
|         with pytest.raises(ValueError) as e: | ||||
|             im.save(temp_file, method=0) | ||||
|         assert str(e.value) == "encoding error 6" | ||||
| 
 | ||||
|     def test_WebPEncode_with_invalid_args(self): | ||||
|     def test_WebPEncode_with_invalid_args(self) -> None: | ||||
|         """ | ||||
|         Calling encoder functions with no arguments should result in an error. | ||||
|         """ | ||||
|  | @ -211,7 +212,7 @@ class TestFileWebp: | |||
|         with pytest.raises(TypeError): | ||||
|             _webp.WebPEncode() | ||||
| 
 | ||||
|     def test_WebPDecode_with_invalid_args(self): | ||||
|     def test_WebPDecode_with_invalid_args(self) -> None: | ||||
|         """ | ||||
|         Calling decoder functions with no arguments should result in an error. | ||||
|         """ | ||||
|  | @ -222,14 +223,14 @@ class TestFileWebp: | |||
|         with pytest.raises(TypeError): | ||||
|             _webp.WebPDecode() | ||||
| 
 | ||||
|     def test_no_resource_warning(self, tmp_path): | ||||
|     def test_no_resource_warning(self, tmp_path: Path) -> None: | ||||
|         file_path = "Tests/images/hopper.webp" | ||||
|         with Image.open(file_path) as image: | ||||
|             temp_file = str(tmp_path / "temp.webp") | ||||
|             with warnings.catch_warnings(): | ||||
|                 image.save(temp_file) | ||||
| 
 | ||||
|     def test_file_pointer_could_be_reused(self): | ||||
|     def test_file_pointer_could_be_reused(self) -> None: | ||||
|         file_path = "Tests/images/hopper.webp" | ||||
|         with open(file_path, "rb") as blob: | ||||
|             Image.open(blob).load() | ||||
|  | @ -240,14 +241,14 @@ class TestFileWebp: | |||
|         (0, (0,), (-1, 0, 1, 2), (253, 254, 255, 256)), | ||||
|     ) | ||||
|     @skip_unless_feature("webp_anim") | ||||
|     def test_invalid_background(self, background, tmp_path): | ||||
|     def test_invalid_background(self, background, tmp_path: Path) -> None: | ||||
|         temp_file = str(tmp_path / "temp.webp") | ||||
|         im = hopper() | ||||
|         with pytest.raises(OSError): | ||||
|             im.save(temp_file, save_all=True, append_images=[im], background=background) | ||||
| 
 | ||||
|     @skip_unless_feature("webp_anim") | ||||
|     def test_background_from_gif(self, tmp_path): | ||||
|     def test_background_from_gif(self, tmp_path: Path) -> None: | ||||
|         # Save L mode GIF with background | ||||
|         with Image.open("Tests/images/no_palette_with_background.gif") as im: | ||||
|             out_webp = str(tmp_path / "temp.webp") | ||||
|  | @ -272,7 +273,7 @@ class TestFileWebp: | |||
|         assert difference < 5 | ||||
| 
 | ||||
|     @skip_unless_feature("webp_anim") | ||||
|     def test_duration(self, tmp_path): | ||||
|     def test_duration(self, tmp_path: Path) -> None: | ||||
|         with Image.open("Tests/images/dispose_bgnd.gif") as im: | ||||
|             assert im.info["duration"] == 1000 | ||||
| 
 | ||||
|  | @ -283,7 +284,7 @@ class TestFileWebp: | |||
|             reloaded.load() | ||||
|             assert reloaded.info["duration"] == 1000 | ||||
| 
 | ||||
|     def test_roundtrip_rgba_palette(self, tmp_path): | ||||
|     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" | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
| from PIL import Image | ||||
|  | @ -14,12 +16,12 @@ from .helper import ( | |||
| _webp = pytest.importorskip("PIL._webp", reason="WebP support not installed") | ||||
| 
 | ||||
| 
 | ||||
| def setup_module(): | ||||
| def setup_module() -> None: | ||||
|     if _webp.WebPDecoderBuggyAlpha(): | ||||
|         pytest.skip("Buggy early version of WebP installed, not testing transparency") | ||||
| 
 | ||||
| 
 | ||||
| def test_read_rgba(): | ||||
| def test_read_rgba() -> None: | ||||
|     """ | ||||
|     Can we read an RGBA mode file without error? | ||||
|     Does it have the bits we expect? | ||||
|  | @ -39,7 +41,7 @@ def test_read_rgba(): | |||
|         assert_image_similar_tofile(image, "Tests/images/transparent.png", 20.0) | ||||
| 
 | ||||
| 
 | ||||
| def test_write_lossless_rgb(tmp_path): | ||||
| def test_write_lossless_rgb(tmp_path: Path) -> None: | ||||
|     """ | ||||
|     Can we write an RGBA mode file with lossless compression without error? | ||||
|     Does it have the bits we expect? | ||||
|  | @ -68,7 +70,7 @@ def test_write_lossless_rgb(tmp_path): | |||
|         assert_image_equal(image, pil_image) | ||||
| 
 | ||||
| 
 | ||||
| def test_write_rgba(tmp_path): | ||||
| def test_write_rgba(tmp_path: Path) -> None: | ||||
|     """ | ||||
|     Can we write a RGBA mode file to WebP without error. | ||||
|     Does it have the bits we expect? | ||||
|  | @ -99,7 +101,7 @@ def test_write_rgba(tmp_path): | |||
|             assert_image_similar(image, pil_image, 1.0) | ||||
| 
 | ||||
| 
 | ||||
| def test_keep_rgb_values_when_transparent(tmp_path): | ||||
| def test_keep_rgb_values_when_transparent(tmp_path: Path) -> None: | ||||
|     """ | ||||
|     Saving transparent pixels should retain their original RGB values | ||||
|     when using the "exact" parameter. | ||||
|  | @ -128,7 +130,7 @@ def test_keep_rgb_values_when_transparent(tmp_path): | |||
|         assert_image_equal(reloaded.convert("RGB"), image) | ||||
| 
 | ||||
| 
 | ||||
| def test_write_unsupported_mode_PA(tmp_path): | ||||
| def test_write_unsupported_mode_PA(tmp_path: Path) -> None: | ||||
|     """ | ||||
|     Saving a palette-based file with transparency to WebP format | ||||
|     should work, and be similar to the original file. | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| from packaging.version import parse as parse_version | ||||
| 
 | ||||
|  | @ -18,7 +20,7 @@ pytestmark = [ | |||
| ] | ||||
| 
 | ||||
| 
 | ||||
| def test_n_frames(): | ||||
| def test_n_frames() -> None: | ||||
|     """Ensure that WebP format sets n_frames and is_animated attributes correctly.""" | ||||
| 
 | ||||
|     with Image.open("Tests/images/hopper.webp") as im: | ||||
|  | @ -30,7 +32,7 @@ def test_n_frames(): | |||
|         assert im.is_animated | ||||
| 
 | ||||
| 
 | ||||
| def test_write_animation_L(tmp_path): | ||||
| def test_write_animation_L(tmp_path: Path) -> None: | ||||
|     """ | ||||
|     Convert an animated GIF to animated WebP, then compare the frame count, and first | ||||
|     and last frames to ensure they're visually similar. | ||||
|  | @ -60,13 +62,13 @@ def test_write_animation_L(tmp_path): | |||
|             assert_image_similar(im, orig.convert("RGBA"), 32.9) | ||||
| 
 | ||||
| 
 | ||||
| def test_write_animation_RGB(tmp_path): | ||||
| def test_write_animation_RGB(tmp_path: Path) -> None: | ||||
|     """ | ||||
|     Write an animated WebP from RGB frames, and ensure the frames | ||||
|     are visually similar to the originals. | ||||
|     """ | ||||
| 
 | ||||
|     def check(temp_file): | ||||
|     def check(temp_file) -> None: | ||||
|         with Image.open(temp_file) as im: | ||||
|             assert im.n_frames == 2 | ||||
| 
 | ||||
|  | @ -105,7 +107,7 @@ def test_write_animation_RGB(tmp_path): | |||
|             check(temp_file2) | ||||
| 
 | ||||
| 
 | ||||
| def test_timestamp_and_duration(tmp_path): | ||||
| def test_timestamp_and_duration(tmp_path: Path) -> None: | ||||
|     """ | ||||
|     Try passing a list of durations, and make sure the encoded | ||||
|     timestamps and durations are correct. | ||||
|  | @ -136,7 +138,7 @@ def test_timestamp_and_duration(tmp_path): | |||
|             ts += durations[frame] | ||||
| 
 | ||||
| 
 | ||||
| def test_float_duration(tmp_path): | ||||
| def test_float_duration(tmp_path: Path) -> None: | ||||
|     temp_file = str(tmp_path / "temp.webp") | ||||
|     with Image.open("Tests/images/iss634.apng") as im: | ||||
|         assert im.info["duration"] == 70.0 | ||||
|  | @ -148,7 +150,7 @@ def test_float_duration(tmp_path): | |||
|         assert reloaded.info["duration"] == 70 | ||||
| 
 | ||||
| 
 | ||||
| def test_seeking(tmp_path): | ||||
| def test_seeking(tmp_path: Path) -> None: | ||||
|     """ | ||||
|     Create an animated WebP file, and then try seeking through frames in reverse-order, | ||||
|     verifying the timestamps and durations are correct. | ||||
|  | @ -179,7 +181,7 @@ def test_seeking(tmp_path): | |||
|             ts -= dur | ||||
| 
 | ||||
| 
 | ||||
| def test_seek_errors(): | ||||
| def test_seek_errors() -> None: | ||||
|     with Image.open("Tests/images/iss634.webp") as im: | ||||
|         with pytest.raises(EOFError): | ||||
|             im.seek(-1) | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
| from PIL import Image | ||||
|  | @ -10,7 +12,7 @@ _webp = pytest.importorskip("PIL._webp", reason="WebP support not installed") | |||
| RGB_MODE = "RGB" | ||||
| 
 | ||||
| 
 | ||||
| def test_write_lossless_rgb(tmp_path): | ||||
| def test_write_lossless_rgb(tmp_path: Path) -> None: | ||||
|     if _webp.WebPDecoderVersion() < 0x0200: | ||||
|         pytest.skip("lossless not included") | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| from io import BytesIO | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -19,7 +20,7 @@ except ImportError: | |||
|     ElementTree = None | ||||
| 
 | ||||
| 
 | ||||
| def test_read_exif_metadata(): | ||||
| def test_read_exif_metadata() -> None: | ||||
|     file_path = "Tests/images/flower.webp" | ||||
|     with Image.open(file_path) as image: | ||||
|         assert image.format == "WEBP" | ||||
|  | @ -37,7 +38,7 @@ def test_read_exif_metadata(): | |||
|             assert exif_data == expected_exif | ||||
| 
 | ||||
| 
 | ||||
| def test_read_exif_metadata_without_prefix(): | ||||
| def test_read_exif_metadata_without_prefix() -> None: | ||||
|     with Image.open("Tests/images/flower2.webp") as im: | ||||
|         # Assert prefix is not present | ||||
|         assert im.info["exif"][:6] != b"Exif\x00\x00" | ||||
|  | @ -49,7 +50,7 @@ def test_read_exif_metadata_without_prefix(): | |||
| @mark_if_feature_version( | ||||
|     pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" | ||||
| ) | ||||
| def test_write_exif_metadata(): | ||||
| def test_write_exif_metadata() -> None: | ||||
|     file_path = "Tests/images/flower.jpg" | ||||
|     test_buffer = BytesIO() | ||||
|     with Image.open(file_path) as image: | ||||
|  | @ -63,7 +64,7 @@ def test_write_exif_metadata(): | |||
|     assert webp_exif == expected_exif[6:], "WebP EXIF didn't match" | ||||
| 
 | ||||
| 
 | ||||
| def test_read_icc_profile(): | ||||
| def test_read_icc_profile() -> None: | ||||
|     file_path = "Tests/images/flower2.webp" | ||||
|     with Image.open(file_path) as image: | ||||
|         assert image.format == "WEBP" | ||||
|  | @ -80,7 +81,7 @@ def test_read_icc_profile(): | |||
| @mark_if_feature_version( | ||||
|     pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" | ||||
| ) | ||||
| def test_write_icc_metadata(): | ||||
| def test_write_icc_metadata() -> None: | ||||
|     file_path = "Tests/images/flower2.jpg" | ||||
|     test_buffer = BytesIO() | ||||
|     with Image.open(file_path) as image: | ||||
|  | @ -100,7 +101,7 @@ def test_write_icc_metadata(): | |||
| @mark_if_feature_version( | ||||
|     pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" | ||||
| ) | ||||
| def test_read_no_exif(): | ||||
| def test_read_no_exif() -> None: | ||||
|     file_path = "Tests/images/flower.jpg" | ||||
|     test_buffer = BytesIO() | ||||
|     with Image.open(file_path) as image: | ||||
|  | @ -113,7 +114,7 @@ def test_read_no_exif(): | |||
|         assert not webp_image._getexif() | ||||
| 
 | ||||
| 
 | ||||
| def test_getxmp(): | ||||
| def test_getxmp() -> None: | ||||
|     with Image.open("Tests/images/flower.webp") as im: | ||||
|         assert "xmp" not in im.info | ||||
|         assert im.getxmp() == {} | ||||
|  | @ -133,7 +134,7 @@ def test_getxmp(): | |||
| 
 | ||||
| 
 | ||||
| @skip_unless_feature("webp_anim") | ||||
| def test_write_animated_metadata(tmp_path): | ||||
| def test_write_animated_metadata(tmp_path: Path) -> None: | ||||
|     iccp_data = b"<iccp_data>" | ||||
|     exif_data = b"<exif_data>" | ||||
|     xmp_data = b"<xmp_data>" | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
| from PIL import Image, WmfImagePlugin | ||||
|  | @ -7,7 +9,7 @@ from PIL import Image, WmfImagePlugin | |||
| from .helper import assert_image_similar_tofile, hopper | ||||
| 
 | ||||
| 
 | ||||
| def test_load_raw(): | ||||
| def test_load_raw() -> None: | ||||
|     # Test basic EMF open and rendering | ||||
|     with Image.open("Tests/images/drawing.emf") as im: | ||||
|         if hasattr(Image.core, "drawwmf"): | ||||
|  | @ -25,17 +27,17 @@ def test_load_raw(): | |||
|             assert_image_similar_tofile(im, "Tests/images/drawing_wmf_ref.png", 2.0) | ||||
| 
 | ||||
| 
 | ||||
| def test_load(): | ||||
| def test_load() -> None: | ||||
|     with Image.open("Tests/images/drawing.emf") as im: | ||||
|         if hasattr(Image.core, "drawwmf"): | ||||
|             assert im.load()[0, 0] == (255, 255, 255) | ||||
| 
 | ||||
| 
 | ||||
| def test_register_handler(tmp_path): | ||||
| def test_register_handler(tmp_path: Path) -> None: | ||||
|     class TestHandler: | ||||
|         methodCalled = False | ||||
| 
 | ||||
|         def save(self, im, fp, filename): | ||||
|         def save(self, im, fp, filename) -> None: | ||||
|             self.methodCalled = True | ||||
| 
 | ||||
|     handler = TestHandler() | ||||
|  | @ -51,12 +53,12 @@ def test_register_handler(tmp_path): | |||
|     WmfImagePlugin.register_handler(original_handler) | ||||
| 
 | ||||
| 
 | ||||
| def test_load_float_dpi(): | ||||
| def test_load_float_dpi() -> None: | ||||
|     with Image.open("Tests/images/drawing.emf") as im: | ||||
|         assert im.info["dpi"] == 1423.7668161434979 | ||||
| 
 | ||||
| 
 | ||||
| def test_load_set_dpi(): | ||||
| def test_load_set_dpi() -> None: | ||||
|     with Image.open("Tests/images/drawing.wmf") as im: | ||||
|         assert im.size == (82, 82) | ||||
| 
 | ||||
|  | @ -68,7 +70,7 @@ def test_load_set_dpi(): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("ext", (".wmf", ".emf")) | ||||
| def test_save(ext, tmp_path): | ||||
| def test_save(ext, tmp_path: Path) -> None: | ||||
|     im = hopper() | ||||
| 
 | ||||
|     tmpfile = str(tmp_path / ("temp" + ext)) | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| from io import BytesIO | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -32,14 +33,14 @@ static char basic_bits[] = { | |||
| """ | ||||
| 
 | ||||
| 
 | ||||
| def test_pil151(): | ||||
| def test_pil151() -> None: | ||||
|     with Image.open(BytesIO(PIL151)) as im: | ||||
|         im.load() | ||||
|         assert im.mode == "1" | ||||
|         assert im.size == (32, 32) | ||||
| 
 | ||||
| 
 | ||||
| def test_open(): | ||||
| def test_open() -> None: | ||||
|     # Arrange | ||||
|     # Created with `convert hopper.png hopper.xbm` | ||||
|     filename = "Tests/images/hopper.xbm" | ||||
|  | @ -51,7 +52,7 @@ def test_open(): | |||
|         assert im.size == (128, 128) | ||||
| 
 | ||||
| 
 | ||||
| def test_open_filename_with_underscore(): | ||||
| def test_open_filename_with_underscore() -> None: | ||||
|     # Arrange | ||||
|     # Created with `convert hopper.png hopper_underscore.xbm` | ||||
|     filename = "Tests/images/hopper_underscore.xbm" | ||||
|  | @ -63,14 +64,14 @@ def test_open_filename_with_underscore(): | |||
|         assert im.size == (128, 128) | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     invalid_file = "Tests/images/flower.jpg" | ||||
| 
 | ||||
|     with pytest.raises(SyntaxError): | ||||
|         XbmImagePlugin.XbmImageFile(invalid_file) | ||||
| 
 | ||||
| 
 | ||||
| def test_save_wrong_mode(tmp_path): | ||||
| def test_save_wrong_mode(tmp_path: Path) -> None: | ||||
|     im = hopper() | ||||
|     out = str(tmp_path / "temp.xbm") | ||||
| 
 | ||||
|  | @ -78,7 +79,7 @@ def test_save_wrong_mode(tmp_path): | |||
|         im.save(out) | ||||
| 
 | ||||
| 
 | ||||
| def test_hotspot(tmp_path): | ||||
| def test_hotspot(tmp_path: Path) -> None: | ||||
|     im = hopper("1") | ||||
|     out = str(tmp_path / "temp.xbm") | ||||
| 
 | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ from .helper import assert_image_similar, hopper | |||
| TEST_FILE = "Tests/images/hopper.xpm" | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(): | ||||
| def test_sanity() -> None: | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         im.load() | ||||
|         assert im.mode == "P" | ||||
|  | @ -20,14 +20,14 @@ def test_sanity(): | |||
|         assert_image_similar(im.convert("RGB"), hopper("RGB"), 60) | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     invalid_file = "Tests/images/flower.jpg" | ||||
| 
 | ||||
|     with pytest.raises(SyntaxError): | ||||
|         XpmImagePlugin.XpmImageFile(invalid_file) | ||||
| 
 | ||||
| 
 | ||||
| def test_load_read(): | ||||
| def test_load_read() -> None: | ||||
|     # Arrange | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         dummy_bytes = 1 | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ from .helper import assert_image_similar, hopper | |||
| TEST_FILE = "Tests/images/hopper.p7" | ||||
| 
 | ||||
| 
 | ||||
| def test_open(): | ||||
| def test_open() -> None: | ||||
|     # Act | ||||
|     with Image.open(TEST_FILE) as im: | ||||
|         # Assert | ||||
|  | @ -20,7 +20,7 @@ def test_open(): | |||
|         assert_image_similar(im, im_hopper, 9) | ||||
| 
 | ||||
| 
 | ||||
| def test_unexpected_eof(): | ||||
| def test_unexpected_eof() -> None: | ||||
|     # Test unexpected EOF reading XV thumbnail file | ||||
|     # Arrange | ||||
|     bad_file = "Tests/images/hopper_bad.p7" | ||||
|  | @ -30,7 +30,7 @@ def test_unexpected_eof(): | |||
|         XVThumbImagePlugin.XVThumbImageFile(bad_file) | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     # Arrange | ||||
|     invalid_file = "Tests/images/flower.jpg" | ||||
| 
 | ||||
|  |  | |||
|  | @ -7,7 +7,7 @@ from PIL import BdfFontFile, FontFile | |||
| filename = "Tests/images/courB08.bdf" | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(): | ||||
| def test_sanity() -> None: | ||||
|     with open(filename, "rb") as test_file: | ||||
|         font = BdfFontFile.BdfFontFile(test_file) | ||||
| 
 | ||||
|  | @ -15,7 +15,7 @@ def test_sanity(): | |||
|     assert len([_f for _f in font.glyph if _f]) == 190 | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     with open("Tests/images/flower.jpg", "rb") as fp: | ||||
|         with pytest.raises(SyntaxError): | ||||
|             BdfFontFile.BdfFontFile(fp) | ||||
|  |  | |||
|  | @ -8,7 +8,7 @@ from .helper import skip_unless_feature | |||
| 
 | ||||
| 
 | ||||
| class TestFontCrash: | ||||
|     def _fuzz_font(self, font): | ||||
|     def _fuzz_font(self, font: ImageFont.FreeTypeFont) -> None: | ||||
|         # from fuzzers.fuzz_font | ||||
|         font.getbbox("ABC") | ||||
|         font.getmask("test text") | ||||
|  | @ -18,7 +18,7 @@ class TestFontCrash: | |||
|             draw.text((10, 10), "Test Text", font=font, fill="#000") | ||||
| 
 | ||||
|     @skip_unless_feature("freetype2") | ||||
|     def test_segfault(self): | ||||
|     def test_segfault(self) -> None: | ||||
|         with pytest.raises(OSError): | ||||
|             font = ImageFont.truetype("Tests/fonts/fuzz_font-5203009437302784") | ||||
|             self._fuzz_font(font) | ||||
|  |  | |||
|  | @ -10,7 +10,7 @@ class TestTTypeFontLeak(PillowLeakTestCase): | |||
|     iterations = 10 | ||||
|     mem_limit = 4096  # k | ||||
| 
 | ||||
|     def _test_font(self, font): | ||||
|     def _test_font(self, font: ImageFont.FreeTypeFont) -> None: | ||||
|         im = Image.new("RGB", (255, 255), "white") | ||||
|         draw = ImageDraw.ImageDraw(im) | ||||
|         self._test_leak( | ||||
|  | @ -20,7 +20,7 @@ class TestTTypeFontLeak(PillowLeakTestCase): | |||
|         ) | ||||
| 
 | ||||
|     @skip_unless_feature("freetype2") | ||||
|     def test_leak(self): | ||||
|     def test_leak(self) -> None: | ||||
|         ttype = ImageFont.truetype("Tests/fonts/FreeMono.ttf", 20) | ||||
|         self._test_font(ttype) | ||||
| 
 | ||||
|  | @ -30,6 +30,6 @@ class TestDefaultFontLeak(TestTTypeFontLeak): | |||
|     iterations = 100 | ||||
|     mem_limit = 1024  # k | ||||
| 
 | ||||
|     def test_leak(self): | ||||
|     def test_leak(self) -> None: | ||||
|         default_font = ImageFont.load_default() | ||||
|         self._test_font(default_font) | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| import os | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -20,7 +21,7 @@ message = "hello, world" | |||
| pytestmark = skip_unless_feature("zlib") | ||||
| 
 | ||||
| 
 | ||||
| def save_font(request, tmp_path): | ||||
| def save_font(request: pytest.FixtureRequest, tmp_path: Path) -> str: | ||||
|     with open(fontname, "rb") as test_file: | ||||
|         font = PcfFontFile.PcfFontFile(test_file) | ||||
|     assert isinstance(font, FontFile.FontFile) | ||||
|  | @ -29,7 +30,7 @@ def save_font(request, tmp_path): | |||
| 
 | ||||
|     tempname = str(tmp_path / "temp.pil") | ||||
| 
 | ||||
|     def delete_tempfile(): | ||||
|     def delete_tempfile() -> None: | ||||
|         try: | ||||
|             os.remove(tempname[:-4] + ".pbm") | ||||
|         except OSError: | ||||
|  | @ -47,11 +48,11 @@ def save_font(request, tmp_path): | |||
|     return tempname | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(request, tmp_path): | ||||
| def test_sanity(request: pytest.FixtureRequest, tmp_path: Path) -> None: | ||||
|     save_font(request, tmp_path) | ||||
| 
 | ||||
| 
 | ||||
| def test_less_than_256_characters(): | ||||
| def test_less_than_256_characters() -> None: | ||||
|     with open("Tests/fonts/10x20-ISO8859-1-fewer-characters.pcf", "rb") as test_file: | ||||
|         font = PcfFontFile.PcfFontFile(test_file) | ||||
|     assert isinstance(font, FontFile.FontFile) | ||||
|  | @ -59,13 +60,13 @@ def test_less_than_256_characters(): | |||
|     assert len([_f for _f in font.glyph if _f]) == 127 | ||||
| 
 | ||||
| 
 | ||||
| def test_invalid_file(): | ||||
| def test_invalid_file() -> None: | ||||
|     with open("Tests/images/flower.jpg", "rb") as fp: | ||||
|         with pytest.raises(SyntaxError): | ||||
|             PcfFontFile.PcfFontFile(fp) | ||||
| 
 | ||||
| 
 | ||||
| def test_draw(request, tmp_path): | ||||
| def test_draw(request: pytest.FixtureRequest, tmp_path: Path) -> None: | ||||
|     tempname = save_font(request, tmp_path) | ||||
|     font = ImageFont.load(tempname) | ||||
|     im = Image.new("L", (130, 30), "white") | ||||
|  | @ -74,7 +75,7 @@ def test_draw(request, tmp_path): | |||
|     assert_image_similar_tofile(im, "Tests/images/test_draw_pbm_target.png", 0) | ||||
| 
 | ||||
| 
 | ||||
| def test_textsize(request, tmp_path): | ||||
| def test_textsize(request: pytest.FixtureRequest, tmp_path: Path) -> None: | ||||
|     tempname = save_font(request, tmp_path) | ||||
|     font = ImageFont.load(tempname) | ||||
|     for i in range(255): | ||||
|  | @ -90,7 +91,9 @@ def test_textsize(request, tmp_path): | |||
|         assert font.getbbox(msg) == (0, 0, len(msg) * 10, 20) | ||||
| 
 | ||||
| 
 | ||||
| def _test_high_characters(request, tmp_path, message): | ||||
| def _test_high_characters( | ||||
|     request: pytest.FixtureRequest, tmp_path: Path, message: str | bytes | ||||
| ) -> None: | ||||
|     tempname = save_font(request, tmp_path) | ||||
|     font = ImageFont.load(tempname) | ||||
|     im = Image.new("L", (750, 30), "white") | ||||
|  | @ -99,7 +102,7 @@ def _test_high_characters(request, tmp_path, message): | |||
|     assert_image_similar_tofile(im, "Tests/images/high_ascii_chars.png", 0) | ||||
| 
 | ||||
| 
 | ||||
| def test_high_characters(request, tmp_path): | ||||
| def test_high_characters(request: pytest.FixtureRequest, tmp_path: Path) -> None: | ||||
|     message = "".join(chr(i + 1) for i in range(140, 232)) | ||||
|     _test_high_characters(request, tmp_path, message) | ||||
|     # accept bytes instances. | ||||
|  |  | |||
|  | @ -1,6 +1,8 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| import os | ||||
| from pathlib import Path | ||||
| from typing import TypedDict | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
|  | @ -14,7 +16,14 @@ from .helper import ( | |||
| 
 | ||||
| fontname = "Tests/fonts/ter-x20b.pcf" | ||||
| 
 | ||||
| charsets = { | ||||
| 
 | ||||
| class Charset(TypedDict): | ||||
|     glyph_count: int | ||||
|     message: str | ||||
|     image1: str | ||||
| 
 | ||||
| 
 | ||||
| charsets: dict[str, Charset] = { | ||||
|     "iso8859-1": { | ||||
|         "glyph_count": 223, | ||||
|         "message": "hello, world", | ||||
|  | @ -36,7 +45,7 @@ charsets = { | |||
| pytestmark = skip_unless_feature("zlib") | ||||
| 
 | ||||
| 
 | ||||
| def save_font(request, tmp_path, encoding): | ||||
| def save_font(request: pytest.FixtureRequest, tmp_path: Path, encoding: str) -> str: | ||||
|     with open(fontname, "rb") as test_file: | ||||
|         font = PcfFontFile.PcfFontFile(test_file, encoding) | ||||
|     assert isinstance(font, FontFile.FontFile) | ||||
|  | @ -45,7 +54,7 @@ def save_font(request, tmp_path, encoding): | |||
| 
 | ||||
|     tempname = str(tmp_path / "temp.pil") | ||||
| 
 | ||||
|     def delete_tempfile(): | ||||
|     def delete_tempfile() -> None: | ||||
|         try: | ||||
|             os.remove(tempname[:-4] + ".pbm") | ||||
|         except OSError: | ||||
|  | @ -64,12 +73,12 @@ def save_font(request, tmp_path, encoding): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("encoding", ("iso8859-1", "iso8859-2", "cp1250")) | ||||
| def test_sanity(request, tmp_path, encoding): | ||||
| def test_sanity(request: pytest.FixtureRequest, tmp_path: Path, encoding: str) -> None: | ||||
|     save_font(request, tmp_path, encoding) | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("encoding", ("iso8859-1", "iso8859-2", "cp1250")) | ||||
| def test_draw(request, tmp_path, encoding): | ||||
| def test_draw(request: pytest.FixtureRequest, tmp_path: Path, encoding: str) -> None: | ||||
|     tempname = save_font(request, tmp_path, encoding) | ||||
|     font = ImageFont.load(tempname) | ||||
|     im = Image.new("L", (150, 30), "white") | ||||
|  | @ -80,7 +89,9 @@ def test_draw(request, tmp_path, encoding): | |||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("encoding", ("iso8859-1", "iso8859-2", "cp1250")) | ||||
| def test_textsize(request, tmp_path, encoding): | ||||
| def test_textsize( | ||||
|     request: pytest.FixtureRequest, tmp_path: Path, encoding: str | ||||
| ) -> None: | ||||
|     tempname = save_font(request, tmp_path, encoding) | ||||
|     font = ImageFont.load(tempname) | ||||
|     for i in range(255): | ||||
|  |  | |||
|  | @ -1,11 +1,13 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| from pathlib import Path | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
| from PIL import FontFile | ||||
| 
 | ||||
| 
 | ||||
| def test_save(tmp_path): | ||||
| def test_save(tmp_path: Path) -> None: | ||||
|     tempname = str(tmp_path / "temp.pil") | ||||
| 
 | ||||
|     font = FontFile.FontFile() | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ def tuple_to_ints(tp): | |||
|     return int(x * 255.0), int(y * 255.0), int(z * 255.0) | ||||
| 
 | ||||
| 
 | ||||
| def test_sanity(): | ||||
| def test_sanity() -> None: | ||||
|     Image.new("HSV", (100, 100)) | ||||
| 
 | ||||
| 
 | ||||
|  | @ -78,7 +78,7 @@ def to_rgb_colorsys(im): | |||
|     return to_xxx_colorsys(im, colorsys.hsv_to_rgb, "RGB") | ||||
| 
 | ||||
| 
 | ||||
| def test_wedge(): | ||||
| def test_wedge() -> None: | ||||
|     src = wedge().resize((3 * 32, 32), Image.Resampling.BILINEAR) | ||||
|     im = src.convert("HSV") | ||||
|     comparable = to_hsv_colorsys(src) | ||||
|  | @ -110,7 +110,7 @@ def test_wedge(): | |||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| def test_convert(): | ||||
| def test_convert() -> None: | ||||
|     im = hopper("RGB").convert("HSV") | ||||
|     comparable = to_hsv_colorsys(hopper("RGB")) | ||||
| 
 | ||||
|  | @ -128,7 +128,7 @@ def test_convert(): | |||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| def test_hsv_to_rgb(): | ||||
| def test_hsv_to_rgb() -> None: | ||||
|     comparable = to_hsv_colorsys(hopper("RGB")) | ||||
|     converted = comparable.convert("RGB") | ||||
|     comparable = to_rgb_colorsys(comparable) | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ from __future__ import annotations | |||
| from PIL import Image | ||||
| 
 | ||||
| 
 | ||||
| def test_white(): | ||||
| def test_white() -> None: | ||||
|     with Image.open("Tests/images/lab.tif") as i: | ||||
|         i.load() | ||||
| 
 | ||||
|  | @ -24,7 +24,7 @@ def test_white(): | |||
|     assert list(b) == [128] * 100 | ||||
| 
 | ||||
| 
 | ||||
| def test_green(): | ||||
| def test_green() -> None: | ||||
|     # l= 50 (/100), a = -100 (-128 .. 128) b=0 in PS | ||||
|     # == RGB: 0, 152, 117 | ||||
|     with Image.open("Tests/images/lab-green.tif") as i: | ||||
|  | @ -32,7 +32,7 @@ def test_green(): | |||
|     assert k == (128, 28, 128) | ||||
| 
 | ||||
| 
 | ||||
| def test_red(): | ||||
| def test_red() -> None: | ||||
|     # l= 50 (/100), a = 100 (-128 .. 128) b=0 in PS | ||||
|     # == RGB: 255, 0, 124 | ||||
|     with Image.open("Tests/images/lab-red.tif") as i: | ||||
|  |  | |||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue
	
	Block a user