Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/pillow-10.4.0-py3.8-linux-x86_64.egg/PIL/features.py: 17%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

157 statements  

1from __future__ import annotations 

2 

3import collections 

4import os 

5import sys 

6import warnings 

7from typing import IO 

8 

9import PIL 

10 

11from . import Image 

12 

13modules = { 

14 "pil": ("PIL._imaging", "PILLOW_VERSION"), 

15 "tkinter": ("PIL._tkinter_finder", "tk_version"), 

16 "freetype2": ("PIL._imagingft", "freetype2_version"), 

17 "littlecms2": ("PIL._imagingcms", "littlecms_version"), 

18 "webp": ("PIL._webp", "webpdecoder_version"), 

19} 

20 

21 

22def check_module(feature: str) -> bool: 

23 """ 

24 Checks if a module is available. 

25 

26 :param feature: The module to check for. 

27 :returns: ``True`` if available, ``False`` otherwise. 

28 :raises ValueError: If the module is not defined in this version of Pillow. 

29 """ 

30 if feature not in modules: 

31 msg = f"Unknown module {feature}" 

32 raise ValueError(msg) 

33 

34 module, ver = modules[feature] 

35 

36 try: 

37 __import__(module) 

38 return True 

39 except ModuleNotFoundError: 

40 return False 

41 except ImportError as ex: 

42 warnings.warn(str(ex)) 

43 return False 

44 

45 

46def version_module(feature: str) -> str | None: 

47 """ 

48 :param feature: The module to check for. 

49 :returns: 

50 The loaded version number as a string, or ``None`` if unknown or not available. 

51 :raises ValueError: If the module is not defined in this version of Pillow. 

52 """ 

53 if not check_module(feature): 

54 return None 

55 

56 module, ver = modules[feature] 

57 

58 return getattr(__import__(module, fromlist=[ver]), ver) 

59 

60 

61def get_supported_modules() -> list[str]: 

62 """ 

63 :returns: A list of all supported modules. 

64 """ 

65 return [f for f in modules if check_module(f)] 

66 

67 

68codecs = { 

69 "jpg": ("jpeg", "jpeglib"), 

70 "jpg_2000": ("jpeg2k", "jp2klib"), 

71 "zlib": ("zip", "zlib"), 

72 "libtiff": ("libtiff", "libtiff"), 

73} 

74 

75 

76def check_codec(feature: str) -> bool: 

77 """ 

78 Checks if a codec is available. 

79 

80 :param feature: The codec to check for. 

81 :returns: ``True`` if available, ``False`` otherwise. 

82 :raises ValueError: If the codec is not defined in this version of Pillow. 

83 """ 

84 if feature not in codecs: 

85 msg = f"Unknown codec {feature}" 

86 raise ValueError(msg) 

87 

88 codec, lib = codecs[feature] 

89 

90 return f"{codec}_encoder" in dir(Image.core) 

91 

92 

93def version_codec(feature: str) -> str | None: 

94 """ 

95 :param feature: The codec to check for. 

96 :returns: 

97 The version number as a string, or ``None`` if not available. 

98 Checked at compile time for ``jpg``, run-time otherwise. 

99 :raises ValueError: If the codec is not defined in this version of Pillow. 

100 """ 

101 if not check_codec(feature): 

102 return None 

103 

104 codec, lib = codecs[feature] 

105 

106 version = getattr(Image.core, f"{lib}_version") 

107 

108 if feature == "libtiff": 

109 return version.split("\n")[0].split("Version ")[1] 

110 

111 return version 

112 

113 

114def get_supported_codecs() -> list[str]: 

115 """ 

116 :returns: A list of all supported codecs. 

117 """ 

118 return [f for f in codecs if check_codec(f)] 

119 

120 

