Upgrade Python syntax for 3.6+

Co-authored-by: nulano <nulano@nulano.eu>
This commit is contained in:
Hugo van Kemenade 2020-07-16 12:43:29 +03:00
parent e42aec8c90
commit 10615a7da7
69 changed files with 323 additions and 363 deletions

View File

@ -28,15 +28,17 @@ def timer(func, label, *args):
func(*args) func(*args)
if time.time() - starttime > 10: if time.time() - starttime > 10:
print( print(
"%s: breaking at %s iterations, %.6f per iteration" "{}: breaking at {} iterations, {:.6f} per iteration".format(
% (label, x + 1, (time.time() - starttime) / (x + 1.0)) label, x + 1, (time.time() - starttime) / (x + 1.0)
)
) )
break break
if x == iterations - 1: if x == iterations - 1:
endtime = time.time() endtime = time.time()
print( print(
"%s: %.4f s %.6f per iteration" "{}: {:.4f} s {:.6f} per iteration".format(
% (label, endtime - starttime, (endtime - starttime) / (x + 1.0)) label, endtime - starttime, (endtime - starttime) / (x + 1.0)
)
) )

View File

@ -25,7 +25,7 @@ def _test_leak(min_iterations, max_iterations, fn, *args, **kwargs):
if i < min_iterations: if i < min_iterations:
mem_limit = mem + 1 mem_limit = mem + 1
continue 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 assert mem <= mem_limit, msg

View File

@ -42,8 +42,8 @@ def test_dos_total_memory():
info = PngImagePlugin.PngInfo() info = PngImagePlugin.PngInfo()
for x in range(64): for x in range(64):
info.add_text("t%s" % x, compressed_data, zip=True) info.add_text(f"t{x}", compressed_data, zip=True)
info.add_itxt("i%s" % x, compressed_data, zip=True) info.add_itxt(f"i{x}", compressed_data, zip=True)
b = BytesIO() b = BytesIO()
im.save(b, "PNG", pnginfo=info) im.save(b, "PNG", pnginfo=info)

View File

@ -9,4 +9,4 @@ def pytest_report_header(config):
features.pilinfo(out=out, supported_formats=False) features.pilinfo(out=out, supported_formats=False)
return out.getvalue() return out.getvalue()
except Exception as e: except Exception as e:
return "pytest_report_header failed: %s" % e return f"pytest_report_header failed: {e}"

View File

@ -6,7 +6,7 @@ if __name__ == "__main__":
# create font data chunk for embedding # create font data chunk for embedding
font = "Tests/images/courB08" font = "Tests/images/courB08"
print(" f._load_pilfont_data(") print(" f._load_pilfont_data(")
print(" # %s" % os.path.basename(font)) print(f" # {os.path.basename(font)}")
print(" BytesIO(base64.decodestring(b'''") print(" BytesIO(base64.decodestring(b'''")
with open(font + ".pil", "rb") as fp: with open(font + ".pil", "rb") as fp:
print(base64.b64encode(fp.read()).decode()) print(base64.b64encode(fp.read()).decode())

View File

@ -67,37 +67,31 @@ def convert_to_comparable(a, b):
def assert_deep_equal(a, b, msg=None): def assert_deep_equal(a, b, msg=None):
try: try:
assert len(a) == len(b), msg or "got length {}, expected {}".format( assert len(a) == len(b), msg or f"got length {len(a)}, expected {len(b)}"
len(a), len(b)
)
except Exception: except Exception:
assert a == b, msg assert a == b, msg
def assert_image(im, mode, size, msg=None): def assert_image(im, mode, size, msg=None):
if mode is not None: if mode is not None:
assert im.mode == mode, msg or "got mode {!r}, expected {!r}".format( assert im.mode == mode, (
im.mode, mode msg or f"got mode {repr(im.mode)}, expected {repr(mode)}"
) )
if size is not None: if size is not None:
assert im.size == size, msg or "got size {!r}, expected {!r}".format( assert im.size == size, (
im.size, size msg or f"got size {repr(im.size)}, expected {repr(size)}"
) )
def assert_image_equal(a, b, msg=None): def assert_image_equal(a, b, msg=None):
assert a.mode == b.mode, msg or "got mode {!r}, expected {!r}".format( assert a.mode == b.mode, msg or f"got mode {repr(a.mode)}, expected {repr(b.mode)}"
a.mode, b.mode assert a.size == b.size, msg or f"got size {repr(a.size)}, expected {repr(b.size)}"
)
assert a.size == b.size, msg or "got size {!r}, expected {!r}".format(
a.size, b.size
)
if a.tobytes() != b.tobytes(): if a.tobytes() != b.tobytes():
if HAS_UPLOADER: if HAS_UPLOADER:
try: try:
url = test_image_results.upload(a, b) 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: except Exception:
pass pass
@ -112,12 +106,8 @@ def assert_image_equal_tofile(a, filename, msg=None, mode=None):
def assert_image_similar(a, b, epsilon, msg=None): def assert_image_similar(a, b, epsilon, msg=None):
assert a.mode == b.mode, msg or "got mode {!r}, expected {!r}".format( assert a.mode == b.mode, msg or f"got mode {repr(a.mode)}, expected {repr(b.mode)}"
a.mode, b.mode assert a.size == b.size, msg or f"got size {repr(a.size)}, expected {repr(b.size)}"
)
assert a.size == b.size, msg or "got size {!r}, expected {!r}".format(
a.size, b.size
)
a, b = convert_to_comparable(a, b) a, b = convert_to_comparable(a, b)
@ -129,13 +119,14 @@ def assert_image_similar(a, b, epsilon, msg=None):
ave_diff = diff / (a.size[0] * a.size[1]) ave_diff = diff / (a.size[0] * a.size[1])
try: try:
assert epsilon >= ave_diff, ( assert epsilon >= ave_diff, (
msg or "" (msg or "")
) + " average pixel value difference %.4f > epsilon %.4f" % (ave_diff, epsilon) + f" average pixel value difference {ave_diff:.4f} > epsilon {epsilon:.4f}"
)
except Exception as e: except Exception as e:
if HAS_UPLOADER: if HAS_UPLOADER:
try: try:
url = test_image_results.upload(a, b) 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: except Exception:
pass pass
raise e raise e
@ -166,7 +157,7 @@ def assert_tuple_approx_equal(actuals, targets, threshold, msg):
def skip_unless_feature(feature): 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) return pytest.mark.skipif(not features.check(feature), reason=reason)
@ -204,7 +195,7 @@ class PillowLeakTestCase:
for cycle in range(self.iterations): for cycle in range(self.iterations):
core() core()
mem = self._get_mem_usage() - start_mem 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 assert mem < self.mem_limit, msg

View File

@ -49,7 +49,7 @@ def test_questionable():
with Image.open(f) as im: with Image.open(f) as im:
im.load() im.load()
if os.path.basename(f) not in supported: 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: except Exception: # as msg:
if os.path.basename(f) in supported: if os.path.basename(f) in supported:
raise raise
@ -84,7 +84,7 @@ def test_good():
if name in file_map: if name in file_map:
return os.path.join(base, "html", file_map[name]) return os.path.join(base, "html", file_map[name])
name = os.path.splitext(name)[0] 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"): for f in get_files("g"):
try: try:
@ -107,4 +107,4 @@ def test_good():
os.path.join(base, "g", "pal8rle.bmp"), os.path.join(base, "g", "pal8rle.bmp"),
os.path.join(base, "g", "pal4rle.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}"

View File

@ -311,7 +311,7 @@ def test_apng_sequence_errors():
] ]
for f in test_files: for f in test_files:
with pytest.raises(SyntaxError): 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.seek(im.n_frames - 1)
im.load() im.load()

View File

@ -173,18 +173,18 @@ class TestFileLibTiff(LibTiffTestCase):
assert ( assert (
c_float(val[0][0] / val[0][1]).value c_float(val[0][0] / val[0][1]).value
== c_float(value[0][0] / value[0][1]).value == c_float(value[0][0] / value[0][1]).value
), ("%s didn't roundtrip" % tag) ), f"{tag} didn't roundtrip"
else: else:
assert c_float(val).value == c_float(value).value, ( assert (
"%s didn't roundtrip" % tag c_float(val).value == c_float(value).value
) ), f"{tag} didn't roundtrip"
else: 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 # https://github.com/python-pillow/Pillow/issues/1561
requested_fields = ["StripByteCounts", "RowsPerStrip", "StripOffsets"] requested_fields = ["StripByteCounts", "RowsPerStrip", "StripOffsets"]
for field in requested_fields: 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): def test_additional_metadata(self, tmp_path):
# these should not crash. Seriously dummy data, most of it doesn't make # these should not crash. Seriously dummy data, most of it doesn't make

View File

@ -45,7 +45,7 @@ def test_others():
with Image.open(path) as im: with Image.open(path) as im:
im.load() im.load()
assert isinstance(im, SunImagePlugin.SunImageFile) 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) # im.save(target_file)
with Image.open(target_path) as target: with Image.open(target_path) as target:
assert_image_equal(im, target) assert_image_equal(im, target)

View File

@ -35,9 +35,7 @@ def test_sanity(tmp_path):
assert_image_equal(saved_im, original_im) assert_image_equal(saved_im, original_im)
png_paths = glob( png_paths = glob(os.path.join(_TGA_DIR_COMMON, f"*x*_{mode.lower()}.png"))
os.path.join(_TGA_DIR_COMMON, "*x*_{}.png".format(mode.lower()))
)
for png_path in png_paths: for png_path in png_paths:
with Image.open(png_path) as reference_im: with Image.open(png_path) as reference_im:

View File

@ -144,16 +144,16 @@ def test_write_metadata(tmp_path):
assert_deep_equal( assert_deep_equal(
original[tag], original[tag],
value, value,
"{} didn't roundtrip, {}, {}".format(tag, original[tag], value), f"{tag} didn't roundtrip, {original[tag]}, {value}",
) )
else: else:
assert original[tag] == value, "{} didn't roundtrip, {}, {}".format( assert (
tag, original[tag], value original[tag] == value
) ), f"{tag} didn't roundtrip, {original[tag]}, {value}"
for tag, value in original.items(): for tag, value in original.items():
if tag not in ignored: 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): def test_change_stripbytecounts_tag_type(tmp_path):

View File

@ -47,11 +47,11 @@ def save_font(request, tmp_path, encoding):
font.save(tempname) font.save(tempname)
with Image.open(tempname.replace(".pil", ".pbm")) as loaded: 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) assert_image_equal(loaded, target)
with open(tempname, "rb") as f_loaded: 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() assert f_loaded.read() == f_target.read()
return tempname return tempname

View File

