mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-10-31 07:57:27 +03:00 
			
		
		
		
	Merge pull request #4794 from hugovk/rm-3.5
This commit is contained in:
		
						commit
						5ce2fac3d6
					
				|  | @ -3,7 +3,7 @@ repos: | |||
|     rev: e66be67b9b6811913470f70c28b4d50f94d05b22  # frozen: 20.8b1 | ||||
|     hooks: | ||||
|       - id: black | ||||
|         args: ["--target-version", "py35"] | ||||
|         args: ["--target-version", "py36"] | ||||
|         # Only .py files, until https://github.com/psf/black/issues/402 resolved | ||||
|         files: \.py$ | ||||
|         types: [] | ||||
|  |  | |||
|  | @ -28,15 +28,17 @@ def timer(func, label, *args): | |||
|         func(*args) | ||||
|         if time.time() - starttime > 10: | ||||
|             print( | ||||
|                 "%s: breaking at %s iterations, %.6f per iteration" | ||||
|                 % (label, x + 1, (time.time() - starttime) / (x + 1.0)) | ||||
|                 "{}: breaking at {} iterations, {:.6f} per iteration".format( | ||||
|                     label, x + 1, (time.time() - starttime) / (x + 1.0) | ||||
|                 ) | ||||
|             ) | ||||
|             break | ||||
|     if x == iterations - 1: | ||||
|         endtime = time.time() | ||||
|         print( | ||||
|             "%s: %.4f s  %.6f per iteration" | ||||
|             % (label, endtime - starttime, (endtime - starttime) / (x + 1.0)) | ||||
|             "{}: {:.4f} s  {:.6f} per iteration".format( | ||||
|                 label, endtime - starttime, (endtime - starttime) / (x + 1.0) | ||||
|             ) | ||||
|         ) | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -26,7 +26,7 @@ def _test_leak(min_iterations, max_iterations, fn, *args, **kwargs): | |||
|         if i < min_iterations: | ||||
|             mem_limit = mem + 1 | ||||
|             continue | ||||
|         msg = "memory usage limit exceeded after %d iterations" % (i + 1) | ||||
|         msg = f"memory usage limit exceeded after {i + 1} iterations" | ||||
|         assert mem <= mem_limit, msg | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -42,8 +42,8 @@ def test_dos_total_memory(): | |||
|     info = PngImagePlugin.PngInfo() | ||||
| 
 | ||||
|     for x in range(64): | ||||
|         info.add_text("t%s" % x, compressed_data, zip=True) | ||||
|         info.add_itxt("i%s" % x, compressed_data, zip=True) | ||||
|         info.add_text(f"t{x}", compressed_data, zip=True) | ||||
|         info.add_itxt(f"i{x}", compressed_data, zip=True) | ||||
| 
 | ||||
|     b = BytesIO() | ||||
|     im.save(b, "PNG", pnginfo=info) | ||||
|  |  | |||
|  | @ -9,4 +9,4 @@ def pytest_report_header(config): | |||
|             features.pilinfo(out=out, supported_formats=False) | ||||
|             return out.getvalue() | ||||
|     except Exception as e: | ||||
|         return "pytest_report_header failed: %s" % e | ||||
|         return f"pytest_report_header failed: {e}" | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ if __name__ == "__main__": | |||
|     # create font data chunk for embedding | ||||
|     font = "Tests/images/courB08" | ||||
|     print("    f._load_pilfont_data(") | ||||
|     print("         # %s" % os.path.basename(font)) | ||||
|     print(f"         # {os.path.basename(font)}") | ||||
|     print("         BytesIO(base64.decodestring(b'''") | ||||
|     with open(font + ".pil", "rb") as fp: | ||||
|         print(base64.b64encode(fp.read()).decode()) | ||||
|  |  | |||
|  | @ -68,37 +68,31 @@ def convert_to_comparable(a, b): | |||
| 
 | ||||
| def assert_deep_equal(a, b, msg=None): | ||||
|     try: | ||||
|         assert len(a) == len(b), msg or "got length {}, expected {}".format( | ||||
|             len(a), len(b) | ||||
|         ) | ||||
|         assert len(a) == len(b), msg or f"got length {len(a)}, expected {len(b)}" | ||||
|     except Exception: | ||||
|         assert a == b, msg | ||||
| 
 | ||||
| 
 | ||||
| def assert_image(im, mode, size, msg=None): | ||||
|     if mode is not None: | ||||
|         assert im.mode == mode, msg or "got mode {!r}, expected {!r}".format( | ||||
|             im.mode, mode | ||||
|         assert im.mode == mode, ( | ||||
|             msg or f"got mode {repr(im.mode)}, expected {repr(mode)}" | ||||
|         ) | ||||
| 
 | ||||
|     if size is not None: | ||||
|         assert im.size == size, msg or "got size {!r}, expected {!r}".format( | ||||
|             im.size, size | ||||
|         assert im.size == size, ( | ||||
|             msg or f"got size {repr(im.size)}, expected {repr(size)}" | ||||
|         ) | ||||
| 
 | ||||
| 
 | ||||
| def assert_image_equal(a, b, msg=None): | ||||
|     assert a.mode == b.mode, msg or "got mode {!r}, expected {!r}".format( | ||||
|         a.mode, b.mode | ||||
|     ) | ||||
|     assert a.size == b.size, msg or "got size {!r}, expected {!r}".format( | ||||
|         a.size, b.size | ||||
|     ) | ||||
|     assert a.mode == b.mode, msg or f"got mode {repr(a.mode)}, expected {repr(b.mode)}" | ||||
|     assert a.size == b.size, msg or f"got size {repr(a.size)}, expected {repr(b.size)}" | ||||
|     if a.tobytes() != b.tobytes(): | ||||
|         if HAS_UPLOADER: | ||||
|             try: | ||||
|                 url = test_image_results.upload(a, b) | ||||
|                 logger.error("Url for test images: %s" % url) | ||||
|                 logger.error(f"Url for test images: {url}") | ||||
|             except Exception: | ||||
|                 pass | ||||
| 
 | ||||
|  | @ -113,12 +107,8 @@ def assert_image_equal_tofile(a, filename, msg=None, mode=None): | |||
| 
 | ||||
| 
 | ||||
| def assert_image_similar(a, b, epsilon, msg=None): | ||||
|     assert a.mode == b.mode, msg or "got mode {!r}, expected {!r}".format( | ||||
|         a.mode, b.mode | ||||
|     ) | ||||
|     assert a.size == b.size, msg or "got size {!r}, expected {!r}".format( | ||||
|         a.size, b.size | ||||
|     ) | ||||
|     assert a.mode == b.mode, msg or f"got mode {repr(a.mode)}, expected {repr(b.mode)}" | ||||
|     assert a.size == b.size, msg or f"got size {repr(a.size)}, expected {repr(b.size)}" | ||||
| 
 | ||||
|     a, b = convert_to_comparable(a, b) | ||||
| 
 | ||||
|  | @ -130,13 +120,14 @@ def assert_image_similar(a, b, epsilon, msg=None): | |||
|     ave_diff = diff / (a.size[0] * a.size[1]) | ||||
|     try: | ||||
|         assert epsilon >= ave_diff, ( | ||||
|             msg or "" | ||||
|         ) + " average pixel value difference %.4f > epsilon %.4f" % (ave_diff, epsilon) | ||||
|             (msg or "") | ||||
|             + f" average pixel value difference {ave_diff:.4f} > epsilon {epsilon:.4f}" | ||||
|         ) | ||||
|     except Exception as e: | ||||
|         if HAS_UPLOADER: | ||||
|             try: | ||||
|                 url = test_image_results.upload(a, b) | ||||
|                 logger.error("Url for test images: %s" % url) | ||||
|                 logger.error(f"Url for test images: {url}") | ||||
|             except Exception: | ||||
|                 pass | ||||
|         raise e | ||||
|  | @ -167,7 +158,7 @@ def assert_tuple_approx_equal(actuals, targets, threshold, msg): | |||
| 
 | ||||
| 
 | ||||
| def skip_unless_feature(feature): | ||||
|     reason = "%s not available" % feature | ||||
|     reason = f"{feature} not available" | ||||
|     return pytest.mark.skipif(not features.check(feature), reason=reason) | ||||
| 
 | ||||
| 
 | ||||
|  | @ -205,7 +196,7 @@ class PillowLeakTestCase: | |||
|         for cycle in range(self.iterations): | ||||
|             core() | ||||
|             mem = self._get_mem_usage() - start_mem | ||||
|             msg = "memory usage limit exceeded in iteration %d" % cycle | ||||
|             msg = f"memory usage limit exceeded in iteration {cycle}" | ||||
|             assert mem < self.mem_limit, msg | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -50,7 +50,7 @@ def test_questionable(): | |||
|             with Image.open(f) as im: | ||||
|                 im.load() | ||||
|             if os.path.basename(f) not in supported: | ||||
|                 print("Please add %s to the partially supported bmp specs." % f) | ||||
|                 print(f"Please add {f} to the partially supported bmp specs.") | ||||
|         except Exception:  # as msg: | ||||
|             if os.path.basename(f) in supported: | ||||
|                 raise | ||||
|  | @ -85,7 +85,7 @@ def test_good(): | |||
|         if name in file_map: | ||||
|             return os.path.join(base, "html", file_map[name]) | ||||
|         name = os.path.splitext(name)[0] | ||||
|         return os.path.join(base, "html", "%s.png" % name) | ||||
|         return os.path.join(base, "html", f"{name}.png") | ||||
| 
 | ||||
|     for f in get_files("g"): | ||||
|         try: | ||||
|  | @ -108,4 +108,4 @@ def test_good(): | |||
|                 os.path.join(base, "g", "pal8rle.bmp"), | ||||
|                 os.path.join(base, "g", "pal4rle.bmp"), | ||||
|             ) | ||||
|             assert f in unsupported, "Unsupported Image {}: {}".format(f, msg) | ||||
|             assert f in unsupported, f"Unsupported Image {f}: {msg}" | ||||
|  |  | |||
|  | @ -312,7 +312,7 @@ def test_apng_sequence_errors(): | |||
|     ] | ||||
|     for f in test_files: | ||||
|         with pytest.raises(SyntaxError): | ||||
|             with Image.open("Tests/images/apng/{0}".format(f)) as im: | ||||
|             with Image.open(f"Tests/images/apng/{f}") as im: | ||||
|                 im.seek(im.n_frames - 1) | ||||
|                 im.load() | ||||
| 
 | ||||
|  |  | |||
|  | @ -171,18 +171,18 @@ class TestFileLibTiff(LibTiffTestCase): | |||
|                             assert ( | ||||
|                                 c_float(val[0][0] / val[0][1]).value | ||||
|                                 == c_float(value[0][0] / value[0][1]).value | ||||
|                             ), ("%s didn't roundtrip" % tag) | ||||
|                             ), f"{tag} didn't roundtrip" | ||||
|                         else: | ||||
|                             assert c_float(val).value == c_float(value).value, ( | ||||
|                                 "%s didn't roundtrip" % tag | ||||
|                             ) | ||||
|                             assert ( | ||||
|                                 c_float(val).value == c_float(value).value | ||||
|                             ), f"{tag} didn't roundtrip" | ||||
|                     else: | ||||
|                         assert val == value, "%s didn't roundtrip" % tag | ||||
|                         assert val == value, f"{tag} didn't roundtrip" | ||||
| 
 | ||||
|             # https://github.com/python-pillow/Pillow/issues/1561 | ||||
|             requested_fields = ["StripByteCounts", "RowsPerStrip", "StripOffsets"] | ||||
|             for field in requested_fields: | ||||
|                 assert field in reloaded, "%s not in metadata" % field | ||||
|                 assert field in reloaded, f"{field} not in metadata" | ||||
| 
 | ||||
|     def test_additional_metadata(self, tmp_path): | ||||
|         # these should not crash. Seriously dummy data, most of it doesn't make | ||||
|  |  | |||
|  | @ -46,7 +46,7 @@ def test_others(): | |||
|         with Image.open(path) as im: | ||||
|             im.load() | ||||
|             assert isinstance(im, SunImagePlugin.SunImageFile) | ||||
|             target_path = "%s.png" % os.path.splitext(path)[0] | ||||
|             target_path = f"{os.path.splitext(path)[0]}.png" | ||||
|             # im.save(target_file) | ||||
|             with Image.open(target_path) as target: | ||||
|                 assert_image_equal(im, target) | ||||
|  |  | |||
|  | @ -36,9 +36,7 @@ def test_sanity(tmp_path): | |||
| 
 | ||||
|                 assert_image_equal(saved_im, original_im) | ||||
| 
 | ||||
|         png_paths = glob( | ||||
|             os.path.join(_TGA_DIR_COMMON, "*x*_{}.png".format(mode.lower())) | ||||
|         ) | ||||
|         png_paths = glob(os.path.join(_TGA_DIR_COMMON, f"*x*_{mode.lower()}.png")) | ||||
| 
 | ||||
|         for png_path in png_paths: | ||||
|             with Image.open(png_path) as reference_im: | ||||
|  |  | |||
|  | @ -145,16 +145,16 @@ def test_write_metadata(tmp_path): | |||
|             assert_deep_equal( | ||||
|                 original[tag], | ||||
|                 value, | ||||
|                 "{} didn't roundtrip, {}, {}".format(tag, original[tag], value), | ||||
|                 f"{tag} didn't roundtrip, {original[tag]}, {value}", | ||||
|             ) | ||||
|         else: | ||||
|             assert original[tag] == value, "{} didn't roundtrip, {}, {}".format( | ||||
|                 tag, original[tag], value | ||||
|             ) | ||||
|             assert ( | ||||
|                 original[tag] == value | ||||
|             ), f"{tag} didn't roundtrip, {original[tag]}, {value}" | ||||
| 
 | ||||
|     for tag, value in original.items(): | ||||
|         if tag not in ignored: | ||||
|             assert value == reloaded[tag], "%s didn't roundtrip" % tag | ||||
|             assert value == reloaded[tag], f"{tag} didn't roundtrip" | ||||
| 
 | ||||
| 
 | ||||
| def test_change_stripbytecounts_tag_type(tmp_path): | ||||
|  |  | |||
|  | @ -47,11 +47,11 @@ def save_font(request, tmp_path, encoding): | |||
|     font.save(tempname) | ||||
| 
 | ||||
|     with Image.open(tempname.replace(".pil", ".pbm")) as loaded: | ||||
|         with Image.open("Tests/fonts/ter-x20b-%s.pbm" % encoding) as target: | ||||
|         with Image.open(f"Tests/fonts/ter-x20b-{encoding}.pbm") as target: | ||||
|             assert_image_equal(loaded, target) | ||||
| 
 | ||||
|     with open(tempname, "rb") as f_loaded: | ||||
|         with open("Tests/fonts/ter-x20b-%s.pil" % encoding, "rb") as f_target: | ||||
|         with open(f"Tests/fonts/ter-x20b-{encoding}.pil", "rb") as f_target: | ||||
|             assert f_loaded.read() == f_target.read() | ||||
|     return tempname | ||||
| 
 | ||||
|  |  | |||
|  | @ -128,16 +128,13 @@ class TestImageGetPixel(AccessTest): | |||
|         im.putpixel((0, 0), c) | ||||
|         assert ( | ||||
|             im.getpixel((0, 0)) == c | ||||
|         ), "put/getpixel roundtrip failed for mode {}, color {}".format(mode, c) | ||||
|         ), f"put/getpixel roundtrip failed for mode {mode}, color {c}" | ||||
| 
 | ||||
