Use `filetype` as `imghdr` built-in module is deprecated and slated for removal in Python 3.13 (#8581)

* Ensure Imghdr compatibility with Kivy

* Use iletype to get file extension

* Reformat file and Refactor string formats

* Delete kivy/lib/imghdr.py

* Add filetype to `full`

* fix PEP8_test

* Fix integer bug
This commit is contained in:
Kenechukwu Akubue 2024-03-05 19:23:22 +01:00 committed by GitHub
parent 6bb27a91cb
commit 7e6d86197a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 30 additions and 34 deletions

View File

@ -62,7 +62,7 @@ Or you can get the bytes (new in `1.11.0`):
'''
import re
from base64 import b64decode
import imghdr
from filetype import guess_extension
__all__ = ('Image', 'ImageLoader', 'ImageData')
@ -79,11 +79,9 @@ from kivy.setupconfig import USE_SDL2
import zipfile
from io import BytesIO
# late binding
Texture = TextureRegion = None
# register image caching only for keep_data=True
Cache.register('kv.image', timeout=60)
Cache.register('kv.atlas')
@ -187,7 +185,7 @@ class ImageData(object):
.. versionadded:: 1.0.7
'''
if level == 0:
return (self.width, self.height, self.data, self.rowlength)
return self.width, self.height, self.data, self.rowlength
assert level < len(self.mipmaps)
return self.mipmaps[level]
@ -257,17 +255,15 @@ class ImageLoaderBase(object):
# first, check if a texture with the same name already exist in the
# cache
chr = type(fname)
uid = chr(u'%s|%d|%d') % (fname, self._mipmap, count)
uid = f'{fname}|{self._mipmap:d}|{count:d}'
texture = Cache.get('kv.texture', uid)
# if not create it and append to the cache
if texture is None:
imagedata = self._data[count]
source = '{}{}|'.format(
'zip|' if fname.endswith('.zip') else '',
self._nocache)
imagedata.source = chr(source) + uid
source = (f"{'zip|' if fname.endswith('.zip') else ''}"
f"{self._nocache}|")
imagedata.source = f'{source}{uid}'
texture = Texture.create_from_data(
imagedata, mipmap=self._mipmap)
if not self._nocache:
@ -298,7 +294,7 @@ class ImageLoaderBase(object):
def size(self):
'''Image size (width, height)
'''
return (self._data[0].width, self._data[0].height)
return self._data[0].width, self._data[0].height
@property
def texture(self):
@ -330,7 +326,6 @@ class ImageLoaderBase(object):
class ImageLoader(object):
loaders = []
@staticmethod
@ -413,8 +408,8 @@ class ImageLoader(object):
# kv.texture cache.
if atlas:
texture = atlas[uid]
fn = 'atlas://%s/%s' % (rfn, uid)
cid = '{}|{:d}|{:d}'.format(fn, False, 0)
fn = f'atlas://{rfn}/{uid}'
cid = f'{fn}|0|0'
Cache.append('kv.texture', cid, texture)
return Image(texture)
@ -429,8 +424,8 @@ class ImageLoader(object):
Cache.append('kv.atlas', rfn, atlas)
# first time, fill our texture cache.
for nid, texture in atlas.textures.items():
fn = 'atlas://%s/%s' % (rfn, nid)
cid = '{}|{:d}|{:d}'.format(fn, False, 0)
fn = f'atlas://{rfn}/{nid}'
cid = f'{fn}|0|0'
Cache.append('kv.texture', cid, texture)
return Image(atlas[uid])
@ -438,11 +433,14 @@ class ImageLoader(object):
ext = filename.split('.')[-1].lower()
# prevent url querystrings
if filename.startswith((('http://', 'https://'))):
if filename.startswith(('http://', 'https://')):
ext = ext.split('?')[0]
filename = resource_find(filename)
# Get actual image format instead of extension if possible
ext = guess_extension(filename) or ext
# special case. When we are trying to load a "zip" file with image, we
# will use the special zip_loader in ImageLoader. This might return a
# sequence of images contained in the zip.
@ -450,17 +448,14 @@ class ImageLoader(object):
return ImageLoader.zip_loader(filename)
else:
im = None
# Get actual image format instead of extension if possible
ext = imghdr.what(filename) or ext
for loader in ImageLoader.loaders:
if ext not in loader.extensions():
continue
Logger.debug('Image%s: Load <%s>' %
(loader.__name__[11:], filename))
Logger.debug(f'Image{loader.__name__[11:]}: Load <{filename}>')
im = loader(filename, **kwargs)
break
if im is None:
raise Exception('Unknown <%s> type, no loader found.' % ext)
raise Exception(f'Unknown <{ext}> type, no loader found.')
return im
@ -578,14 +573,12 @@ class Image(EventDispatcher):
'''
count = 0
f = self.filename
pat = type(f)(u'%s|%d|%d')
uid = pat % (f, self._mipmap, count)
uid = f'{self.filename}|{self._mipmap:d}|{count:d}'
Cache.remove("kv.image", uid)
while Cache.get("kv.texture", uid):
Cache.remove("kv.texture", uid)
count += 1
uid = pat % (f, self._mipmap, count)
uid = f'{self.filename}|{self._mipmap:d}|{count:d}'
def _anim(self, *largs):
if not self._image:
@ -724,7 +717,7 @@ class Image(EventDispatcher):
# construct uid as a key for Cache
f = self.filename
uid = type(f)(u'%s|%d|%d') % (f, self._mipmap, 0)
uid = f'{f}|{self._mipmap:d}|0'
# in case of Image have been asked with keep_data
# check the kv.image cache instead of texture.
@ -777,10 +770,10 @@ class Image(EventDispatcher):
loader.can_load_memory() and
ext in loader.extensions()]
if not loaders:
raise Exception('No inline loader found to load {}'.format(ext))
raise Exception(f'No inline loader found to load {ext}')
image = loaders[0](filename, ext=ext, rawdata=data, inline=True,
nocache=self._nocache, mipmap=self._mipmap,
keep_data=self._keep_data)
nocache=self._nocache, mipmap=self._mipmap,
keep_data=self._keep_data)
if isinstance(image, Texture):
self._texture = image
self._size = image.size
@ -908,9 +901,9 @@ class Image(EventDispatcher):
def _find_format_from_filename(self, filename):
ext = filename.rsplit(".", 1)[-1].lower()
if ext in {
'bmp', 'jpe', 'lbm', 'pcx', 'png', 'pnm',
'tga', 'tiff', 'webp', 'xcf', 'xpm', 'xv'}:
if (ext in
{'bmp', 'jpe', 'lbm', 'pcx', 'png', 'pnm', 'tga',
'tiff', 'webp', 'xcf', 'xpm', 'xv'}):
return ext
elif ext in ('jpg', 'jpeg'):
return 'jpg'
@ -945,7 +938,7 @@ class Image(EventDispatcher):
# check bounds
x, y = int(x), int(y)
if not (0 <= x < data.width and 0 <= y < data.height):
raise IndexError('Position (%d, %d) is out of range.' % (x, y))
raise IndexError(f'Position ({x:d}, {y:d}) is out of range.')
assert data.fmt in ImageData._supported_fmts
size = 3 if data.fmt in ('rgb', 'bgr') else 4
@ -992,6 +985,7 @@ image_libs += [
libs_loaded = core_register_libs('image', image_libs)
from os import environ
if 'KIVY_DOC' not in environ and not libs_loaded:
import sys

View File

@ -50,6 +50,7 @@ dev =
base =
pillow>=9.5.0,<11
requests
filetype
docutils
pygments
kivy_deps.angle~=0.4.0; sys_platform == "win32"
@ -63,6 +64,7 @@ full =
pillow>=9.5.0,<11
docutils
pygments
filetype
kivy_deps.gstreamer~=0.3.3; sys_platform == "win32"
kivy_deps.angle~=0.4.0; sys_platform == "win32"
kivy_deps.sdl2~=0.7.0; sys_platform == "win32"