Coverage for src/lektor_ng/imagetools/_compat.py: 65%

20 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-08-31 01:21 +0000

1"""Compatibility with various versions of Pillow.""" 

2 

3from __future__ import annotations 

4 

5from collections.abc import Iterable, Mapping 

6from enum import IntEnum 

7from types import ModuleType, SimpleNamespace 

8 

9import PIL.ExifTags 

10import PIL.Image 

11 

12__all__ = ["ExifTags", "Transpose", "UnidentifiedImageError"] 

13 

14PILLOW_VERSION_INFO = tuple(map(int, PIL.__version__.split("."))) 

15 

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. 

21 

22 def _reverse_map(mapping: Mapping[int, str]) -> dict[str, int]: 

23 return dict(map(reversed, mapping.items())) # type: ignore[arg-type] 

24 

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 ) 

32 

33 

34if hasattr(PIL.Image, "Transpose"): 

35 # pillow >= 9.1 

36 Transpose = PIL.Image.Transpose 

37else: 

38 

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) 

42 

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 ) 

55 

56 

57# UnidentifiedImageError only exists in Pillow >= 7.0.0 

58UnidentifiedImageError = getattr(PIL, "UnidentifiedImageError", OSError)