@ -125,14 +125,13 @@ class TestImageGetPixel(AccessTest):
im.putpixel((0, 0), c) im.putpixel((0, 0), c)
assert ( assert (
im.getpixel((0, 0)) == c 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 # check putpixel negative index
im.putpixel((-1, -1), c) im.putpixel((-1, -1), c)
assert im.getpixel((-1, -1)) == c, ( assert (
"put/getpixel roundtrip negative index failed for mode %s, color %s" im.getpixel((-1, -1)) == c
% (mode, c) ), f"put/getpixel roundtrip negative index failed for mode {mode}, color {c}"
)
# Check 0 # Check 0
im = Image.new(mode, (0, 0), None) im = Image.new(mode, (0, 0), None)
@ -150,11 +149,11 @@ class TestImageGetPixel(AccessTest):
im = Image.new(mode, (1, 1), c) im = Image.new(mode, (1, 1), c)
assert ( assert (
im.getpixel((0, 0)) == c 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 # check initial color negative index
assert ( assert (
im.getpixel((-1, -1)) == c 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 # Check 0
im = Image.new(mode, (0, 0), c) im = Image.new(mode, (0, 0), c)

View File

@ -161,8 +161,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): 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.mode == b.mode, f"got mode {repr(a.mode)}, expected {repr(b.mode)}"
assert a.size == b.size, "got size %r, expected %r" % (a.size, b.size) assert a.size == b.size, f"got size {repr(a.size)}, expected {repr(b.size)}"
a, b = convert_to_comparable(a, b) a, b = convert_to_comparable(a, b)
@ -175,16 +175,15 @@ def assert_compare_images(a, b, max_average_diff, max_diff=255):
a.size[0] * a.size[1] a.size[0] * a.size[1]
) )
msg = ( msg = (
"average pixel value difference {:.4f} > expected {:.4f} " f"average pixel value difference {average_diff:.4f} > "
"for '{}' band".format(average_diff, max_average_diff, band) f"expected {max_average_diff:.4f} for '{band}' band"
) )
assert max_average_diff >= average_diff, msg assert max_average_diff >= average_diff, msg
last_diff = [i for i, num in enumerate(ch_hist) if num > 0][-1] last_diff = [i for i, num in enumerate(ch_hist) if num > 0][-1]
assert ( assert max_diff >= last_diff, (
max_diff >= last_diff f"max pixel value difference {last_diff} > expected {max_diff} "
), "max pixel value difference {} > expected {} for '{}' band".format( f"for '{band}' band"
last_diff, max_diff, band
) )

View File

@ -81,15 +81,16 @@ class TestImagingCoreResampleAccuracy:
for y in range(case.size[1]): for y in range(case.size[1]):
for x in range(case.size[0]): for x in range(case.size[0]):
if c_px[x, y] != s_px[x, y]: if c_px[x, y] != s_px[x, y]:
message = "\nHave: \n{}\n\nExpected: \n{}".format( message = (
self.serialize_image(case), self.serialize_image(sample) 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 assert s_px[x, y] == c_px[x, y], message
def serialize_image(self, image): def serialize_image(self, image):
s_px = image.load() s_px = image.load()
return "\n".join( 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]) for y in range(image.size[1])
) )
@ -229,7 +230,7 @@ class TestCoreResampleConsistency:
for x in range(channel.size[0]): for x in range(channel.size[0]):
for y in range(channel.size[1]): for y in range(channel.size[1]):
if px[x, y] != color: 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 assert px[x, y] == color, message
def test_8u(self): def test_8u(self):
@ -268,10 +269,9 @@ class TestCoreResampleAlphaCorrect:
px = i.load() px = i.load()
for y in range(i.size[1]): for y in range(i.size[1]):
used_colors = {px[x, y][0] for x in range(i.size[0])} used_colors = {px[x, y][0] for x in range(i.size[0])}
assert 256 == len( assert 256 == len(used_colors), (
used_colors "All colors should be present in resized image. "
), "All colors should present in resized image. Only {} on {} line.".format( f"Only {len(used_colors)} on {y} line."
len(used_colors), y
) )
@pytest.mark.xfail(reason="Current implementation isn't precise enough") @pytest.mark.xfail(reason="Current implementation isn't precise enough")
@ -307,8 +307,9 @@ class TestCoreResampleAlphaCorrect:
for y in range(i.size[1]): for y in range(i.size[1]):
for x in range(i.size[0]): for x in range(i.size[0]):
if px[x, y][-1] != 0 and px[x, y][:-1] != clean_pixel: if px[x, y][-1] != 0 and px[x, y][:-1] != clean_pixel:
message = "pixel at ({}, {}) is differ:\n{}\n{}".format( message = (
x, y, px[x, y], clean_pixel f"pixel at ({x}, {y}) is different:\n"
f"{px[x, y]}\n{clean_pixel}"
) )
assert px[x, y][:3] == clean_pixel, message assert px[x, y][:3] == clean_pixel, message
@ -503,7 +504,7 @@ class TestCoreResampleBox:
]: ]:
res = im.resize(size, Image.LANCZOS, box) res = im.resize(size, Image.LANCZOS, box)
assert res.size == size 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): def test_no_passthrough(self):
# When resize is required # When resize is required
@ -519,9 +520,7 @@ class TestCoreResampleBox:
assert res.size == size assert res.size == size
with pytest.raises(AssertionError, match=r"difference \d"): with pytest.raises(AssertionError, match=r"difference \d"):
# check that the difference at least that much # check that the difference at least that much
assert_image_similar( assert_image_similar(res, im.crop(box), 20, f">>> {size} {box}")
res, im.crop(box), 20, ">>> {} {}".format(size, box)
)
def test_skip_horizontal(self): def test_skip_horizontal(self):
# Can skip resize for one dimension # Can skip resize for one dimension
@ -538,10 +537,7 @@ class TestCoreResampleBox:
assert res.size == size assert res.size == size
# Borders should be slightly different # Borders should be slightly different
assert_image_similar( assert_image_similar(
res, res, im.crop(box).resize(size, flt), 0.4, f">>> {size} {box} {flt}",
im.crop(box).resize(size, flt),
0.4,
">>> {} {} {}".format(size, box, flt),
) )
def test_skip_vertical(self): def test_skip_vertical(self):
@ -559,8 +555,5 @@ class TestCoreResampleBox:
assert res.size == size assert res.size == size
# Borders should be slightly different # Borders should be slightly different
assert_image_similar( assert_image_similar(
res, res, im.crop(box).resize(size, flt), 0.4, f">>> {size} {box} {flt}",
im.crop(box).resize(size, flt),
0.4,
">>> {} {} {}".format(size, box, flt),
) )

View File

@ -181,7 +181,7 @@ def helper_chord(mode, bbox, start, end):
# Arrange # Arrange
im = Image.new(mode, (W, H)) im = Image.new(mode, (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
expected = "Tests/images/imagedraw_chord_{}.png".format(mode) expected = f"Tests/images/imagedraw_chord_{mode}.png"
# Act # Act
draw.chord(bbox, start, end, fill="red", outline="yellow") draw.chord(bbox, start, end, fill="red", outline="yellow")
@ -243,7 +243,7 @@ def helper_ellipse(mode, bbox):
# Arrange # Arrange
im = Image.new(mode, (W, H)) im = Image.new(mode, (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
expected = "Tests/images/imagedraw_ellipse_{}.png".format(mode) expected = f"Tests/images/imagedraw_ellipse_{mode}.png"
# Act # Act
draw.ellipse(bbox, fill="green", outline="blue") draw.ellipse(bbox, fill="green", outline="blue")
@ -513,7 +513,7 @@ def test_polygon_kite():
# Arrange # Arrange
im = Image.new(mode, (W, H)) im = Image.new(mode, (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
expected = "Tests/images/imagedraw_polygon_kite_{}.png".format(mode) expected = f"Tests/images/imagedraw_polygon_kite_{mode}.png"
# Act # Act
draw.polygon(KITE_POINTS, fill="blue", outline="yellow") draw.polygon(KITE_POINTS, fill="blue", outline="yellow")
@ -1087,7 +1087,5 @@ def test_same_color_outline():
draw_method(*args) draw_method(*args)
# Assert # Assert
expected = "Tests/images/imagedraw_outline_{}_{}.png".format( expected = f"Tests/images/imagedraw_outline_{operation}_{mode}.png"
operation, mode
)
assert_image_similar_tofile(im, expected, 1) assert_image_similar_tofile(im, expected, 1)

View File

@ -55,7 +55,7 @@ def helper_ellipse(mode, bbox):
draw = ImageDraw2.Draw(im) draw = ImageDraw2.Draw(im)
pen = ImageDraw2.Pen("blue", width=2) pen = ImageDraw2.Pen("blue", width=2)
brush = ImageDraw2.Brush("green") brush = ImageDraw2.Brush("green")
expected = "Tests/images/imagedraw_ellipse_{}.png".format(mode) expected = f"Tests/images/imagedraw_ellipse_{mode}.png"
# Act # Act
draw.ellipse(bbox, pen, brush) draw.ellipse(bbox, pen, brush)

View File

@ -33,9 +33,7 @@ def _half_transparent_image():
def _check_alpha(im, original, op, amount): def _check_alpha(im, original, op, amount):
assert im.getbands() == original.getbands() assert im.getbands() == original.getbands()
assert_image_equal( assert_image_equal(
im.getchannel("A"), im.getchannel("A"), original.getchannel("A"), f"Diff on {op}: {amount}",
original.getchannel("A"),
"Diff on {}: {}".format(op, amount),
) )

View File

@ -3,7 +3,7 @@ from PIL import Image, ImageMath
def pixel(im): def pixel(im):
if hasattr(im, "im"): if hasattr(im, "im"):
return "{} {!r}".format(im.mode, im.getpixel((0, 0))) return "{} {}".format(im.mode, repr(im.getpixel((0, 0))))
else: else:
if isinstance(im, int): if isinstance(im, int):
return int(im) # hack to deal with booleans return int(im) # hack to deal with booleans

View File

@ -64,7 +64,7 @@ def create_lut():
for op in ("corner", "dilation4", "dilation8", "erosion4", "erosion8", "edge"): for op in ("corner", "dilation4", "dilation8", "erosion4", "erosion8", "edge"):
lb = ImageMorph.LutBuilder(op_name=op) lb = ImageMorph.LutBuilder(op_name=op)
lut = lb.build_lut() 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) f.write(lut)
@ -75,7 +75,7 @@ def test_lut():
assert lb.get_lut() is None assert lb.get_lut() is None
lut = lb.build_lut() 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()) assert lut == bytearray(f.read())

View File

@ -26,7 +26,7 @@ def setup_module():
tk.Frame() tk.Frame()
# root = tk.Tk() # root = tk.Tk()
except tk.TclError as v: except tk.TclError as v:
pytest.skip("TCL Error: %s" % v) pytest.skip(f"TCL Error: {v}")
def test_kw(): def test_kw():

View File

@ -15,9 +15,9 @@ def verify(im1):
xy = x, y xy = x, y
p1 = pix1[xy] p1 = pix1[xy]
p2 = pix2[xy] p2 = pix2[xy]
assert p1 == p2, "got {!r} from mode {} at {}, expected {!r}".format( assert (
p1, im1.mode, xy, p2 p1 == p2
) ), f"got {repr(p1)} from mode {im1.mode} at {xy}, expected {repr(p2)}"
def test_basic(tmp_path): def test_basic(tmp_path):

View File

@ -42,7 +42,7 @@ def test_sanity(tmp_path):
continue continue
# Test saving the file # Test saving the file
tempfile = str(tmp_path / "temp_{}.png".format(mode)) tempfile = str(tmp_path / f"temp_{mode}.png")
data.save(tempfile) data.save(tempfile)
# Check that it actually worked. # Check that it actually worked.

View File

@ -16,5 +16,5 @@ class TestToQPixmap(PillowQPixmapTestCase):
assert not data.isNull() assert not data.isNull()
# Test saving the file # Test saving the file
tempfile = str(tmp_path / "temp_{}.png".format(mode)) tempfile = str(tmp_path / f"temp_{mode}.png")
data.save(tempfile) data.save(tempfile)

View File

@ -212,10 +212,10 @@ class DdsImageFile(ImageFile.ImageFile):
def _open(self): def _open(self):
magic, header_size = struct.unpack("<II", self.fp.read(8)) magic, header_size = struct.unpack("<II", self.fp.read(8))
if header_size != 124: 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) header_bytes = self.fp.read(header_size - 4)
if len(header_bytes) != 120: 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) header = BytesIO(header_bytes)
flags, height, width = struct.unpack("<3I", header.read(12)) flags, height, width = struct.unpack("<3I", header.read(12))
@ -235,7 +235,7 @@ class DdsImageFile(ImageFile.ImageFile):
elif fourcc == b"DXT5": elif fourcc == b"DXT5":
self.decoder = "DXT5" self.decoder = "DXT5"
else: 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))] self.tile = [(self.decoder, (0, 0) + self.size, 0, (self.mode, 0, 1))]

