Add PERF to lint and fix findings (#9510)

This commit is contained in:
Andrew Murray 2026-03-28 21:56:07 +11:00 committed by GitHub
commit b62ff96779
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 50 additions and 69 deletions

View File

@ -56,7 +56,7 @@ def test_questionable() -> None:
im.load()
if os.path.basename(f) not in supported:
print(f"Please add {f} to the partially supported bmp specs.")
except Exception: # as msg:
except Exception: # noqa: PERF203
if os.path.basename(f) in supported:
raise
@ -106,7 +106,7 @@ def test_good() -> None:
assert_image_similar(im_converted, compare_converted, 5)
except Exception as msg:
except Exception as msg: # noqa: PERF203
# there are three here that are unsupported:
unsupported = (
os.path.join(base, "g", "rgb32bf.bmp"),

View File

@ -179,9 +179,7 @@ def test_iter(bytesmode: bool) -> None:
container = ContainerIO.ContainerIO(fh, 0, 120)
# Act
data = []
for line in container:
data.append(line)
data = list(container)
# Assert
if bytesmode:

View File

@ -224,10 +224,7 @@ class TestFileLibTiff(LibTiffTestCase):
with Image.open("Tests/images/hopper_g4.tif") as im:
assert isinstance(im, TiffImagePlugin.TiffImageFile)
for tag in im.tag_v2:
try:
del core_items[tag]
except KeyError:
pass
core_items.pop(tag, None)
del core_items[320] # colormap is special, tested below
# Type codes:

View File

@ -146,6 +146,7 @@ lint.select = [
"I", # isort
"ISC", # flake8-implicit-str-concat
"LOG", # flake8-logging
"PERF", # perflint
"PGH", # pygrep-hooks
"PIE", # flake8-pie
"PT", # flake8-pytest-style

View File

@ -302,7 +302,7 @@ def _pkg_config(name: str) -> tuple[list[str], list[str]] | None:
subprocess.check_output(command_cflags).decode("utf8").strip(),
)[::2][1:]
return libs, cflags
except Exception:
except Exception: # noqa: PERF203
pass
return None
@ -1078,10 +1078,10 @@ libraries: list[tuple[str, _BuildInfo]] = [
]
files: list[str | os.PathLike[str]] = ["src/_imaging.c"]
for src_file in _IMAGING:
files.append("src/" + src_file + ".c")
for src_file in _LIB_IMAGING:
files.append(os.path.join("src/libImaging", src_file + ".c"))
files.extend("src/" + src_file + ".c" for src_file in _IMAGING)
files.extend(
os.path.join("src/libImaging", src_file + ".c") for src_file in _LIB_IMAGING
)
ext_modules = [
Extension("PIL._imaging", files),
Extension("PIL._imagingft", ["src/_imagingft.c"]),

View File

@ -164,13 +164,13 @@ class GifImageFile(ImageFile.ImageFile):
self._seek(0)
last_frame = self.__frame
for f in range(self.__frame + 1, frame + 1):
try:
try:
for f in range(self.__frame + 1, frame + 1):
self._seek(f)
except EOFError as e:
self.seek(last_frame)
msg = "no more images in GIF file"
raise EOFError(msg) from e
except EOFError as e:
self.seek(last_frame)
msg = "no more images in GIF file"
raise EOFError(msg) from e
def _seek(self, frame: int, update_image: bool = True) -> None:
if isinstance(self._fp, DeferredError):

View File

@ -80,8 +80,7 @@ def read_32(
if byte_int & 0x80:
blocksize = byte_int - 125
byte = fobj.read(1)
for i in range(blocksize):
data.append(byte)
data.extend([byte] * blocksize)
else:
blocksize = byte_int + 1
data.append(fobj.read(blocksize))

View File

@ -488,7 +488,7 @@ def init() -> bool:
try:
logger.debug("Importing %s", plugin)
__import__(f"{__spec__.parent}.{plugin}", globals(), locals(), [])
except ImportError as e:
except ImportError as e: # noqa: PERF203
logger.debug("Image: failed to import %s: %s", plugin, e)
if OPEN or SAVE:

View File

@ -597,9 +597,7 @@ class ImageDraw:
mode = self.fontmode
if stroke_width == 0 and embedded_color:
mode = "RGBA"
coord = []
for i in range(2):
coord.append(int(xy[i]))
coord = [int(xy[i]) for i in range(2)]
start = (math.modf(xy[0])[0], math.modf(xy[1])[0])
try:
mask, offset = image_text.font.getmask2( # type: ignore[union-attr,misc]

View File

@ -215,8 +215,10 @@ class ImageFile(Image.Image):
if subifd_offsets:
if not isinstance(subifd_offsets, tuple):
subifd_offsets = (subifd_offsets,)
for subifd_offset in subifd_offsets:
ifds.append((exif._get_ifd_dict(subifd_offset), subifd_offset))
ifds = [
(exif._get_ifd_dict(subifd_offset), subifd_offset)
for subifd_offset in subifd_offsets
]
ifd1 = exif.get_ifd(ExifTags.IFD.IFD1)
if ifd1 and ifd1.get(ExifTags.Base.JpegIFOffset):
assert exif._info is not None

View File

@ -930,7 +930,7 @@ def load_path(filename: str | bytes) -> ImageFont:
for directory in sys.path:
try:
return load(os.path.join(directory, filename))
except OSError:
except OSError: # noqa: PERF203
pass
msg = f'cannot find font file "{filename}" in sys.path'
if os.path.exists(filename):

View File

@ -198,13 +198,11 @@ class ImagePalette:
try:
fp.write("# Palette\n")
fp.write(f"# Mode: {self.mode}\n")
palette_len = len(self.palette)
for i in range(256):
fp.write(f"{i}")
for j in range(i * len(self.mode), (i + 1) * len(self.mode)):
try:
fp.write(f" {self.palette[j]}")
except IndexError:
fp.write(" 0")
fp.write(f" {self.palette[j] if j < palette_len else 0}")
fp.write("\n")
finally:
if open_fp:

View File

@ -185,13 +185,9 @@ def getiptcinfo(
data = None
info: dict[tuple[int, int], bytes | list[bytes]] = {}
if isinstance(im, IptcImageFile):
# return info dictionary right away
for k, v in im.info.items():
if isinstance(k, tuple):
info[k] = v
return info
return {k: v for k, v in im.info.items() if isinstance(k, tuple)}
elif isinstance(im, JpegImagePlugin.JpegImageFile):
# extract the IPTC/NAA resource
@ -227,7 +223,4 @@ def getiptcinfo(
except (IndexError, KeyError):
pass # expected failure
for k, v in iptc_im.info.items():
if isinstance(k, tuple):
info[k] = v
return info
return {k: v for k, v in iptc_im.info.items() if isinstance(k, tuple)}

View File

@ -127,8 +127,8 @@ def APP(self: JpegImageFile, marker: int) -> None:
# parse the image resource block
offset = 14
photoshop = self.info.setdefault("photoshop", {})
while s[offset : offset + 4] == b"8BIM":
try:
try:
while s[offset : offset + 4] == b"8BIM":
offset += 4
# resource code
code = i16(s, offset)
@ -153,8 +153,8 @@ def APP(self: JpegImageFile, marker: int) -> None:
photoshop[code] = data
offset += size
offset += offset & 1 # align
except struct.error:
break # insufficient data
except struct.error:
pass # insufficient data
elif marker == 0xFFEE and s.startswith(b"Adobe"):
self.info["adobe"] = i16(s, 5)
@ -738,17 +738,15 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
if not (0 < len(qtables) < 5):
msg = "None or too many quantization tables"
raise ValueError(msg)
for idx, table in enumerate(qtables):
try:
try:
for idx, table in enumerate(qtables):
if len(table) != 64:
msg = "Invalid quantization table"
raise TypeError(msg)
table_array = array.array("H", table)
except TypeError as e:
msg = "Invalid quantization table"
raise ValueError(msg) from e
else:
qtables[idx] = list(table_array)
qtables[idx] = list(array.array("H", table))
except TypeError as e:
msg = "Invalid quantization table"
raise ValueError(msg) from e
return qtables
if qtables == "keep":

View File

@ -251,7 +251,7 @@ class PcfFontFile(FontFile.FontFile):
]
if encoding_offset != 0xFFFF:
encoding[i] = encoding_offset
except UnicodeDecodeError:
except UnicodeDecodeError: # noqa: PERF203
# character is not supported in selected encoding
pass

View File

@ -866,13 +866,13 @@ class PngImageFile(ImageFile.ImageFile):
self._seek(0, True)
last_frame = self.__frame
for f in range(self.__frame + 1, frame + 1):
try:
try:
for f in range(self.__frame + 1, frame + 1):
self._seek(f)
except EOFError as e:
self.seek(last_frame)
msg = "no more images in APNG file"
raise EOFError(msg) from e
except EOFError as e:
self.seek(last_frame)
msg = "no more images in APNG file"
raise EOFError(msg) from e
def _seek(self, frame: int, rewind: bool = False) -> None:
assert self.png is not None

View File

@ -542,14 +542,11 @@ def write_script(
def get_footer(dep: dict[str, Any]) -> list[str]:
lines = []
for out in dep.get("headers", []):
lines.append(cmd_copy(out, "{inc_dir}"))
for out in dep.get("libs", []):
lines.append(cmd_copy(out, "{lib_dir}"))
for out in dep.get("bins", []):
lines.append(cmd_copy(out, "{bin_dir}"))
return lines
return (
[cmd_copy(out, "{inc_dir}") for out in dep.get("headers", [])]
+ [cmd_copy(out, "{lib_dir}") for out in dep.get("libs", [])]
+ [cmd_copy(out, "{bin_dir}") for out in dep.get("bins", [])]
)
def build_env(prefs: dict[str, str], verbose: bool) -> None: