Skip to content

Commit 5dab922

Browse files
rtibblesclaude
andcommitted
fix: scope models imports in utils/files.py to break boot-time circular import
The GCS storage backend imports utils.files at module load. files' top-level `from contentcuration.models import File / generate_object_storage_name` then re-entered a partially initialized contentcuration.models during app boot (DEFAULT_FILE_STORAGE=GCS), raising ImportError and crash-looping the pods. The test suite missed it: pytest imports models early, so models is complete before the storage modules load files. Move File and generate_object_storage_name imports into their call sites (create_file_from_contents, get_file_diff, get_thumbnail_encoding). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019ineqU2EGLAcWW2WPWR3mE
1 parent 67181da commit 5dab922

1 file changed

Lines changed: 12 additions & 2 deletions

File tree

  • contentcuration/contentcuration/utils

contentcuration/contentcuration/utils/files.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616
from PIL import ImageFile
1717

1818
from contentcuration.api import write_raw_content_to_storage
19-
from contentcuration.models import File
20-
from contentcuration.models import generate_object_storage_name
2119

2220

2321
# Do this to ensure that we infer mimetypes for files properly, specifically
@@ -32,6 +30,11 @@
3230
def create_file_from_contents(
3331
contents, ext=None, node=None, preset_id=None, uploaded_by=None
3432
):
33+
# Imported here rather than at module level to avoid a circular import:
34+
# the GCS storage backend imports this module, and importing models at load
35+
# time re-enters a partially initialized contentcuration.models during boot.
36+
from contentcuration.models import File
37+
3538
checksum, _, path = write_raw_content_to_storage(contents, ext=ext)
3639

3740
result = File(
@@ -53,6 +56,10 @@ def get_file_diff(files):
5356
5457
"""
5558

59+
# Imported here rather than at module level to avoid a circular import (see
60+
# create_file_from_contents).
61+
from contentcuration.models import generate_object_storage_name
62+
5663
# We use a thread pool in here, making direct HEAD requests to the storage URL
5764
# to see if the objects exist.
5865
# The threaded method is found to be the fastest -- see
@@ -101,6 +108,9 @@ def get_thumbnail_encoding(filename, dimension=THUMBNAIL_WIDTH):
101108
dimension (int, optional): desired width of thumbnail. Defaults to 400.
102109
Returns base64 encoding of resized thumbnail
103110
"""
111+
# Imported here rather than at module level to avoid a circular import (see
112+
# create_file_from_contents).
113+
from contentcuration.models import generate_object_storage_name
104114

105115
if filename.startswith("data:image"):
106116
return filename

0 commit comments

Comments
 (0)