Enhance backfill_image_dimensions command to update image metadata; add tests for edge cases
All checks were successful
Deploy to Server / deploy (push) Successful in 9s

This commit is contained in:
Joakim Hellsén 2026-03-09 19:57:13 +01:00
commit 53765c3b27
Signed by: Joakim Hellsén
SSH key fingerprint: SHA256:/9h/CsExpFp+PRhsfA0xznFx2CGfTT5R/kpuFfUgEQk
2 changed files with 45 additions and 6 deletions

View file

@ -14,17 +14,22 @@ class Command(BaseCommand):
help = "Backfill image dimensions for existing cached images" help = "Backfill image dimensions for existing cached images"
def handle(self, *args, **options) -> None: # noqa: ARG002 def handle(self, *args, **options) -> None: # noqa: ARG002, PLR0915
"""Execute the command.""" """Execute the command."""
total_updated = 0 total_updated = 0
# Update Game box art # Update Game box art
self.stdout.write("Processing Game box_art_file...") self.stdout.write("Processing Game box_art_file...")
for game in Game.objects.exclude(box_art_file=""): for game in Game.objects.exclude(box_art_file=""):
if game.box_art_file and not game.box_art_width: needs_update = (
not game.box_art_size_bytes
or not game.box_art_mime_type
or not game.box_art_width
)
if game.box_art_file and needs_update:
try: try:
# Opening the file and saving triggers dimension calculation if not game.box_art_width:
game.box_art_file.open() game.box_art_file.open()
# populate size and mime if available # populate size and mime if available
with contextlib.suppress(Exception): with contextlib.suppress(Exception):
@ -42,9 +47,15 @@ class Command(BaseCommand):
# Update DropCampaign images # Update DropCampaign images
self.stdout.write("Processing DropCampaign image_file...") self.stdout.write("Processing DropCampaign image_file...")
for campaign in DropCampaign.objects.exclude(image_file=""): for campaign in DropCampaign.objects.exclude(image_file=""):
if campaign.image_file and not campaign.image_width: needs_update: bool = (
not campaign.image_size_bytes
or not campaign.image_mime_type
or not campaign.image_width
)
if campaign.image_file and needs_update:
try: try:
campaign.image_file.open() if not campaign.image_width:
campaign.image_file.open()
with contextlib.suppress(Exception): with contextlib.suppress(Exception):
campaign.image_size_bytes = campaign.image_file.size campaign.image_size_bytes = campaign.image_file.size

View file

@ -244,6 +244,34 @@ class RSSFeedTestCase(TestCase):
assert campaign2.image_mime_type == "image/jpeg" assert campaign2.image_mime_type == "image/jpeg"
assert game2.box_art_size_bytes == len(b"hello") assert game2.box_art_size_bytes == len(b"hello")
assert game2.box_art_mime_type == "image/png" assert game2.box_art_mime_type == "image/png"
# run again; nothing should error and metadata should still be present
call_command("backfill_image_dimensions")
campaign2.refresh_from_db()
game2.refresh_from_db()
assert campaign2.image_size_bytes == len(b"world")
assert campaign2.image_mime_type == "image/jpeg"
assert game2.box_art_size_bytes == len(b"hello")
assert game2.box_art_mime_type == "image/png"
# simulate a case where width is already set but mime/size empty; the
# command should still fill size/mime even if width gets cleared by the
# model on save (invalid image data may reset the dimensions).
game2.box_art_width = 999
game2.box_art_size_bytes = None
game2.box_art_mime_type = ""
game2.save()
campaign2.image_width = 888
campaign2.image_size_bytes = None
campaign2.image_mime_type = ""
campaign2.save()
call_command("backfill_image_dimensions")
campaign2.refresh_from_db()
game2.refresh_from_db()
assert campaign2.image_size_bytes == len(b"world")
assert campaign2.image_mime_type == "image/jpeg"
assert game2.box_art_size_bytes == len(b"hello")
assert game2.box_art_mime_type == "image/png"
QueryAsserter = Callable[..., AbstractContextManager[object]] QueryAsserter = Callable[..., AbstractContextManager[object]]