Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve exception traceback readability #6836

Merged
merged 3 commits into from Dec 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion .pre-commit-config.yaml
Expand Up @@ -35,7 +35,8 @@ repos:
rev: 6.0.0
hooks:
- id: flake8
additional_dependencies: [flake8-2020, flake8-implicit-str-concat]
additional_dependencies:
[flake8-2020, flake8-errmsg, flake8-implicit-str-concat]

- repo: https://github.com/pre-commit/pygrep-hooks
rev: v1.9.0
Expand Down
18 changes: 12 additions & 6 deletions docs/example/DdsImagePlugin.py
Expand Up @@ -211,13 +211,16 @@ class DdsImageFile(ImageFile.ImageFile):

def _open(self):
if not _accept(self.fp.read(4)):
raise SyntaxError("not a DDS file")
msg = "not a DDS file"
raise SyntaxError(msg)
(header_size,) = struct.unpack("<I", self.fp.read(4))
if header_size != 124:
raise OSError(f"Unsupported header size {repr(header_size)}")
msg = f"Unsupported header size {repr(header_size)}"
raise OSError(msg)
header_bytes = self.fp.read(header_size - 4)
if len(header_bytes) != 120:
raise OSError(f"Incomplete header: {len(header_bytes)} bytes")
msg = f"Incomplete header: {len(header_bytes)} bytes"
raise OSError(msg)
header = BytesIO(header_bytes)

flags, height, width = struct.unpack("<3I", header.read(12))
Expand All @@ -237,7 +240,8 @@ def _open(self):
elif fourcc == b"DXT5":
self.decoder = "DXT5"
else:
raise NotImplementedError(f"Unimplemented pixel format {fourcc}")
msg = f"Unimplemented pixel format {fourcc}"
raise NotImplementedError(msg)

self.tile = [(self.decoder, (0, 0) + self.size, 0, (self.mode, 0, 1))]

Expand All @@ -252,7 +256,8 @@ def decode(self, buffer):
try:
self.set_as_raw(_dxt1(self.fd, self.state.xsize, self.state.ysize))
except struct.error as e:
raise OSError("Truncated DDS file") from e
msg = "Truncated DDS file"
raise OSError(msg) from e
return -1, 0


Expand All @@ -263,7 +268,8 @@ def decode(self, buffer):
try:
self.set_as_raw(_dxt5(self.fd, self.state.xsize, self.state.ysize))
except struct.error as e:
raise OSError("Truncated DDS file") from e
msg = "Truncated DDS file"
raise OSError(msg) from e
return -1, 0


Expand Down
3 changes: 2 additions & 1 deletion docs/handbook/writing-your-own-image-plugin.rst
Expand Up @@ -78,7 +78,8 @@ true color.
elif bits == 24:
self.mode = "RGB"
else:
raise SyntaxError("unknown number of bits")
msg = "unknown number of bits"
raise SyntaxError(msg)

# data descriptor
self.tile = [("raw", (0, 0) + self.size, 128, (self.mode, 0, 1))]
Expand Down
18 changes: 8 additions & 10 deletions setup.py
Expand Up @@ -362,15 +362,15 @@ def finalize_options(self):
self.feature.required.discard(x)
_dbg("Disabling %s", x)
if getattr(self, f"enable_{x}"):
raise ValueError(
f"Conflicting options: --enable-{x} and --disable-{x}"
)
msg = f"Conflicting options: --enable-{x} and --disable-{x}"
raise ValueError(msg)
if x == "freetype":
_dbg("--disable-freetype implies --disable-raqm")
if getattr(self, "enable_raqm"):
raise ValueError(
msg = (
"Conflicting options: --enable-raqm and --disable-freetype"
)
raise ValueError(msg)
setattr(self, "disable_raqm", True)
if getattr(self, f"enable_{x}"):
_dbg("Requiring %s", x)
Expand All @@ -381,13 +381,11 @@ def finalize_options(self):
for x in ("raqm", "fribidi"):
if getattr(self, f"vendor_{x}"):
if getattr(self, "disable_raqm"):
raise ValueError(
f"Conflicting options: --vendor-{x} and --disable-raqm"
)
msg = f"Conflicting options: --vendor-{x} and --disable-raqm"
raise ValueError(msg)
if x == "fribidi" and not getattr(self, "vendor_raqm"):
raise ValueError(
f"Conflicting options: --vendor-{x} and not --vendor-raqm"
)
msg = f"Conflicting options: --vendor-{x} and not --vendor-raqm"
raise ValueError(msg)
_dbg("Using vendored version of %s", x)
self.feature.vendor.add(x)

Expand Down
3 changes: 2 additions & 1 deletion src/PIL/BdfFontFile.py
Expand Up @@ -86,7 +86,8 @@ def __init__(self, fp):

s = fp.readline()
if s[:13] != b"STARTFONT 2.1":
raise SyntaxError("not a valid BDF file")
msg = "not a valid BDF file"
raise SyntaxError(msg)

props = {}
comments = []
Expand Down
35 changes: 18 additions & 17 deletions src/PIL/BlpImagePlugin.py
Expand Up @@ -65,7 +65,8 @@ def __getattr__(name):
if name in enum.__members__:
deprecate(f"{prefix}{name}", 10, f"{enum.__name__}.{name}")
return enum[name]
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
msg = f"module '{__name__}' has no attribute '{name}'"
raise AttributeError(msg)


def unpack_565(i):
Expand Down Expand Up @@ -278,7 +279,8 @@ def _open(self):
if self.magic in (b"BLP1", b"BLP2"):
decoder = self.magic.decode()
else:
raise BLPFormatError(f"Bad BLP magic {repr(self.magic)}")
msg = f"Bad BLP magic {repr(self.magic)}"
raise BLPFormatError(msg)

self.mode = "RGBA" if self._blp_alpha_depth else "RGB"
self.tile = [(decoder, (0, 0) + self.size, 0, (self.mode, 0, 1))]
Expand All @@ -292,7 +294,8 @@ def decode(self, buffer):
self._read_blp_header()
self._load()
except struct.error as e:
raise OSError("Truncated BLP file") from e
msg = "Truncated BLP file"
raise OSError(msg) from e
return -1, 0

def _read_blp_header(self):
Expand Down Expand Up @@ -354,13 +357,11 @@ def _load(self):
data = self._read_bgra(palette)
self.set_as_raw(bytes(data))
else:
raise BLPFormatError(
f"Unsupported BLP encoding {repr(self._blp_encoding)}"
)
msg = f"Unsupported BLP encoding {repr(self._blp_encoding)}"
raise BLPFormatError(msg)
else:
raise BLPFormatError(
f"Unsupported BLP compression {repr(self._blp_encoding)}"
)
msg = f"Unsupported BLP compression {repr(self._blp_encoding)}"
raise BLPFormatError(msg)

def _decode_jpeg_stream(self):
from .JpegImagePlugin import JpegImageFile
Expand Down Expand Up @@ -415,16 +416,15 @@ def _load(self):
for d in decode_dxt5(self._safe_read(linesize)):
data += d
else:
raise BLPFormatError(
f"Unsupported alpha encoding {repr(self._blp_alpha_encoding)}"
)
msg = f"Unsupported alpha encoding {repr(self._blp_alpha_encoding)}"
raise BLPFormatError(msg)
else:
raise BLPFormatError(f"Unknown BLP encoding {repr(self._blp_encoding)}")
msg = f"Unknown BLP encoding {repr(self._blp_encoding)}"
raise BLPFormatError(msg)

else:
raise BLPFormatError(
f"Unknown BLP compression {repr(self._blp_compression)}"
)
msg = f"Unknown BLP compression {repr(self._blp_compression)}"
raise BLPFormatError(msg)

self.set_as_raw(bytes(data))

Expand Down Expand Up @@ -460,7 +460,8 @@ def encode(self, bufsize):

def _save(im, fp, filename, save_all=False):
if im.mode != "P":
raise ValueError("Unsupported BLP image mode")
msg = "Unsupported BLP image mode"
raise ValueError(msg)

magic = b"BLP1" if im.encoderinfo.get("blp_version") == "BLP1" else b"BLP2"
fp.write(magic)
Expand Down
27 changes: 18 additions & 9 deletions src/PIL/BmpImagePlugin.py
Expand Up @@ -146,7 +146,8 @@ def _bitmap(self, header=0, offset=0):
file_info["a_mask"],
)
else:
raise OSError(f"Unsupported BMP header type ({file_info['header_size']})")
msg = f"Unsupported BMP header type ({file_info['header_size']})"
raise OSError(msg)

# ------------------ Special case : header is reported 40, which
# ---------------------- is shorter than real size for bpp >= 16
Expand All @@ -164,7 +165,8 @@ def _bitmap(self, header=0, offset=0):
# ---------------------- Check bit depth for unusual unsupported values
self.mode, raw_mode = BIT2MODE.get(file_info["bits"], (None, None))
if self.mode is None:
raise OSError(f"Unsupported BMP pixel depth ({file_info['bits']})")
msg = f"Unsupported BMP pixel depth ({file_info['bits']})"
raise OSError(msg)

# ---------------- Process BMP with Bitfields compression (not palette)
decoder_name = "raw"
Expand Down Expand Up @@ -205,23 +207,27 @@ def _bitmap(self, header=0, offset=0):
):
raw_mode = MASK_MODES[(file_info["bits"], file_info["rgb_mask"])]
else:
raise OSError("Unsupported BMP bitfields layout")
msg = "Unsupported BMP bitfields layout"
raise OSError(msg)
else:
raise OSError("Unsupported BMP bitfields layout")
msg = "Unsupported BMP bitfields layout"
raise OSError(msg)
elif file_info["compression"] == self.RAW:
if file_info["bits"] == 32 and header == 22: # 32-bit .cur offset
raw_mode, self.mode = "BGRA", "RGBA"
elif file_info["compression"] in (self.RLE8, self.RLE4):
decoder_name = "bmp_rle"
else:
raise OSError(f"Unsupported BMP compression ({file_info['compression']})")
msg = f"Unsupported BMP compression ({file_info['compression']})"
raise OSError(msg)

# --------------- Once the header is processed, process the palette/LUT
if self.mode == "P": # Paletted for 1, 4 and 8 bit images

# ---------------------------------------------------- 1-bit images
if not (0 < file_info["colors"] <= 65536):
raise OSError(f"Unsupported BMP Palette size ({file_info['colors']})")
msg = f"Unsupported BMP Palette size ({file_info['colors']})"
raise OSError(msg)
else:
padding = file_info["palette_padding"]
palette = read(padding * file_info["colors"])
Expand Down Expand Up @@ -271,7 +277,8 @@ def _open(self):
head_data = self.fp.read(14)
# choke if the file does not have the required magic bytes
if not _accept(head_data):
raise SyntaxError("Not a BMP file")
msg = "Not a BMP file"
raise SyntaxError(msg)
# read the start position of the BMP image data (u32)
offset = i32(head_data, 10)
# load bitmap information (offset=raster info)
Expand Down Expand Up @@ -383,7 +390,8 @@ def _save(im, fp, filename, bitmap_header=True):
try:
rawmode, bits, colors = SAVE[im.mode]
except KeyError as e:
raise OSError(f"cannot write mode {im.mode} as BMP") from e
msg = f"cannot write mode {im.mode} as BMP"
raise OSError(msg) from e

info = im.encoderinfo