View File

@ -124,7 +124,7 @@ Identify Image Files
for infile in sys.argv[1:]: for infile in sys.argv[1:]:
try: try:
with Image.open(infile) as im: 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: except OSError:
pass pass

View File

@ -18,7 +18,7 @@ Example: Vary the sharpness of an image
for i in range(8): for i in range(8):
factor = i / 4.0 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/` Also see the :file:`enhancer.py` demo program in the :file:`Scripts/`
directory. directory.

View File

@ -17,7 +17,7 @@ Extracting frames from an animation
with Image.open("animation.fli") as im: with Image.open("animation.fli") as im:
index = 1 index = 1
for frame in ImageSequence.Iterator(im): for frame in ImageSequence.Iterator(im):
frame.save("frame%d.png" % index) frame.save(f"frame{index}.png")
index += 1 index += 1
The :py:class:`~PIL.ImageSequence.Iterator` class The :py:class:`~PIL.ImageSequence.Iterator` class

View File

@ -22,7 +22,7 @@ from setuptools import Extension, setup
def get_version(): def get_version():
version_file = "src/PIL/_version.py" 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")) exec(compile(f.read(), version_file, "exec"))
return locals()["__version__"] return locals()["__version__"]
@ -40,10 +40,10 @@ ZLIB_ROOT = None
if sys.platform == "win32" and sys.version_info >= (3, 9): if sys.platform == "win32" and sys.version_info >= (3, 9):
warnings.warn( warnings.warn(
"Pillow {} does not support Python {}.{} and does not provide prebuilt " f"Pillow {PILLOW_VERSION} does not support Python "
"Windows binaries. We do not recommend building from source on Windows.".format( f"{sys.version_info.major}.{sys.version_info.minor} and does not provide "
PILLOW_VERSION, sys.version_info.major, sys.version_info.minor "prebuilt Windows binaries. We do not recommend building from source on "
), "Windows.",
RuntimeWarning, RuntimeWarning,
) )
@ -175,7 +175,7 @@ def _find_library_dirs_ldconfig():
# Assuming GLIBC's ldconfig (with option -p) # Assuming GLIBC's ldconfig (with option -p)
# Alpine Linux uses musl that can't print cache # Alpine Linux uses musl that can't print cache
args = ["/sbin/ldconfig", "-p"] args = ["/sbin/ldconfig", "-p"]
expr = r".*\(%s.*\) => (.*)" % abi_type expr = fr".*\({abi_type}.*\) => (.*)"
env = dict(os.environ) env = dict(os.environ)
env["LC_ALL"] = "C" env["LC_ALL"] = "C"
env["LANG"] = "C" env["LANG"] = "C"
@ -308,8 +308,8 @@ class pil_build_ext(build_ext):
user_options = ( user_options = (
build_ext.user_options build_ext.user_options
+ [("disable-%s" % x, None, "Disable support for %s" % x) for x in feature] + [(f"disable-{x}", None, f"Disable support for {x}") for x in feature]
+ [("enable-%s" % x, None, "Enable support for %s" % 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"), ("disable-platform-guessing", None, "Disable platform guessing on Linux"),
("debug", None, "Debug logging"), ("debug", None, "Debug logging"),
@ -322,8 +322,8 @@ class pil_build_ext(build_ext):
self.add_imaging_libs = "" self.add_imaging_libs = ""
build_ext.initialize_options(self) build_ext.initialize_options(self)
for x in self.feature: for x in self.feature:
setattr(self, "disable_%s" % x, None) setattr(self, f"disable_{x}", None)
setattr(self, "enable_%s" % x, None) setattr(self, f"enable_{x}", None)
def finalize_options(self): def finalize_options(self):
build_ext.finalize_options(self) build_ext.finalize_options(self)
@ -340,15 +340,15 @@ class pil_build_ext(build_ext):
except TypeError: except TypeError:
self.parallel = None self.parallel = None
for x in self.feature: for x in self.feature:
if getattr(self, "disable_%s" % x): if getattr(self, f"disable_{x}"):
setattr(self.feature, x, False) setattr(self.feature, x, False)
self.feature.required.discard(x) self.feature.required.discard(x)
_dbg("Disabling %s", x) _dbg("Disabling %s", x)
if getattr(self, "enable_%s" % x): if getattr(self, f"enable_{x}"):
raise ValueError( 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) _dbg("Requiring %s", x)
self.feature.required.add(x) self.feature.required.add(x)
@ -383,12 +383,12 @@ class pil_build_ext(build_ext):
if root is None and pkg_config: if root is None and pkg_config:
if isinstance(lib_name, tuple): if isinstance(lib_name, tuple):
for lib_name2 in lib_name: 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) root = pkg_config(lib_name2)
if root: if root:
break break
else: else:
_dbg("Looking for `%s` using pkg-config." % lib_name) _dbg(f"Looking for `{lib_name}` using pkg-config.")
root = pkg_config(lib_name) root = pkg_config(lib_name)
if isinstance(root, tuple): if isinstance(root, tuple):
@ -733,9 +733,9 @@ class pil_build_ext(build_ext):
and sys.version_info < (3, 9) and sys.version_info < (3, 9)
and not (PLATFORM_PYPY or PLATFORM_MINGW) and not (PLATFORM_PYPY or PLATFORM_MINGW)
): ):
defs.append(("PILLOW_VERSION", '"\\"%s\\""' % PILLOW_VERSION)) defs.append(("PILLOW_VERSION", f'"\\"{PILLOW_VERSION}\\""'))
else: else:
defs.append(("PILLOW_VERSION", '"%s"' % PILLOW_VERSION)) defs.append(("PILLOW_VERSION", f'"{PILLOW_VERSION}"'))
exts = [(Extension("PIL._imaging", files, libraries=libs, define_macros=defs))] exts = [(Extension("PIL._imaging", files, libraries=libs, define_macros=defs))]
@ -808,11 +808,11 @@ class pil_build_ext(build_ext):
print("-" * 68) print("-" * 68)
print("PIL SETUP SUMMARY") print("PIL SETUP SUMMARY")
print("-" * 68) print("-" * 68)
print("version Pillow %s" % PILLOW_VERSION) print(f"version Pillow {PILLOW_VERSION}")
v = sys.version.split("[") 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:]: for v in v[1:]:
print(" [%s" % v.strip()) print(f" [{v.strip()}")
print("-" * 68) print("-" * 68)
options = [ options = [
@ -833,10 +833,10 @@ class pil_build_ext(build_ext):
if option[0]: if option[0]:
version = "" version = ""
if len(option) >= 3 and option[2]: if len(option) >= 3 and option[2]:
version = " (%s)" % option[2] version = f" ({option[2]})"
print("--- {} support available{}".format(option[1], version)) print(f"--- {option[1]} support available{version}")
else: else:
print("*** %s support not available" % option[1]) print(f"*** {option[1]} support not available")
all = 0 all = 0
print("-" * 68) print("-" * 68)
@ -900,28 +900,23 @@ try:
zip_safe=not (debug_build() or PLATFORM_MINGW), zip_safe=not (debug_build() or PLATFORM_MINGW),
) )
except RequiredDependencyException as err: 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. a required dependency when compiling Pillow from source.
Please see the install instructions at: Please see the install instructions at:
https://pillow.readthedocs.io/en/latest/installation.html https://pillow.readthedocs.io/en/latest/installation.html
""" % ( """
str(err)
)
sys.stderr.write(msg) sys.stderr.write(msg)
raise RequiredDependencyException(msg) raise RequiredDependencyException(msg)
except DependencyException as err: except DependencyException 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)},
which was requested by the option flag --enable-%s which was requested by the option flag --enable-{str(err)}
""" % ( """
str(err),
str(err),
)
sys.stderr.write(msg) sys.stderr.write(msg)
raise DependencyException(msg) raise DependencyException(msg)

View File

@ -250,7 +250,7 @@ class BlpImageFile(ImageFile.ImageFile):
decoder = "BLP2" decoder = "BLP2"
self.mode = "RGBA" if self._blp_alpha_depth else "RGB" self.mode = "RGBA" if self._blp_alpha_depth else "RGB"
else: 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))] 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)) self.set_as_raw(bytes(data))
else: else:
raise BLPFormatError( raise BLPFormatError(
"Unsupported BLP encoding %r" % (self._blp_encoding) f"Unsupported BLP encoding {repr(self._blp_encoding)}"
) )
else: else:
raise BLPFormatError( raise BLPFormatError(
"Unsupported BLP compression %r" % (self._blp_encoding) f"Unsupported BLP compression {repr(self._blp_encoding)}"
) )
def _decode_jpeg_stream(self): def _decode_jpeg_stream(self):
@ -400,13 +400,15 @@ class BLP2Decoder(_BLPBaseDecoder):
data += d data += d
else: else:
raise BLPFormatError( raise BLPFormatError(
"Unsupported alpha encoding %r" % (self._blp_alpha_encoding) f"Unsupported alpha encoding {repr(self._blp_alpha_encoding)}"
) )
else: else:
raise BLPFormatError("Unknown BLP encoding %r" % (self._blp_encoding)) raise BLPFormatError(f"Unknown BLP encoding {repr(self._blp_encoding)}")
else: 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)) self.set_as_raw(bytes(data))

View File

@ -144,7 +144,7 @@ class BmpImageFile(ImageFile.ImageFile):
file_info["a_mask"], file_info["a_mask"],
) )
else: 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 # ------------------ Special case : header is reported 40, which
# ---------------------- is shorter than real size for bpp >= 16 # ---------------------- is shorter than real size for bpp >= 16
@ -164,7 +164,7 @@ class BmpImageFile(ImageFile.ImageFile):
# ---------------------- Check bit depth for unusual unsupported values # ---------------------- Check bit depth for unusual unsupported values
self.mode, raw_mode = BIT2MODE.get(file_info["bits"], (None, None)) self.mode, raw_mode = BIT2MODE.get(file_info["bits"], (None, None))
if self.mode is 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) # ---------------- Process BMP with Bitfields compression (not palette)
if file_info["compression"] == self.BITFIELDS: if file_info["compression"] == self.BITFIELDS:
@ -209,14 +209,14 @@ class BmpImageFile(ImageFile.ImageFile):
if file_info["bits"] == 32 and header == 22: # 32-bit .cur offset if file_info["bits"] == 32 and header == 22: # 32-bit .cur offset
raw_mode, self.mode = "BGRA", "RGBA" raw_mode, self.mode = "BGRA", "RGBA"
else: 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 # --------------- Once the header is processed, process the palette/LUT
if self.mode == "P": # Paletted for 1, 4 and 8 bit images if self.mode == "P": # Paletted for 1, 4 and 8 bit images
# ---------------------------------------------------- 1-bit images # ---------------------------------------------------- 1-bit images
if not (0 < file_info["colors"] <= 65536): 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: else:
padding = file_info["palette_padding"] padding = file_info["palette_padding"]
palette = read(padding * file_info["colors"]) palette = read(padding * file_info["colors"])
@ -305,7 +305,7 @@ def _save(im, fp, filename, bitmap_header=True):
try: try:
rawmode, bits, colors = SAVE[im.mode] rawmode, bits, colors = SAVE[im.mode]
except KeyError as e: 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 info = im.encoderinfo

View File

@ -106,10 +106,10 @@ class DdsImageFile(ImageFile.ImageFile):
def _open(self): def _open(self):
magic, header_size = struct.unpack("<II", self.fp.read(8)) magic, header_size = struct.unpack("<II", self.fp.read(8))
if header_size != 124: 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) header_bytes = self.fp.read(header_size - 4)
if len(header_bytes) != 120: 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) header = BytesIO(header_bytes)
flags, height, width = struct.unpack("<3I", header.read(12)) flags, height, width = struct.unpack("<3I", header.read(12))
@ -159,10 +159,10 @@ class DdsImageFile(ImageFile.ImageFile):
n = 7 n = 7
else: else:
raise NotImplementedError( raise NotImplementedError(
"Unimplemented DXGI format %d" % (dxgi_format) f"Unimplemented DXGI format {dxgi_format}"
) )
else: 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))] self.tile = [("bcn", (0, 0) + self.size, data_start, (n))]

View File

@ -118,10 +118,10 @@ def Ghostscript(tile, size, fp, scale=1):
"-dNOPAUSE", # don't pause between pages "-dNOPAUSE", # don't pause between pages
"-dSAFER", # safe mode "-dSAFER", # safe mode
"-sDEVICE=ppmraw", # ppm driver "-sDEVICE=ppmraw", # ppm driver
"-sOutputFile=%s" % outfile, # output file f"-sOutputFile={outfile}", # output file
# adjust for image origin # adjust for image origin
"-c", "-c",
"%d %d translate" % (-bbox[0], -bbox[1]), f"{-bbox[0]} {-bbox[1]} translate",
"-f", "-f",
infile, # input file infile, # input file
# showpage (see https://bugs.ghostscript.com/show_bug.cgi?id=698272) # showpage (see https://bugs.ghostscript.com/show_bug.cgi?id=698272)
@ -386,10 +386,10 @@ def _save(im, fp, filename, eps=1):
# image header # image header
fp.write("gsave\n") fp.write("gsave\n")
fp.write("10 dict begin\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 scale\n" % im.size)
fp.write("%d %d 8\n" % im.size) # <= bits 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("{ currentfile buf readhexstring pop } bind\n")
fp.write(operator[2] + "\n") fp.write(operator[2] + "\n")
if hasattr(fp, "flush"): if hasattr(fp, "flush"):

View File

@ -130,7 +130,7 @@ class FliImageFile(ImageFile.ImageFile):
self.load() self.load()
if frame != self.__frame + 1: 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.__frame = frame
# move to next frame # move to next frame

View File

@ -101,7 +101,7 @@ class FontFile:
# font metrics # font metrics
with open(os.path.splitext(filename)[0] + ".pil", "wb") as fp: with open(os.path.splitext(filename)[0] + ".pil", "wb") as fp:
fp.write(b"PILfont\n") 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") fp.write(b"DATA\n")
for id in range(256): for id in range(256):
m = self.metrics[id] m = self.metrics[id]

View File

@ -72,7 +72,7 @@ class FpxImageFile(ImageFile.ImageFile):
# get the Image Contents Property Set # get the Image Contents Property Set
prop = self.ole.getproperties( prop = self.ole.getproperties(
["Data Object Store %06d" % index, "\005Image Contents"] [f"Data Object Store {index:06d}", "\005Image Contents"]
) )
# size (highest resolution) # size (highest resolution)
@ -120,8 +120,8 @@ class FpxImageFile(ImageFile.ImageFile):
# setup tile descriptors for a given subimage # setup tile descriptors for a given subimage
stream = [ stream = [
"Data Object Store %06d" % index, f"Data Object Store {index:06d}",
"Resolution %04d" % subimage, f"Resolution {subimage:04d}",
"Subimage 0000 Header", "Subimage 0000 Header",
] ]

View File

@ -89,7 +89,7 @@ class FtexImageFile(ImageFile.ImageFile):
elif format == FORMAT_UNCOMPRESSED: elif format == FORMAT_UNCOMPRESSED:
self.tile = [("raw", (0, 0) + self.size, 0, ("RGB", 0, 1))] self.tile = [("raw", (0, 0) + self.size, 0, ("RGB", 0, 1))]
else: else:
raise ValueError("Invalid texture compression format: %r" % (format)) raise ValueError(f"Invalid texture compression format: {repr(format)}")
self.fp.close() self.fp.close()
self.fp = BytesIO(data) self.fp = BytesIO(data)

View File

@ -47,7 +47,7 @@ class GbrImageFile(ImageFile.ImageFile):
if header_size < 20: if header_size < 20:
raise SyntaxError("not a GIMP brush") raise SyntaxError("not a GIMP brush")
if version not in (1, 2): 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)) width = i32(self.fp.read(4))
height = 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: if width <= 0 or height <= 0:
raise SyntaxError("not a GIMP brush") raise SyntaxError("not a GIMP brush")
if color_depth not in (1, 4): 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: if version == 1:
comment_length = header_size - 20 comment_length = header_size - 20

View File

@ -151,7 +151,7 @@ class GifImageFile(ImageFile.ImageFile):
self.load() self.load()
if frame != self.__frame + 1: 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.__frame = frame
self.tile = [] self.tile = []

View File

@ -83,7 +83,7 @@ def read_32(fobj, start_length, size):
if bytesleft <= 0: if bytesleft <= 0:
break break
if bytesleft != 0: 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) band = Image.frombuffer("L", pixel_size, b"".join(data), "raw", "L", 0, 1)
im.im.putband(band.im, band_ix) im.im.putband(band.im, band_ix)
return {"RGB": im} return {"RGB": im}
@ -321,7 +321,7 @@ def _save(im, fp, filename):
last_w = None last_w = None
second_path = None second_path = None
for w in [16, 32, 128, 256, 512]: 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") first_path = os.path.join(iconset, prefix + ".png")
if last_w == w: if last_w == w:

View File

@ -86,16 +86,16 @@ OPEN = {
# ifunc95 extensions # ifunc95 extensions
for i in ["8", "8S", "16", "16S", "32", "32F"]: for i in ["8", "8S", "16", "16S", "32", "32F"]:
OPEN["L %s image" % i] = ("F", "F;%s" % i) OPEN[f"L {i} image"] = ("F", f"F;{i}")
OPEN["L*%s image" % i] = ("F", "F;%s" % i) OPEN[f"L*{i} image"] = ("F", f"F;{i}")
for i in ["16", "16L", "16B"]: for i in ["16", "16L", "16B"]:
OPEN["L %s image" % i] = ("I;%s" % i, "I;%s" % i) OPEN[f"L {i} image"] = (f"I;{i}", f"I;{i}")
OPEN["L*%s image" % i] = ("I;%s" % i, "I;%s" % i) OPEN[f"L*{i} image"] = (f"I;{i}", f"I;{i}")
for i in ["32S"]: for i in ["32S"]:
OPEN["L %s image" % i] = ("I", "I;%s" % i) OPEN[f"L {i} image"] = ("I", f"I;{i}")
OPEN["L*%s image" % i] = ("I", "I;%s" % i) OPEN[f"L*{i} image"] = ("I", f"I;{i}")
for i in range(2, 33): 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: try:
image_type, rawmode = SAVE[im.mode] image_type, rawmode = SAVE[im.mode]
except KeyError as e: 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) 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: if filename:
# Each line must be 100 characters or less, # Each line must be 100 characters or less,
# or: SyntaxError("not an IM file") # 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, ext = os.path.splitext(os.path.basename(filename))
name = "".join([name[: 92 - len(ext)], ext]) 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(("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"]: if im.mode in ["P", "PA"]:
fp.write(b"Lut: 1\r\n") fp.write(b"Lut: 1\r\n")
fp.write(b"\000" * (511 - fp.tell()) + b"\032") fp.write(b"\000" * (511 - fp.tell()) + b"\032")

View File

@ -59,7 +59,7 @@ if sys.version_info >= (3, 7):
if name == "PILLOW_VERSION": if name == "PILLOW_VERSION":
_raise_version_warning() _raise_version_warning()
return __version__ return __version__
raise AttributeError("module '{}' has no attribute '{}'".format(__name__, name)) raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
else: else:
@ -96,8 +96,8 @@ try:
if __version__ != getattr(core, "PILLOW_VERSION", None): if __version__ != getattr(core, "PILLOW_VERSION", None):
raise ImportError( raise ImportError(
"The _imaging extension was built for another version of Pillow or PIL:\n" "The _imaging extension was built for another version of Pillow or PIL:\n"
"Core version: %s\n" f"Core version: {getattr(core, 'PILLOW_VERSION', None)}\n"
"Pillow version: %s" % (getattr(core, "PILLOW_VERSION", None), __version__) f"Pillow version: {__version__}"
) )
except ImportError as v: except ImportError as v:
@ -403,7 +403,7 @@ def init():
for plugin in _plugins: for plugin in _plugins:
try: try:
logger.debug("Importing %s", plugin) logger.debug("Importing %s", plugin)
__import__("PIL.%s" % plugin, globals(), locals(), []) __import__(f"PIL.{plugin}", globals(), locals(), [])
except ImportError as e: except ImportError as e:
logger.debug("Image: failed to import %s: %s", plugin, e) logger.debug("Image: failed to import %s: %s", plugin, e)
@ -435,7 +435,7 @@ def _getdecoder(mode, decoder_name, args, extra=()):
# get decoder # get decoder
decoder = getattr(core, decoder_name + "_decoder") decoder = getattr(core, decoder_name + "_decoder")
except AttributeError as e: 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) return decoder(mode, *args + extra)
@ -458,7 +458,7 @@ def _getencoder(mode, encoder_name, args, extra=()):
# get encoder # get encoder
encoder = getattr(core, encoder_name + "_encoder") encoder = getattr(core, encoder_name + "_encoder")
except AttributeError as e: 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) return encoder(mode, *args + extra)
@ -742,7 +742,7 @@ class Image:
if s: if s:
break break
if s < 0: if s < 0:
raise RuntimeError("encoder error %d in tobytes" % s) raise RuntimeError(f"encoder error {s} in tobytes")
return b"".join(data) return b"".join(data)
@ -763,9 +763,9 @@ class Image:
data = self.tobytes("xbm") data = self.tobytes("xbm")
return b"".join( return b"".join(
[ [
("#define %s_width %d\n" % (name, self.size[0])).encode("ascii"), f"#define {name}_width {self.size[0]}\n".encode("ascii"),
("#define %s_height %d\n" % (name, self.size[1])).encode("ascii"), f"#define {name}_height {self.size[1]}\n".encode("ascii"),
("static char %s_bits[] = {\n" % name).encode("ascii"), f"static char {name}_bits[] = {{\n".encode("ascii"),
data, data,
b"};", b"};",
] ]
@ -1861,7 +1861,7 @@ class Image:
""" """
if resample not in (NEAREST, BILINEAR, BICUBIC, LANCZOS, BOX, HAMMING): if resample not in (NEAREST, BILINEAR, BICUBIC, LANCZOS, BOX, HAMMING):
message = "Unknown resampling filter ({}).".format(resample) message = f"Unknown resampling filter ({resample})."
filters = [ filters = [
"{} ({})".format(filter[1], filter[0]) "{} ({})".format(filter[1], filter[0])
@ -2129,7 +2129,7 @@ class Image:
try: try:
format = EXTENSION[ext] format = EXTENSION[ext]
except KeyError as e: 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: if format.upper() not in SAVE:
init() init()
@ -2241,7 +2241,7 @@ class Image:
try: try:
channel = self.getbands().index(channel) channel = self.getbands().index(channel)
except ValueError as e: 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)) return self._new(self.im.getband(channel))
@ -2462,9 +2462,9 @@ class Image:
BOX: "Image.BOX", BOX: "Image.BOX",
HAMMING: "Image.HAMMING", HAMMING: "Image.HAMMING",
LANCZOS: "Image.LANCZOS/Image.ANTIALIAS", LANCZOS: "Image.LANCZOS/Image.ANTIALIAS",
}[resample] + " ({}) cannot be used.".format(resample) }[resample] + f" ({resample}) cannot be used."
else: else:
message = "Unknown resampling filter ({}).".format(resample) message = f"Unknown resampling filter ({resample})."
filters = [ filters = [
"{} ({})".format(filter[1], filter[0]) "{} ({})".format(filter[1], filter[0])
@ -2758,7 +2758,7 @@ def fromarray(obj, mode=None):
else: else:
ndmax = 4 ndmax = 4
if ndim > ndmax: 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] size = 1 if ndim == 1 else shape[1], shape[0]
if strides is not None: if strides is not None:
@ -2824,14 +2824,14 @@ def _decompression_bomb_check(size):
if pixels > 2 * MAX_IMAGE_PIXELS: if pixels > 2 * MAX_IMAGE_PIXELS:
raise DecompressionBombError( raise DecompressionBombError(
"Image size (%d pixels) exceeds limit of %d pixels, " f"Image size ({pixels} pixels) exceeds limit of {2 * MAX_IMAGE_PIXELS} "
"could be decompression bomb DOS attack." % (pixels, 2 * MAX_IMAGE_PIXELS) "pixels, could be decompression bomb DOS attack."
) )
if pixels > MAX_IMAGE_PIXELS: if pixels > MAX_IMAGE_PIXELS:
warnings.warn( warnings.warn(
"Image size (%d pixels) exceeds limit of %d pixels, " f"Image size ({pixels} pixels) exceeds limit of {MAX_IMAGE_PIXELS} pixels, "
"could be decompression bomb DOS attack." % (pixels, MAX_IMAGE_PIXELS), "could be decompression bomb DOS attack.",
DecompressionBombWarning, DecompressionBombWarning,
) )
@ -2860,7 +2860,7 @@ def open(fp, mode="r"):
""" """
if mode != "r": if mode != "r":
raise ValueError("bad mode %r" % mode) raise ValueError(f"bad mode {repr(mode)}")
elif isinstance(fp, io.StringIO): elif isinstance(fp, io.StringIO):
raise ValueError( raise ValueError(
"StringIO cannot be used to open an image. " "StringIO cannot be used to open an image. "
@ -3241,13 +3241,13 @@ def _apply_env_variables(env=None):
try: try:
var = int(var) * units var = int(var) * units
except ValueError: except ValueError:
warnings.warn("{} is not int".format(var_name)) warnings.warn(f"{var_name} is not int")
continue continue
try: try:
setter(var) setter(var)
except ValueError as e: except ValueError as e:
warnings.warn("{}: {}".format(var_name, e)) warnings.warn(f"{var_name}: {e}")
_apply_env_variables() _apply_env_variables()
@ -3370,8 +3370,8 @@ class Exif(MutableMapping):
if len(data) != size: if len(data) != size:
warnings.warn( warnings.warn(
"Possibly corrupt EXIF MakerNote data. " "Possibly corrupt EXIF MakerNote data. "
"Expecting to read %d bytes but only got %d." f"Expecting to read {size} bytes but only got "
" Skipping tag %s" % (size, len(data), ifd_tag) f"{len(data)}. Skipping tag {ifd_tag}"
) )
continue continue

View File

@ -678,8 +678,7 @@ def createProfile(colorSpace, colorTemp=-1):
if colorSpace not in ["LAB", "XYZ", "sRGB"]: if colorSpace not in ["LAB", "XYZ", "sRGB"]:
raise PyCMSError( raise PyCMSError(
"Color space not supported for on-the-fly profile creation (%s)" f"Color space not supported for on-the-fly profile creation ({colorSpace})"
% colorSpace
) )
if colorSpace == "LAB": if colorSpace == "LAB":
@ -687,7 +686,7 @@ def createProfile(colorSpace, colorTemp=-1):
colorTemp = float(colorTemp) colorTemp = float(colorTemp)
except (TypeError, ValueError) as e: except (TypeError, ValueError) as e:
raise PyCMSError( raise PyCMSError(
'Color temperature must be numeric, "%s" not valid' % colorTemp f'Color temperature must be numeric, "{colorTemp}" not valid'
) from e ) from e
try: try:
@ -732,7 +731,7 @@ def getProfileName(profile):
return (profile.profile.profile_description or "") + "\n" return (profile.profile.profile_description or "") + "\n"
if not manufacturer or len(model) > 30: if not manufacturer or len(model) > 30:
return model + "\n" return model + "\n"
return "{} - {}\n".format(model, manufacturer) return f"{model} - {manufacturer}\n"
except (AttributeError, OSError, TypeError, ValueError) as v: except (AttributeError, OSError, TypeError, ValueError) as v:
raise PyCMSError(v) from v raise PyCMSError(v) from v

View File

@ -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) m = re.match(r"rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$", color)
if m: if m:
return (int(m.group(1)), int(m.group(2)), int(m.group(3)), int(m.group(4))) 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): def getcolor(color, mode):

View File

@ -61,7 +61,7 @@ def raise_oserror(error):
except AttributeError: except AttributeError:
message = ERRORS.get(error) message = ERRORS.get(error)
if not message: if not message:
message = "decoder error %d" % error message = f"decoder error {error}"
raise OSError(message + " when reading image file") raise OSError(message + " when reading image file")
@ -201,7 +201,7 @@ class ImageFile(Image.Image):
# use mmap, if possible # use mmap, if possible
import mmap import mmap
with open(self.filename, "r") as fp: with open(self.filename) as fp:
self.map = mmap.mmap( self.map = mmap.mmap(
fp.fileno(), 0, access=mmap.ACCESS_READ fp.fileno(), 0, access=mmap.ACCESS_READ
) )
@ -256,7 +256,7 @@ class ImageFile(Image.Image):
else: else:
raise OSError( raise OSError(
"image file is truncated " "image file is truncated "
"(%d bytes not processed)" % len(b) f"({len(b)} bytes not processed)"
) )
b = b + s b = b + s
@ -332,7 +332,7 @@ class StubImageFile(ImageFile):
def load(self): def load(self):
loader = self._load() loader = self._load()
if loader is None: 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) image = loader.load(self)
assert image is not None assert image is not None
# become the other object (!) # become the other object (!)
@ -524,7 +524,7 @@ def _save(im, fp, tile, bufsize=0):
if s: if s:
break break
if s < 0: if s < 0:
raise OSError("encoder error %d when writing image file" % s) from e raise OSError(f"encoder error {s} when writing image file") from e
e.cleanup() e.cleanup()
else: else:
# slight speedup: compress to real file object # slight speedup: compress to real file object
@ -539,7 +539,7 @@ def _save(im, fp, tile, bufsize=0):
else: else:
s = e.encode_to_file(fh, bufsize) s = e.encode_to_file(fh, bufsize)
if s < 0: 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() e.cleanup()
if hasattr(fp, "flush"): if hasattr(fp, "flush"):
fp.flush() fp.flush()

View File

@ -401,9 +401,8 @@ class Color3DLUT(MultibandFilter):
raise ValueError( raise ValueError(
"The table should have either channels * size**3 float items " "The table should have either channels * size**3 float items "
"or size**3 items of channels-sized tuples with floats. " "or size**3 items of channels-sized tuples with floats. "
"Table should be: {}x{}x{}x{}. Actual length: {}".format( f"Table should be: {channels}x{size[0]}x{size[1]}x{size[2]}. "
channels, size[0], size[1], size[2], len(table) f"Actual length: {len(table)}"
)
) )
self.table = table self.table = table
@ -513,12 +512,12 @@ class Color3DLUT(MultibandFilter):
def __repr__(self): def __repr__(self):
r = [ 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), "size={:d}x{:d}x{:d}".format(*self.size),
"channels={:d}".format(self.channels), f"channels={self.channels:d}",
] ]
if self.mode: if self.mode:
r.append("target_mode={}".format(self.mode)) r.append(f"target_mode={self.mode}")
return "<{}>".format(" ".join(r)) return "<{}>".format(" ".join(r))
def filter(self, image): def filter(self, image):

View File

@ -41,7 +41,7 @@ class _Operand:
elif im1.im.mode in ("I", "F"): elif im1.im.mode in ("I", "F"):
return im1.im return im1.im
else: else:
raise ValueError("unsupported mode: %s" % im1.im.mode) raise ValueError(f"unsupported mode: {im1.im.mode}")
else: else:
# argument was a constant # argument was a constant
if _isconstant(im1) and self.im.mode in ("1", "L", "I"): if _isconstant(im1) and self.im.mode in ("1", "L", "I"):
@ -58,7 +58,7 @@ class _Operand:
try: try:
op = getattr(_imagingmath, op + "_" + im1.mode) op = getattr(_imagingmath, op + "_" + im1.mode)
except AttributeError as e: 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) _imagingmath.unop(op, out.im.id, im1.im.id)
else: else:
# binary operation # binary operation
@ -86,7 +86,7 @@ class _Operand:
try: try:
op = getattr(_imagingmath, op + "_" + im1.mode) op = getattr(_imagingmath, op + "_" + im1.mode)
except AttributeError as e: 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) _imagingmath.binop(op, out.im.id, im1.im.id, im2.im.id)
return _Operand(out) return _Operand(out)

View File

@ -111,7 +111,7 @@ class ImagePalette:
self.dirty = 1 self.dirty = 1
return index return index
else: else:
raise ValueError("unknown color specifier: %r" % color) raise ValueError(f"unknown color specifier: {repr(color)}")
def save(self, fp): def save(self, fp):
"""Save palette to text file. """Save palette to text file.
@ -123,12 +123,12 @@ class ImagePalette:
if isinstance(fp, str): if isinstance(fp, str):
fp = open(fp, "w") fp = open(fp, "w")
fp.write("# Palette\n") fp.write("# Palette\n")
fp.write("# Mode: %s\n" % self.mode) fp.write(f"# Mode: {self.mode}\n")
for i in range(256): 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)): for j in range(i * len(self.mode), (i + 1) * len(self.mode)):
try: try:
fp.write(" %d" % self.palette[j]) fp.write(f" {self.palette[j]}")
except IndexError: except IndexError:
fp.write(" 0") fp.write(" 0")
fp.write("\n") fp.write("\n")

View File

@ -145,7 +145,7 @@ def _toqclass_helper(im):
data = im.tobytes("raw", "BGRA") data = im.tobytes("raw", "BGRA")
format = QImage.Format_ARGB32 format = QImage.Format_ARGB32
else: 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) __data = data or align8to32(im.tobytes(), im.size[0], im.mode)
return {"data": __data, "im": im, "format": format, "colortable": colortable} return {"data": __data, "im": im, "format": format, "colortable": colortable}

View File

@ -123,9 +123,9 @@ class WindowsViewer(Viewer):
def get_command(self, file, **options): def get_command(self, file, **options):
return ( return (
'start "Pillow" /WAIT "%s" ' f'start "Pillow" /WAIT "{file}" '
"&& ping -n 2 127.0.0.1 >NUL " "&& 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 # on darwin open returns immediately resulting in the temp
# file removal while app is opening # file removal while app is opening
command = "open -a Preview.app" command = "open -a Preview.app"
command = "({} {}; sleep 20; rm -f {})&".format( command = f"({command} {quote(file)}; sleep 20; rm -f {quote(file)})&"
command, quote(file), quote(file)
)
return command return command
def show_file(self, file, **options): def show_file(self, file, **options):
@ -153,7 +151,7 @@ class MacViewer(Viewer):
fd, path = tempfile.mkstemp() fd, path = tempfile.mkstemp()
with os.fdopen(fd, "w") as f: with os.fdopen(fd, "w") as f:
f.write(file) f.write(file)
with open(path, "r") as f: with open(path) as f:
subprocess.Popen( subprocess.Popen(
["im=$(cat); open -a Preview.app $im; sleep 20; rm -f $im"], ["im=$(cat); open -a Preview.app $im; sleep 20; rm -f $im"],
shell=True, shell=True,
@ -173,14 +171,14 @@ class UnixViewer(Viewer):
def get_command(self, file, **options): def get_command(self, file, **options):
command = self.get_command_ex(file, **options)[0] 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): def show_file(self, file, **options):
"""Display given file""" """Display given file"""
fd, path = tempfile.mkstemp() fd, path = tempfile.mkstemp()
with os.fdopen(fd, "w") as f: with os.fdopen(fd, "w") as f:
f.write(file) f.write(file)
with open(path, "r") as f: with open(path) as f:
command = self.get_command_ex(file, **options)[0] command = self.get_command_ex(file, **options)[0]
subprocess.Popen( subprocess.Popen(
["im=$(cat);" + command + " $im; rm -f $im"], shell=True, stdin=f ["im=$(cat);" + command + " $im; rm -f $im"], shell=True, stdin=f
@ -216,7 +214,7 @@ class XVViewer(UnixViewer):
# imagemagick's display command instead. # imagemagick's display command instead.
command = executable = "xv" command = executable = "xv"
if title: if title:
command += " -name %s" % quote(title) command += f" -name {quote(title)}"
return command, executable return command, executable

View File

@ -41,7 +41,7 @@ def _pilbitmap_check():
if _pilbitmap_ok is None: if _pilbitmap_ok is None:
try: try:
im = Image.new("1", (1, 1)) 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 _pilbitmap_ok = 1
except tkinter.TclError: except tkinter.TclError:
_pilbitmap_ok = 0 _pilbitmap_ok = 0
@ -229,7 +229,7 @@ class BitmapImage:
if _pilbitmap_check(): if _pilbitmap_check():
# fast way (requires the pilbitmap booster patch) # fast way (requires the pilbitmap booster patch)
image.load() image.load()
kw["data"] = "PIL:%d" % image.im.id kw["data"] = f"PIL:{image.im.id}"
self.__im = image # must keep a reference self.__im = image # must keep a reference
else: else:
# slow but safe way # slow but safe way

View File

@ -195,7 +195,7 @@ def SOF(self, marker):
self.bits = i8(s[0]) self.bits = i8(s[0])
if self.bits != 8: 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]) self.layers = i8(s[5])
if self.layers == 1: if self.layers == 1:
@ -205,7 +205,7 @@ def SOF(self, marker):
elif self.layers == 4: elif self.layers == 4:
self.mode = "CMYK" self.mode = "CMYK"
else: 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]: if marker in [0xFFC2, 0xFFC6, 0xFFCA, 0xFFCE]:
self.info["progressive"] = self.info["progression"] = 1 self.info["progressive"] = self.info["progression"] = 1
@ -518,7 +518,7 @@ def _getmp(self):
rawmpentries = mp[0xB002] rawmpentries = mp[0xB002]
for entrynum in range(0, quant): for entrynum in range(0, quant):
unpackedentry = struct.unpack_from( unpackedentry = struct.unpack_from(
"{}LLLHH".format(endianness), rawmpentries, entrynum * 16 f"{endianness}LLLHH", rawmpentries, entrynum * 16
) )
labels = ("Attribute", "Size", "DataOffset", "EntryNo1", "EntryNo2") labels = ("Attribute", "Size", "DataOffset", "EntryNo1", "EntryNo2")
mpentry = dict(zip(labels, unpackedentry)) mpentry = dict(zip(labels, unpackedentry))
@ -613,7 +613,7 @@ def _save(im, fp, filename):
try: try:
rawmode = RAWMODE[im.mode] rawmode = RAWMODE[im.mode]
except KeyError as e: 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 info = im.encoderinfo

View File

@ -114,7 +114,7 @@ class MspDecoder(ImageFile.PyDecoder):
try: try:
self.fd.seek(32) self.fd.seek(32)
rowmap = struct.unpack_from( 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: except struct.error as e:
raise OSError("Truncated MSP file in row map") from e raise OSError("Truncated MSP file in row map") from e
@ -143,7 +143,7 @@ class MspDecoder(ImageFile.PyDecoder):
idx += runcount idx += runcount
except struct.error as e: 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)) self.set_as_raw(img.getvalue(), ("1", 0, 1))
@ -160,7 +160,7 @@ Image.register_decoder("MSP", MspDecoder)
def _save(im, fp, filename): def _save(im, fp, filename):
if im.mode != "1": 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 # create MSP header
header = [0] * 16 header = [0] * 16

View File

@ -71,10 +71,10 @@ class PSDraw:
""" """
if font not in self.isofont: if font not in self.isofont:
# reencode font # 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 self.isofont[font] = 1
# rough # 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): def line(self, xy0, xy1):
""" """
@ -82,8 +82,7 @@ class PSDraw:
PostScript point coordinates (72 points per inch, (0, 0) is the lower PostScript point coordinates (72 points per inch, (0, 0) is the lower
left corner of the page). left corner of the page).
""" """
xy = xy0 + xy1 self._fp_write("%d %d %d %d Vl\n" % (*xy0, *xy1))
self._fp_write("%d %d %d %d Vl\n" % xy)
def rectangle(self, box): def rectangle(self, box):
""" """
@ -107,8 +106,7 @@ class PSDraw:
""" """
text = "\\(".join(text.split("(")) text = "\\(".join(text.split("("))
text = "\\)".join(text.split(")")) text = "\\)".join(text.split(")"))
xy = xy + (text,) self._fp_write(f"{xy[0]} {xy[1]} M ({text}) S\n")
self._fp_write("%d %d M (%s) S\n" % xy)
def image(self, box, im, dpi=None): def image(self, box, im, dpi=None):
"""Draw a PIL image, centered in the given box.""" """Draw a PIL image, centered in the given box."""
@ -132,12 +130,12 @@ class PSDraw:
y = ymax y = ymax
dx = (xmax - x) / 2 + box[0] dx = (xmax - x) / 2 + box[0]
dy = (ymax - y) / 2 + box[1] 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: if (x, y) != im.size:
# EpsImagePlugin._save prints the image at (0,0,xsize,ysize) # EpsImagePlugin._save prints the image at (0,0,xsize,ysize)
sx = x / im.size[0] sx = x / im.size[0]
sy = y / im.size[1] 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) EpsImagePlugin._save(im, self.fp, None, 0)
self._fp_write("\ngrestore\n") self._fp_write("\ngrestore\n")

View File

@ -137,7 +137,7 @@ def _save(im, fp, filename):
bpp = im.info["bpp"] bpp = im.info["bpp"]
im = im.point(lambda x, maxval=(1 << bpp) - 1: maxval - (x & maxval)) im = im.point(lambda x, maxval=(1 << bpp) - 1: maxval - (x & maxval))
else: 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 # we ignore the palette here
im.mode = "P" im.mode = "P"
@ -153,7 +153,7 @@ def _save(im, fp, filename):
else: 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 # make sure image data is available

View File

@ -132,7 +132,7 @@ def _save(im, fp, filename):
try: try:
version, bits, planes, rawmode = SAVE[im.mode] version, bits, planes, rawmode = SAVE[im.mode]
except KeyError as e: 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 # bytes per plane
stride = (im.size[0] * bits + 7) // 8 stride = (im.size[0] * bits + 7) // 8

View File

@ -77,7 +77,7 @@ def _save(im, fp, filename, save_all=False):
existing_pdf.start_writing() existing_pdf.start_writing()
existing_pdf.write_header() 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 # pages
@ -129,7 +129,7 @@ def _save(im, fp, filename, save_all=False):
bits = 1 bits = 1
elif im.mode == "L": elif im.mode == "L":
filter = "DCTDecode" filter = "DCTDecode"
# params = "<< /Predictor 15 /Columns %d >>" % (width-2) # params = f"<< /Predictor 15 /Columns {width-2} >>"
colorspace = PdfParser.PdfName("DeviceGray") colorspace = PdfParser.PdfName("DeviceGray")
procset = "ImageB" # grayscale procset = "ImageB" # grayscale
elif im.mode == "P": elif im.mode == "P":
@ -151,7 +151,7 @@ def _save(im, fp, filename, save_all=False):
colorspace = PdfParser.PdfName("DeviceCMYK") colorspace = PdfParser.PdfName("DeviceCMYK")
procset = "ImageC" # color images procset = "ImageC" # color images
else: else:
raise ValueError("cannot save mode %s" % im.mode) raise ValueError(f"cannot save mode {im.mode}")
# #
# image # image
@ -173,7 +173,7 @@ def _save(im, fp, filename, save_all=False):
elif filter == "RunLengthDecode": elif filter == "RunLengthDecode":
ImageFile._save(im, op, [("packbits", (0, 0) + im.size, 0, im.mode)]) ImageFile._save(im, op, [("packbits", (0, 0) + im.size, 0, im.mode)])
else: else:
raise ValueError("unsupported PDF filter (%s)" % filter) raise ValueError(f"unsupported PDF filter ({filter})")
# #
# Get image characteristics # Get image characteristics

View File

@ -183,8 +183,8 @@ class XrefTable:
this_deleted_object_id = deleted_keys.pop(0) this_deleted_object_id = deleted_keys.pop(0)
check_format_condition( check_format_condition(
object_id == this_deleted_object_id, object_id == this_deleted_object_id,
"expected the next deleted object ID to be %s, instead found %s" f"expected the next deleted object ID to be {object_id}, "
% (object_id, this_deleted_object_id), f"instead found {this_deleted_object_id}",
) )
try: try:
next_in_linked_list = deleted_keys[0] next_in_linked_list = deleted_keys[0]
@ -218,7 +218,7 @@ class PdfName:
return hash(self.name) return hash(self.name)
def __repr__(self): def __repr__(self):
return "PdfName(%s)" % repr(self.name) return f"PdfName({repr(self.name)})"
@classmethod @classmethod
def from_pdf_stream(cls, data): def from_pdf_stream(cls, data):
@ -315,7 +315,7 @@ class PdfStream:
return zlib.decompress(self.buf, bufsize=int(expected_length)) return zlib.decompress(self.buf, bufsize=int(expected_length))
else: else:
raise NotImplementedError( 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") self.f.write(b"%PDF-1.4\n")
def write_comment(self, s): 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): def write_catalog(self):
self.del_root() self.del_root()
@ -966,9 +966,8 @@ class PdfParser:
offset, generation = self.xref_table[ref[0]] offset, generation = self.xref_table[ref[0]]
check_format_condition( check_format_condition(
generation == ref[1], generation == ref[1],
"expected to find generation %s for object ID %s in xref table, " f"expected to find generation {ref[1]} for object ID {ref[0]} in xref "
"instead found generation %s at offset %s" f"table, instead found generation {generation} at offset {offset}",
% (ref[1], ref[0], generation, offset),
) )
value = self.get_value( value = self.get_value(
self.buf, self.buf,

View File

@ -159,7 +159,7 @@ class ChunkStream:
if not is_cid(cid): if not is_cid(cid):
if not ImageFile.LOAD_TRUNCATED_IMAGES: 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 return cid, pos, length
@ -196,10 +196,12 @@ class ChunkStream:
crc1 = _crc32(data, _crc32(cid)) crc1 = _crc32(data, _crc32(cid))
crc2 = i32(self.fp.read(4)) crc2 = i32(self.fp.read(4))
if crc1 != crc2: 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: except struct.error as e:
raise SyntaxError( raise SyntaxError(
"broken PNG file (incomplete checksum in %r)" % cid f"broken PNG file (incomplete checksum in {repr(cid)})"
) from e ) from e
def crc_skip(self, cid, data): def crc_skip(self, cid, data):
@ -351,8 +353,8 @@ class PngStream(ChunkStream):
self.text_memory += chunklen self.text_memory += chunklen
if self.text_memory > MAX_TEXT_MEMORY: if self.text_memory > MAX_TEXT_MEMORY:
raise ValueError( raise ValueError(
"Too much memory used in text chunks: %s>MAX_TEXT_MEMORY" "Too much memory used in text chunks: "
% self.text_memory f"{self.text_memory}>MAX_TEXT_MEMORY"
) )
def save_rewind(self): def save_rewind(self):
@ -381,9 +383,7 @@ class PngStream(ChunkStream):
logger.debug("Compression method %s", i8(s[i])) logger.debug("Compression method %s", i8(s[i]))
comp_method = i8(s[i]) comp_method = i8(s[i])
if comp_method != 0: if comp_method != 0:
raise SyntaxError( raise SyntaxError(f"Unknown compression method {comp_method} in iCCP chunk")
"Unknown compression method %s in iCCP chunk" % comp_method
)
try: try:
icc_profile = _safe_zlib_decompress(s[i + 2 :]) icc_profile = _safe_zlib_decompress(s[i + 2 :])
except ValueError: except ValueError:
@ -530,9 +530,7 @@ class PngStream(ChunkStream):
else: else:
comp_method = 0 comp_method = 0
if comp_method != 0: if comp_method != 0:
raise SyntaxError( raise SyntaxError(f"Unknown compression method {comp_method} in zTXt chunk")
"Unknown compression method %s in zTXt chunk" % comp_method
)
try: try:
v = _safe_zlib_decompress(v[1:]) v = _safe_zlib_decompress(v[1:])
except ValueError: except ValueError:
@ -794,7 +792,7 @@ class PngImageFile(ImageFile.ImageFile):
return return
else: else:
if frame != self.__frame + 1: 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 # ensure previous frame was loaded
self.load() self.load()
@ -1186,7 +1184,7 @@ def _save(im, fp, filename, chunk=putchunk, save_all=False):
else: else:
bits = 8 bits = 8
if bits != 8: if bits != 8:
mode = "%s;%d" % (mode, bits) mode = f"{mode};{bits}"
# encoder options # encoder options
im.encoderconfig = ( im.encoderconfig = (
@ -1200,7 +1198,7 @@ def _save(im, fp, filename, chunk=putchunk, save_all=False):
try: try:
rawmode, mode = _OUTMODES[mode] rawmode, mode = _OUTMODES[mode]
except KeyError as e: 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 # write minimal PNG file

View File

@ -104,7 +104,7 @@ class PpmImageFile(ImageFile.ImageFile):
# maxgrey # maxgrey
if s > 255: if s > 255:
if not mode == "L": 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: if s < 2 ** 16:
self.mode = "I" self.mode = "I"
rawmode = "I;16B" rawmode = "I;16B"
@ -135,7 +135,7 @@ def _save(im, fp, filename):
elif im.mode == "RGBA": elif im.mode == "RGBA":
rawmode, head = "RGB", b"P6" rawmode, head = "RGB", b"P6"
else: 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")) fp.write(head + ("\n%d %d\n" % im.size).encode("ascii"))
if head == b"P6": if head == b"P6":
fp.write(b"255\n") fp.write(b"255\n")

View File

@ -158,9 +158,7 @@ def _save(im, fp, filename):
# assert we've got the right number of bands. # assert we've got the right number of bands.
if len(im.getbands()) != z: if len(im.getbands()) != z:
raise ValueError( raise ValueError(
"incorrect number of bands in SGI write: {} vs {}".format( f"incorrect number of bands in SGI write: {z} vs {len(im.getbands())}"
z, len(im.getbands())
)
) )
# Minimum Byte value # Minimum Byte value

View File

@ -213,7 +213,7 @@ def loadImageSeries(filelist=None):
imglist = [] imglist = []
for img in filelist: for img in filelist:
if not os.path.exists(img): if not os.path.exists(img):
print("unable to find %s" % img) print(f"unable to find {img}")
continue continue
try: try:
with Image.open(img) as im: with Image.open(img) as im:
@ -318,7 +318,7 @@ if __name__ == "__main__":
# perform some image operation # perform some image operation
im = im.transpose(Image.FLIP_LEFT_RIGHT) im = im.transpose(Image.FLIP_LEFT_RIGHT)
print( print(
"saving a flipped version of %s as %s " f"saving a flipped version of {os.path.basename(filename)} "
% (os.path.basename(filename), outfile) f"as {outfile} "
) )
im.save(outfile, SpiderImageFile.format) im.save(outfile, SpiderImageFile.format)

View File

@ -168,7 +168,7 @@ def _save(im, fp, filename):
try: try:
rawmode, bits, colormaptype, imagetype = SAVE[im.mode] rawmode, bits, colormaptype, imagetype = SAVE[im.mode]
except KeyError as e: 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: if "rle" in im.encoderinfo:
rle = im.encoderinfo["rle"] rle = im.encoderinfo["rle"]

View File

@ -464,7 +464,7 @@ class ImageFileDirectory_v2(MutableMapping):
:param prefix: Override the endianness of the file. :param prefix: Override the endianness of the file.
""" """
if ifh[:4] not in PREFIXES: 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] self._prefix = prefix if prefix is not None else ifh[:2]
if self._prefix == MM: if self._prefix == MM:
self._endian = ">" self._endian = ">"
@ -592,8 +592,8 @@ class ImageFileDirectory_v2(MutableMapping):
except ValueError: except ValueError:
# We've got a builtin tag with 1 expected entry # We've got a builtin tag with 1 expected entry
warnings.warn( warnings.warn(
"Metadata Warning, tag %s had too many entries: %s, expected 1" f"Metadata Warning, tag {tag} had too many entries: "
% (tag, len(values)) f"{len(values)}, expected 1"
) )
dest[tag] = values[0] dest[tag] = values[0]
@ -728,7 +728,7 @@ class ImageFileDirectory_v2(MutableMapping):
if len(ret) != size: if len(ret) != size:
raise OSError( raise OSError(
"Corrupt EXIF data. " "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 return ret
@ -743,18 +743,18 @@ class ImageFileDirectory_v2(MutableMapping):
tagname = TiffTags.lookup(tag).name tagname = TiffTags.lookup(tag).name
typname = TYPES.get(typ, "unknown") 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: try:
unit_size, handler = self._load_dispatch[typ] unit_size, handler = self._load_dispatch[typ]
except KeyError: except KeyError:
logger.debug(msg + " - unsupported type {}".format(typ)) logger.debug(msg + f" - unsupported type {typ}")
continue # ignore unsupported type continue # ignore unsupported type
size = count * unit_size size = count * unit_size
if size > 4: if size > 4:
here = fp.tell() here = fp.tell()
(offset,) = self._unpack("L", data) (offset,) = self._unpack("L", data)
msg += " Tag Location: {} - Data Location: {}".format(here, offset) msg += f" Tag Location: {here} - Data Location: {offset}"
fp.seek(offset) fp.seek(offset)
data = ImageFile._safe_read(fp, size) data = ImageFile._safe_read(fp, size)
fp.seek(here) fp.seek(here)
@ -764,8 +764,8 @@ class ImageFileDirectory_v2(MutableMapping):
if len(data) != size: if len(data) != size:
warnings.warn( warnings.warn(
"Possibly corrupt EXIF data. " "Possibly corrupt EXIF data. "
"Expecting to read %d bytes but only got %d." f"Expecting to read {size} bytes but only got {len(data)}."
" Skipping tag %s" % (size, len(data), tag) f" Skipping tag {tag}"
) )
logger.debug(msg) logger.debug(msg)
continue continue
@ -801,13 +801,13 @@ class ImageFileDirectory_v2(MutableMapping):
if tag == STRIPOFFSETS: if tag == STRIPOFFSETS:
stripoffsets = len(entries) stripoffsets = len(entries)
typ = self.tagtype.get(tag) typ = self.tagtype.get(tag)
logger.debug("Tag {}, Type: {}, Value: {}".format(tag, typ, value)) logger.debug(f"Tag {tag}, Type: {typ}, Value: {value}")
values = value if isinstance(value, tuple) else (value,) values = value if isinstance(value, tuple) else (value,)
data = self._write_dispatch[typ](self, *values) data = self._write_dispatch[typ](self, *values)
tagname = TiffTags.lookup(tag).name tagname = TiffTags.lookup(tag).name
typname = TYPES.get(typ, "unknown") typname = 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: " + ( msg += " - value: " + (
"<table: %d bytes>" % len(data) if len(data) >= 16 else str(values) "<table: %d bytes>" % len(data) if len(data) >= 16 else str(values)
) )
@ -835,9 +835,7 @@ class ImageFileDirectory_v2(MutableMapping):
# pass 2: write entries to file # pass 2: write entries to file
for tag, typ, count, value, data in entries: for tag, typ, count, value, data in entries:
logger.debug( logger.debug(f"{tag} {typ} {count} {repr(value)} {repr(data)}")
"{} {} {} {} {}".format(tag, typ, count, repr(value), repr(data))
)
result += self._pack("HHL4s", tag, typ, count, value) result += self._pack("HHL4s", tag, typ, count, value)
# -- overwrite here for multi-page -- # -- overwrite here for multi-page --
@ -1002,8 +1000,8 @@ class TiffImageFile(ImageFile.ImageFile):
self._n_frames = None self._n_frames = None
logger.debug("*** TiffImageFile._open ***") logger.debug("*** TiffImageFile._open ***")
logger.debug("- __first: {}".format(self.__first)) logger.debug(f"- __first: {self.__first}")
logger.debug("- ifh: {!r}".format(ifh)) # Use !r to avoid str(bytes) logger.debug(f"- ifh: {repr(ifh)}") # Use repr to avoid str(bytes)
# and load the first frame # and load the first frame
self._seek(0) self._seek(0)
@ -1035,8 +1033,8 @@ class TiffImageFile(ImageFile.ImageFile):
if not self.__next: if not self.__next:
raise EOFError("no more images in TIFF file") raise EOFError("no more images in TIFF file")
logger.debug( logger.debug(
"Seeking to frame %s, on frame %s, __next %s, location: %s" f"Seeking to frame {frame}, on frame {self.__frame}, "
% (frame, self.__frame, self.__next, self.fp.tell()) f"__next {self.__next}, location: {self.fp.tell()}"
) )
# reset buffered io handle in case fp # reset buffered io handle in case fp
# was passed to libtiff, invalidating the buffer # was passed to libtiff, invalidating the buffer
@ -1193,18 +1191,18 @@ class TiffImageFile(ImageFile.ImageFile):
fillorder = self.tag_v2.get(FILLORDER, 1) fillorder = self.tag_v2.get(FILLORDER, 1)
logger.debug("*** Summary ***") logger.debug("*** Summary ***")
logger.debug("- compression: {}".format(self._compression)) logger.debug(f"- compression: {self._compression}")
logger.debug("- photometric_interpretation: {}".format(photo)) logger.debug(f"- photometric_interpretation: {photo}")
logger.debug("- planar_configuration: {}".format(self._planar_configuration)) logger.debug(f"- planar_configuration: {self._planar_configuration}")
logger.debug("- fill_order: {}".format(fillorder)) logger.debug(f"- fill_order: {fillorder}")
logger.debug("- YCbCr subsampling: {}".format(self.tag.get(530))) logger.debug(f"- YCbCr subsampling: {self.tag.get(530)}")
# size # size
xsize = int(self.tag_v2.get(IMAGEWIDTH)) xsize = int(self.tag_v2.get(IMAGEWIDTH))
ysize = int(self.tag_v2.get(IMAGELENGTH)) ysize = int(self.tag_v2.get(IMAGELENGTH))
self._size = xsize, ysize self._size = xsize, ysize
logger.debug("- size: {}".format(self.size)) logger.debug(f"- size: {self.size}")
sampleFormat = self.tag_v2.get(SAMPLEFORMAT, (1,)) sampleFormat = self.tag_v2.get(SAMPLEFORMAT, (1,))
if len(sampleFormat) > 1 and max(sampleFormat) == min(sampleFormat) == 1: if len(sampleFormat) > 1 and max(sampleFormat) == min(sampleFormat) == 1:
@ -1238,15 +1236,15 @@ class TiffImageFile(ImageFile.ImageFile):
bps_tuple, bps_tuple,
extra_tuple, extra_tuple,
) )
logger.debug("format key: {}".format(key)) logger.debug(f"format key: {key}")
try: try:
self.mode, rawmode = OPEN_INFO[key] self.mode, rawmode = OPEN_INFO[key]
except KeyError as e: except KeyError as e:
logger.debug("- unsupported format") logger.debug("- unsupported format")
raise SyntaxError("unknown pixel mode") from e raise SyntaxError("unknown pixel mode") from e
logger.debug("- raw mode: {}".format(rawmode)) logger.debug(f"- raw mode: {rawmode}")
logger.debug("- pil mode: {}".format(self.mode)) logger.debug(f"- pil mode: {self.mode}")
self.info["compression"] = self._compression self.info["compression"] = self._compression
@ -1287,7 +1285,7 @@ class TiffImageFile(ImageFile.ImageFile):
if fillorder == 2: if fillorder == 2:
# Replace fillorder with fillorder=1 # Replace fillorder with fillorder=1
key = key[:3] + (1,) + key[4:] 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 # this should always work, since all the
# fillorder==2 modes have a corresponding # fillorder==2 modes have a corresponding
# fillorder=1 mode # fillorder=1 mode
@ -1411,7 +1409,7 @@ def _save(im, fp, filename):
try: try:
rawmode, prefix, photo, format, bits, extra = SAVE_INFO[im.mode] rawmode, prefix, photo, format, bits, extra = SAVE_INFO[im.mode]
except KeyError as e: 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) ifd = ImageFileDirectory_v2(prefix=prefix)
@ -1608,7 +1606,7 @@ def _save(im, fp, filename):
if s: if s:
break break
if s < 0: if s < 0:
raise OSError("encoder error %d when writing image file" % s) raise OSError(f"encoder error {s} when writing image file")
else: else:
offset = ifd.save(fp) offset = ifd.save(fp)
@ -1774,29 +1772,29 @@ class AppendingTiffWriter:
self.f.seek(-2, os.SEEK_CUR) self.f.seek(-2, os.SEEK_CUR)
bytesWritten = self.f.write(struct.pack(self.longFmt, value)) bytesWritten = self.f.write(struct.pack(self.longFmt, value))
if bytesWritten is not None and bytesWritten != 4: 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): def rewriteLastShort(self, value):
self.f.seek(-2, os.SEEK_CUR) self.f.seek(-2, os.SEEK_CUR)
bytesWritten = self.f.write(struct.pack(self.shortFmt, value)) bytesWritten = self.f.write(struct.pack(self.shortFmt, value))
if bytesWritten is not None and bytesWritten != 2: 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): def rewriteLastLong(self, value):
self.f.seek(-4, os.SEEK_CUR) self.f.seek(-4, os.SEEK_CUR)
bytesWritten = self.f.write(struct.pack(self.longFmt, value)) bytesWritten = self.f.write(struct.pack(self.longFmt, value))
if bytesWritten is not None and bytesWritten != 4: 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): def writeShort(self, value):
bytesWritten = self.f.write(struct.pack(self.shortFmt, value)) bytesWritten = self.f.write(struct.pack(self.shortFmt, value))
if bytesWritten is not None and bytesWritten != 2: 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): def writeLong(self, value):
bytesWritten = self.f.write(struct.pack(self.longFmt, value)) bytesWritten = self.f.write(struct.pack(self.longFmt, value))
if bytesWritten is not None and bytesWritten != 4: 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): def close(self):
self.finalize() self.finalize()

View File

@ -69,15 +69,15 @@ class XbmImageFile(ImageFile.ImageFile):
def _save(im, fp, filename): def _save(im, fp, filename):
if im.mode != "1": 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(f"#define im_width {im.size[0]}\n".encode("ascii"))
fp.write(("#define im_height %d\n" % im.size[1]).encode("ascii")) fp.write(f"#define im_height {im.size[1]}\n".encode("ascii"))
hotspot = im.encoderinfo.get("hotspot") hotspot = im.encoderinfo.get("hotspot")
if hotspot: if hotspot:
fp.write(("#define im_x_hot %d\n" % hotspot[0]).encode("ascii")) fp.write(f"#define im_x_hot {hotspot[0]}\n".encode("ascii"))
fp.write(("#define im_y_hot %d\n" % hotspot[1]).encode("ascii")) fp.write(f"#define im_y_hot {hotspot[1]}\n".encode("ascii"))
fp.write(b"static char im_bits[] = {\n") fp.write(b"static char im_bits[] = {\n")

View File

@ -39,7 +39,7 @@ if sys.version_info >= (3, 7):
if name == "PILLOW_VERSION": if name == "PILLOW_VERSION":
_raise_version_warning() _raise_version_warning()
return __version__ return __version__
raise AttributeError("module '{}' has no attribute '{}'".format(__name__, name)) raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
else: else:

View File

@ -25,7 +25,7 @@ def check_module(feature):
:raises ValueError: If the module is not defined in this version of Pillow. :raises ValueError: If the module is not defined in this version of Pillow.
""" """
if not (feature in modules): if not (feature in modules):
raise ValueError("Unknown module %s" % feature) raise ValueError(f"Unknown module {feature}")
module, ver = modules[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. :raises ValueError: If the codec is not defined in this version of Pillow.
""" """
if feature not in codecs: if feature not in codecs:
raise ValueError("Unknown codec %s" % feature) raise ValueError(f"Unknown codec {feature}")
codec, lib = codecs[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. :raises ValueError: If the feature is not defined in this version of Pillow.
""" """
if feature not in features: if feature not in features:
raise ValueError("Unknown feature %s" % feature) raise ValueError(f"Unknown feature {feature}")
module, flag, ver = features[feature] module, flag, ver = features[feature]
@ -182,7 +182,7 @@ def check(feature):
return check_codec(feature) return check_codec(feature)
if feature in features: if feature in features:
return check_feature(feature) return check_feature(feature)
warnings.warn("Unknown feature '%s'." % feature, stacklevel=2) warnings.warn(f"Unknown feature '{feature}'.", stacklevel=2)
return False return False
@ -230,19 +230,17 @@ def pilinfo(out=None, supported_formats=True):
Image.init() Image.init()
print("-" * 68, file=out) print("-" * 68, file=out)
print("Pillow {}".format(PIL.__version__), file=out) print(f"Pillow {PIL.__version__}", file=out)
py_version = sys.version.splitlines() 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:]: 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("-" * 68, file=out)
print( print(
"Python modules loaded from {}".format(os.path.dirname(Image.__file__)), f"Python modules loaded from {os.path.dirname(Image.__file__)}", file=out,
file=out,
) )
print( 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,
file=out,
) )
print("-" * 68, file=out) print("-" * 68, file=out)
@ -283,9 +281,9 @@ def pilinfo(out=None, supported_formats=True):
extensions[i].append(ext) extensions[i].append(ext)
for i in sorted(Image.ID): for i in sorted(Image.ID):
line = "{}".format(i) line = f"{i}"
if i in Image.MIME: if i in Image.MIME:
line = "{} {}".format(line, Image.MIME[i]) line = f"{line} {Image.MIME[i]}"
print(line, file=out) print(line, file=out)
if i in extensions: if i in extensions:

View File

@ -417,7 +417,7 @@ def build_dep(name):
for patch_file, patch_list in dep.get("patch", {}).items(): for patch_file, patch_list in dep.get("patch", {}).items():
patch_file = os.path.join(build_dir, dir, patch_file.format(**prefs)) patch_file = os.path.join(build_dir, dir, patch_file.format(**prefs))
with open(patch_file, "r") as f: with open(patch_file) as f:
text = f.read() text = f.read()
for patch_from, patch_to in patch_list.items(): for patch_from, patch_to in patch_list.items():
text = text.replace(patch_from.format(**prefs), patch_to.format(**prefs)) text = text.replace(patch_from.format(**prefs), patch_to.format(**prefs))