Background
While bringing dj42.unglue.it back online (2026-04-28) for #1123 testing, surfaced a latent bug in core/models/bibmodels.py. The Edition.cover_image_* methods reference ImageFile.is_default, which was removed from sorl-thumbnail in the 12.6 → 12.11 upgrade (#1123 bumps sorl-thumbnail 12.6.3 → 12.11.0).
The bug
Three methods on Edition use the deprecated attribute:
core/models/bibmodels.py:896-915
def cover_image_small(self):
if self.cover_image:
im = get_thumbnail(self.cover_image, 'x80', crop='noop', quality=95)
if not im.is_default: # AttributeError in sorl 12.11.0
return im.url
if self.googlebooks_id:
return "https://encrypted.google.com/books?id=%s..." % self.googlebooks_id
return DEFAULT_COVER_SMALL
def cover_image_thumbnail(self): # same pattern with 'x128'
...
def cover_image_large(self): # also same pattern (line ~890)
...
In sorl 12.11.0, BaseImageFile/ImageFile/DummyImageFile no longer expose is_default. The replacement is im.exists() (a method that returns whether the thumbnail file actually exists).
Why dj42 still appears to render covers
Despite the missing attribute, on dj42 (running #1123's branch) the methods do return correct cover URLs — at least for warm code paths. Direct probe of im.is_default reliably raises AttributeError, but execution traces (sys.settrace) show line 900 evaluating without raising during normal method invocation. Likely related to sorl's KVStore state — the AttributeError is intermittent rather than deterministic, which is more dangerous than a clean failure.
This means current behavior is fragile/heisenbug-prone:
- Cold thumbnail cache: may surface the AttributeError → 500 on the page
- Warm cache: silently works but on a deprecated API path
Proposed fix
Three-call-site mechanical change:
- if not im.is_default:
+ if im.exists():
Applied to all three cover_image_* methods (small, thumbnail, large). The semantic is identical: "if the generated thumbnail file actually exists, return its URL; otherwise fall through to the Google Books / DEFAULT_COVER fallback."
Reference: sorl-thumbnail 12.11.0 release notes — no formal CHANGELOG entry for is_default removal but the attribute is gone from the source.
Discovered via
Comparison testing of dj42 (Django 4.2 / sorl 12.11.0) against test (Django 1.11 / sorl 12.6.3) for the same DB content. Same work, same edition, same cover_image field — both stacks return identical cover URLs (no behavioral regression for end users), but the dj42 path goes through the deprecated attribute access.
Test plan when fixing
Scope
Only core/models/bibmodels.py (3 call sites, one file). Trivial change but should be in #1123 (or a fast follow-up PR against fix/django-upgrade-libraryauth) before the migration cuts over to prod.
Related
Background
While bringing dj42.unglue.it back online (2026-04-28) for #1123 testing, surfaced a latent bug in
core/models/bibmodels.py. TheEdition.cover_image_*methods referenceImageFile.is_default, which was removed from sorl-thumbnail in the 12.6 → 12.11 upgrade (#1123 bumpssorl-thumbnail 12.6.3 → 12.11.0).The bug
Three methods on
Editionuse the deprecated attribute:core/models/bibmodels.py:896-915In sorl 12.11.0,
BaseImageFile/ImageFile/DummyImageFileno longer exposeis_default. The replacement isim.exists()(a method that returns whether the thumbnail file actually exists).Why dj42 still appears to render covers
Despite the missing attribute, on dj42 (running #1123's branch) the methods do return correct cover URLs — at least for warm code paths. Direct probe of
im.is_defaultreliably raisesAttributeError, but execution traces (sys.settrace) show line 900 evaluating without raising during normal method invocation. Likely related to sorl's KVStore state — the AttributeError is intermittent rather than deterministic, which is more dangerous than a clean failure.This means current behavior is fragile/heisenbug-prone:
Proposed fix
Three-call-site mechanical change:
Applied to all three
cover_image_*methods (small, thumbnail, large). The semantic is identical: "if the generated thumbnail file actually exists, return its URL; otherwise fall through to the Google Books / DEFAULT_COVER fallback."Reference: sorl-thumbnail 12.11.0 release notes — no formal CHANGELOG entry for
is_defaultremoval but the attribute is gone from the source.Discovered via
Comparison testing of dj42 (Django 4.2 / sorl 12.11.0) against test (Django 1.11 / sorl 12.6.3) for the same DB content. Same work, same edition, same
cover_imagefield — both stacks return identical cover URLs (no behavioral regression for end users), but the dj42 path goes through the deprecated attribute access.Test plan when fixing
Edition.cover_image_small/thumbnail/large()for at least 3 editions with valid cover_image — should return valid URL, not raiseScope
Only
core/models/bibmodels.py(3 call sites, one file). Trivial change but should be in #1123 (or a fast follow-up PR againstfix/django-upgrade-libraryauth) before the migration cuts over to prod.Related