121features = { 

122 "webp_anim": ("PIL._webp", "HAVE_WEBPANIM", None), 

123 "webp_mux": ("PIL._webp", "HAVE_WEBPMUX", None), 

124 "transp_webp": ("PIL._webp", "HAVE_TRANSPARENCY", None), 

125 "raqm": ("PIL._imagingft", "HAVE_RAQM", "raqm_version"), 

126 "fribidi": ("PIL._imagingft", "HAVE_FRIBIDI", "fribidi_version"), 

127 "harfbuzz": ("PIL._imagingft", "HAVE_HARFBUZZ", "harfbuzz_version"), 

128 "libjpeg_turbo": ("PIL._imaging", "HAVE_LIBJPEGTURBO", "libjpeg_turbo_version"), 

129 "libimagequant": ("PIL._imaging", "HAVE_LIBIMAGEQUANT", "imagequant_version"), 

130 "xcb": ("PIL._imaging", "HAVE_XCB", None), 

131} 

132 

133 

134def check_feature(feature: str) -> bool | None: 

135 """ 

136 Checks if a feature is available. 

137 

138 :param feature: The feature to check for. 

139 :returns: ``True`` if available, ``False`` if unavailable, ``None`` if unknown. 

140 :raises ValueError: If the feature is not defined in this version of Pillow. 

141 """ 

142 if feature not in features: 

143 msg = f"Unknown feature {feature}" 

144 raise ValueError(msg) 

145 

146 module, flag, ver = features[feature] 

147 

148 try: 

149 imported_module = __import__(module, fromlist=["PIL"]) 

150 return getattr(imported_module, flag) 

151 except ModuleNotFoundError: 

152 return None 

153 except ImportError as ex: 

154 warnings.warn(str(ex)) 

155 return None 

156 

157 

158def version_feature(feature: str) -> str | None: 

159 """ 

160 :param feature: The feature to check for. 

161 :returns: The version number as a string, or ``None`` if not available. 

162 :raises ValueError: If the feature is not defined in this version of Pillow. 

163 """ 

164 if not check_feature(feature): 

165 return None 

166 

167 module, flag, ver = features[feature] 

168 

169 if ver is None: 

170 return None 

171 

172 return getattr(__import__(module, fromlist=[ver]), ver) 

173 

174 

175def get_supported_features() -> list[str]: 

176 """ 

177 :returns: A list of all supported features. 

178 """ 

179 return [f for f in features if check_feature(f)] 

180 

181 

182def check(feature: str) -> bool | None: 

183 """ 

184 :param feature: A module, codec, or feature name. 

185 :returns: 

186 ``True`` if the module, codec, or feature is available, 

187 ``False`` or ``None`` otherwise. 

188 """ 

189 

190 if feature in modules: 

191 return check_module(feature) 

192 if feature in codecs: 

193 return check_codec(feature) 

194 if feature in features: 

195 return check_feature(feature) 

196 warnings.warn(f"Unknown feature '{feature}'.", stacklevel=2) 

197 return False 

198 

199 

200def version(feature: str) -> str | None: 

201 """ 

202 :param feature: 

203 The module, codec, or feature to check for. 

204 :returns: 

205 The version number as a string, or ``None`` if unknown or not available. 

206 """ 

207 if feature in modules: 

208 return version_module(feature) 

209 if feature in codecs: 

210 return version_codec(feature) 

211 if feature in features: 

212 return version_feature(feature) 

213 return None 

214 

215 

216def get_supported() -> list[str]: 

217 """ 

218 :returns: A list of all supported modules, features, and codecs. 

219 """ 

220 

221 ret = get_supported_modules() 

222 ret.extend(get_supported_features()) 

223 ret.extend(get_supported_codecs()) 

224 return ret 

225 

226 

227def pilinfo(out: IO[str] | None = None, supported_formats: bool = True) -> None: 

228 """ 

229 Prints information about this installation of Pillow. 

230 This function can be called with ``python3 -m PIL``. 

231 It can also be called with ``python3 -m PIL.report`` or ``python3 -m PIL --report`` 

232 to have "supported_formats" set to ``False``, omitting the list of all supported 

233 image file formats. 

234 

235 :param out: 

236 The output stream to print to. Defaults to ``sys.stdout`` if ``None``. 

237 :param supported_formats: 

238 If ``True``, a list of all supported image file formats will be printed. 

239 """ 

240 

241 if out is None: 

242 out = sys.stdout 

243 

244 Image.init() 

245 

246 print("-" * 68, file=out) 

247 print(f"Pillow {PIL.__version__}", file=out) 

248 py_version_lines = sys.version.splitlines() 

249 print(f"Python {py_version_lines[0].strip()}", file=out) 

250 for py_version in py_version_lines[1:]: 

251 print(f" {py_version.strip()}", file=out) 

252 print("-" * 68, file=out) 

253 print(f"Python executable is {sys.executable or 'unknown'}", file=out) 

254 if sys.prefix != sys.base_prefix: 

255 print(f"Environment Python files loaded from {sys.prefix}", file=out) 

256 print(f"System Python files loaded from {sys.base_prefix}", file=out) 

257 print("-" * 68, file=out) 

258 print( 

259 f"Python Pillow modules loaded from {os.path.dirname(Image.__file__)}", 

260 file=out, 

261 ) 

262 print( 

263 f"Binary Pillow modules loaded from {os.path.dirname(Image.core.__file__)}", 

264 file=out, 

265 ) 

266 print("-" * 68, file=out) 

267 

268 for name, feature in [ 

269 ("pil", "PIL CORE"), 

270 ("tkinter", "TKINTER"), 

271 ("freetype2", "FREETYPE2"), 

272 ("littlecms2", "LITTLECMS2"), 

273 ("webp", "WEBP"), 

274 ("transp_webp", "WEBP Transparency"), 

275 ("webp_mux", "WEBPMUX"), 

276 ("webp_anim", "WEBP Animation"), 

277 ("jpg", "JPEG"), 

278 ("jpg_2000", "OPENJPEG (JPEG2000)"), 

279 ("zlib", "ZLIB (PNG/ZIP)"), 

280 ("libtiff", "LIBTIFF"), 

281 ("raqm", "RAQM (Bidirectional Text)"), 

282 ("libimagequant", "LIBIMAGEQUANT (Quantization method)"), 

283 ("xcb", "XCB (X protocol)"), 

284 ]: 

285 if check(name): 

286 v: str | None = None 

287 if name == "jpg": 

288 libjpeg_turbo_version = version_feature("libjpeg_turbo") 

289 if libjpeg_turbo_version is not None: 

290 v = "libjpeg-turbo " + libjpeg_turbo_version 

291 if v is None: 

292 v = version(name) 

293 if v is not None: 

294 version_static = name in ("pil", "jpg") 

295 if name == "littlecms2": 

296 # this check is also in src/_imagingcms.c:setup_module() 

297 version_static = tuple(int(x) for x in v.split(".")) < (2, 7) 

298 t = "compiled for" if version_static else "loaded" 

299 if name == "raqm": 

300 for f in ("fribidi", "harfbuzz"): 

301 v2 = version_feature(f) 

302 if v2 is not None: 

303 v += f", {f} {v2}" 

304 print("---", feature, "support ok,", t, v, file=out) 

305 else: 

306 print("---", feature, "support ok", file=out) 

307 else: 

308 print("***", feature, "support not installed", file=out) 

309 print("-" * 68, file=out) 

310 

311 if supported_formats: 

312 extensions = collections.defaultdict(list) 

313 for ext, i in Image.EXTENSION.items(): 

314 extensions[i].append(ext) 

315 

316 for i in sorted(Image.ID): 

317 line = f"{i}" 

318 if i in Image.MIME: 

319 line = f"{line} {Image.MIME[i]}" 

320 print(line, file=out) 

321 

322 if i in extensions: 

323 print( 

324 "Extensions: {}".format(", ".join(sorted(extensions[i]))), file=out 

325 ) 

326 

327 features = [] 

328 if i in Image.OPEN: 

329 features.append("open") 

330 if i in Image.SAVE: 

331 features.append("save") 

332 if i in Image.SAVE_ALL: 

333 features.append("save_all") 

334 if i in Image.DECODERS: 

335 features.append("decode") 

336 if i in Image.ENCODERS: 

337 features.append("encode") 

338 

339 print("Features: {}".format(", ".join(features)), file=out) 

340 print("-" * 68, file=out)