|         # check putpixel negative index | ||||
|         im.putpixel((-1, -1), c) | ||||
|         assert ( | ||||
|             im.getpixel((-1, -1)) == c | ||||
|         ), "put/getpixel roundtrip negative index failed for mode %s, color %s" % ( | ||||
|             mode, | ||||
|             c, | ||||
|         ) | ||||
|         ), f"put/getpixel roundtrip negative index failed for mode {mode}, color {c}" | ||||
| 
 | ||||
|         # Check 0 | ||||
|         im = Image.new(mode, (0, 0), None) | ||||
|  | @ -155,11 +152,11 @@ class TestImageGetPixel(AccessTest): | |||
|         im = Image.new(mode, (1, 1), c) | ||||
|         assert ( | ||||
|             im.getpixel((0, 0)) == c | ||||
|         ), "initial color failed for mode {}, color {} ".format(mode, c) | ||||
|         ), f"initial color failed for mode {mode}, color {c} " | ||||
|         # check initial color negative index | ||||
|         assert ( | ||||
|             im.getpixel((-1, -1)) == c | ||||
|         ), "initial color failed with negative index for mode %s, color %s " % (mode, c) | ||||
|         ), f"initial color failed with negative index for mode {mode}, color {c} " | ||||
| 
 | ||||
|         # Check 0 | ||||
|         im = Image.new(mode, (0, 0), c) | ||||
|  |  | |||
|  | @ -162,8 +162,8 @@ def compare_reduce_with_reference(im, factor, average_diff=0.4, max_diff=1): | |||
| 
 | ||||
| 
 | ||||
| def assert_compare_images(a, b, max_average_diff, max_diff=255): | ||||
|     assert a.mode == b.mode, "got mode %r, expected %r" % (a.mode, b.mode) | ||||
|     assert a.size == b.size, "got size %r, expected %r" % (a.size, b.size) | ||||
|     assert a.mode == b.mode, f"got mode {repr(a.mode)}, expected {repr(b.mode)}" | ||||
|     assert a.size == b.size, f"got size {repr(a.size)}, expected {repr(b.size)}" | ||||
| 
 | ||||
|     a, b = convert_to_comparable(a, b) | ||||
| 
 | ||||
|  | @ -176,16 +176,15 @@ def assert_compare_images(a, b, max_average_diff, max_diff=255): | |||
|             a.size[0] * a.size[1] | ||||
|         ) | ||||
|         msg = ( | ||||
|             "average pixel value difference {:.4f} > expected {:.4f} " | ||||
|             "for '{}' band".format(average_diff, max_average_diff, band) | ||||
|             f"average pixel value difference {average_diff:.4f} > " | ||||
|             f"expected {max_average_diff:.4f} for '{band}' band" | ||||
|         ) | ||||
|         assert max_average_diff >= average_diff, msg | ||||
| 
 | ||||