Expand Down Expand Up @@ -411,7 +419,8 @@ def _save(im, fp, filename, bitmap_header=True):
offset = 14 + header + colors * 4
file_size = offset + image
if file_size > 2**32 - 1:
raise ValueError("File size is too large for the BMP format")
msg = "File size is too large for the BMP format"
raise ValueError(msg)
fp.write(
b"BM" # file type (magic)
+ o32(file_size) # file size
Expand Down
6 changes: 4 additions & 2 deletions src/PIL/BufrStubImagePlugin.py
Expand Up @@ -42,7 +42,8 @@ def _open(self):
offset = self.fp.tell()

if not _accept(self.fp.read(4)):
raise SyntaxError("Not a BUFR file")
msg = "Not a BUFR file"
raise SyntaxError(msg)

self.fp.seek(offset)

Expand All @@ -60,7 +61,8 @@ def _load(self):

def _save(im, fp, filename):
if _handler is None or not hasattr(_handler, "save"):
raise OSError("BUFR save handler not installed")
msg = "BUFR save handler not installed"
raise OSError(msg)
_handler.save(im, fp, filename)


Expand Down
6 changes: 4 additions & 2 deletions src/PIL/CurImagePlugin.py
Expand Up @@ -43,7 +43,8 @@ def _open(self):
# check magic
s = self.fp.read(6)
if not _accept(s):
raise SyntaxError("not a CUR file")
msg = "not a CUR file"
raise SyntaxError(msg)

# pick the largest cursor in the file
m = b""
Expand All @@ -54,7 +55,8 @@ def _open(self):
elif s[0] > m[0] and s[1] > m[1]:
m = s
if not m:
raise TypeError("No cursors were found")
msg = "No cursors were found"
raise TypeError(msg)

# load as bitmap
self._bitmap(i32(m, 12) + offset)
Expand Down
3 changes: 2 additions & 1 deletion src/PIL/DcxImagePlugin.py
Expand Up @@ -47,7 +47,8 @@ def _open(self):
# Header
s = self.fp.read(4)
if not _accept(s):
raise SyntaxError("not a DCX file")
msg = "not a DCX file"
raise SyntaxError(msg)

# Component directory
self._offset = []
Expand Down
20 changes: 12 additions & 8 deletions src/PIL/DdsImagePlugin.py
Expand Up @@ -114,13 +114,16 @@ class DdsImageFile(ImageFile.ImageFile):

def _open(self):
if not _accept(self.fp.read(4)):
raise SyntaxError("not a DDS file")
msg = "not a DDS file"
raise SyntaxError(msg)
(header_size,) = struct.unpack("<I", self.fp.read(4))
if header_size != 124:
raise OSError(f"Unsupported header size {repr(header_size)}")
msg = f"Unsupported header size {repr(header_size)}"
raise OSError(msg)
header_bytes = self.fp.read(header_size - 4)
if len(header_bytes) != 120:
raise OSError(f"Incomplete header: {len(header_bytes)} bytes")
msg = f"Incomplete header: {len(header_bytes)} bytes"
raise OSError(msg)
header = BytesIO(header_bytes)

flags, height, width = struct.unpack("<3I", header.read(12))
Expand Down Expand Up @@ -216,11 +219,11 @@ def _open(self):
self.info["gamma"] = 1 / 2.2
return
else:
raise NotImplementedError(
f"Unimplemented DXGI format {dxgi_format}"
)
msg = f"Unimplemented DXGI format {dxgi_format}"
raise NotImplementedError(msg)
else:
raise NotImplementedError(f"Unimplemented pixel format {repr(fourcc)}")
msg = f"Unimplemented pixel format {repr(fourcc)}"
raise NotImplementedError(msg)

self.tile = [
("bcn", (0, 0) + self.size, data_start, (n, self.pixel_format))
Expand All @@ -232,7 +235,8 @@ def load_seek(self, pos):

def _save(im, fp, filename):
if im.mode not in ("RGB", "RGBA", "L", "LA"):
raise OSError(f"cannot write mode {im.mode} as DDS")
msg = f"cannot write mode {im.mode} as DDS"
raise OSError(msg)

rawmode = im.mode
masks = [0xFF0000, 0xFF00, 0xFF]
Expand Down