Skip to content

Commit

Permalink
feat: Accept new STORAGES setting, introduced in Django 4.2 (#1472)
Browse files Browse the repository at this point in the history
* fix: use Django's `STORAGES` setting if it exists

* fix: pyupgrade to 3.8+
  • Loading branch information
fsbraun committed May 19, 2024
1 parent 2ac8c15 commit 1d709ae
Show file tree
Hide file tree
Showing 16 changed files with 43 additions and 38 deletions.
4 changes: 3 additions & 1 deletion docs/settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ e.g::

Defaults to FileSystemStorage in ``<MEDIA_ROOT>/filer_public/`` and ``<MEDIA_ROOT>/filer_public_thumbnails/`` for public files and
``<MEDIA_ROOT>/../smedia/filer_private/`` and ``<MEDIA_ROOT>/../smedia/filer_private_thumbnails/`` for private files.
Public storage uses ``DEFAULT_FILE_STORAGE`` as default storage backend.
Public storage uses the default storage's backend. This is taken from Django's ``STORAGES``
setting if it exists or, if not, from the ``DEFAULT_FILE_STORAGE`` setting for compatibility
with earlier Django versions (5.0 or below).

``UPLOAD_TO`` is the function to generate the path relative to the storage root. The
default generates a random path like ``1d/a5/1da50fee-5003-46a1-a191-b547125053a8/filename.jpg``. This
Expand Down
2 changes: 1 addition & 1 deletion filer/admin/fileadmin.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ def get_model_perms(self, request):
def display_canonical(self, instance):
canonical = instance.canonical_url
if canonical:
return mark_safe('<a href="{}">{}</a>'.format(canonical, canonical))
return mark_safe(f'<a href="{canonical}">{canonical}</a>')
else:
return '-'
display_canonical.allow_tags = True
Expand Down
8 changes: 4 additions & 4 deletions filer/admin/folderadmin.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,10 +253,10 @@ def directory_listing(self, request, folder_id=None, viewtype=None):
self.get_queryset(request).get(id=last_folder_id)
except self.model.DoesNotExist:
url = reverse('admin:filer-directory_listing-root')
url = "{}{}".format(url, admin_url_params_encoded(request))
url = f"{url}{admin_url_params_encoded(request)}"
else:
url = reverse('admin:filer-directory_listing', kwargs={'folder_id': last_folder_id})
url = "{}{}".format(url, admin_url_params_encoded(request))
url = f"{url}{admin_url_params_encoded(request)}"
return HttpResponseRedirect(url)
elif folder_id is None:
folder = FolderRoot()
Expand Down Expand Up @@ -840,7 +840,7 @@ def _format_callback(self, obj, user, admin_site, perms_needed):
else:
# Don't display link to edit, because it either has no
# admin or is edited inline.
return '{}: {}'.format(capfirst(opts.verbose_name), force_str(obj))
return f'{capfirst(opts.verbose_name)}: {force_str(obj)}'

def _check_copy_perms(self, request, files_queryset, folders_queryset):
try:
Expand Down Expand Up @@ -1073,7 +1073,7 @@ def _get_available_name(self, destination, name):
count = itertools.count(1)
original = name
while destination.contains_folder(name):
name = "{}_{}".format(original, next(count))
name = f"{original}_{next(count)}"
return name

def _copy_folder(self, folder, destination, suffix, overwrite):
Expand Down
2 changes: 1 addition & 1 deletion filer/fields/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def render(self, name, value, attrs=None, renderer=None):
hidden_input = super(ForeignKeyRawIdWidget, self).render(name, value, attrs) # grandparent super
context = {
'hidden_input': hidden_input,
'lookup_url': '{}{}'.format(related_url, lookup_url),
'lookup_url': f'{related_url}{lookup_url}',
'change_url': change_url,
'object': obj,
'lookup_name': name,
Expand Down
2 changes: 1 addition & 1 deletion filer/fields/folder.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def render(self, name, value, attrs=None, renderer=None):
# API to determine the ID dynamically.
context = {
'hidden_input': hidden_input,
'lookup_url': '{}{}'.format(related_url, url),
'lookup_url': f'{related_url}{url}',
'lookup_name': name,
'span_id': css_id_description_txt,
'object': obj,
Expand Down
2 changes: 1 addition & 1 deletion filer/fields/multistorage_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ def value_to_string(self, obj):
encoded_string = base64.b64encode(payload_file.read()).decode('utf-8')
return value, encoded_string
except OSError:
warnings.warn('The payload for "{}" is missing. No such file on disk: {}!'.format(obj.original_filename, self.storage.location))
warnings.warn(f'The payload for "{obj.original_filename}" is missing. No such file on disk: {self.storage.location}!')
return value

def to_python(self, value):
Expand Down
2 changes: 1 addition & 1 deletion filer/models/clipboardmodels.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def append_file(self, file_obj):
return True

def __str__(self):
return "Clipboard {} of {}".format(self.id, self.user)
return f"Clipboard {self.id} of {self.user}"


class ClipboardItem(models.Model):
Expand Down
6 changes: 3 additions & 3 deletions filer/models/filemodels.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,9 @@ class Meta:

def __str__(self):
if self.name in ('', None):
text = "{}".format(self.original_filename)
text = f"{self.original_filename}"
else:
text = "{}".format(self.name)
text = f"{self.name}"
return text

@classmethod
Expand Down Expand Up @@ -312,7 +312,7 @@ def label(self):
text = self.original_filename or 'unnamed file'
else:
text = self.name
text = "{}".format(text)
text = f"{text}"
return text

def __lt__(self, other):
Expand Down
2 changes: 1 addition & 1 deletion filer/models/thumbnailoptionmodels.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class Meta:
verbose_name_plural = _("thumbnail options")

def __str__(self):
return '{} -- {} x {}'.format(self.name, self.width, self.height)
return f'{self.name} -- {self.width} x {self.height}'

@property
def as_dict(self):
Expand Down
5 changes: 4 additions & 1 deletion filer/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@
settings, 'FILER_FILE_MODELS',
(FILER_IMAGE_MODEL, 'filer.File'))

DEFAULT_FILE_STORAGE = getattr(settings, 'DEFAULT_FILE_STORAGE', 'django.core.files.storage.FileSystemStorage')
if hasattr(settings, "STORAGES") and 'default' in settings.STORAGES:
DEFAULT_FILE_STORAGE = settings.STORAGES['default'].get('BACKEND', 'django.core.files.storage.FileSystemStorage')
else:
DEFAULT_FILE_STORAGE = getattr(settings, 'DEFAULT_FILE_STORAGE', 'django.core.files.storage.FileSystemStorage')

MINIMAL_FILER_STORAGES = {
'public': {
Expand Down
2 changes: 1 addition & 1 deletion filer/templatetags/filer_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def filesize(bytes, format='auto1024'):
unit = '{}{}'.format(base == 1024 and unit.upper() or unit,
base == 1024 and 'iB' or 'B')

return '{} {}'.format(bytes, unit)
return f'{bytes} {unit}'

if bytes == 0:
return bytes
Expand Down
2 changes: 1 addition & 1 deletion tests/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def create_folder_structure(depth=2, sibling=2, parent=None):
depth_range.reverse()
for d in depth_range:
for s in range(1, sibling + 1):
name = "folder: %s -- %s" % (str(d), str(s))
name = "folder: {} -- {}".format(str(d), str(s))
folder = Folder(name=name, parent=parent)
folder.save()
create_folder_structure(depth=d - 1, sibling=sibling, parent=folder)
Expand Down
32 changes: 16 additions & 16 deletions tests/test_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ def test_filer_ajax_upload_file_error(self):
'admin:filer-ajax_upload',
kwargs={
'folder_id': folder.pk + 1}
) + '?filename={0}'.format(self.image_name)
) + f'?filename={self.image_name}'
response = self.client.post(
url,
data=file_obj.read(),
Expand Down Expand Up @@ -693,7 +693,7 @@ def test_filer_ajax_upload_without_permissions_error(self, extra_headers={}):
'admin:filer-ajax_upload',
kwargs={
'folder_id': folder.pk}
) + '?filename={0}'.format(self.image_name)
) + f'?filename={self.image_name}'
response = self.client.post(
url,
data=file_obj.read(),
Expand Down Expand Up @@ -759,7 +759,7 @@ def test_filer_ajax_upload_permissions_error(self, extra_headers={}):
'admin:filer-ajax_upload',
kwargs={
'folder_id': folder.pk}
) + '?filename={0}'.format(self.image_name)
) + f'?filename={self.image_name}'
response = self.client.post(
url,
data=file_obj.read(),
Expand Down Expand Up @@ -1103,10 +1103,10 @@ def _do_test_rename(self, url, new_name, file_obj=None, folder_obj=None):
'new_name' should be a plain string, no formatting supported.
"""
if file_obj is not None:
checkbox_name = 'file-{}'.format(file_obj.id)
checkbox_name = f'file-{file_obj.id}'
files = [file_obj]
elif folder_obj is not None:
checkbox_name = 'folder-{}'.format(folder_obj.id)
checkbox_name = f'folder-{folder_obj.id}'
# files inside this folder, non-recursive
files = File.objects.filter(folder=folder_obj)
else:
Expand Down Expand Up @@ -1322,9 +1322,9 @@ def test_with_permissions_disabled(self):
item_list = response.context['paginated_items'].object_list
# user sees all items: FOO, BAR, BAZ, SAMP
self.assertEqual(
set(folder.pk for folder in item_list),
set([self.foo_folder.pk, self.bar_folder.pk, self.baz_folder.pk,
self.spam_file.pk]))
{folder.pk for folder in item_list},
{self.foo_folder.pk, self.bar_folder.pk, self.baz_folder.pk, self.spam_file.pk}
)

def test_folder_ownership(self):
with SettingsOverride(filer_settings, FILER_ENABLE_PERMISSIONS=True):
Expand All @@ -1336,8 +1336,8 @@ def test_folder_ownership(self):
# he doesn't see BAR, BAZ and SPAM because he doesn't own them
# and no permission has been given
self.assertEqual(
set(folder.pk for folder in item_list),
set([self.foo_folder.pk]))
{folder.pk for folder in item_list},
{self.foo_folder.pk})

def test_with_permission_given_to_folder(self):
with SettingsOverride(filer_settings, FILER_ENABLE_PERMISSIONS=True):
Expand All @@ -1355,8 +1355,8 @@ def test_with_permission_given_to_folder(self):
item_list = response.context['paginated_items'].object_list
# user sees 2 folder : FOO, BAR
self.assertEqual(
set(folder.pk for folder in item_list),
set([self.foo_folder.pk, self.bar_folder.pk]))
{folder.pk for folder in item_list},
{self.foo_folder.pk, self.bar_folder.pk})

def test_with_permission_given_to_parent_folder(self):
with SettingsOverride(filer_settings, FILER_ENABLE_PERMISSIONS=True):
Expand All @@ -1373,9 +1373,9 @@ def test_with_permission_given_to_parent_folder(self):
item_list = response.context['paginated_items'].object_list
# user sees all items because he has permissions on the parent folder
self.assertEqual(
set(folder.pk for folder in item_list),
set([self.foo_folder.pk, self.bar_folder.pk, self.baz_folder.pk,
self.spam_file.pk]))
{folder.pk for folder in item_list},
{self.foo_folder.pk, self.bar_folder.pk, self.baz_folder.pk, self.spam_file.pk}
)

def test_search_against_owner(self):
url = reverse('admin:filer-directory_listing',
Expand Down Expand Up @@ -1416,7 +1416,7 @@ def test_search_special_characters(self):

# Create a file with a problematic filename
problematic_file = django.core.files.base.ContentFile('some data')
filename = u'christopher_eccleston'
filename = 'christopher_eccleston'
problematic_file.name = filename
self.spam_file = File.objects.create(
owner=self.staff_user, original_filename=filename,
Expand Down
2 changes: 1 addition & 1 deletion tests/test_form_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@ def test_widget_has_change_button(self):
content = widget.render("foo", file.id, {})

self.assertIn(
"/admin/filer/file/{}/change/?_edit_from_widget=1".format(file.id), content
f"/admin/filer/file/{file.id}/change/?_edit_from_widget=1", content
)
2 changes: 1 addition & 1 deletion tests/test_migrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ def test_for_missing_migrations(self):
status_code = '0'

if status_code == '1':
self.fail('There are missing migrations:\n {}'.format(output.getvalue()))
self.fail(f'There are missing migrations:\n {output.getvalue()}')
6 changes: 3 additions & 3 deletions tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,19 +87,19 @@ def test_create_icons(self):
self.assertEqual(len(icons), len(filer_settings.FILER_ADMIN_ICON_SIZES))
for size in filer_settings.FILER_ADMIN_ICON_SIZES:
self.assertEqual(os.path.basename(icons[size]),
file_basename + '__%sx%s_q85_crop_subsampling-2_upscale.jpg' % (size, size))
file_basename + '__{}x{}_q85_crop_subsampling-2_upscale.jpg'.format(size, size))

def test_access_icons_property(self):
"""Test IconsMixin that calls static on a non-existent file"""

class CustomObj(IconsMixin, object):
class CustomObj(IconsMixin):
_icon = 'custom'

custom_obj = CustomObj()
try:
icons = custom_obj.icons
except Exception as e:
self.fail("'.icons' access raised Exception {0} unexpectedly!".format(e))
self.fail(f"'.icons' access raised Exception {e} unexpectedly!")
self.assertEqual(len(icons), len(filer_settings.FILER_ADMIN_ICON_SIZES))

def test_file_upload_public_destination(self):
Expand Down

0 comments on commit 1d709ae

Please sign in to comment.