|         last_diff = [i for i, num in enumerate(ch_hist) if num > 0][-1] | ||||
|         assert ( | ||||
|             max_diff >= last_diff | ||||
|         ), "max pixel value difference {} > expected {} for '{}' band".format( | ||||
|             last_diff, max_diff, band | ||||
|         assert max_diff >= last_diff, ( | ||||
|             f"max pixel value difference {last_diff} > expected {max_diff} " | ||||
|             f"for '{band}' band" | ||||
|         ) | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -82,15 +82,16 @@ class TestImagingCoreResampleAccuracy: | |||
|         for y in range(case.size[1]): | ||||
|             for x in range(case.size[0]): | ||||
|                 if c_px[x, y] != s_px[x, y]: | ||||
|                     message = "\nHave: \n{}\n\nExpected: \n{}".format( | ||||
|                         self.serialize_image(case), self.serialize_image(sample) | ||||
|                     message = ( | ||||
|                         f"\nHave: \n{self.serialize_image(case)}\n" | ||||
|                         f"\nExpected: \n{self.serialize_image(sample)}" | ||||
|                     ) | ||||
|                     assert s_px[x, y] == c_px[x, y], message | ||||
| 
 | ||||
|     def serialize_image(self, image): | ||||
|         s_px = image.load() | ||||
|         return "\n".join( | ||||
|             " ".join("{:02x}".format(s_px[x, y]) for x in range(image.size[0])) | ||||
|             " ".join(f"{s_px[x, y]:02x}" for x in range(image.size[0])) | ||||
|             for y in range(image.size[1]) | ||||
|         ) | ||||
| 
 | ||||
|  | @ -230,7 +231,7 @@ class TestCoreResampleConsistency: | |||
|         for x in range(channel.size[0]): | ||||
|             for y in range(channel.size[1]): | ||||
|                 if px[x, y] != color: | ||||
|                     message = "{} != {} for pixel {}".format(px[x, y], color, (x, y)) | ||||
|                     message = f"{px[x, y]} != {color} for pixel {(x, y)}" | ||||
|                     assert px[x, y] == color, message | ||||
| 
 | ||||
|     def test_8u(self): | ||||
|  | @ -269,10 +270,9 @@ class TestCoreResampleAlphaCorrect: | |||
|         px = i.load() | ||||
|         for y in range(i.size[1]): | ||||
|             used_colors = {px[x, y][0] for x in range(i.size[0])} | ||||
|             assert 256 == len( | ||||
|                 used_colors | ||||
|             ), "All colors should present in resized image. Only {} on {} line.".format( | ||||
|                 len(used_colors), y | ||||
|             assert 256 == len(used_colors), ( | ||||
|                 "All colors should be present in resized image. " | ||||
|                 f"Only {len(used_colors)} on {y} line." | ||||
|             ) | ||||
| 
 | ||||
|     @pytest.mark.xfail(reason="Current implementation isn't precise enough") | ||||
|  | @ -308,8 +308,9 @@ class TestCoreResampleAlphaCorrect: | |||
|         for y in range(i.size[1]): | ||||
|             for x in range(i.size[0]): | ||||
|                 if px[x, y][-1] != 0 and px[x, y][:-1] != clean_pixel: | ||||
|                     message = "pixel at ({}, {}) is differ:\n{}\n{}".format( | ||||
|                         x, y, px[x, y], clean_pixel | ||||
|                     message = ( | ||||
|                         f"pixel at ({x}, {y}) is different:\n" | ||||
|                         f"{px[x, y]}\n{clean_pixel}" | ||||
|                     ) | ||||
|                     assert px[x, y][:3] == clean_pixel, message | ||||
| 
 | ||||
|  | @ -504,7 +505,7 @@ class TestCoreResampleBox: | |||
|         ]: | ||||
|             res = im.resize(size, Image.LANCZOS, box) | ||||
|             assert res.size == size | ||||
|             assert_image_equal(res, im.crop(box), ">>> {} {}".format(size, box)) | ||||
|             assert_image_equal(res, im.crop(box), f">>> {size} {box}") | ||||
| 
 | ||||
|     def test_no_passthrough(self): | ||||
|         # When resize is required | ||||
|  | @ -520,9 +521,7 @@ class TestCoreResampleBox: | |||
|             assert res.size == size | ||||
|             with pytest.raises(AssertionError, match=r"difference \d"): | ||||
|                 # check that the difference at least that much | ||||
|                 assert_image_similar( | ||||
|                     res, im.crop(box), 20, ">>> {} {}".format(size, box) | ||||
|                 ) | ||||
|                 assert_image_similar(res, im.crop(box), 20, f">>> {size} {box}") | ||||
| 
 | ||||
|     def test_skip_horizontal(self): | ||||
|         # Can skip resize for one dimension | ||||
|  | @ -542,7 +541,7 @@ class TestCoreResampleBox: | |||
|                     res, | ||||
|                     im.crop(box).resize(size, flt), | ||||
|                     0.4, | ||||
|                     ">>> {} {} {}".format(size, box, flt), | ||||
|                     f">>> {size} {box} {flt}", | ||||
|                 ) | ||||
| 
 | ||||
|     def test_skip_vertical(self): | ||||
|  | @ -563,5 +562,5 @@ class TestCoreResampleBox: | |||
|                     res, | ||||
|                     im.crop(box).resize(size, flt), | ||||
|                     0.4, | ||||
|                     ">>> {} {} {}".format(size, box, flt), | ||||
|                     f">>> {size} {box} {flt}", | ||||
|                 ) | ||||
|  |  | |||
|  | @ -182,7 +182,7 @@ def helper_chord(mode, bbox, start, end): | |||
|     # Arrange | ||||
|     im = Image.new(mode, (W, H)) | ||||
|     draw = ImageDraw.Draw(im) | ||||
|     expected = "Tests/images/imagedraw_chord_{}.png".format(mode) | ||||
|     expected = f"Tests/images/imagedraw_chord_{mode}.png" | ||||
| 
 | ||||
|     # Act | ||||
|     draw.chord(bbox, start, end, fill="red", outline="yellow") | ||||
|  | @ -244,7 +244,7 @@ def helper_ellipse(mode, bbox): | |||
|     # Arrange | ||||
|     im = Image.new(mode, (W, H)) | ||||
|     draw = ImageDraw.Draw(im) | ||||
|     expected = "Tests/images/imagedraw_ellipse_{}.png".format(mode) | ||||
|     expected = f"Tests/images/imagedraw_ellipse_{mode}.png" | ||||
| 
 | ||||
|     # Act | ||||
|     draw.ellipse(bbox, fill="green", outline="blue") | ||||
|  | @ -514,7 +514,7 @@ def test_polygon_kite(): | |||
|         # Arrange | ||||
|         im = Image.new(mode, (W, H)) | ||||
|         draw = ImageDraw.Draw(im) | ||||
|         expected = "Tests/images/imagedraw_polygon_kite_{}.png".format(mode) | ||||
|         expected = f"Tests/images/imagedraw_polygon_kite_{mode}.png" | ||||
| 
 | ||||
|         # Act | ||||
|         draw.polygon(KITE_POINTS, fill="blue", outline="yellow") | ||||
|  | @ -1091,7 +1091,5 @@ def test_same_color_outline(): | |||
|                 draw_method(*args) | ||||
| 
 | ||||
|                 # Assert | ||||
|                 expected = "Tests/images/imagedraw_outline_{}_{}.png".format( | ||||
|                     operation, mode | ||||
|                 ) | ||||
|                 expected = f"Tests/images/imagedraw_outline_{operation}_{mode}.png" | ||||
|                 assert_image_similar_tofile(im, expected, 1) | ||||
|  |  | |||
|  | @ -55,7 +55,7 @@ def helper_ellipse(mode, bbox): | |||
|     draw = ImageDraw2.Draw(im) | ||||
|     pen = ImageDraw2.Pen("blue", width=2) | ||||
|     brush = ImageDraw2.Brush("green") | ||||
|     expected = "Tests/images/imagedraw_ellipse_{}.png".format(mode) | ||||
|     expected = f"Tests/images/imagedraw_ellipse_{mode}.png" | ||||
| 
 | ||||
|     # Act | ||||
|     draw.ellipse(bbox, pen, brush) | ||||
|  |  | |||
|  | @ -35,7 +35,7 @@ def _check_alpha(im, original, op, amount): | |||
|     assert_image_equal( | ||||
|         im.getchannel("A"), | ||||
|         original.getchannel("A"), | ||||
|         "Diff on {}: {}".format(op, amount), | ||||
|         f"Diff on {op}: {amount}", | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ from PIL import Image, ImageMath | |||
| 
 | ||||
| def pixel(im): | ||||
|     if hasattr(im, "im"): | ||||
|         return "{} {!r}".format(im.mode, im.getpixel((0, 0))) | ||||
|         return "{} {}".format(im.mode, repr(im.getpixel((0, 0)))) | ||||
|     else: | ||||
|         if isinstance(im, int): | ||||
|             return int(im)  # hack to deal with booleans | ||||
|  |  | |||
|  | @ -65,7 +65,7 @@ def create_lut(): | |||
|     for op in ("corner", "dilation4", "dilation8", "erosion4", "erosion8", "edge"): | ||||
|         lb = ImageMorph.LutBuilder(op_name=op) | ||||
|         lut = lb.build_lut() | ||||
|         with open("Tests/images/%s.lut" % op, "wb") as f: | ||||
|         with open(f"Tests/images/{op}.lut", "wb") as f: | ||||
|             f.write(lut) | ||||
| 
 | ||||
| 
 | ||||
|  | @ -76,7 +76,7 @@ def test_lut(): | |||
|         assert lb.get_lut() is None | ||||
| 
 | ||||
|         lut = lb.build_lut() | ||||
|         with open("Tests/images/%s.lut" % op, "rb") as f: | ||||
|         with open(f"Tests/images/{op}.lut", "rb") as f: | ||||
|             assert lut == bytearray(f.read()) | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -27,7 +27,7 @@ def setup_module(): | |||
|         tk.Frame() | ||||
|         # root = tk.Tk() | ||||
|     except tk.TclError as v: | ||||
|         pytest.skip("TCL Error: %s" % v) | ||||
|         pytest.skip(f"TCL Error: {v}") | ||||
| 
 | ||||
| 
 | ||||
| def test_kw(): | ||||
|  |  | |||
|  | @ -15,9 +15,9 @@ def verify(im1): | |||
|             xy = x, y | ||||
|             p1 = pix1[xy] | ||||
|             p2 = pix2[xy] | ||||
|             assert p1 == p2, "got {!r} from mode {} at {}, expected {!r}".format( | ||||
|                 p1, im1.mode, xy, p2 | ||||
|             ) | ||||
|             assert ( | ||||
|                 p1 == p2 | ||||
|             ), f"got {repr(p1)} from mode {im1.mode} at {xy}, expected {repr(p2)}" | ||||
| 
 | ||||
| 
 | ||||
| def test_basic(tmp_path): | ||||
|  |  | |||
|  | @ -43,7 +43,7 @@ def test_sanity(tmp_path): | |||
|             continue | ||||
| 
 | ||||
|         # Test saving the file | ||||
|         tempfile = str(tmp_path / "temp_{}.png".format(mode)) | ||||
|         tempfile = str(tmp_path / f"temp_{mode}.png") | ||||
|         data.save(tempfile) | ||||
| 
 | ||||
|         # Check that it actually worked. | ||||
|  |  | |||
|  | @ -16,5 +16,5 @@ class TestToQPixmap(PillowQPixmapTestCase): | |||
|             assert not data.isNull() | ||||
| 
 | ||||
|             # Test saving the file | ||||
|             tempfile = str(tmp_path / "temp_{}.png".format(mode)) | ||||
|             tempfile = str(tmp_path / f"temp_{mode}.png") | ||||
|             data.save(tempfile) | ||||
|  |  | |||
|  | @ -14,7 +14,6 @@ def test_is_path(): | |||
|     assert it_is | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.skipif(not _util.py36, reason="os.path support for Paths added in 3.6") | ||||
| def test_path_obj_is_path(): | ||||
|     # Arrange | ||||
|     from pathlib import Path | ||||
|  |  | |||
|  | @ -212,10 +212,10 @@ class DdsImageFile(ImageFile.ImageFile): | |||
|     def _open(self): | ||||
|         magic, header_size = struct.unpack("<II", self.fp.read(8)) | ||||
|         if header_size != 124: | ||||
|             raise OSError("Unsupported header size %r" % (header_size)) | ||||
|             raise OSError(f"Unsupported header size {repr(header_size)}") | ||||
|         header_bytes = self.fp.read(header_size - 4) | ||||
|         if len(header_bytes) != 120: | ||||
|             raise OSError("Incomplete header: %s bytes" % len(header_bytes)) | ||||
|             raise OSError(f"Incomplete header: {len(header_bytes)} bytes") | ||||
|         header = BytesIO(header_bytes) | ||||
| 
 | ||||
|         flags, height, width = struct.unpack("<3I", header.read(12)) | ||||
|  | @ -235,7 +235,7 @@ class DdsImageFile(ImageFile.ImageFile): | |||
|         elif fourcc == b"DXT5": | ||||
|             self.decoder = "DXT5" | ||||
|         else: | ||||
|             raise NotImplementedError("Unimplemented pixel format %r" % fourcc) | ||||
|             raise NotImplementedError(f"Unimplemented pixel format {fourcc}") | ||||
| 
 | ||||
|         self.tile = [(self.decoder, (0, 0) + self.size, 0, (self.mode, 0, 1))] | ||||
| 
 | ||||
|  |  | |||
|  | @ -124,7 +124,7 @@ Identify Image Files | |||
|     for infile in sys.argv[1:]: | ||||
|         try: | ||||
|             with Image.open(infile) as im: | ||||
|                 print(infile, im.format, "%dx%d" % im.size, im.mode) | ||||
|                 print(infile, im.format, f"{im.size}x{im.mode}") | ||||
|         except OSError: | ||||
|             pass | ||||
| 
 | ||||
|  |  | |||
|  | @ -18,7 +18,7 @@ Example: Vary the sharpness of an image | |||
| 
 | ||||
|     for i in range(8): | ||||
|         factor = i / 4.0 | ||||
|         enhancer.enhance(factor).show("Sharpness %f" % factor) | ||||
|         enhancer.enhance(factor).show(f"Sharpness {factor:f}") | ||||
| 
 | ||||
| Also see the :file:`enhancer.py` demo program in the :file:`Scripts/` | ||||
| directory. | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ Extracting frames from an animation | |||
|     with Image.open("animation.fli") as im: | ||||
|         index = 1 | ||||
|         for frame in ImageSequence.Iterator(im): | ||||
|             frame.save("frame%d.png" % index) | ||||
|             frame.save(f"frame{index}.png") | ||||
|             index += 1 | ||||
| 
 | ||||
| The :py:class:`~PIL.ImageSequence.Iterator` class | ||||
|  |  | |||
							
								
								
									
										67
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										67
									
								
								setup.py
									
									
									
									
									
								
							|  | @ -21,7 +21,7 @@ from setuptools.command.build_ext import build_ext | |||
| 
 | ||||
| def get_version(): | ||||
|     version_file = "src/PIL/_version.py" | ||||
|     with open(version_file, "r") as f: | ||||
|     with open(version_file) as f: | ||||
|         exec(compile(f.read(), version_file, "exec")) | ||||
|     return locals()["__version__"] | ||||
| 
 | ||||
|  | @ -39,10 +39,10 @@ ZLIB_ROOT = None | |||
| 
 | ||||
| if sys.platform == "win32" and sys.version_info >= (3, 9): | ||||
|     warnings.warn( | ||||
|         "Pillow {} does not support Python {}.{} and does not provide prebuilt " | ||||
|         "Windows binaries. We do not recommend building from source on Windows.".format( | ||||
|             PILLOW_VERSION, sys.version_info.major, sys.version_info.minor | ||||
|         ), | ||||
|         f"Pillow {PILLOW_VERSION} does not support Python " | ||||
|         f"{sys.version_info.major}.{sys.version_info.minor} and does not provide " | ||||
|         "prebuilt Windows binaries. We do not recommend building from source on " | ||||
|         "Windows.", | ||||
|         RuntimeWarning, | ||||
|     ) | ||||
| 
 | ||||
|  | @ -174,7 +174,7 @@ def _find_library_dirs_ldconfig(): | |||
|         # Assuming GLIBC's ldconfig (with option -p) | ||||
|         # Alpine Linux uses musl that can't print cache | ||||
|         args = ["/sbin/ldconfig", "-p"] | ||||
|         expr = r".*\(%s.*\) => (.*)" % abi_type | ||||
|         expr = fr".*\({abi_type}.*\) => (.*)" | ||||
|         env = dict(os.environ) | ||||
|         env["LC_ALL"] = "C" | ||||
|         env["LANG"] = "C" | ||||
|  | @ -302,8 +302,8 @@ class pil_build_ext(build_ext): | |||
| 
 | ||||
|     user_options = ( | ||||
|         build_ext.user_options | ||||
|         + [("disable-%s" % x, None, "Disable support for %s" % x) for x in feature] | ||||
|         + [("enable-%s" % x, None, "Enable support for %s" % x) for x in feature] | ||||
|         + [(f"disable-{x}", None, f"Disable support for {x}") for x in feature] | ||||
|         + [(f"enable-{x}", None, f"Enable support for {x}") for x in feature] | ||||
|         + [ | ||||
|             ("disable-platform-guessing", None, "Disable platform guessing on Linux"), | ||||
|             ("debug", None, "Debug logging"), | ||||
|  | @ -316,8 +316,8 @@ class pil_build_ext(build_ext): | |||
|         self.add_imaging_libs = "" | ||||
|         build_ext.initialize_options(self) | ||||
|         for x in self.feature: | ||||
|             setattr(self, "disable_%s" % x, None) | ||||
|             setattr(self, "enable_%s" % x, None) | ||||
|             setattr(self, f"disable_{x}", None) | ||||
|             setattr(self, f"enable_{x}", None) | ||||
| 
 | ||||
|     def finalize_options(self): | ||||
|         build_ext.finalize_options(self) | ||||
|  | @ -334,15 +334,15 @@ class pil_build_ext(build_ext): | |||
|             except TypeError: | ||||
|                 self.parallel = None | ||||
|         for x in self.feature: | ||||
|             if getattr(self, "disable_%s" % x): | ||||
|             if getattr(self, f"disable_{x}"): | ||||
|                 setattr(self.feature, x, False) | ||||
|                 self.feature.required.discard(x) | ||||
|                 _dbg("Disabling %s", x) | ||||
|                 if getattr(self, "enable_%s" % x): | ||||
|                 if getattr(self, f"enable_{x}"): | ||||
|                     raise ValueError( | ||||
|                         "Conflicting options: --enable-{} and --disable-{}".format(x, x) | ||||
|                         f"Conflicting options: --enable-{x} and --disable-{x}" | ||||
|                     ) | ||||
|             if getattr(self, "enable_%s" % x): | ||||
|             if getattr(self, f"enable_{x}"): | ||||
|                 _dbg("Requiring %s", x) | ||||
|                 self.feature.required.add(x) | ||||
| 
 | ||||
|  | @ -393,12 +393,12 @@ class pil_build_ext(build_ext): | |||
|             if root is None and pkg_config: | ||||
|                 if isinstance(lib_name, tuple): | ||||
|                     for lib_name2 in lib_name: | ||||
|                         _dbg("Looking for `%s` using pkg-config." % lib_name2) | ||||
|                         _dbg(f"Looking for `{lib_name2}` using pkg-config.") | ||||
|                         root = pkg_config(lib_name2) | ||||
|                         if root: | ||||
|                             break | ||||
|                 else: | ||||
|                     _dbg("Looking for `%s` using pkg-config." % lib_name) | ||||
|                     _dbg(f"Looking for `{lib_name}` using pkg-config.") | ||||
|                     root = pkg_config(lib_name) | ||||
| 
 | ||||
|             if isinstance(root, tuple): | ||||
|  | @ -740,9 +740,9 @@ class pil_build_ext(build_ext): | |||
|             and sys.version_info < (3, 9) | ||||
|             and not (PLATFORM_PYPY or PLATFORM_MINGW) | ||||
|         ): | ||||
|             defs.append(("PILLOW_VERSION", '"\\"%s\\""' % PILLOW_VERSION)) | ||||
|             defs.append(("PILLOW_VERSION", f'"\\"{PILLOW_VERSION}\\""')) | ||||
|         else: | ||||
|             defs.append(("PILLOW_VERSION", '"%s"' % PILLOW_VERSION)) | ||||
|             defs.append(("PILLOW_VERSION", f'"{PILLOW_VERSION}"')) | ||||
| 
 | ||||
|         self._update_extension("PIL._imaging", libs, defs) | ||||
| 
 | ||||
|  | @ -792,11 +792,11 @@ class pil_build_ext(build_ext): | |||
|         print("-" * 68) | ||||
|         print("PIL SETUP SUMMARY") | ||||
|         print("-" * 68) | ||||
|         print("version      Pillow %s" % PILLOW_VERSION) | ||||
|         print(f"version      Pillow {PILLOW_VERSION}") | ||||
|         v = sys.version.split("[") | ||||
|         print("platform     {} {}".format(sys.platform, v[0].strip())) | ||||
|         print(f"platform     {sys.platform} {v[0].strip()}") | ||||
|         for v in v[1:]: | ||||
|             print("             [%s" % v.strip()) | ||||
|             print(f"             [{v.strip()}") | ||||
|         print("-" * 68) | ||||
| 
 | ||||
|         options = [ | ||||
|  | @ -817,10 +817,10 @@ class pil_build_ext(build_ext): | |||
|             if option[0]: | ||||
|                 version = "" | ||||
|                 if len(option) >= 3 and option[2]: | ||||
|                     version = " (%s)" % option[2] | ||||
|                 print("--- {} support available{}".format(option[1], version)) | ||||
|                     version = f" ({option[2]})" | ||||
|                 print(f"--- {option[1]} support available{version}") | ||||
|             else: | ||||
|                 print("*** %s support not available" % option[1]) | ||||
|                 print(f"*** {option[1]} support not available") | ||||
|                 all = 0 | ||||
| 
 | ||||
|         print("-" * 68) | ||||
|  | @ -903,28 +903,23 @@ try: | |||
|         zip_safe=not (debug_build() or PLATFORM_MINGW), | ||||
|     ) | ||||
| except RequiredDependencyException as err: | ||||
|     msg = """ | ||||
|     msg = f""" | ||||
| 
 | ||||
| The headers or library files could not be found for %s, | ||||
| The headers or library files could not be found for {str(err)}, | ||||
| a required dependency when compiling Pillow from source. | ||||
| 
 | ||||
| Please see the install instructions at: | ||||
|    https://pillow.readthedocs.io/en/latest/installation.html | ||||
| 
 | ||||
| """ % ( | ||||
|         str(err) | ||||
|     ) | ||||
| """ | ||||
|     sys.stderr.write(msg) | ||||
|     raise RequiredDependencyException(msg) | ||||
| except DependencyException as err: | ||||
|     msg = """ | ||||
|     msg = f""" | ||||
| 
 | ||||
| The headers or library files could not be found for %s, | ||||
| which was requested by the option flag --enable-%s | ||||
| The headers or library files could not be found for {str(err)}, | ||||
| which was requested by the option flag --enable-{str(err)} | ||||
| 
 | ||||
| """ % ( | ||||
|         str(err), | ||||
|         str(err), | ||||
|     ) | ||||
| """ | ||||
|     sys.stderr.write(msg) | ||||
|     raise DependencyException(msg) | ||||
|  |  | |||
|  | @ -250,7 +250,7 @@ class BlpImageFile(ImageFile.ImageFile): | |||
|             decoder = "BLP2" | ||||
|             self.mode = "RGBA" if self._blp_alpha_depth else "RGB" | ||||
|         else: | ||||
|             raise BLPFormatError("Bad BLP magic %r" % (self.magic)) | ||||
|             raise BLPFormatError(f"Bad BLP magic {repr(self.magic)}") | ||||
| 
 | ||||
|         self.tile = [(decoder, (0, 0) + self.size, 0, (self.mode, 0, 1))] | ||||
| 
 | ||||
|  | @ -336,11 +336,11 @@ class BLP1Decoder(_BLPBaseDecoder): | |||
|                 self.set_as_raw(bytes(data)) | ||||
|             else: | ||||
|                 raise BLPFormatError( | ||||
|                     "Unsupported BLP encoding %r" % (self._blp_encoding) | ||||
|                     f"Unsupported BLP encoding {repr(self._blp_encoding)}" | ||||
|                 ) | ||||
|         else: | ||||
|             raise BLPFormatError( | ||||
|                 "Unsupported BLP compression %r" % (self._blp_encoding) | ||||
|                 f"Unsupported BLP compression {repr(self._blp_encoding)}" | ||||
|             ) | ||||
| 
 | ||||
|     def _decode_jpeg_stream(self): | ||||
|  | @ -400,13 +400,15 @@ class BLP2Decoder(_BLPBaseDecoder): | |||
|                             data += d | ||||
|                 else: | ||||
|                     raise BLPFormatError( | ||||
|                         "Unsupported alpha encoding %r" % (self._blp_alpha_encoding) | ||||
|                         f"Unsupported alpha encoding {repr(self._blp_alpha_encoding)}" | ||||
|                     ) | ||||
|             else: | ||||
|                 raise BLPFormatError("Unknown BLP encoding %r" % (self._blp_encoding)) | ||||
|                 raise BLPFormatError(f"Unknown BLP encoding {repr(self._blp_encoding)}") | ||||
| 
 | ||||
|         else: | ||||
|             raise BLPFormatError("Unknown BLP compression %r" % (self._blp_compression)) | ||||
|             raise BLPFormatError( | ||||
|                 f"Unknown BLP compression {repr(self._blp_compression)}" | ||||
|             ) | ||||
| 
 | ||||
|         self.set_as_raw(bytes(data)) | ||||
| 
 | ||||
|  |  | |||
|  | @ -149,7 +149,7 @@ class BmpImageFile(ImageFile.ImageFile): | |||
|                     file_info["a_mask"], | ||||
|                 ) | ||||
|         else: | ||||
|             raise OSError("Unsupported BMP header type (%d)" % file_info["header_size"]) | ||||
|             raise OSError(f"Unsupported BMP header type ({file_info['header_size']})") | ||||
| 
 | ||||
|         # ------------------ Special case : header is reported 40, which | ||||
|         # ---------------------- is shorter than real size for bpp >= 16 | ||||
|  | @ -169,7 +169,7 @@ class BmpImageFile(ImageFile.ImageFile): | |||
|         # ---------------------- Check bit depth for unusual unsupported values | ||||
|         self.mode, raw_mode = BIT2MODE.get(file_info["bits"], (None, None)) | ||||
|         if self.mode is None: | ||||
|             raise OSError("Unsupported BMP pixel depth (%d)" % file_info["bits"]) | ||||
|             raise OSError(f"Unsupported BMP pixel depth ({file_info['bits']})") | ||||
| 
 | ||||
|         # ---------------- Process BMP with Bitfields compression (not palette) | ||||
|         if file_info["compression"] == self.BITFIELDS: | ||||
|  | @ -214,14 +214,14 @@ class BmpImageFile(ImageFile.ImageFile): | |||
|             if file_info["bits"] == 32 and header == 22:  # 32-bit .cur offset | ||||
|                 raw_mode, self.mode = "BGRA", "RGBA" | ||||
|         else: | ||||
|             raise OSError("Unsupported BMP compression (%d)" % file_info["compression"]) | ||||
|             raise OSError(f"Unsupported BMP compression ({file_info['compression']})") | ||||
| 
 | ||||
|         # --------------- Once the header is processed, process the palette/LUT | ||||
|         if self.mode == "P":  # Paletted for 1, 4 and 8 bit images | ||||
| 
 | ||||
|             # ---------------------------------------------------- 1-bit images | ||||
|             if not (0 < file_info["colors"] <= 65536): | ||||
|                 raise OSError("Unsupported BMP Palette size (%d)" % file_info["colors"]) | ||||
|                 raise OSError(f"Unsupported BMP Palette size ({file_info['colors']})") | ||||
|             else: | ||||
|                 padding = file_info["palette_padding"] | ||||
|                 palette = read(padding * file_info["colors"]) | ||||
|  | @ -310,7 +310,7 @@ def _save(im, fp, filename, bitmap_header=True): | |||
|     try: | ||||
|         rawmode, bits, colors = SAVE[im.mode] | ||||
|     except KeyError as e: | ||||
|         raise OSError("cannot write mode %s as BMP" % im.mode) from e | ||||
|         raise OSError(f"cannot write mode {im.mode} as BMP") from e | ||||
| 
 | ||||
|     info = im.encoderinfo | ||||
| 
 | ||||
|  |  | |||
|  | @ -106,10 +106,10 @@ class DdsImageFile(ImageFile.ImageFile): | |||
|     def _open(self): | ||||
|         magic, header_size = struct.unpack("<II", self.fp.read(8)) | ||||
|         if header_size != 124: | ||||
|             raise OSError("Unsupported header size %r" % (header_size)) | ||||
|             raise OSError(f"Unsupported header size {repr(header_size)}") | ||||
|         header_bytes = self.fp.read(header_size - 4) | ||||
|         if len(header_bytes) != 120: | ||||
|             raise OSError("Incomplete header: %s bytes" % len(header_bytes)) | ||||
|             raise OSError(f"Incomplete header: {len(header_bytes)} bytes") | ||||
|         header = BytesIO(header_bytes) | ||||
| 
 | ||||
|         flags, height, width = struct.unpack("<3I", header.read(12)) | ||||
|  | @ -159,10 +159,10 @@ class DdsImageFile(ImageFile.ImageFile): | |||
|                     n = 7 | ||||
|                 else: | ||||
|                     raise NotImplementedError( | ||||
|                         "Unimplemented DXGI format %d" % (dxgi_format) | ||||
|                         f"Unimplemented DXGI format {dxgi_format}" | ||||
|                     ) | ||||
|             else: | ||||
|                 raise NotImplementedError("Unimplemented pixel format %r" % (fourcc)) | ||||
|                 raise NotImplementedError(f"Unimplemented pixel format {repr(fourcc)}") | ||||
| 
 | ||||
|             self.tile = [("bcn", (0, 0) + self.size, data_start, (n))] | ||||
| 
 | ||||
|  |  | |||
|  | @ -118,10 +118,10 @@ def Ghostscript(tile, size, fp, scale=1): | |||
|         "-dNOPAUSE",  # don't pause between pages | ||||
|         "-dSAFER",  # safe mode | ||||
|         "-sDEVICE=ppmraw",  # ppm driver | ||||
|         "-sOutputFile=%s" % outfile,  # output file | ||||
|         f"-sOutputFile={outfile}",  # output file | ||||
|         # adjust for image origin | ||||
|         "-c", | ||||
|         "%d %d translate" % (-bbox[0], -bbox[1]), | ||||
|         f"{-bbox[0]} {-bbox[1]} translate", | ||||
|         "-f", | ||||
|         infile,  # input file | ||||
|         # showpage (see https://bugs.ghostscript.com/show_bug.cgi?id=698272) | ||||
|  | @ -386,10 +386,10 @@ def _save(im, fp, filename, eps=1): | |||
|         # image header | ||||
|         fp.write("gsave\n") | ||||
|         fp.write("10 dict begin\n") | ||||
|         fp.write("/buf %d string def\n" % (im.size[0] * operator[1])) | ||||
|         fp.write(f"/buf {im.size[0] * operator[1]} string def\n") | ||||
|         fp.write("%d %d scale\n" % im.size) | ||||
|         fp.write("%d %d 8\n" % im.size)  # <= bits | ||||
|         fp.write("[%d 0 0 -%d 0 %d]\n" % (im.size[0], im.size[1], im.size[1])) | ||||
|         fp.write(f"[{im.size[0]} 0 0 -{im.size[1]} 0 {im.size[1]}]\n") | ||||
|         fp.write("{ currentfile buf readhexstring pop } bind\n") | ||||
|         fp.write(operator[2] + "\n") | ||||
|         if hasattr(fp, "flush"): | ||||
|  |  | |||
|  | @ -133,7 +133,7 @@ class FliImageFile(ImageFile.ImageFile): | |||
|             self.load() | ||||
| 
 | ||||
|         if frame != self.__frame + 1: | ||||
|             raise ValueError("cannot seek to frame %d" % frame) | ||||
|             raise ValueError(f"cannot seek to frame {frame}") | ||||
|         self.__frame = frame | ||||
| 
 | ||||
|         # move to next frame | ||||
|  |  | |||
|  | @ -101,7 +101,7 @@ class FontFile: | |||
|         # font metrics | ||||
|         with open(os.path.splitext(filename)[0] + ".pil", "wb") as fp: | ||||
|             fp.write(b"PILfont\n") | ||||
|             fp.write((";;;;;;%d;\n" % self.ysize).encode("ascii"))  # HACK!!! | ||||
|             fp.write(f";;;;;;{self.ysize};\n".encode("ascii"))  # HACK!!! | ||||
|             fp.write(b"DATA\n") | ||||
|             for id in range(256): | ||||
|                 m = self.metrics[id] | ||||
|  |  | |||
|  | @ -73,7 +73,7 @@ class FpxImageFile(ImageFile.ImageFile): | |||
|         # get the Image Contents Property Set | ||||
| 
 | ||||
|         prop = self.ole.getproperties( | ||||
|             ["Data Object Store %06d" % index, "\005Image Contents"] | ||||
|             [f"Data Object Store {index:06d}", "\005Image Contents"] | ||||
|         ) | ||||
| 
 | ||||
|         # size (highest resolution) | ||||
|  | @ -121,8 +121,8 @@ class FpxImageFile(ImageFile.ImageFile): | |||
|         # setup tile descriptors for a given subimage | ||||
| 
 | ||||
|         stream = [ | ||||
|             "Data Object Store %06d" % index, | ||||
|             "Resolution %04d" % subimage, | ||||
|             f"Data Object Store {index:06d}", | ||||
|             f"Resolution {subimage:04d}", | ||||
|             "Subimage 0000 Header", | ||||
|         ] | ||||
| 
 | ||||
|  |  | |||
|  | @ -89,7 +89,7 @@ class FtexImageFile(ImageFile.ImageFile): | |||
|         elif format == FORMAT_UNCOMPRESSED: | ||||
|             self.tile = [("raw", (0, 0) + self.size, 0, ("RGB", 0, 1))] | ||||
|         else: | ||||
|             raise ValueError("Invalid texture compression format: %r" % (format)) | ||||
|             raise ValueError(f"Invalid texture compression format: {repr(format)}") | ||||
| 
 | ||||
|         self.fp.close() | ||||
|         self.fp = BytesIO(data) | ||||
|  |  | |||
|  | @ -47,7 +47,7 @@ class GbrImageFile(ImageFile.ImageFile): | |||
|         if header_size < 20: | ||||
|             raise SyntaxError("not a GIMP brush") | ||||
|         if version not in (1, 2): | ||||
|             raise SyntaxError("Unsupported GIMP brush version: %s" % version) | ||||
|             raise SyntaxError(f"Unsupported GIMP brush version: {version}") | ||||
| 
 | ||||
|         width = i32(self.fp.read(4)) | ||||
|         height = i32(self.fp.read(4)) | ||||
|  | @ -55,7 +55,7 @@ class GbrImageFile(ImageFile.ImageFile): | |||
|         if width <= 0 or height <= 0: | ||||
|             raise SyntaxError("not a GIMP brush") | ||||
|         if color_depth not in (1, 4): | ||||
|             raise SyntaxError("Unsupported GIMP brush color depth: %s" % color_depth) | ||||
|             raise SyntaxError(f"Unsupported GIMP brush color depth: {color_depth}") | ||||
| 
 | ||||
|         if version == 1: | ||||
|             comment_length = header_size - 20 | ||||
|  |  | |||
|  | @ -154,7 +154,7 @@ class GifImageFile(ImageFile.ImageFile): | |||
|                 self.load() | ||||
| 
 | ||||
|         if frame != self.__frame + 1: | ||||
|             raise ValueError("cannot seek to frame %d" % frame) | ||||
|             raise ValueError(f"cannot seek to frame {frame}") | ||||
|         self.__frame = frame | ||||
| 
 | ||||
|         self.tile = [] | ||||
|  |  | |||
|  | @ -83,7 +83,7 @@ def read_32(fobj, start_length, size): | |||
|                 if bytesleft <= 0: | ||||
|                     break | ||||
|             if bytesleft != 0: | ||||
|                 raise SyntaxError("Error reading channel [%r left]" % bytesleft) | ||||
|                 raise SyntaxError(f"Error reading channel [{repr(bytesleft)} left]") | ||||
|             band = Image.frombuffer("L", pixel_size, b"".join(data), "raw", "L", 0, 1) | ||||
|             im.im.putband(band.im, band_ix) | ||||
|     return {"RGB": im} | ||||
|  | @ -321,7 +321,7 @@ def _save(im, fp, filename): | |||
|         last_w = None | ||||
|         second_path = None | ||||
|         for w in [16, 32, 128, 256, 512]: | ||||
|             prefix = "icon_{}x{}".format(w, w) | ||||
|             prefix = f"icon_{w}x{w}" | ||||
| 
 | ||||
|             first_path = os.path.join(iconset, prefix + ".png") | ||||
|             if last_w == w: | ||||
|  |  | |||
|  | @ -86,16 +86,16 @@ OPEN = { | |||
| 
 | ||||
| # ifunc95 extensions | ||||
| for i in ["8", "8S", "16", "16S", "32", "32F"]: | ||||
|     OPEN["L %s image" % i] = ("F", "F;%s" % i) | ||||
|     OPEN["L*%s image" % i] = ("F", "F;%s" % i) | ||||
|     OPEN[f"L {i} image"] = ("F", f"F;{i}") | ||||
|     OPEN[f"L*{i} image"] = ("F", f"F;{i}") | ||||
| for i in ["16", "16L", "16B"]: | ||||
|     OPEN["L %s image" % i] = ("I;%s" % i, "I;%s" % i) | ||||
|     OPEN["L*%s image" % i] = ("I;%s" % i, "I;%s" % i) | ||||
|     OPEN[f"L {i} image"] = (f"I;{i}", f"I;{i}") | ||||
|     OPEN[f"L*{i} image"] = (f"I;{i}", f"I;{i}") | ||||
| for i in ["32S"]: | ||||
|     OPEN["L %s image" % i] = ("I", "I;%s" % i) | ||||
|     OPEN["L*%s image" % i] = ("I", "I;%s" % i) | ||||
|     OPEN[f"L {i} image"] = ("I", f"I;{i}") | ||||
|     OPEN[f"L*{i} image"] = ("I", f"I;{i}") | ||||
| for i in range(2, 33): | ||||
|     OPEN["L*%s image" % i] = ("F", "F;%s" % i) | ||||
|     OPEN[f"L*{i} image"] = ("F", f"F;{i}") | ||||
| 
 | ||||
| 
 | ||||
| # -------------------------------------------------------------------- | ||||
|  | @ -342,11 +342,11 @@ def _save(im, fp, filename): | |||
|     try: | ||||
|         image_type, rawmode = SAVE[im.mode] | ||||
|     except KeyError as e: | ||||
|         raise ValueError("Cannot save %s images as IM" % im.mode) from e | ||||
|         raise ValueError(f"Cannot save {im.mode} images as IM") from e | ||||
| 
 | ||||
|     frames = im.encoderinfo.get("frames", 1) | ||||
| 
 | ||||
|     fp.write(("Image type: %s image\r\n" % image_type).encode("ascii")) | ||||
|     fp.write(f"Image type: {image_type} image\r\n".encode("ascii")) | ||||
|     if filename: | ||||
|         # Each line must be 100 characters or less, | ||||
|         # or: SyntaxError("not an IM file") | ||||
|  | @ -355,9 +355,9 @@ def _save(im, fp, filename): | |||
|         name, ext = os.path.splitext(os.path.basename(filename)) | ||||
|         name = "".join([name[: 92 - len(ext)], ext]) | ||||
| 
 | ||||
|         fp.write(("Name: %s\r\n" % name).encode("ascii")) | ||||
|         fp.write(f"Name: {name}\r\n".encode("ascii")) | ||||
|     fp.write(("Image size (x*y): %d*%d\r\n" % im.size).encode("ascii")) | ||||
|     fp.write(("File size (no of images): %d\r\n" % frames).encode("ascii")) | ||||
|     fp.write(f"File size (no of images): {frames}\r\n".encode("ascii")) | ||||
|     if im.mode in ["P", "PA"]: | ||||
|         fp.write(b"Lut: 1\r\n") | ||||
|     fp.write(b"\000" * (511 - fp.tell()) + b"\032") | ||||
|  |  | |||
|  | @ -59,7 +59,7 @@ if sys.version_info >= (3, 7): | |||
|         if name == "PILLOW_VERSION": | ||||
|             _raise_version_warning() | ||||
|             return __version__ | ||||
|         raise AttributeError("module '{}' has no attribute '{}'".format(__name__, name)) | ||||
|         raise AttributeError(f"module '{__name__}' has no attribute '{name}'") | ||||
| 
 | ||||
| 
 | ||||
| else: | ||||
|  | @ -96,8 +96,8 @@ try: | |||
|     if __version__ != getattr(core, "PILLOW_VERSION", None): | ||||
|         raise ImportError( | ||||
|             "The _imaging extension was built for another version of Pillow or PIL:\n" | ||||
|             "Core version: %s\n" | ||||
|             "Pillow version: %s" % (getattr(core, "PILLOW_VERSION", None), __version__) | ||||
|             f"Core version: {getattr(core, 'PILLOW_VERSION', None)}\n" | ||||
|             f"Pillow version: {__version__}" | ||||
|         ) | ||||
| 
 | ||||
| except ImportError as v: | ||||
|  | @ -403,7 +403,7 @@ def init(): | |||
|     for plugin in _plugins: | ||||
|         try: | ||||
|             logger.debug("Importing %s", plugin) | ||||
|             __import__("PIL.%s" % plugin, globals(), locals(), []) | ||||
|             __import__(f"PIL.{plugin}", globals(), locals(), []) | ||||
|         except ImportError as e: | ||||
|             logger.debug("Image: failed to import %s: %s", plugin, e) | ||||
| 
 | ||||
|  | @ -435,7 +435,7 @@ def _getdecoder(mode, decoder_name, args, extra=()): | |||
|         # get decoder | ||||
|         decoder = getattr(core, decoder_name + "_decoder") | ||||
|     except AttributeError as e: | ||||
|         raise OSError("decoder %s not available" % decoder_name) from e | ||||
|         raise OSError(f"decoder {decoder_name} not available") from e | ||||
|     return decoder(mode, *args + extra) | ||||
| 
 | ||||
| 
 | ||||
|  | @ -458,7 +458,7 @@ def _getencoder(mode, encoder_name, args, extra=()): | |||
|         # get encoder | ||||
|         encoder = getattr(core, encoder_name + "_encoder") | ||||
|     except AttributeError as e: | ||||
|         raise OSError("encoder %s not available" % encoder_name) from e | ||||
|         raise OSError(f"encoder {encoder_name} not available") from e | ||||
|     return encoder(mode, *args + extra) | ||||
| 
 | ||||
| 
 | ||||
|  | @ -743,7 +743,7 @@ class Image: | |||
|             if s: | ||||
|                 break | ||||
|         if s < 0: | ||||
|             raise RuntimeError("encoder error %d in tobytes" % s) | ||||
|             raise RuntimeError(f"encoder error {s} in tobytes") | ||||
| 
 | ||||
|         return b"".join(data) | ||||
| 
 | ||||
|  | @ -764,9 +764,9 @@ class Image: | |||
|         data = self.tobytes("xbm") | ||||
|         return b"".join( | ||||
|             [ | ||||
|                 ("#define %s_width %d\n" % (name, self.size[0])).encode("ascii"), | ||||
|                 ("#define %s_height %d\n" % (name, self.size[1])).encode("ascii"), | ||||
|                 ("static char %s_bits[] = {\n" % name).encode("ascii"), | ||||
|                 f"#define {name}_width {self.size[0]}\n".encode("ascii"), | ||||
|                 f"#define {name}_height {self.size[1]}\n".encode("ascii"), | ||||
|                 f"static char {name}_bits[] = {{\n".encode("ascii"), | ||||
|                 data, | ||||
|                 b"};", | ||||
|             ] | ||||
|  | @ -1862,7 +1862,7 @@ class Image: | |||
|         """ | ||||
| 
 | ||||
|         if resample not in (NEAREST, BILINEAR, BICUBIC, LANCZOS, BOX, HAMMING): | ||||
|             message = "Unknown resampling filter ({}).".format(resample) | ||||
|             message = f"Unknown resampling filter ({resample})." | ||||
| 
 | ||||
|             filters = [ | ||||
|                 "{} ({})".format(filter[1], filter[0]) | ||||
|  | @ -2130,7 +2130,7 @@ class Image: | |||
|             try: | ||||
|                 format = EXTENSION[ext] | ||||
|             except KeyError as e: | ||||
|                 raise ValueError("unknown file extension: {}".format(ext)) from e | ||||
|                 raise ValueError(f"unknown file extension: {ext}") from e | ||||
| 
 | ||||
|         if format.upper() not in SAVE: | ||||
|             init() | ||||
|  | @ -2242,7 +2242,7 @@ class Image: | |||
|             try: | ||||
|                 channel = self.getbands().index(channel) | ||||
|             except ValueError as e: | ||||
|                 raise ValueError('The image has no channel "{}"'.format(channel)) from e | ||||
|                 raise ValueError(f'The image has no channel "{channel}"') from e | ||||
| 
 | ||||
|         return self._new(self.im.getband(channel)) | ||||
| 
 | ||||
|  | @ -2463,9 +2463,9 @@ class Image: | |||
|                     BOX: "Image.BOX", | ||||
|                     HAMMING: "Image.HAMMING", | ||||
|                     LANCZOS: "Image.LANCZOS/Image.ANTIALIAS", | ||||
|                 }[resample] + " ({}) cannot be used.".format(resample) | ||||
|                 }[resample] + f" ({resample}) cannot be used." | ||||
|             else: | ||||
|                 message = "Unknown resampling filter ({}).".format(resample) | ||||
|                 message = f"Unknown resampling filter ({resample})." | ||||
| 
 | ||||
|             filters = [ | ||||
|                 "{} ({})".format(filter[1], filter[0]) | ||||
|  | @ -2759,7 +2759,7 @@ def fromarray(obj, mode=None): | |||
|     else: | ||||
|         ndmax = 4 | ||||
|     if ndim > ndmax: | ||||
|         raise ValueError("Too many dimensions: %d > %d." % (ndim, ndmax)) | ||||
|         raise ValueError(f"Too many dimensions: {ndim} > {ndmax}.") | ||||
| 
 | ||||
|     size = 1 if ndim == 1 else shape[1], shape[0] | ||||
|     if strides is not None: | ||||
|  | @ -2825,14 +2825,14 @@ def _decompression_bomb_check(size): | |||
| 
 | ||||
|     if pixels > 2 * MAX_IMAGE_PIXELS: | ||||
|         raise DecompressionBombError( | ||||
|             "Image size (%d pixels) exceeds limit of %d pixels, " | ||||
|             "could be decompression bomb DOS attack." % (pixels, 2 * MAX_IMAGE_PIXELS) | ||||
|             f"Image size ({pixels} pixels) exceeds limit of {2 * MAX_IMAGE_PIXELS} " | ||||
|             "pixels, could be decompression bomb DOS attack." | ||||
|         ) | ||||
| 
 | ||||
|     if pixels > MAX_IMAGE_PIXELS: | ||||
|         warnings.warn( | ||||
|             "Image size (%d pixels) exceeds limit of %d pixels, " | ||||
|             "could be decompression bomb DOS attack." % (pixels, MAX_IMAGE_PIXELS), | ||||
|             f"Image size ({pixels} pixels) exceeds limit of {MAX_IMAGE_PIXELS} pixels, " | ||||
|             "could be decompression bomb DOS attack.", | ||||
|             DecompressionBombWarning, | ||||
|         ) | ||||
| 
 | ||||
|  | @ -2861,7 +2861,7 @@ def open(fp, mode="r"): | |||
|     """ | ||||
| 
 | ||||
|     if mode != "r": | ||||
|         raise ValueError("bad mode %r" % mode) | ||||
|         raise ValueError(f"bad mode {repr(mode)}") | ||||
|     elif isinstance(fp, io.StringIO): | ||||
|         raise ValueError( | ||||
|             "StringIO cannot be used to open an image. " | ||||
|  | @ -3242,13 +3242,13 @@ def _apply_env_variables(env=None): | |||
|         try: | ||||
|             var = int(var) * units | ||||
|         except ValueError: | ||||
|             warnings.warn("{} is not int".format(var_name)) | ||||
|             warnings.warn(f"{var_name} is not int") | ||||
|             continue | ||||
| 
 | ||||
|         try: | ||||
|             setter(var) | ||||
|         except ValueError as e: | ||||
|             warnings.warn("{}: {}".format(var_name, e)) | ||||
|             warnings.warn(f"{var_name}: {e}") | ||||
| 
 | ||||
| 
 | ||||
| _apply_env_variables() | ||||
|  | @ -3371,8 +3371,8 @@ class Exif(MutableMapping): | |||
|                         if len(data) != size: | ||||
|                             warnings.warn( | ||||
|                                 "Possibly corrupt EXIF MakerNote data.  " | ||||
|                                 "Expecting to read %d bytes but only got %d." | ||||
|                                 " Skipping tag %s" % (size, len(data), ifd_tag) | ||||
|                                 f"Expecting to read {size} bytes but only got " | ||||
|                                 f"{len(data)}. Skipping tag {ifd_tag}" | ||||
|                             ) | ||||
|                             continue | ||||
| 
 | ||||
|  |  | |||
|  | @ -680,8 +680,7 @@ def createProfile(colorSpace, colorTemp=-1): | |||
| 
 | ||||
|     if colorSpace not in ["LAB", "XYZ", "sRGB"]: | ||||
|         raise PyCMSError( | ||||
|             "Color space not supported for on-the-fly profile creation (%s)" | ||||
|             % colorSpace | ||||
|             f"Color space not supported for on-the-fly profile creation ({colorSpace})" | ||||
|         ) | ||||
| 
 | ||||
|     if colorSpace == "LAB": | ||||
|  | @ -689,7 +688,7 @@ def createProfile(colorSpace, colorTemp=-1): | |||
|             colorTemp = float(colorTemp) | ||||
|         except (TypeError, ValueError) as e: | ||||
|             raise PyCMSError( | ||||
|                 'Color temperature must be numeric, "%s" not valid' % colorTemp | ||||
|                 f'Color temperature must be numeric, "{colorTemp}" not valid' | ||||
|             ) from e | ||||
| 
 | ||||
|     try: | ||||
|  | @ -734,7 +733,7 @@ def getProfileName(profile): | |||
|             return (profile.profile.profile_description or "") + "\n" | ||||
|         if not manufacturer or len(model) > 30: | ||||
|             return model + "\n" | ||||
|         return "{} - {}\n".format(model, manufacturer) | ||||
|         return f"{model} - {manufacturer}\n" | ||||
| 
 | ||||
|     except (AttributeError, OSError, TypeError, ValueError) as v: | ||||
|         raise PyCMSError(v) from v | ||||
|  |  | |||
|  | @ -113,7 +113,7 @@ def getrgb(color): | |||
|     m = re.match(r"rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$", color) | ||||
|     if m: | ||||
|         return (int(m.group(1)), int(m.group(2)), int(m.group(3)), int(m.group(4))) | ||||
|     raise ValueError("unknown color specifier: %r" % color) | ||||
|     raise ValueError(f"unknown color specifier: {repr(color)}") | ||||
| 
 | ||||
| 
 | ||||
| def getcolor(color, mode): | ||||
|  |  | |||
|  | @ -276,7 +276,7 @@ class ImageDraw: | |||
|         stroke_width=0, | ||||
|         stroke_fill=None, | ||||
|         *args, | ||||
|         **kwargs | ||||
|         **kwargs, | ||||
|     ): | ||||
|         if self._multiline_check(text): | ||||
|             return self.multiline_text( | ||||
|  |  | |||
|  | @ -63,7 +63,7 @@ def raise_oserror(error): | |||
|     except AttributeError: | ||||
|         message = ERRORS.get(error) | ||||
|     if not message: | ||||
|         message = "decoder error %d" % error | ||||
|         message = f"decoder error {error}" | ||||
|     raise OSError(message + " when reading image file") | ||||
| 
 | ||||
| 
 | ||||
|  | @ -203,7 +203,7 @@ class ImageFile(Image.Image): | |||
|                         # use mmap, if possible | ||||
|                         import mmap | ||||
| 
 | ||||
|                         with open(self.filename, "r") as fp: | ||||
|                         with open(self.filename) as fp: | ||||
|                             self.map = mmap.mmap( | ||||
|                                 fp.fileno(), 0, access=mmap.ACCESS_READ | ||||
|                             ) | ||||
|  | @ -258,7 +258,7 @@ class ImageFile(Image.Image): | |||
|                                 else: | ||||
|                                     raise OSError( | ||||
|                                         "image file is truncated " | ||||
|                                         "(%d bytes not processed)" % len(b) | ||||
|                                         f"({len(b)} bytes not processed)" | ||||
|                                     ) | ||||
| 
 | ||||
|                             b = b + s | ||||
|  | @ -334,7 +334,7 @@ class StubImageFile(ImageFile): | |||
|     def load(self): | ||||
|         loader = self._load() | ||||
|         if loader is None: | ||||
|             raise OSError("cannot find loader for this %s file" % self.format) | ||||
|             raise OSError(f"cannot find loader for this {self.format} file") | ||||
|         image = loader.load(self) | ||||
|         assert image is not None | ||||
|         # become the other object (!) | ||||
|  | @ -526,7 +526,7 @@ def _save(im, fp, tile, bufsize=0): | |||
|                     if s: | ||||
|                         break | ||||
|             if s < 0: | ||||
|                 raise OSError("encoder error %d when writing image file" % s) from exc | ||||
|                 raise OSError(f"encoder error {s} when writing image file") from exc | ||||
|             e.cleanup() | ||||
|     else: | ||||
|         # slight speedup: compress to real file object | ||||
|  | @ -541,7 +541,7 @@ def _save(im, fp, tile, bufsize=0): | |||
|             else: | ||||
|                 s = e.encode_to_file(fh, bufsize) | ||||
|             if s < 0: | ||||
|                 raise OSError("encoder error %d when writing image file" % s) | ||||
|                 raise OSError(f"encoder error {s} when writing image file") | ||||
|             e.cleanup() | ||||
|     if hasattr(fp, "flush"): | ||||
|         fp.flush() | ||||
|  |  | |||
|  | @ -401,9 +401,8 @@ class Color3DLUT(MultibandFilter): | |||
|             raise ValueError( | ||||
|                 "The table should have either channels * size**3 float items " | ||||
|                 "or size**3 items of channels-sized tuples with floats. " | ||||
|                 "Table should be: {}x{}x{}x{}. Actual length: {}".format( | ||||
|                     channels, size[0], size[1], size[2], len(table) | ||||
|                 ) | ||||
|                 f"Table should be: {channels}x{size[0]}x{size[1]}x{size[2]}. " | ||||
|                 f"Actual length: {len(table)}" | ||||
|             ) | ||||
|         self.table = table | ||||
| 
 | ||||
|  | @ -513,12 +512,12 @@ class Color3DLUT(MultibandFilter): | |||
| 
 | ||||
|     def __repr__(self): | ||||
|         r = [ | ||||
|             "{} from {}".format(self.__class__.__name__, self.table.__class__.__name__), | ||||
|             f"{self.__class__.__name__} from {self.table.__class__.__name__}", | ||||
|             "size={:d}x{:d}x{:d}".format(*self.size), | ||||
|             "channels={:d}".format(self.channels), | ||||
|             f"channels={self.channels:d}", | ||||
|         ] | ||||
|         if self.mode: | ||||
|             r.append("target_mode={}".format(self.mode)) | ||||
|             r.append(f"target_mode={self.mode}") | ||||
|         return "<{}>".format(" ".join(r)) | ||||
| 
 | ||||
|     def filter(self, image): | ||||
|  |  | |||
|  | @ -415,7 +415,7 @@ class FreeTypeFont: | |||
|         language=None, | ||||
|         stroke_width=0, | ||||
|         *args, | ||||
|         **kwargs | ||||
|         **kwargs, | ||||
|     ): | ||||
|         """ | ||||
|         Create a bitmap for the text. | ||||
|  |  | |||
|  | @ -41,7 +41,7 @@ class _Operand: | |||
|             elif im1.im.mode in ("I", "F"): | ||||
|                 return im1.im | ||||
|             else: | ||||
|                 raise ValueError("unsupported mode: %s" % im1.im.mode) | ||||
|                 raise ValueError(f"unsupported mode: {im1.im.mode}") | ||||
|         else: | ||||
|             # argument was a constant | ||||
|             if _isconstant(im1) and self.im.mode in ("1", "L", "I"): | ||||
|  | @ -58,7 +58,7 @@ class _Operand: | |||
|             try: | ||||
|                 op = getattr(_imagingmath, op + "_" + im1.mode) | ||||
|             except AttributeError as e: | ||||
|                 raise TypeError("bad operand type for '%s'" % op) from e | ||||
|                 raise TypeError(f"bad operand type for '{op}'") from e | ||||
|             _imagingmath.unop(op, out.im.id, im1.im.id) | ||||
|         else: | ||||
|             # binary operation | ||||
|  | @ -86,7 +86,7 @@ class _Operand: | |||
|             try: | ||||
|                 op = getattr(_imagingmath, op + "_" + im1.mode) | ||||
|             except AttributeError as e: | ||||
|                 raise TypeError("bad operand type for '%s'" % op) from e | ||||
|                 raise TypeError(f"bad operand type for '{op}'") from e | ||||
|             _imagingmath.binop(op, out.im.id, im1.im.id, im2.im.id) | ||||
|         return _Operand(out) | ||||
| 
 | ||||
|  |  | |||
|  | @ -111,7 +111,7 @@ class ImagePalette: | |||
|                 self.dirty = 1 | ||||
|                 return index | ||||
|         else: | ||||
|             raise ValueError("unknown color specifier: %r" % color) | ||||
|             raise ValueError(f"unknown color specifier: {repr(color)}") | ||||
| 
 | ||||
|     def save(self, fp): | ||||
|         """Save palette to text file. | ||||
|  | @ -123,12 +123,12 @@ class ImagePalette: | |||
|         if isinstance(fp, str): | ||||
|             fp = open(fp, "w") | ||||
|         fp.write("# Palette\n") | ||||
|         fp.write("# Mode: %s\n" % self.mode) | ||||
|         fp.write(f"# Mode: {self.mode}\n") | ||||
|         for i in range(256): | ||||
|             fp.write("%d" % i) | ||||
|             fp.write(f"{i}") | ||||
|             for j in range(i * len(self.mode), (i + 1) * len(self.mode)): | ||||
|                 try: | ||||
|                     fp.write(" %d" % self.palette[j]) | ||||
|                     fp.write(f" {self.palette[j]}") | ||||
|                 except IndexError: | ||||
|                     fp.write(" 0") | ||||
|             fp.write("\n") | ||||
|  |  | |||
|  | @ -145,7 +145,7 @@ def _toqclass_helper(im): | |||
|         data = im.tobytes("raw", "BGRA") | ||||
|         format = QImage.Format_ARGB32 | ||||
|     else: | ||||
|         raise ValueError("unsupported image mode %r" % im.mode) | ||||
|         raise ValueError(f"unsupported image mode {repr(im.mode)}") | ||||
| 
 | ||||
|     __data = data or align8to32(im.tobytes(), im.size[0], im.mode) | ||||
|     return {"data": __data, "im": im, "format": format, "colortable": colortable} | ||||
|  |  | |||
|  | @ -123,9 +123,9 @@ class WindowsViewer(Viewer): | |||
| 
 | ||||
|     def get_command(self, file, **options): | ||||
|         return ( | ||||
|             'start "Pillow" /WAIT "%s" ' | ||||
|             f'start "Pillow" /WAIT "{file}" ' | ||||
|             "&& ping -n 2 127.0.0.1 >NUL " | ||||
|             '&& del /f "%s"' % (file, file) | ||||
|             f'&& del /f "{file}"' | ||||
|         ) | ||||
| 
 | ||||
| 
 | ||||
|  | @ -143,9 +143,7 @@ class MacViewer(Viewer): | |||
|         # on darwin open returns immediately resulting in the temp | ||||
|         # file removal while app is opening | ||||
|         command = "open -a Preview.app" | ||||
|         command = "({} {}; sleep 20; rm -f {})&".format( | ||||
|             command, quote(file), quote(file) | ||||
|         ) | ||||
|         command = f"({command} {quote(file)}; sleep 20; rm -f {quote(file)})&" | ||||
|         return command | ||||
| 
 | ||||
|     def show_file(self, file, **options): | ||||
|  | @ -153,7 +151,7 @@ class MacViewer(Viewer): | |||
|         fd, path = tempfile.mkstemp() | ||||
|         with os.fdopen(fd, "w") as f: | ||||
|             f.write(file) | ||||
|         with open(path, "r") as f: | ||||
|         with open(path) as f: | ||||
|             subprocess.Popen( | ||||
|                 ["im=$(cat); open -a Preview.app $im; sleep 20; rm -f $im"], | ||||
|                 shell=True, | ||||
|  | @ -173,14 +171,14 @@ class UnixViewer(Viewer): | |||
| 
 | ||||
|     def get_command(self, file, **options): | ||||
|         command = self.get_command_ex(file, **options)[0] | ||||
|         return "({} {}; rm -f {})&".format(command, quote(file), quote(file)) | ||||
|         return f"({command} {quote(file)}; rm -f {quote(file)})&" | ||||
| 
 | ||||
|     def show_file(self, file, **options): | ||||
|         """Display given file""" | ||||
|         fd, path = tempfile.mkstemp() | ||||
|         with os.fdopen(fd, "w") as f: | ||||
|             f.write(file) | ||||
|         with open(path, "r") as f: | ||||
|         with open(path) as f: | ||||
|             command = self.get_command_ex(file, **options)[0] | ||||
|             subprocess.Popen( | ||||
|                 ["im=$(cat);" + command + " $im; rm -f $im"], shell=True, stdin=f | ||||
|  | @ -216,7 +214,7 @@ class XVViewer(UnixViewer): | |||
|         # imagemagick's display command instead. | ||||
|         command = executable = "xv" | ||||
|         if title: | ||||
|             command += " -name %s" % quote(title) | ||||
|             command += f" -name {quote(title)}" | ||||
|         return command, executable | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -41,7 +41,7 @@ def _pilbitmap_check(): | |||
|     if _pilbitmap_ok is None: | ||||
|         try: | ||||
|             im = Image.new("1", (1, 1)) | ||||
|             tkinter.BitmapImage(data="PIL:%d" % im.im.id) | ||||
|             tkinter.BitmapImage(data=f"PIL:{im.im.id}") | ||||
|             _pilbitmap_ok = 1 | ||||
|         except tkinter.TclError: | ||||
|             _pilbitmap_ok = 0 | ||||
|  | @ -229,7 +229,7 @@ class BitmapImage: | |||
|         if _pilbitmap_check(): | ||||
|             # fast way (requires the pilbitmap booster patch) | ||||
|             image.load() | ||||
|             kw["data"] = "PIL:%d" % image.im.id | ||||
|             kw["data"] = f"PIL:{image.im.id}" | ||||
|             self.__im = image  # must keep a reference | ||||
|         else: | ||||
|             # slow but safe way | ||||
|  |  | |||
|  | @ -198,7 +198,7 @@ def SOF(self, marker): | |||
| 
 | ||||
|     self.bits = i8(s[0]) | ||||
|     if self.bits != 8: | ||||
|         raise SyntaxError("cannot handle %d-bit layers" % self.bits) | ||||
|         raise SyntaxError(f"cannot handle {self.bits}-bit layers") | ||||
| 
 | ||||
|     self.layers = i8(s[5]) | ||||
|     if self.layers == 1: | ||||
|  | @ -208,7 +208,7 @@ def SOF(self, marker): | |||
|     elif self.layers == 4: | ||||
|         self.mode = "CMYK" | ||||
|     else: | ||||
|         raise SyntaxError("cannot handle %d-layer images" % self.layers) | ||||
|         raise SyntaxError(f"cannot handle {self.layers}-layer images") | ||||
| 
 | ||||
|     if marker in [0xFFC2, 0xFFC6, 0xFFCA, 0xFFCE]: | ||||
|         self.info["progressive"] = self.info["progression"] = 1 | ||||
|  | @ -521,7 +521,7 @@ def _getmp(self): | |||
|         rawmpentries = mp[0xB002] | ||||
|         for entrynum in range(0, quant): | ||||
|             unpackedentry = struct.unpack_from( | ||||
|                 "{}LLLHH".format(endianness), rawmpentries, entrynum * 16 | ||||
|                 f"{endianness}LLLHH", rawmpentries, entrynum * 16 | ||||
|             ) | ||||
|             labels = ("Attribute", "Size", "DataOffset", "EntryNo1", "EntryNo2") | ||||
|             mpentry = dict(zip(labels, unpackedentry)) | ||||
|  | @ -616,7 +616,7 @@ def _save(im, fp, filename): | |||
|     try: | ||||
|         rawmode = RAWMODE[im.mode] | ||||
|     except KeyError as e: | ||||
|         raise OSError("cannot write mode %s as JPEG" % im.mode) from e | ||||
|         raise OSError(f"cannot write mode {im.mode} as JPEG") from e | ||||
| 
 | ||||
|     info = im.encoderinfo | ||||
| 
 | ||||
|  |  | |||
|  | @ -116,7 +116,7 @@ class MspDecoder(ImageFile.PyDecoder): | |||
|         try: | ||||
|             self.fd.seek(32) | ||||
|             rowmap = struct.unpack_from( | ||||
|                 "<%dH" % (self.state.ysize), self.fd.read(self.state.ysize * 2) | ||||
|                 f"<{self.state.ysize}H", self.fd.read(self.state.ysize * 2) | ||||
|             ) | ||||
|         except struct.error as e: | ||||
|             raise OSError("Truncated MSP file in row map") from e | ||||
|  | @ -145,7 +145,7 @@ class MspDecoder(ImageFile.PyDecoder): | |||
|                         idx += runcount | ||||
| 
 | ||||
|             except struct.error as e: | ||||
|                 raise OSError("Corrupted MSP file in row %d" % x) from e | ||||
|                 raise OSError(f"Corrupted MSP file in row {x}") from e | ||||
| 
 | ||||
|         self.set_as_raw(img.getvalue(), ("1", 0, 1)) | ||||
| 
 | ||||
|  | @ -162,7 +162,7 @@ Image.register_decoder("MSP", MspDecoder) | |||
| def _save(im, fp, filename): | ||||
| 
 | ||||
|     if im.mode != "1": | ||||
|         raise OSError("cannot write mode %s as MSP" % im.mode) | ||||
|         raise OSError(f"cannot write mode {im.mode} as MSP") | ||||
| 
 | ||||
|     # create MSP header | ||||
|     header = [0] * 16 | ||||
|  |  | |||
|  | @ -71,10 +71,10 @@ class PSDraw: | |||
|         """ | ||||
|         if font not in self.isofont: | ||||
|             # reencode font | ||||
|             self._fp_write("/PSDraw-{} ISOLatin1Encoding /{} E\n".format(font, font)) | ||||
|             self._fp_write(f"/PSDraw-{font} ISOLatin1Encoding /{font} E\n") | ||||
|             self.isofont[font] = 1 | ||||
|         # rough | ||||
|         self._fp_write("/F0 %d /PSDraw-%s F\n" % (size, font)) | ||||
|         self._fp_write(f"/F0 {size} /PSDraw-{font} F\n") | ||||
| 
 | ||||
|     def line(self, xy0, xy1): | ||||
|         """ | ||||
|  | @ -82,8 +82,7 @@ class PSDraw: | |||
|         PostScript point coordinates (72 points per inch, (0, 0) is the lower | ||||
|         left corner of the page). | ||||
|         """ | ||||
|         xy = xy0 + xy1 | ||||
|         self._fp_write("%d %d %d %d Vl\n" % xy) | ||||
|         self._fp_write("%d %d %d %d Vl\n" % (*xy0, *xy1)) | ||||
| 
 | ||||
|     def rectangle(self, box): | ||||
|         """ | ||||
|  | @ -107,8 +106,7 @@ class PSDraw: | |||
|         """ | ||||
|         text = "\\(".join(text.split("(")) | ||||
|         text = "\\)".join(text.split(")")) | ||||
|         xy = xy + (text,) | ||||
|         self._fp_write("%d %d M (%s) S\n" % xy) | ||||
|         self._fp_write(f"{xy[0]} {xy[1]} M ({text}) S\n") | ||||
| 
 | ||||
|     def image(self, box, im, dpi=None): | ||||
|         """Draw a PIL image, centered in the given box.""" | ||||
|  | @ -132,12 +130,12 @@ class PSDraw: | |||
|             y = ymax | ||||
|         dx = (xmax - x) / 2 + box[0] | ||||
|         dy = (ymax - y) / 2 + box[1] | ||||
|         self._fp_write("gsave\n{:f} {:f} translate\n".format(dx, dy)) | ||||
|         self._fp_write(f"gsave\n{dx:f} {dy:f} translate\n") | ||||
|         if (x, y) != im.size: | ||||
|             # EpsImagePlugin._save prints the image at (0,0,xsize,ysize) | ||||
|             sx = x / im.size[0] | ||||
|             sy = y / im.size[1] | ||||
|             self._fp_write("{:f} {:f} scale\n".format(sx, sy)) | ||||
|             self._fp_write(f"{sx:f} {sy:f} scale\n") | ||||
|         EpsImagePlugin._save(im, self.fp, None, 0) | ||||
|         self._fp_write("\ngrestore\n") | ||||
| 
 | ||||
|  |  | |||
|  | @ -138,7 +138,7 @@ def _save(im, fp, filename): | |||
|             bpp = im.info["bpp"] | ||||
|             im = im.point(lambda x, maxval=(1 << bpp) - 1: maxval - (x & maxval)) | ||||
|         else: | ||||
|             raise OSError("cannot write mode %s as Palm" % im.mode) | ||||
|             raise OSError(f"cannot write mode {im.mode} as Palm") | ||||
| 
 | ||||
|         # we ignore the palette here | ||||
|         im.mode = "P" | ||||
|  | @ -154,7 +154,7 @@ def _save(im, fp, filename): | |||
| 
 | ||||
|     else: | ||||
| 
 | ||||
|         raise OSError("cannot write mode %s as Palm" % im.mode) | ||||
|         raise OSError(f"cannot write mode {im.mode} as Palm") | ||||
| 
 | ||||
|     # | ||||
|     # make sure image data is available | ||||
|  |  | |||
|  | @ -135,7 +135,7 @@ def _save(im, fp, filename): | |||
|     try: | ||||
|         version, bits, planes, rawmode = SAVE[im.mode] | ||||
|     except KeyError as e: | ||||
|         raise ValueError("Cannot save %s images as PCX" % im.mode) from e | ||||
|         raise ValueError(f"Cannot save {im.mode} images as PCX") from e | ||||
| 
 | ||||
|     # bytes per plane | ||||
|     stride = (im.size[0] * bits + 7) // 8 | ||||
|  |  | |||
|  | @ -77,7 +77,7 @@ def _save(im, fp, filename, save_all=False): | |||
| 
 | ||||
|     existing_pdf.start_writing() | ||||
|     existing_pdf.write_header() | ||||
|     existing_pdf.write_comment("created by Pillow {} PDF driver".format(__version__)) | ||||
|     existing_pdf.write_comment(f"created by Pillow {__version__} PDF driver") | ||||
| 
 | ||||
|     # | ||||
|     # pages | ||||
|  | @ -130,7 +130,7 @@ def _save(im, fp, filename, save_all=False): | |||
|                 bits = 1 | ||||
|             elif im.mode == "L": | ||||
|                 filter = "DCTDecode" | ||||
|                 # params = "<< /Predictor 15 /Columns %d >>" % (width-2) | ||||
|                 # params = f"<< /Predictor 15 /Columns {width-2} >>" | ||||
|                 colorspace = PdfParser.PdfName("DeviceGray") | ||||
|                 procset = "ImageB"  # grayscale | ||||
|             elif im.mode == "P": | ||||
|  | @ -153,7 +153,7 @@ def _save(im, fp, filename, save_all=False): | |||
|                 procset = "ImageC"  # color images | ||||
|                 decode = [1, 0, 1, 0, 1, 0, 1, 0] | ||||
|             else: | ||||
|                 raise ValueError("cannot save mode %s" % im.mode) | ||||
|                 raise ValueError(f"cannot save mode {im.mode}") | ||||
| 
 | ||||
|             # | ||||
|             # image | ||||
|  | @ -175,7 +175,7 @@ def _save(im, fp, filename, save_all=False): | |||
|             elif filter == "RunLengthDecode": | ||||
|                 ImageFile._save(im, op, [("packbits", (0, 0) + im.size, 0, im.mode)]) | ||||
|             else: | ||||
|                 raise ValueError("unsupported PDF filter (%s)" % filter) | ||||
|                 raise ValueError(f"unsupported PDF filter ({filter})") | ||||
| 
 | ||||
|             # | ||||
|             # Get image characteristics | ||||
|  |  | |||
|  | @ -183,8 +183,8 @@ class XrefTable: | |||
|                     this_deleted_object_id = deleted_keys.pop(0) | ||||
|                     check_format_condition( | ||||
|                         object_id == this_deleted_object_id, | ||||
|                         "expected the next deleted object ID to be %s, instead found %s" | ||||
|                         % (object_id, this_deleted_object_id), | ||||
|                         f"expected the next deleted object ID to be {object_id}, " | ||||
|                         f"instead found {this_deleted_object_id}", | ||||
|                     ) | ||||
|                     try: | ||||
|                         next_in_linked_list = deleted_keys[0] | ||||
|  | @ -218,7 +218,7 @@ class PdfName: | |||
|         return hash(self.name) | ||||
| 
 | ||||
|     def __repr__(self): | ||||
|         return "PdfName(%s)" % repr(self.name) | ||||
|         return f"PdfName({repr(self.name)})" | ||||
| 
 | ||||
|     @classmethod | ||||
|     def from_pdf_stream(cls, data): | ||||
|  | @ -315,7 +315,7 @@ class PdfStream: | |||
|             return zlib.decompress(self.buf, bufsize=int(expected_length)) | ||||
|         else: | ||||
|             raise NotImplementedError( | ||||
|                 "stream filter %s unknown/unsupported" % repr(self.dictionary.Filter) | ||||
|                 f"stream filter {repr(self.dictionary.Filter)} unknown/unsupported" | ||||
|             ) | ||||
| 
 | ||||
| 
 | ||||
|  | @ -423,7 +423,7 @@ class PdfParser: | |||
|         self.f.write(b"%PDF-1.4\n") | ||||
| 
 | ||||
|     def write_comment(self, s): | ||||
|         self.f.write(("% {}\n".format(s)).encode("utf-8")) | ||||
|         self.f.write(f"% {s}\n".encode("utf-8")) | ||||
| 
 | ||||
|     def write_catalog(self): | ||||
|         self.del_root() | ||||
|  | @ -966,9 +966,8 @@ class PdfParser: | |||
|         offset, generation = self.xref_table[ref[0]] | ||||
|         check_format_condition( | ||||
|             generation == ref[1], | ||||
|             "expected to find generation %s for object ID %s in xref table, " | ||||
|             "instead found generation %s at offset %s" | ||||
|             % (ref[1], ref[0], generation, offset), | ||||
|             f"expected to find generation {ref[1]} for object ID {ref[0]} in xref " | ||||
|             f"table, instead found generation {generation} at offset {offset}", | ||||
|         ) | ||||
|         value = self.get_value( | ||||
|             self.buf, | ||||
|  |  | |||
|  | @ -164,7 +164,7 @@ class ChunkStream: | |||
| 
 | ||||
|         if not is_cid(cid): | ||||
|             if not ImageFile.LOAD_TRUNCATED_IMAGES: | ||||
|                 raise SyntaxError("broken PNG file (chunk %s)" % repr(cid)) | ||||
|                 raise SyntaxError(f"broken PNG file (chunk {repr(cid)})") | ||||
| 
 | ||||
|         return cid, pos, length | ||||
| 
 | ||||
|  | @ -201,10 +201,12 @@ class ChunkStream: | |||
|             crc1 = _crc32(data, _crc32(cid)) | ||||
|             crc2 = i32(self.fp.read(4)) | ||||
|             if crc1 != crc2: | ||||
|                 raise SyntaxError("broken PNG file (bad header checksum in %r)" % cid) | ||||
|                 raise SyntaxError( | ||||
|                     f"broken PNG file (bad header checksum in {repr(cid)})" | ||||
|                 ) | ||||
|         except struct.error as e: | ||||
|             raise SyntaxError( | ||||
|                 "broken PNG file (incomplete checksum in %r)" % cid | ||||
|                 f"broken PNG file (incomplete checksum in {repr(cid)})" | ||||
|             ) from e | ||||
| 
 | ||||
|     def crc_skip(self, cid, data): | ||||
|  | @ -356,8 +358,8 @@ class PngStream(ChunkStream): | |||
|         self.text_memory += chunklen | ||||
|         if self.text_memory > MAX_TEXT_MEMORY: | ||||
|             raise ValueError( | ||||
|                 "Too much memory used in text chunks: %s>MAX_TEXT_MEMORY" | ||||
|                 % self.text_memory | ||||
|                 "Too much memory used in text chunks: " | ||||
|                 f"{self.text_memory}>MAX_TEXT_MEMORY" | ||||
|             ) | ||||
| 
 | ||||
|     def save_rewind(self): | ||||
|  | @ -386,9 +388,7 @@ class PngStream(ChunkStream): | |||
|         logger.debug("Compression method %s", i8(s[i])) | ||||
|         comp_method = i8(s[i]) | ||||
|         if comp_method != 0: | ||||
|             raise SyntaxError( | ||||
|                 "Unknown compression method %s in iCCP chunk" % comp_method | ||||
|             ) | ||||
|             raise SyntaxError(f"Unknown compression method {comp_method} in iCCP chunk") | ||||
|         try: | ||||
|             icc_profile = _safe_zlib_decompress(s[i + 2 :]) | ||||
|         except ValueError: | ||||
|  | @ -536,9 +536,7 @@ class PngStream(ChunkStream): | |||
|         else: | ||||
|             comp_method = 0 | ||||
|         if comp_method != 0: | ||||
|             raise SyntaxError( | ||||
|                 "Unknown compression method %s in zTXt chunk" % comp_method | ||||
|             ) | ||||
|             raise SyntaxError(f"Unknown compression method {comp_method} in zTXt chunk") | ||||
|         try: | ||||
|             v = _safe_zlib_decompress(v[1:]) | ||||
|         except ValueError: | ||||
|  | @ -800,7 +798,7 @@ class PngImageFile(ImageFile.ImageFile): | |||
|             return | ||||
|         else: | ||||
|             if frame != self.__frame + 1: | ||||
|                 raise ValueError("cannot seek to frame %d" % frame) | ||||
|                 raise ValueError(f"cannot seek to frame {frame}") | ||||
| 
 | ||||
|         # ensure previous frame was loaded | ||||
|         self.load() | ||||
|  | @ -1197,7 +1195,7 @@ def _save(im, fp, filename, chunk=putchunk, save_all=False): | |||
|         else: | ||||
|             bits = 8 | ||||
|         if bits != 8: | ||||
|             mode = "%s;%d" % (mode, bits) | ||||
|             mode = f"{mode};{bits}" | ||||
| 
 | ||||
|     # encoder options | ||||
|     im.encoderconfig = ( | ||||
|  | @ -1211,7 +1209,7 @@ def _save(im, fp, filename, chunk=putchunk, save_all=False): | |||
|     try: | ||||
|         rawmode, mode = _OUTMODES[mode] | ||||
|     except KeyError as e: | ||||
|         raise OSError("cannot write mode %s as PNG" % mode) from e | ||||
|         raise OSError(f"cannot write mode {mode} as PNG") from e | ||||
| 
 | ||||
|     # | ||||
|     # write minimal PNG file | ||||
|  |  | |||
|  | @ -104,7 +104,7 @@ class PpmImageFile(ImageFile.ImageFile): | |||
|                 # maxgrey | ||||
|                 if s > 255: | ||||
|                     if not mode == "L": | ||||
|                         raise ValueError("Too many colors for band: %s" % s) | ||||
|                         raise ValueError(f"Too many colors for band: {s}") | ||||
|                     if s < 2 ** 16: | ||||
|                         self.mode = "I" | ||||
|                         rawmode = "I;16B" | ||||
|  | @ -135,7 +135,7 @@ def _save(im, fp, filename): | |||
|     elif im.mode == "RGBA": | ||||
|         rawmode, head = "RGB", b"P6" | ||||
|     else: | ||||
|         raise OSError("cannot write mode %s as PPM" % im.mode) | ||||
|         raise OSError(f"cannot write mode {im.mode} as PPM") | ||||
|     fp.write(head + ("\n%d %d\n" % im.size).encode("ascii")) | ||||
|     if head == b"P6": | ||||
|         fp.write(b"255\n") | ||||
|  |  | |||
|  | @ -160,9 +160,7 @@ def _save(im, fp, filename): | |||
|     # assert we've got the right number of bands. | ||||
|     if len(im.getbands()) != z: | ||||
|         raise ValueError( | ||||
|             "incorrect number of bands in SGI write: {} vs {}".format( | ||||
|                 z, len(im.getbands()) | ||||
|             ) | ||||
|             f"incorrect number of bands in SGI write: {z} vs {len(im.getbands())}" | ||||
|         ) | ||||
| 
 | ||||
|     # Minimum Byte value | ||||
|  |  | |||
|  | @ -213,7 +213,7 @@ def loadImageSeries(filelist=None): | |||
|     imglist = [] | ||||
|     for img in filelist: | ||||
|         if not os.path.exists(img): | ||||
|             print("unable to find %s" % img) | ||||
|             print(f"unable to find {img}") | ||||
|             continue | ||||
|         try: | ||||
|             with Image.open(img) as im: | ||||
|  | @ -318,7 +318,7 @@ if __name__ == "__main__": | |||
|             # perform some image operation | ||||
|             im = im.transpose(Image.FLIP_LEFT_RIGHT) | ||||
|             print( | ||||
|                 "saving a flipped version of %s as %s " | ||||
|                 % (os.path.basename(filename), outfile) | ||||
|                 f"saving a flipped version of {os.path.basename(filename)} " | ||||
|                 f"as {outfile} " | ||||
|             ) | ||||
|             im.save(outfile, SpiderImageFile.format) | ||||
|  |  | |||
|  | @ -171,7 +171,7 @@ def _save(im, fp, filename): | |||
|     try: | ||||
|         rawmode, bits, colormaptype, imagetype = SAVE[im.mode] | ||||
|     except KeyError as e: | ||||
|         raise OSError("cannot write mode %s as TGA" % im.mode) from e | ||||
|         raise OSError(f"cannot write mode {im.mode} as TGA") from e | ||||
| 
 | ||||
|     if "rle" in im.encoderinfo: | ||||
|         rle = im.encoderinfo["rle"] | ||||
|  |  | |||
|  | @ -466,7 +466,7 @@ class ImageFileDirectory_v2(MutableMapping): | |||
|         :param prefix: Override the endianness of the file. | ||||
|         """ | ||||
|         if ifh[:4] not in PREFIXES: | ||||
|             raise SyntaxError("not a TIFF file (header %r not valid)" % ifh) | ||||
|             raise SyntaxError(f"not a TIFF file (header {repr(ifh)} not valid)") | ||||
|         self._prefix = prefix if prefix is not None else ifh[:2] | ||||
|         if self._prefix == MM: | ||||
|             self._endian = ">" | ||||
|  | @ -596,8 +596,8 @@ class ImageFileDirectory_v2(MutableMapping): | |||
|             except ValueError: | ||||
|                 # We've got a builtin tag with 1 expected entry | ||||
|                 warnings.warn( | ||||
|                     "Metadata Warning, tag %s had too many entries: %s, expected 1" | ||||
|                     % (tag, len(values)) | ||||
|                     f"Metadata Warning, tag {tag} had too many entries: " | ||||
|                     f"{len(values)}, expected 1" | ||||
|                 ) | ||||
|                 dest[tag] = values[0] | ||||
| 
 | ||||
|  | @ -732,7 +732,7 @@ class ImageFileDirectory_v2(MutableMapping): | |||
|         if len(ret) != size: | ||||
|             raise OSError( | ||||
|                 "Corrupt EXIF data.  " | ||||
|                 + "Expecting to read %d bytes but only got %d. " % (size, len(ret)) | ||||
|                 f"Expecting to read {size} bytes but only got {len(ret)}. " | ||||
|             ) | ||||
|         return ret | ||||
| 
 | ||||
|  | @ -747,18 +747,18 @@ class ImageFileDirectory_v2(MutableMapping): | |||
| 
 | ||||
|                 tagname = TiffTags.lookup(tag).name | ||||
|                 typname = TYPES.get(typ, "unknown") | ||||
|                 msg = "tag: %s (%d) - type: %s (%d)" % (tagname, tag, typname, typ) | ||||
|                 msg = f"tag: {tagname} ({tag}) - type: {typname} ({typ})" | ||||
| 
 | ||||
|                 try: | ||||
|                     unit_size, handler = self._load_dispatch[typ] | ||||
|                 except KeyError: | ||||
|                     logger.debug(msg + " - unsupported type {}".format(typ)) | ||||
|                     logger.debug(msg + f" - unsupported type {typ}") | ||||
|                     continue  # ignore unsupported type | ||||
|                 size = count * unit_size | ||||
|                 if size > 4: | ||||
|                     here = fp.tell() | ||||
|                     (offset,) = self._unpack("L", data) | ||||
|                     msg += " Tag Location: {} - Data Location: {}".format(here, offset) | ||||
|                     msg += f" Tag Location: {here} - Data Location: {offset}" | ||||
|                     fp.seek(offset) | ||||
|                     data = ImageFile._safe_read(fp, size) | ||||
|                     fp.seek(here) | ||||
|  | @ -768,8 +768,8 @@ class ImageFileDirectory_v2(MutableMapping): | |||
|                 if len(data) != size: | ||||
|                     warnings.warn( | ||||
|                         "Possibly corrupt EXIF data.  " | ||||
|                         "Expecting to read %d bytes but only got %d." | ||||
|                         " Skipping tag %s" % (size, len(data), tag) | ||||
|                         f"Expecting to read {size} bytes but only got {len(data)}." | ||||
|                         f" Skipping tag {tag}" | ||||
|                     ) | ||||
|                     logger.debug(msg) | ||||
|                     continue | ||||
|  | @ -805,7 +805,7 @@ class ImageFileDirectory_v2(MutableMapping): | |||
|             if tag == STRIPOFFSETS: | ||||
|                 stripoffsets = len(entries) | ||||
|             typ = self.tagtype.get(tag) | ||||
|             logger.debug("Tag {}, Type: {}, Value: {}".format(tag, typ, value)) | ||||
|             logger.debug(f"Tag {tag}, Type: {typ}, Value: {value}") | ||||
|             is_ifd = typ == TiffTags.LONG and isinstance(value, dict) | ||||
|             if is_ifd: | ||||
|                 if self._endian == "<": | ||||
|  | @ -822,7 +822,7 @@ class ImageFileDirectory_v2(MutableMapping): | |||
| 
 | ||||
|             tagname = TiffTags.lookup(tag).name | ||||
|             typname = "ifd" if is_ifd else TYPES.get(typ, "unknown") | ||||
|             msg = "save: %s (%d) - type: %s (%d)" % (tagname, tag, typname, typ) | ||||
|             msg = f"save: {tagname} ({tag}) - type: {typname} ({typ})" | ||||
|             msg += " - value: " + ( | ||||
|                 "<table: %d bytes>" % len(data) if len(data) >= 16 else str(values) | ||||
|             ) | ||||
|  | @ -852,9 +852,7 @@ class ImageFileDirectory_v2(MutableMapping): | |||
| 
 | ||||
|         # pass 2: write entries to file | ||||
|         for tag, typ, count, value, data in entries: | ||||
|             logger.debug( | ||||
|                 "{} {} {} {} {}".format(tag, typ, count, repr(value), repr(data)) | ||||
|             ) | ||||
|             logger.debug(f"{tag} {typ} {count} {repr(value)} {repr(data)}") | ||||
|             result += self._pack("HHL4s", tag, typ, count, value) | ||||
| 
 | ||||
|         # -- overwrite here for multi-page -- | ||||
|  | @ -1023,8 +1021,8 @@ class TiffImageFile(ImageFile.ImageFile): | |||
|         self._n_frames = None | ||||
| 
 | ||||
|         logger.debug("*** TiffImageFile._open ***") | ||||
|         logger.debug("- __first: {}".format(self.__first)) | ||||
|         logger.debug("- ifh: {!r}".format(ifh))  # Use !r to avoid str(bytes) | ||||
|         logger.debug(f"- __first: {self.__first}") | ||||
|         logger.debug(f"- ifh: {repr(ifh)}")  # Use repr to avoid str(bytes) | ||||
| 
 | ||||
|         # and load the first frame | ||||
|         self._seek(0) | ||||
|  | @ -1056,8 +1054,8 @@ class TiffImageFile(ImageFile.ImageFile): | |||
|             if not self.__next: | ||||
|                 raise EOFError("no more images in TIFF file") | ||||
|             logger.debug( | ||||
|                 "Seeking to frame %s, on frame %s, __next %s, location: %s" | ||||
|                 % (frame, self.__frame, self.__next, self.fp.tell()) | ||||
|                 f"Seeking to frame {frame}, on frame {self.__frame}, " | ||||
|                 f"__next {self.__next}, location: {self.fp.tell()}" | ||||
|             ) | ||||
|             # reset buffered io handle in case fp | ||||
|             # was passed to libtiff, invalidating the buffer | ||||
|  | @ -1214,18 +1212,18 @@ class TiffImageFile(ImageFile.ImageFile): | |||
|         fillorder = self.tag_v2.get(FILLORDER, 1) | ||||
| 
 | ||||
|         logger.debug("*** Summary ***") | ||||
|         logger.debug("- compression: {}".format(self._compression)) | ||||
|         logger.debug("- photometric_interpretation: {}".format(photo)) | ||||
|         logger.debug("- planar_configuration: {}".format(self._planar_configuration)) | ||||
|         logger.debug("- fill_order: {}".format(fillorder)) | ||||
|         logger.debug("- YCbCr subsampling: {}".format(self.tag.get(530))) | ||||
|         logger.debug(f"- compression: {self._compression}") | ||||
|         logger.debug(f"- photometric_interpretation: {photo}") | ||||
|         logger.debug(f"- planar_configuration: {self._planar_configuration}") | ||||
|         logger.debug(f"- fill_order: {fillorder}") | ||||
|         logger.debug(f"- YCbCr subsampling: {self.tag.get(530)}") | ||||
| 
 | ||||
|         # size | ||||
|         xsize = int(self.tag_v2.get(IMAGEWIDTH)) | ||||
|         ysize = int(self.tag_v2.get(IMAGELENGTH)) | ||||
|         self._size = xsize, ysize | ||||
| 
 | ||||
|         logger.debug("- size: {}".format(self.size)) | ||||
|         logger.debug(f"- size: {self.size}") | ||||
| 
 | ||||
|         sampleFormat = self.tag_v2.get(SAMPLEFORMAT, (1,)) | ||||
|         if len(sampleFormat) > 1 and max(sampleFormat) == min(sampleFormat) == 1: | ||||
|  | @ -1259,15 +1257,15 @@ class TiffImageFile(ImageFile.ImageFile): | |||
|             bps_tuple, | ||||
|             extra_tuple, | ||||
|         ) | ||||
|         logger.debug("format key: {}".format(key)) | ||||
|         logger.debug(f"format key: {key}") | ||||
|         try: | ||||
|             self.mode, rawmode = OPEN_INFO[key] | ||||
|         except KeyError as e: | ||||
|             logger.debug("- unsupported format") | ||||
|             raise SyntaxError("unknown pixel mode") from e | ||||
| 
 | ||||
|         logger.debug("- raw mode: {}".format(rawmode)) | ||||
|         logger.debug("- pil mode: {}".format(self.mode)) | ||||
|         logger.debug(f"- raw mode: {rawmode}") | ||||
|         logger.debug(f"- pil mode: {self.mode}") | ||||
| 
 | ||||
|         self.info["compression"] = self._compression | ||||
| 
 | ||||
|  | @ -1308,7 +1306,7 @@ class TiffImageFile(ImageFile.ImageFile): | |||
|             if fillorder == 2: | ||||
|                 # Replace fillorder with fillorder=1 | ||||
|                 key = key[:3] + (1,) + key[4:] | ||||
|                 logger.debug("format key: {}".format(key)) | ||||
|                 logger.debug(f"format key: {key}") | ||||
|                 # this should always work, since all the | ||||
|                 # fillorder==2 modes have a corresponding | ||||
|                 # fillorder=1 mode | ||||
|  | @ -1432,7 +1430,7 @@ def _save(im, fp, filename): | |||
|     try: | ||||
|         rawmode, prefix, photo, format, bits, extra = SAVE_INFO[im.mode] | ||||
|     except KeyError as e: | ||||
|         raise OSError("cannot write mode %s as TIFF" % im.mode) from e | ||||
|         raise OSError(f"cannot write mode {im.mode} as TIFF") from e | ||||
| 
 | ||||
|     ifd = ImageFileDirectory_v2(prefix=prefix) | ||||
| 
 | ||||
|  | @ -1629,7 +1627,7 @@ def _save(im, fp, filename): | |||
|             if s: | ||||
|                 break | ||||
|         if s < 0: | ||||
|             raise OSError("encoder error %d when writing image file" % s) | ||||
|             raise OSError(f"encoder error {s} when writing image file") | ||||
| 
 | ||||
|     else: | ||||
|         offset = ifd.save(fp) | ||||
|  | @ -1795,29 +1793,29 @@ class AppendingTiffWriter: | |||
|         self.f.seek(-2, os.SEEK_CUR) | ||||
|         bytesWritten = self.f.write(struct.pack(self.longFmt, value)) | ||||
|         if bytesWritten is not None and bytesWritten != 4: | ||||
|             raise RuntimeError("wrote only %u bytes but wanted 4" % bytesWritten) | ||||
|             raise RuntimeError(f"wrote only {bytesWritten} bytes but wanted 4") | ||||
| 
 | ||||
|     def rewriteLastShort(self, value): | ||||
|         self.f.seek(-2, os.SEEK_CUR) | ||||
|         bytesWritten = self.f.write(struct.pack(self.shortFmt, value)) | ||||
|         if bytesWritten is not None and bytesWritten != 2: | ||||
|             raise RuntimeError("wrote only %u bytes but wanted 2" % bytesWritten) | ||||
|             raise RuntimeError(f"wrote only {bytesWritten} bytes but wanted 2") | ||||
| 
 | ||||
|     def rewriteLastLong(self, value): | ||||
|         self.f.seek(-4, os.SEEK_CUR) | ||||
|         bytesWritten = self.f.write(struct.pack(self.longFmt, value)) | ||||
|         if bytesWritten is not None and bytesWritten != 4: | ||||
|             raise RuntimeError("wrote only %u bytes but wanted 4" % bytesWritten) | ||||
|             raise RuntimeError(f"wrote only {bytesWritten} bytes but wanted 4") | ||||
| 
 | ||||
|     def writeShort(self, value): | ||||
|         bytesWritten = self.f.write(struct.pack(self.shortFmt, value)) | ||||
|         if bytesWritten is not None and bytesWritten != 2: | ||||
|             raise RuntimeError("wrote only %u bytes but wanted 2" % bytesWritten) | ||||
|             raise RuntimeError(f"wrote only {bytesWritten} bytes but wanted 2") | ||||
| 
 | ||||
|     def writeLong(self, value): | ||||
|         bytesWritten = self.f.write(struct.pack(self.longFmt, value)) | ||||
|         if bytesWritten is not None and bytesWritten != 4: | ||||
|             raise RuntimeError("wrote only %u bytes but wanted 4" % bytesWritten) | ||||
|             raise RuntimeError(f"wrote only {bytesWritten} bytes but wanted 4") | ||||
| 
 | ||||
|     def close(self): | ||||
|         self.finalize() | ||||
|  |  | |||
|  | @ -69,15 +69,15 @@ class XbmImageFile(ImageFile.ImageFile): | |||
| def _save(im, fp, filename): | ||||
| 
 | ||||
|     if im.mode != "1": | ||||
|         raise OSError("cannot write mode %s as XBM" % im.mode) | ||||
|         raise OSError(f"cannot write mode {im.mode} as XBM") | ||||
| 
 | ||||
|     fp.write(("#define im_width %d\n" % im.size[0]).encode("ascii")) | ||||
|     fp.write(("#define im_height %d\n" % im.size[1]).encode("ascii")) | ||||
|     fp.write(f"#define im_width {im.size[0]}\n".encode("ascii")) | ||||
|     fp.write(f"#define im_height {im.size[1]}\n".encode("ascii")) | ||||
| 
 | ||||
|     hotspot = im.encoderinfo.get("hotspot") | ||||
|     if hotspot: | ||||
|         fp.write(("#define im_x_hot %d\n" % hotspot[0]).encode("ascii")) | ||||
|         fp.write(("#define im_y_hot %d\n" % hotspot[1]).encode("ascii")) | ||||
|         fp.write(f"#define im_x_hot {hotspot[0]}\n".encode("ascii")) | ||||
|         fp.write(f"#define im_y_hot {hotspot[1]}\n".encode("ascii")) | ||||
| 
 | ||||
|     fp.write(b"static char im_bits[] = {\n") | ||||
| 
 | ||||
|  |  | |||
|  | @ -39,7 +39,7 @@ if sys.version_info >= (3, 7): | |||
|         if name == "PILLOW_VERSION": | ||||
|             _raise_version_warning() | ||||
|             return __version__ | ||||
|         raise AttributeError("module '{}' has no attribute '{}'".format(__name__, name)) | ||||
|         raise AttributeError(f"module '{__name__}' has no attribute '{name}'") | ||||
| 
 | ||||
| 
 | ||||
| else: | ||||
|  |  | |||
|  | @ -1,20 +1,9 @@ | |||
| import os | ||||
| import sys | ||||
| 
 | ||||
| py36 = sys.version_info[0:2] >= (3, 6) | ||||
| from pathlib import Path | ||||
| 
 | ||||
| 
 | ||||
| if py36: | ||||
|     from pathlib import Path | ||||
| 
 | ||||
|     def isPath(f): | ||||
|         return isinstance(f, (bytes, str, Path)) | ||||
| 
 | ||||
| 
 | ||||
| else: | ||||
| 
 | ||||
|     def isPath(f): | ||||
|         return isinstance(f, (bytes, str)) | ||||
| def isPath(f): | ||||
|     return isinstance(f, (bytes, str, Path)) | ||||
| 
 | ||||
| 
 | ||||
| # Checks if an object is a string, and that it points to a directory. | ||||
|  |  | |||
|  | @ -25,7 +25,7 @@ def check_module(feature): | |||
|     :raises ValueError: If the module is not defined in this version of Pillow. | ||||
|     """ | ||||
|     if not (feature in modules): | ||||
|         raise ValueError("Unknown module %s" % feature) | ||||
|         raise ValueError(f"Unknown module {feature}") | ||||
| 
 | ||||
|     module, ver = modules[feature] | ||||
| 
 | ||||
|  | @ -78,7 +78,7 @@ def check_codec(feature): | |||
|     :raises ValueError: If the codec is not defined in this version of Pillow. | ||||
|     """ | ||||
|     if feature not in codecs: | ||||
|         raise ValueError("Unknown codec %s" % feature) | ||||
|         raise ValueError(f"Unknown codec {feature}") | ||||
| 
 | ||||
|     codec, lib = codecs[feature] | ||||
| 
 | ||||
|  | @ -133,7 +133,7 @@ def check_feature(feature): | |||
|     :raises ValueError: If the feature is not defined in this version of Pillow. | ||||
|     """ | ||||
|     if feature not in features: | ||||
|         raise ValueError("Unknown feature %s" % feature) | ||||
|         raise ValueError(f"Unknown feature {feature}") | ||||
| 
 | ||||
|     module, flag, ver = features[feature] | ||||
| 
 | ||||
|  | @ -182,7 +182,7 @@ def check(feature): | |||
|         return check_codec(feature) | ||||
|     if feature in features: | ||||
|         return check_feature(feature) | ||||
|     warnings.warn("Unknown feature '%s'." % feature, stacklevel=2) | ||||
|     warnings.warn(f"Unknown feature '{feature}'.", stacklevel=2) | ||||
|     return False | ||||
| 
 | ||||
| 
 | ||||
|  | @ -230,18 +230,18 @@ def pilinfo(out=None, supported_formats=True): | |||
|     Image.init() | ||||
| 
 | ||||
|     print("-" * 68, file=out) | ||||
|     print("Pillow {}".format(PIL.__version__), file=out) | ||||
|     print(f"Pillow {PIL.__version__}", file=out) | ||||
|     py_version = sys.version.splitlines() | ||||
|     print("Python {}".format(py_version[0].strip()), file=out) | ||||
|     print(f"Python {py_version[0].strip()}", file=out) | ||||
|     for py_version in py_version[1:]: | ||||
|         print("       {}".format(py_version.strip()), file=out) | ||||
|         print(f"       {py_version.strip()}", file=out) | ||||
|     print("-" * 68, file=out) | ||||
|     print( | ||||
|         "Python modules loaded from {}".format(os.path.dirname(Image.__file__)), | ||||
|         f"Python modules loaded from {os.path.dirname(Image.__file__)}", | ||||
|         file=out, | ||||
|     ) | ||||
|     print( | ||||
|         "Binary modules loaded from {}".format(os.path.dirname(Image.core.__file__)), | ||||
|         f"Binary modules loaded from {os.path.dirname(Image.core.__file__)}", | ||||
|         file=out, | ||||
|     ) | ||||
|     print("-" * 68, file=out) | ||||
|  | @ -283,9 +283,9 @@ def pilinfo(out=None, supported_formats=True): | |||
|             extensions[i].append(ext) | ||||
| 
 | ||||
|         for i in sorted(Image.ID): | ||||
|             line = "{}".format(i) | ||||
|             line = f"{i}" | ||||
|             if i in Image.MIME: | ||||
|                 line = "{} {}".format(line, Image.MIME[i]) | ||||
|                 line = f"{line} {Image.MIME[i]}" | ||||
|             print(line, file=out) | ||||
| 
 | ||||
|             if i in extensions: | ||||
|  |  | |||
|  | @ -417,7 +417,7 @@ def build_dep(name): | |||
| 
 | ||||
|     for patch_file, patch_list in dep.get("patch", {}).items(): | ||||
|         patch_file = os.path.join(sources_dir, dir, patch_file.format(**prefs)) | ||||
|         with open(patch_file, "r") as f: | ||||
|         with open(patch_file) as f: | ||||
|             text = f.read() | ||||
|         for patch_from, patch_to in patch_list.items(): | ||||
|             patch_from = patch_from.format(**prefs) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user