Skip to content

Commit 293eb45

Browse files
committed
Exclude formats with ! when opening
1 parent 082cf04 commit 293eb45

2 files changed

Lines changed: 32 additions & 26 deletions

File tree

Tests/test_image.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,12 @@ def test_open_formats(self) -> None:
128128
assert im.mode == "RGB"
129129
assert im.size == (128, 128)
130130

131+
@pytest.mark.parametrize("formats", (("!PNG",), ("PNG", "!PNG")))
132+
def test_open_formats_exclude(self, formats: tuple[str]) -> None:
133+
with pytest.raises(UnidentifiedImageError):
134+
with Image.open("Tests/images/hopper.png", formats=formats):
135+
pass
136+
131137
def test_open_verbose_failure(self, monkeypatch: pytest.MonkeyPatch) -> None:
132138
monkeypatch.setattr(Image, "WARN_POSSIBLE_FORMATS", True)
133139

src/PIL/Image.py

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3598,11 +3598,15 @@ def open(
35983598
and be opened in binary mode. The file object will also seek to zero
35993599
before reading.
36003600
:param mode: The mode. If given, this argument must be "r".
3601-
:param formats: A list or tuple of formats to attempt to load the file in.
3602-
This can be used to restrict the set of formats checked.
3603-
Pass ``None`` to try all supported formats. You can print the set of
3604-
available formats by running ``python3 -m PIL`` or using
3605-
the :py:func:`PIL.features.pilinfo` function.
3601+
:param formats: A list or tuple of formats to attempt to load the file in, e.g.
3602+
("JPEG", "GIF"). This can be used to restrict the set of formats checked.
3603+
3604+
To exclude a format, start the format with "!", e.g. ("!EPS", "!PSD").
3605+
3606+
Pass ``None`` to try all supported formats.
3607+
3608+
You can print the set of available formats by running ``python3 -m PIL`` or
3609+
using the :py:func:`PIL.features.pilinfo` function.
36063610
:returns: An :py:class:`~PIL.Image.Image` object.
36073611
:exception FileNotFoundError: If the file cannot be found.
36083612
:exception PIL.UnidentifiedImageError: If the image cannot be opened and
@@ -3622,11 +3626,12 @@ def open(
36223626
)
36233627
raise ValueError(msg)
36243628

3625-
if formats is None:
3626-
formats = ID
3627-
elif not isinstance(formats, (list, tuple)):
3628-
msg = "formats must be a list or tuple" # type: ignore[unreachable]
3629-
raise TypeError(msg)
3629+
if formats is not None:
3630+
if not isinstance(formats, (list, tuple)):
3631+
msg = "formats must be a list or tuple" # type: ignore[unreachable]
3632+
raise TypeError(msg)
3633+
formats = tuple(format.upper() for format in formats)
3634+
exclude = all(format.startswith("!") for format in formats)
36303635

36313636
exclusive_fp = False
36323637
filename: str | bytes = ""
@@ -3657,12 +3662,15 @@ def _open_core(
36573662
fp: IO[bytes],
36583663
filename: str | bytes,
36593664
prefix: bytes,
3660-
formats: list[str] | tuple[str, ...],
3665+
check_formats: list[str],
36613666
) -> ImageFile.ImageFile | None:
3662-
for i in formats:
3663-
i = i.upper()
3664-
if i not in OPEN:
3665-
init()
3667+
for i in check_formats:
3668+
if formats is not None:
3669+
if exclude:
3670+
if "!" + i in formats:
3671+
continue
3672+
elif i not in formats or "!" + i in formats:
3673+
continue
36663674
try:
36673675
factory, accept = OPEN[i]
36683676
result = not accept or accept(prefix)
@@ -3682,21 +3690,13 @@ def _open_core(
36823690
raise
36833691
return None
36843692

3685-
im = _open_core(fp, filename, prefix, formats)
3686-
3687-
if im is None and formats is ID:
3693+
if im := _open_core(fp, filename, prefix, ID):
36883694
# Try preinit (few common plugins) then init (all plugins)
36893695
for loader in (preinit, init):
36903696
checked_formats = ID.copy()
36913697
loader()
3692-
if formats != checked_formats:
3693-
im = _open_core(
3694-
fp,
3695-
filename,
3696-
prefix,
3697-
tuple(f for f in formats if f not in checked_formats),
3698-
)
3699-
if im is not None:
3698+
if check_formats := [f for f in ID if f not in checked_formats]:
3699+
if im := _open_core(fp, filename, prefix, check_formats):
37003700
break
37013701

37023702
if im:

0 commit comments

Comments
 (0)