diff --git a/edxval/__init__.py b/edxval/__init__.py index bddfdd5f..b5a91c28 100644 --- a/edxval/__init__.py +++ b/edxval/__init__.py @@ -2,4 +2,4 @@ init """ -__version__ = '3.1.0' +__version__ = '3.2.0' diff --git a/edxval/tests/test_storages.py b/edxval/tests/test_storages.py index 0814a221..0f9d627f 100644 --- a/edxval/tests/test_storages.py +++ b/edxval/tests/test_storages.py @@ -97,3 +97,28 @@ def test_video_transcript_without_storages_settings(self): 'django.core.files.storage.filesystem.FileSystemStorage', f"{storage_class.__module__}.{storage_class.__name__}", ) + + @override_settings(STORAGES={ + 'video_transcripts': { + 'BACKEND': "storages.backends.s3boto3.S3Boto3Storage", + "OPTIONS": { + 'bucket_name': 'test', + 'default_acl': 'private', + 'location': 'abc/' + } + } + }, VIDEO_TRANSCRIPTS_SETTINGS={ + 'STORAGE_CLASS': 'storages.backends.s3boto3.S3Boto3Storage', + 'STORAGE_KWARGS': { + 'bucket_name': 'custom-bucket', + 'default_acl': 'private', + 'location': 'custom/abc/' + } + }) + def test_django52_storages_takes_priority_over_custom(self): + # + storage = get_video_transcript_storage() + self.assertIsInstance(storage, S3Boto3Storage) + self.assertEqual(storage.bucket_name, "test") + self.assertEqual(storage.default_acl, 'private') + self.assertEqual(storage.location, 'abc/') diff --git a/edxval/utils.py b/edxval/utils.py index 483bce94..757c51bb 100644 --- a/edxval/utils.py +++ b/edxval/utils.py @@ -153,25 +153,31 @@ def video_image_path(video_image_instance, filename): # pylint:disable=unused-a def get_configured_storage(settings_key): """ Generic function to return a configured Django storage backend - based on the settings dictionary at `settings_key`. This function falls - back to the `default` storage class if there is no `STORAGE_CLASS` entry - under the `setting_key` object. + based on the settings dictionary at `settings_key`. This function prioritizes + Django 5.2's STORAGES dictionary over custom settings with the same key, + falling back to legacy settings if no STORAGES entry exists. """ - config = getattr(settings, settings_key, {}) - # Retrieve the storage class path and kwargs from the settings - storage_class_path = config.get('STORAGE_CLASS') - options = config.get('STORAGE_KWARGS', {}) - - # following code only runs for default storages - if not storage_class_path: - storage_class_path = ( - getattr(settings, 'DEFAULT_FILE_STORAGE', None) or - getattr(settings, 'STORAGES', {}).get('default', {}).get('BACKEND') or - 'django.core.files.storage.FileSystemStorage' - ) - - # For Django 5.x, pick options if available - options = getattr(settings, 'STORAGES', {}).get('default', {}).get('OPTIONS', {}) + storages_config = getattr(settings, 'STORAGES', {}) + storage_key = settings_key.replace("_SETTINGS", "") + storage_settings = storages_config.get(storage_key.lower(), {}) + + if storage_settings: + storage_class_path = storage_settings.get('BACKEND') + options = storage_settings.get('OPTIONS', {}) + else: + # Fall back to custom settings configuration + config = getattr(settings, settings_key, {}) + storage_class_path = config.get('STORAGE_CLASS') + options = config.get('STORAGE_KWARGS', {}) + + if not storage_class_path: + storage_class_path = ( + storages_config.get('default', {}).get('BACKEND') or + getattr(settings, 'DEFAULT_FILE_STORAGE', None) or + 'django.core.files.storage.FileSystemStorage' + ) + + options = storages_config.get('default', {}).get('OPTIONS', {}) or options # Import the storage class dynamically storage_class = import_string(storage_class_path)