Coverage for src/lektor_ng/imagetools/_compat.py: 65%
20 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-08-09 00:28 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-08-09 00:28 +0000
1"""Compatibility with various versions of Pillow."""
3from __future__ import annotations
5from collections.abc import Iterable, Mapping
6from enum import IntEnum
7from types import ModuleType, SimpleNamespace
9import PIL.ExifTags
10import PIL.Image
12__all__ = ["ExifTags", "Transpose", "UnidentifiedImageError"]
14PILLOW_VERSION_INFO = tuple(map(int, PIL.__version__.split(".")))
16if PILLOW_VERSION_INFO >= (9, 4):
17 ExifTags: ModuleType | SimpleNamespace = PIL.ExifTags
18else:
19 # Pillow < 9.4 does not provide the PIL.ExifTags.{Base,GPS,IFD} enums. Here we
20 # provide and ExifTags namespace which has them.
22 def _reverse_map(mapping: Mapping[int, str]) -> dict[str, int]:
23 return dict(map(reversed, mapping.items())) # type: ignore[arg-type]
25 ExifTags = SimpleNamespace(
26 Base=IntEnum("Base", _reverse_map(PIL.ExifTags.TAGS)),
27 GPS=IntEnum("GPS", _reverse_map(PIL.ExifTags.GPSTAGS)),
28 IFD=IntEnum("IFD", [("Exif", 34665), ("GPSInfo", 34853)]),
29 TAGS=PIL.ExifTags.TAGS,
30 GPSTAGS=PIL.ExifTags.GPSTAGS,
31 )
34if hasattr(PIL.Image, "Transpose"):
35 # pillow >= 9.1
36 Transpose = PIL.Image.Transpose
37else:
39 def _make_enum(name: str, members: Iterable[str]) -> IntEnum:
40 items = ((member, getattr(PIL.Image, member)) for member in members)
41 return IntEnum(name, items)
43 Transpose = _make_enum( # type: ignore[misc, assignment]
44 "Transpose",
45 (
46 "FLIP_LEFT_RIGHT",
47 "FLIP_TOP_BOTTOM",
48 "ROTATE_90",
49 "ROTATE_180",
50 "ROTATE_270",
51 "TRANSPOSE",
52 "TRANSVERSE",
53 ),
54 )
57# UnidentifiedImageError only exists in Pillow >= 7.0.0
58UnidentifiedImageError = getattr(PIL, "UnidentifiedImageError", OSError)