From 1c03c83c0a8c2c9cee4153873ef4af56c1c716e3 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 29 Jul 2024 15:38:58 -0500 Subject: [PATCH] Fix blocking stat() via is_file in image_upload (#122808) --- .../components/image_upload/__init__.py | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/homeassistant/components/image_upload/__init__.py b/homeassistant/components/image_upload/__init__.py index 8bb3aca3708..5e9cf8c4e0e 100644 --- a/homeassistant/components/image_upload/__init__.py +++ b/homeassistant/components/image_upload/__init__.py @@ -220,18 +220,18 @@ class ImageServeView(HomeAssistantView): hass = request.app[KEY_HASS] target_file = self.image_folder / image_id / f"{width}x{height}" - if not target_file.is_file(): + if not await hass.async_add_executor_job(target_file.is_file): async with self.transform_lock: # Another check in case another request already # finished it while waiting - if not target_file.is_file(): - await hass.async_add_executor_job( - _generate_thumbnail, - self.image_folder / image_id / "original", - image_info["content_type"], - target_file, - (width, height), - ) + await hass.async_add_executor_job( + _generate_thumbnail_if_file_does_not_exist, + target_file, + self.image_folder / image_id / "original", + image_info["content_type"], + target_file, + (width, height), + ) return web.FileResponse( target_file, @@ -239,16 +239,18 @@ class ImageServeView(HomeAssistantView): ) -def _generate_thumbnail( +def _generate_thumbnail_if_file_does_not_exist( + target_file: pathlib.Path, original_path: pathlib.Path, content_type: str, target_path: pathlib.Path, target_size: tuple[int, int], ) -> None: """Generate a size.""" - image = ImageOps.exif_transpose(Image.open(original_path)) - image.thumbnail(target_size) - image.save(target_path, format=content_type.partition("/")[-1]) + if not target_file.is_file(): + image = ImageOps.exif_transpose(Image.open(original_path)) + image.thumbnail(target_size) + image.save(target_path, format=content_type.partition("/")[-1]) def _validate_size_from_filename(filename: str) -> tuple[int, int]: