From 8d9946d35ac3afea8990d8ce5146c81bccc629dc Mon Sep 17 00:00:00 2001 From: jo Date: Wed, 23 Nov 2022 22:36:56 +0100 Subject: [PATCH] refactor: upgrade code to >=python3.7 (pre-commit) Part-of: --- api/config/plugins.py | 6 +-- api/config/settings/__init__.py | 1 - api/config/settings/common.py | 7 +-- api/config/settings/local.py | 3 +- api/config/settings/production.py | 2 - api/config/urls/__init__.py | 3 -- api/funkwhale_api/__init__.py | 1 - api/funkwhale_api/activity/apps.py | 2 +- api/funkwhale_api/activity/utils.py | 2 +- api/funkwhale_api/audio/factories.py | 2 +- api/funkwhale_api/audio/models.py | 2 +- api/funkwhale_api/audio/serializers.py | 20 ++++---- api/funkwhale_api/audio/spa_views.py | 4 +- api/funkwhale_api/audio/views.py | 2 +- api/funkwhale_api/cli/library.py | 2 +- api/funkwhale_api/cli/main.py | 4 +- api/funkwhale_api/cli/media.py | 14 ++---- api/funkwhale_api/cli/users.py | 10 ++-- api/funkwhale_api/common/authentication.py | 4 +- api/funkwhale_api/common/fields.py | 10 ++-- api/funkwhale_api/common/filters.py | 12 ++--- .../common/management/commands/script.py | 2 +- api/funkwhale_api/common/middleware.py | 14 ++---- api/funkwhale_api/common/mixins.py | 2 +- api/funkwhale_api/common/models.py | 8 +-- api/funkwhale_api/common/mutations.py | 6 +-- api/funkwhale_api/common/preferences.py | 10 ++-- .../common/scripts/create_actors.py | 8 ++- .../common/scripts/create_image_variations.py | 8 ++- .../delete_pre_017_federated_uploads.py | 2 +- .../django_permissions_to_user_permissions.py | 4 +- .../scripts/migrate_to_user_libraries.py | 28 ++++------- api/funkwhale_api/common/search.py | 6 +-- api/funkwhale_api/common/serializers.py | 16 +++--- api/funkwhale_api/common/utils.py | 16 +++--- api/funkwhale_api/common/validators.py | 4 +- api/funkwhale_api/contrib/__init__.py | 1 - .../contrib/listenbrainz/client.py | 4 +- .../contrib/scrobbler/scrobbler.py | 16 +++--- api/funkwhale_api/contrib/sites/__init__.py | 1 - api/funkwhale_api/factories.py | 6 +-- api/funkwhale_api/favorites/models.py | 2 +- api/funkwhale_api/federation/activity.py | 6 +-- api/funkwhale_api/federation/actors.py | 2 +- .../federation/api_serializers.py | 2 +- api/funkwhale_api/federation/api_views.py | 4 +- api/funkwhale_api/federation/contexts.py | 4 +- api/funkwhale_api/federation/factories.py | 10 ++-- api/funkwhale_api/federation/jsonld.py | 2 +- api/funkwhale_api/federation/library.py | 2 +- .../management/commands/fix_federation_ids.py | 12 ++--- api/funkwhale_api/federation/models.py | 26 +++++----- api/funkwhale_api/federation/serializers.py | 26 ++++------ api/funkwhale_api/federation/signing.py | 6 +-- api/funkwhale_api/federation/tasks.py | 2 +- api/funkwhale_api/federation/utils.py | 14 ++---- api/funkwhale_api/federation/views.py | 6 +-- api/funkwhale_api/federation/webfinger.py | 2 +- api/funkwhale_api/history/models.py | 2 +- api/funkwhale_api/manage/serializers.py | 6 +-- api/funkwhale_api/moderation/filters.py | 2 +- .../management/commands/mrf_check.py | 2 +- api/funkwhale_api/moderation/mrf_policies.py | 12 ++--- api/funkwhale_api/moderation/serializers.py | 2 +- api/funkwhale_api/moderation/tasks.py | 18 +++---- api/funkwhale_api/music/importers.py | 4 +- api/funkwhale_api/music/licenses.py | 4 +- .../commands/check_inplace_files.py | 8 +-- .../management/commands/check_licenses.py | 2 +- .../music/management/commands/fix_uploads.py | 28 ++++------- .../music/management/commands/import_files.py | 35 ++++++------- .../management/commands/prune_library.py | 18 +++---- api/funkwhale_api/music/metadata.py | 11 ++-- api/funkwhale_api/music/models.py | 50 +++++++++---------- api/funkwhale_api/music/serializers.py | 10 ++-- api/funkwhale_api/music/spa_views.py | 8 +-- api/funkwhale_api/music/tasks.py | 6 +-- api/funkwhale_api/music/utils.py | 4 +- api/funkwhale_api/music/views.py | 6 +-- api/funkwhale_api/musicbrainz/client.py | 12 ++--- api/funkwhale_api/playlists/models.py | 4 +- api/funkwhale_api/radios/filters.py | 8 +-- api/funkwhale_api/radios/radios.py | 2 +- api/funkwhale_api/subsonic/renderers.py | 2 +- api/funkwhale_api/subsonic/serializers.py | 14 +++--- api/funkwhale_api/subsonic/views.py | 6 +-- api/funkwhale_api/tags/serializers.py | 2 +- api/funkwhale_api/tags/tasks.py | 8 ++- api/funkwhale_api/taskapp/celery.py | 4 +- api/funkwhale_api/users/__init__.py | 1 - api/funkwhale_api/users/admin.py | 3 -- api/funkwhale_api/users/authentication.py | 2 +- api/funkwhale_api/users/factories.py | 2 +- api/funkwhale_api/users/models.py | 21 +++----- api/funkwhale_api/users/oauth/permissions.py | 6 +-- api/funkwhale_api/users/oauth/scopes.py | 2 +- api/tests/audio/test_serializers.py | 4 +- api/tests/audio/test_spa_views.py | 10 ++-- api/tests/audio/test_views.py | 2 +- api/tests/common/test_authentication.py | 2 +- api/tests/common/test_fields.py | 2 +- api/tests/common/test_filters.py | 4 +- api/tests/common/test_middleware.py | 2 +- api/tests/common/test_scripts.py | 4 +- api/tests/common/test_serializers.py | 2 +- api/tests/common/test_views.py | 14 ++---- api/tests/favorites/test_activity.py | 2 +- api/tests/federation/test_activity.py | 8 +-- api/tests/federation/test_api_views.py | 4 +- api/tests/federation/test_authentication.py | 18 +++---- api/tests/federation/test_decorators.py | 4 +- api/tests/federation/test_models.py | 6 +-- api/tests/federation/test_routes.py | 4 +- api/tests/federation/test_serializers.py | 2 +- api/tests/federation/test_spa_views.py | 2 +- api/tests/federation/test_tasks.py | 14 +++--- api/tests/federation/test_utils.py | 4 +- api/tests/federation/test_views.py | 14 ++---- api/tests/federation/test_webfinger.py | 2 +- api/tests/history/test_activity.py | 2 +- api/tests/instance/test_stats.py | 5 +- api/tests/loadtesting/library.py | 2 +- api/tests/manage/test_views.py | 4 +- api/tests/moderation/test_tasks.py | 6 +-- api/tests/music/test_activity.py | 6 +-- api/tests/music/test_commands.py | 10 ++-- api/tests/music/test_models.py | 6 +-- api/tests/music/test_music.py | 6 +-- api/tests/music/test_spa_views.py | 12 ++--- api/tests/music/test_tasks.py | 10 ++-- api/tests/music/test_views.py | 26 +++++----- api/tests/subsonic/test_serializers.py | 20 ++++---- api/tests/subsonic/test_views.py | 4 +- api/tests/test_import_audio_file.py | 10 ++-- api/tests/users/oauth/test_views.py | 4 +- api/tests/users/test_models.py | 4 +- api/tests/utils.py | 2 +- docs/conf.py | 5 +- front/scripts/contextualize.py | 2 +- front/scripts/fix-fomantic-css.py | 8 +-- front/scripts/print-duplicates-source.py | 6 +-- scripts/clean-unused-artifacts.py | 2 +- scripts/is-docker-latest.py | 4 +- 143 files changed, 454 insertions(+), 582 deletions(-) diff --git a/api/config/plugins.py b/api/config/plugins.py index 756e90993..ddd5afbb5 100644 --- a/api/config/plugins.py +++ b/api/config/plugins.py @@ -28,7 +28,7 @@ _filters = {} _hooks = {} -class PluginCache(object): +class PluginCache: def __init__(self, prefix): self.prefix = prefix @@ -81,7 +81,7 @@ def load_settings(name, settings): "text": django_settings.ENV, } values = {} - prefix = "FUNKWHALE_PLUGIN_{}".format(name.upper()) + prefix = f"FUNKWHALE_PLUGIN_{name.upper()}" for s in settings: key = "_".join([prefix, s["name"].upper()]) value = mapping[s["type"]](key, default=s.get("default", None)) @@ -262,7 +262,7 @@ def get_serializer_from_conf_template(conf, source=False, user=None): self.fields["library"] = LibraryField(actor=user.actor) for vname, v in validators.items(): - setattr(Serializer, "validate_{}".format(vname), v) + setattr(Serializer, f"validate_{vname}", v) return Serializer diff --git a/api/config/settings/__init__.py b/api/config/settings/__init__.py index 40a96afc6..e69de29bb 100644 --- a/api/config/settings/__init__.py +++ b/api/config/settings/__init__.py @@ -1 +0,0 @@ -# -*- coding: utf-8 -*- diff --git a/api/config/settings/common.py b/api/config/settings/common.py index 710e31fdc..075520a59 100644 --- a/api/config/settings/common.py +++ b/api/config/settings/common.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, unicode_literals - import logging.config import sys from collections import OrderedDict @@ -170,7 +167,7 @@ else: FUNKWHALE_PROTOCOL = FUNKWHALE_PROTOCOL.lower() FUNKWHALE_HOSTNAME = FUNKWHALE_HOSTNAME.lower() -FUNKWHALE_URL = "{}://{}".format(FUNKWHALE_PROTOCOL, FUNKWHALE_HOSTNAME) +FUNKWHALE_URL = f"{FUNKWHALE_PROTOCOL}://{FUNKWHALE_HOSTNAME}" FUNKWHALE_SPA_HTML_ROOT = env( "FUNKWHALE_SPA_HTML_ROOT", default=FUNKWHALE_URL + "/front/" ) @@ -336,7 +333,7 @@ FIXTURE_DIRS = (str(APPS_DIR.path("fixtures")),) # EMAIL # ------------------------------------------------------------------------------ DEFAULT_FROM_EMAIL = env( - "DEFAULT_FROM_EMAIL", default="Funkwhale ".format(FUNKWHALE_HOSTNAME) + "DEFAULT_FROM_EMAIL", default=f"Funkwhale " ) """ The name and email address used to send system emails. diff --git a/api/config/settings/local.py b/api/config/settings/local.py index 0265fc3b8..7564fde53 100644 --- a/api/config/settings/local.py +++ b/api/config/settings/local.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Local settings @@ -102,7 +101,7 @@ CSRF_TRUSTED_ORIGINS = [o for o in ALLOWED_HOSTS] REST_FRAMEWORK["DEFAULT_SCHEMA_CLASS"] = "funkwhale_api.schema.CustomAutoSchema" SPECTACULAR_SETTINGS = { "TITLE": "Funkwhale API", - "DESCRIPTION": open("Readme.md", "r").read(), + "DESCRIPTION": open("Readme.md").read(), "VERSION": funkwhale_version, "SCHEMA_PATH_PREFIX": "/api/(v[0-9])?", "OAUTH_FLOWS": ["authorizationCode"], diff --git a/api/config/settings/production.py b/api/config/settings/production.py index aba347af5..589286ab2 100644 --- a/api/config/settings/production.py +++ b/api/config/settings/production.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Production Configurations @@ -9,7 +8,6 @@ Production Configurations """ -from __future__ import absolute_import, unicode_literals from .common import * # noqa diff --git a/api/config/urls/__init__.py b/api/config/urls/__init__.py index b13a17fe8..d8b4c891e 100644 --- a/api/config/urls/__init__.py +++ b/api/config/urls/__init__.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - from django.conf import settings from django.conf.urls import url from django.conf.urls.static import static diff --git a/api/funkwhale_api/__init__.py b/api/funkwhale_api/__init__.py index 7c7f3009f..ced53d79f 100644 --- a/api/funkwhale_api/__init__.py +++ b/api/funkwhale_api/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- __version__ = "1.2.8" __version_info__ = tuple( [ diff --git a/api/funkwhale_api/activity/apps.py b/api/funkwhale_api/activity/apps.py index b70f65c57..9ca0ccc91 100644 --- a/api/funkwhale_api/activity/apps.py +++ b/api/funkwhale_api/activity/apps.py @@ -7,7 +7,7 @@ class ActivityConfig(AppConfig): name = "funkwhale_api.activity" def ready(self): - super(ActivityConfig, self).ready() + super().ready() app_names = [app.name for app in apps.app_configs.values()] record.registry.autodiscover(app_names) diff --git a/api/funkwhale_api/activity/utils.py b/api/funkwhale_api/activity/utils.py index 236d23d88..8d7cb3bd3 100644 --- a/api/funkwhale_api/activity/utils.py +++ b/api/funkwhale_api/activity/utils.py @@ -17,7 +17,7 @@ def combined_recent(limit, **kwargs): _qs_list = list(querysets.values()) union_qs = _qs_list[0].union(*_qs_list[1:]) records = [] - for row in union_qs.order_by("-{}".format(datetime_field))[:limit]: + for row in union_qs.order_by(f"-{datetime_field}")[:limit]: records.append( {"type": row["__type"], "when": row[datetime_field], "pk": row["pk"]} ) diff --git a/api/funkwhale_api/audio/factories.py b/api/funkwhale_api/audio/factories.py index cf84a7864..a08340e85 100644 --- a/api/funkwhale_api/audio/factories.py +++ b/api/funkwhale_api/audio/factories.py @@ -15,7 +15,7 @@ def set_actor(o): def get_rss_channel_name(): - return "rssfeed-{}".format(uuid.uuid4()) + return f"rssfeed-{uuid.uuid4()}" @registry.register diff --git a/api/funkwhale_api/audio/models.py b/api/funkwhale_api/audio/models.py index 8eced6c43..93a4d873d 100644 --- a/api/funkwhale_api/audio/models.py +++ b/api/funkwhale_api/audio/models.py @@ -93,7 +93,7 @@ class Channel(models.Model): suffix = self.actor.preferred_username else: suffix = self.actor.full_username - return federation_utils.full_url("/channels/{}".format(suffix)) + return federation_utils.full_url(f"/channels/{suffix}") def get_rss_url(self): if not self.artist.is_local or self.is_external_rss: diff --git a/api/funkwhale_api/audio/serializers.py b/api/funkwhale_api/audio/serializers.py index 239e4520c..52bbeaf8e 100644 --- a/api/funkwhale_api/audio/serializers.py +++ b/api/funkwhale_api/audio/serializers.py @@ -62,7 +62,7 @@ class ChannelMetadataSerializer(serializers.Serializer): if child not in categories.ITUNES_CATEGORIES[parent]: raise serializers.ValidationError( - '"{}" is not a valid subcategory for "{}"'.format(child, parent) + f'"{child}" is not a valid subcategory for "{parent}"' ) return child @@ -319,7 +319,7 @@ def retrieve_feed(url): except requests.exceptions.HTTPError as e: if e.response: raise FeedFetchException( - "Error while fetching feed: HTTP {}".format(e.response.status_code) + f"Error while fetching feed: HTTP {e.response.status_code}" ) raise FeedFetchException("Error while fetching feed: unknown error") except requests.exceptions.Timeout: @@ -327,9 +327,9 @@ def retrieve_feed(url): except requests.exceptions.ConnectionError: raise FeedFetchException("Error while fetching feed: connection error") except requests.RequestException as e: - raise FeedFetchException("Error while fetching feed: {}".format(e)) + raise FeedFetchException(f"Error while fetching feed: {e}") except Exception as e: - raise FeedFetchException("Error while fetching feed: {}".format(e)) + raise FeedFetchException(f"Error while fetching feed: {e}") return response @@ -348,7 +348,7 @@ def get_channel_from_rss_url(url, raise_exception=False): parsed_feed = feedparser.parse(response.text) serializer = RssFeedSerializer(data=parsed_feed["feed"]) if not serializer.is_valid(raise_exception=raise_exception): - raise FeedFetchException("Invalid xml content: {}".format(serializer.errors)) + raise FeedFetchException(f"Invalid xml content: {serializer.errors}") # second mrf check with validated data urls_to_check = set() @@ -516,7 +516,7 @@ class RssFeedSerializer(serializers.Serializer): else: artist_kwargs = {"pk": None} actor_kwargs = {"pk": None} - preferred_username = "rssfeed-{}".format(uuid.uuid4()) + preferred_username = f"rssfeed-{uuid.uuid4()}" actor_defaults = { "preferred_username": preferred_username, "type": "Application", @@ -594,7 +594,7 @@ class ItunesDurationField(serializers.CharField): try: int_parts.append(int(part)) except (ValueError, TypeError): - raise serializers.ValidationError("Invalid duration {}".format(v)) + raise serializers.ValidationError(f"Invalid duration {v}") if len(int_parts) == 2: hours = 0 @@ -602,7 +602,7 @@ class ItunesDurationField(serializers.CharField): elif len(int_parts) == 3: hours, minutes, seconds = int_parts else: - raise serializers.ValidationError("Invalid duration {}".format(v)) + raise serializers.ValidationError(f"Invalid duration {v}") return (hours * 3600) + (minutes * 60) + seconds @@ -782,8 +782,8 @@ class RssFeedItemSerializer(serializers.Serializer): # update or create, so we restore the cache by hand if existing_track: for field in ["attachment_cover", "description"]: - cached_id_value = getattr(existing_track, "{}_id".format(field)) - new_id_value = getattr(track, "{}_id".format(field)) + cached_id_value = getattr(existing_track, f"{field}_id") + new_id_value = getattr(track, f"{field}_id") if new_id_value and cached_id_value == new_id_value: setattr(track, field, getattr(existing_track, field)) diff --git a/api/funkwhale_api/audio/spa_views.py b/api/funkwhale_api/audio/spa_views.py index 3825057ae..2be4e4c87 100644 --- a/api/funkwhale_api/audio/spa_views.py +++ b/api/funkwhale_api/audio/spa_views.py @@ -61,7 +61,7 @@ def channel_detail(query, redirect_to_ap): "rel": "alternate", "type": "application/rss+xml", "href": obj.get_rss_url(), - "title": "{} - RSS Podcast Feed".format(obj.artist.name), + "title": f"{obj.artist.name} - RSS Podcast Feed", }, ) @@ -73,7 +73,7 @@ def channel_detail(query, redirect_to_ap): "type": "application/json+oembed", "href": ( utils.join_url(settings.FUNKWHALE_URL, reverse("api:v1:oembed")) - + "?format=json&url={}".format(urllib.parse.quote_plus(obj_url)) + + f"?format=json&url={urllib.parse.quote_plus(obj_url)}" ), } ) diff --git a/api/funkwhale_api/audio/views.py b/api/funkwhale_api/audio/views.py index e1fb9a8c5..83a3b6f1f 100644 --- a/api/funkwhale_api/audio/views.py +++ b/api/funkwhale_api/audio/views.py @@ -31,7 +31,7 @@ ARTIST_PREFETCH_QS = ( ) -class ChannelsMixin(object): +class ChannelsMixin: def dispatch(self, request, *args, **kwargs): if not preferences.get("audio__channels_enabled"): return http.HttpResponse(status=405) diff --git a/api/funkwhale_api/cli/library.py b/api/funkwhale_api/cli/library.py index ed48164c3..14b5ef038 100644 --- a/api/funkwhale_api/cli/library.py +++ b/api/funkwhale_api/cli/library.py @@ -20,7 +20,7 @@ def handler_add_tags_from_tracks( if result is None: click.echo(" No relevant tags found") else: - click.echo(" Relevant tags added to {} objects".format(len(result))) + click.echo(f" Relevant tags added to {len(result)} objects") @base.cli.group() diff --git a/api/funkwhale_api/cli/main.py b/api/funkwhale_api/cli/main.py index 99a83f811..903d3fd58 100644 --- a/api/funkwhale_api/cli/main.py +++ b/api/funkwhale_api/cli/main.py @@ -16,7 +16,7 @@ def invoke(): except ValidationError as e: click.secho("Invalid data:", fg="red") for field, errors in e.detail.items(): - click.secho(" {}:".format(field), fg="red") + click.secho(f" {field}:", fg="red") for error in errors: - click.secho(" - {}".format(error), fg="red") + click.secho(f" - {error}", fg="red") sys.exit(1) diff --git a/api/funkwhale_api/cli/media.py b/api/funkwhale_api/cli/media.py index a2c2efc87..57be179c2 100644 --- a/api/funkwhale_api/cli/media.py +++ b/api/funkwhale_api/cli/media.py @@ -39,19 +39,15 @@ def generate_thumbnails(delete): (Attachment, "file", "attachment_square"), ] for model, attribute, key_set in MODELS: - click.echo( - "Generating thumbnails for {}.{}…".format(model._meta.label, attribute) - ) - qs = model.objects.exclude(**{"{}__isnull".format(attribute): True}) + click.echo(f"Generating thumbnails for {model._meta.label}.{attribute}…") + qs = model.objects.exclude(**{f"{attribute}__isnull": True}) qs = qs.exclude(**{attribute: ""}) cache_key = "*{}{}*".format( settings.MEDIA_URL, vif_settings.VERSATILEIMAGEFIELD_SIZED_DIRNAME ) entries = cache.keys(cache_key) if entries: - click.echo( - " Clearing {} cache entries: {}…".format(len(entries), cache_key) - ) + click.echo(f" Clearing {len(entries)} cache entries: {cache_key}…") for keys in common_utils.batch(iter(entries)): cache.delete_many(keys) warmer = VersatileImageFieldWarmer( @@ -62,6 +58,4 @@ def generate_thumbnails(delete): ) click.echo(" Creating images") num_created, failed_to_create = warmer.warm() - click.echo( - " {} created, {} in error".format(num_created, len(failed_to_create)) - ) + click.echo(f" {num_created} created, {len(failed_to_create)} in error") diff --git a/api/funkwhale_api/cli/users.py b/api/funkwhale_api/cli/users.py index a2d020b6f..0921a73e1 100644 --- a/api/funkwhale_api/cli/users.py +++ b/api/funkwhale_api/cli/users.py @@ -7,7 +7,7 @@ from funkwhale_api.users import models, serializers, tasks from . import base, utils -class FakeRequest(object): +class FakeRequest: def __init__(self, session={}): self.session = session @@ -44,7 +44,7 @@ def handler_create_user( for permission in permissions: if permission in models.PERMISSIONS: utils.logger.debug("Setting %s permission to True", permission) - setattr(user, "permission_{}".format(permission), True) + setattr(user, f"permission_{permission}", True) else: utils.logger.warn("Unknown permission %s", permission) utils.logger.debug("Creating actor…") @@ -56,7 +56,7 @@ def handler_create_user( @transaction.atomic def handler_delete_user(usernames, soft=True): for username in usernames: - click.echo("Deleting {}…".format(username)) + click.echo(f"Deleting {username}…") actor = None user = None try: @@ -178,9 +178,9 @@ def create(username, password, email, superuser, staff, permission, upload_quota permissions=permission, upload_quota=upload_quota, ) - click.echo("User {} created!".format(user.username)) + click.echo(f"User {user.username} created!") if generated_password: - click.echo(" Generated password: {}".format(generated_password)) + click.echo(f" Generated password: {generated_password}") @base.delete_command(group=users, id_var="username") diff --git a/api/funkwhale_api/common/authentication.py b/api/funkwhale_api/common/authentication.py index 827fa50f9..9e63d580d 100644 --- a/api/funkwhale_api/common/authentication.py +++ b/api/funkwhale_api/common/authentication.py @@ -16,7 +16,7 @@ class UnverifiedEmail(Exception): def resend_confirmation_email(request, user): THROTTLE_DELAY = 500 - cache_key = "auth:resent-email-confirmation:{}".format(user.pk) + cache_key = f"auth:resent-email-confirmation:{user.pk}" if cache.get(cache_key): return False @@ -34,7 +34,7 @@ class OAuth2Authentication(BaseOAuth2Authentication): resend_confirmation_email(request, e.user) -class ApplicationTokenAuthentication(object): +class ApplicationTokenAuthentication: def authenticate(self, request): try: header = request.headers["Authorization"] diff --git a/api/funkwhale_api/common/fields.py b/api/funkwhale_api/common/fields.py index 9577a73ab..377c0663f 100644 --- a/api/funkwhale_api/common/fields.py +++ b/api/funkwhale_api/common/fields.py @@ -24,9 +24,9 @@ def privacy_level_query(user, lookup_field="privacy_level", user_field="user"): if user.is_anonymous: return models.Q(**{lookup_field: "everyone"}) - return models.Q( - **{"{}__in".format(lookup_field): ["instance", "everyone"]} - ) | models.Q(**{lookup_field: "me", user_field: user}) + return models.Q(**{f"{lookup_field}__in": ["instance", "everyone"]}) | models.Q( + **{lookup_field: "me", user_field: user} + ) class SearchFilter(django_filters.CharFilter): @@ -97,7 +97,7 @@ def get_generic_filter_query(value, relation_name, choices): obj = related_queryset.get(obj_query) except related_queryset.model.DoesNotExist: raise forms.ValidationError("Invalid object") - filter_query &= models.Q(**{"{}_id".format(relation_name): obj.id}) + filter_query &= models.Q(**{f"{relation_name}_id": obj.id}) return filter_query @@ -163,7 +163,7 @@ class GenericRelation(serializers.JSONField): id_value = v[id_attr] id_value = id_field.to_internal_value(id_value) except (TypeError, KeyError, serializers.ValidationError): - raise serializers.ValidationError("Invalid {}".format(id_attr)) + raise serializers.ValidationError(f"Invalid {id_attr}") query_getter = conf.get( "get_query", lambda attr, value: models.Q(**{attr: value}) diff --git a/api/funkwhale_api/common/filters.py b/api/funkwhale_api/common/filters.py index 957b730f2..1530954ac 100644 --- a/api/funkwhale_api/common/filters.py +++ b/api/funkwhale_api/common/filters.py @@ -7,7 +7,7 @@ from drf_spectacular.utils import extend_schema_field from . import fields, models, search, utils -class NoneObject(object): +class NoneObject: def __eq__(self, other): return other.__class__ == NoneObject @@ -46,7 +46,7 @@ class CoerceChoiceField(forms.ChoiceField): try: return [b for a, b in self.choices if v == a][0] except IndexError: - raise forms.ValidationError("Invalid value {}".format(value)) + raise forms.ValidationError(f"Invalid value {value}") @extend_schema_field(bool) @@ -63,9 +63,7 @@ class NullBooleanFilter(filters.ChoiceFilter): return qs if value == NONE: value = None - qs = self.get_method(qs)( - **{"%s__%s" % (self.field_name, self.lookup_expr): value} - ) + qs = self.get_method(qs)(**{f"{self.field_name}__{self.lookup_expr}": value}) return qs.distinct() if self.distinct else qs @@ -217,7 +215,7 @@ class ActorScopeFilter(filters.CharFilter): if not self.library_field: predicate = "pk__in" else: - predicate = "{}__in".format(self.library_field) + predicate = f"{self.library_field}__in" return Q(**{predicate: followed_libraries}) elif scope.startswith("actor:"): @@ -234,7 +232,7 @@ class ActorScopeFilter(filters.CharFilter): return Q(**{self.actor_field: actor}) elif scope.startswith("domain:"): domain = scope.split("domain:", 1)[1] - return Q(**{"{}__domain_id".format(self.actor_field): domain}) + return Q(**{f"{self.actor_field}__domain_id": domain}) else: raise EmptyQuerySet() diff --git a/api/funkwhale_api/common/management/commands/script.py b/api/funkwhale_api/common/management/commands/script.py index 7f8d5c15d..7f674f2f0 100644 --- a/api/funkwhale_api/common/management/commands/script.py +++ b/api/funkwhale_api/common/management/commands/script.py @@ -50,7 +50,7 @@ class Command(BaseCommand): self.stdout.write(self.style.SUCCESS(name)) self.stdout.write("") for line in script["help"].splitlines(): - self.stdout.write(" {}".format(line)) + self.stdout.write(f" {line}") self.stdout.write("") def get_scripts(self): diff --git a/api/funkwhale_api/common/middleware.py b/api/funkwhale_api/common/middleware.py index c01ff6a53..955214e32 100644 --- a/api/funkwhale_api/common/middleware.py +++ b/api/funkwhale_api/common/middleware.py @@ -78,7 +78,7 @@ def serve_spa(request): # We add the style add the end of the body to ensure it has the highest # priority (since it will come after other stylesheets) body, tail = tail.split("", 1) - css = "".format(css) + css = f"" tail = body + "\n" + css + "\n" + tail # set a csrf token so that visitor can login / query API if needed @@ -93,13 +93,13 @@ TITLE_REGEX = re.compile(r".*") def replace_manifest_url(head, new_url): - replacement = ''.format(new_url) + replacement = f'' head = MANIFEST_LINK_REGEX.sub(replacement, head) return head def replace_title(head, new_title): - replacement = "{}".format(html.escape(new_title)) + replacement = f"{html.escape(new_title)}" head = TITLE_REGEX.sub(replacement, head) return head @@ -117,7 +117,7 @@ def get_spa_file(spa_url, name): # we try to open a local file with open(path, "rb") as f: return f.read().decode("utf-8") - cache_key = "spa-file:{}:{}".format(spa_url, name) + cache_key = f"spa-file:{spa_url}:{name}" cached = caches["local"].get(cache_key) if cached: return cached @@ -170,11 +170,7 @@ def render_tags(tags): yield "<{tag} {attrs} />".format( tag=tag.pop("tag"), attrs=" ".join( - [ - '{}="{}"'.format(a, html.escape(str(v))) - for a, v in sorted(tag.items()) - if v - ] + [f'{a}="{html.escape(str(v))}"' for a, v in sorted(tag.items()) if v] ), ) diff --git a/api/funkwhale_api/common/mixins.py b/api/funkwhale_api/common/mixins.py index 2781c5b21..466bb0d3e 100644 --- a/api/funkwhale_api/common/mixins.py +++ b/api/funkwhale_api/common/mixins.py @@ -3,7 +3,7 @@ from django.shortcuts import get_object_or_404 from rest_framework import serializers -class MultipleLookupDetailMixin(object): +class MultipleLookupDetailMixin: lookup_value_regex = "[^/]+" lookup_field = "composite" diff --git a/api/funkwhale_api/common/models.py b/api/funkwhale_api/common/models.py index 2b6e4c13f..ebd705813 100644 --- a/api/funkwhale_api/common/models.py +++ b/api/funkwhale_api/common/models.py @@ -36,7 +36,7 @@ class NotEqual(Lookup): lhs, lhs_params = self.process_lhs(compiler, connection) rhs, rhs_params = self.process_rhs(compiler, connection) params = lhs_params + rhs_params - return "%s <> %s" % (lhs, rhs), params + return f"{lhs} <> {rhs}", params class NullsLastSQLCompiler(SQLCompiler): @@ -77,8 +77,8 @@ class NullsLastQuerySet(models.QuerySet): class LocalFromFidQuerySet: def local(self, include=True): host = settings.FEDERATION_HOSTNAME - query = models.Q(fid__startswith="http://{}/".format(host)) | models.Q( - fid__startswith="https://{}/".format(host) + query = models.Q(fid__startswith=f"http://{host}/") | models.Q( + fid__startswith=f"https://{host}/" ) if include: return self.filter(query) @@ -362,7 +362,7 @@ CONTENT_FKS = { def remove_attached_content(sender, instance, **kwargs): fk_fields = CONTENT_FKS.get(instance._meta.label, []) for field in fk_fields: - if getattr(instance, "{}_id".format(field)): + if getattr(instance, f"{field}_id"): try: getattr(instance, field).delete() except Content.DoesNotExist: diff --git a/api/funkwhale_api/common/mutations.py b/api/funkwhale_api/common/mutations.py index f402a0276..a21e5e810 100644 --- a/api/funkwhale_api/common/mutations.py +++ b/api/funkwhale_api/common/mutations.py @@ -43,7 +43,7 @@ class Registry(persisting_theory.Registry): def has_perm(self, perm, type, obj, actor): if perm not in ["approve", "suggest"]: - raise ValueError("Invalid permission {}".format(perm)) + raise ValueError(f"Invalid permission {perm}") conf = self.get_conf(type, obj) checker = conf["perm_checkers"].get(perm) if not checker: @@ -54,7 +54,7 @@ class Registry(persisting_theory.Registry): try: type_conf = self[type] except KeyError: - raise ConfNotFound("{} is not a registered mutation".format(type)) + raise ConfNotFound(f"{type} is not a registered mutation") try: conf = type_conf[obj.__class__] @@ -63,7 +63,7 @@ class Registry(persisting_theory.Registry): conf = type_conf[None] except KeyError: raise ConfNotFound( - "No mutation configuration found for {}".format(obj.__class__) + f"No mutation configuration found for {obj.__class__}" ) return conf diff --git a/api/funkwhale_api/common/preferences.py b/api/funkwhale_api/common/preferences.py index 17d348f2a..930bd9e27 100644 --- a/api/funkwhale_api/common/preferences.py +++ b/api/funkwhale_api/common/preferences.py @@ -7,7 +7,7 @@ from dynamic_preferences import serializers, types from dynamic_preferences.registries import global_preferences_registry -class DefaultFromSettingMixin(object): +class DefaultFromSettingMixin: def get_default(self): return getattr(settings, self.setting) @@ -38,7 +38,7 @@ class StringListSerializer(serializers.BaseSerializer): if type(value) not in [list, tuple]: raise cls.exception( - "Cannot serialize, value {} is not a list or a tuple".format(value) + f"Cannot serialize, value {value} is not a list or a tuple" ) if cls.sort: @@ -57,7 +57,7 @@ class StringListPreference(types.BasePreferenceType): field_class = forms.MultipleChoiceField def get_api_additional_data(self): - d = super(StringListPreference, self).get_api_additional_data() + d = super().get_api_additional_data() d["choices"] = self.get("choices") return d @@ -72,14 +72,14 @@ class JSONSerializer(serializers.BaseSerializer): data_serializer = cls.data_serializer_class(data=value) if not data_serializer.is_valid(): raise cls.exception( - "{} is not a valid value: {}".format(value, data_serializer.errors) + f"{value} is not a valid value: {data_serializer.errors}" ) value = data_serializer.validated_data try: return json.dumps(value, sort_keys=True) except TypeError: raise cls.exception( - "Cannot serialize, value {} is not JSON serializable".format(value) + f"Cannot serialize, value {value} is not JSON serializable" ) @classmethod diff --git a/api/funkwhale_api/common/scripts/create_actors.py b/api/funkwhale_api/common/scripts/create_actors.py index 93100540f..920ec6cb1 100644 --- a/api/funkwhale_api/common/scripts/create_actors.py +++ b/api/funkwhale_api/common/scripts/create_actors.py @@ -9,15 +9,13 @@ from funkwhale_api.users.models import User, create_actor def main(command, **kwargs): qs = User.objects.filter(actor__isnull=True).order_by("username") total = len(qs) - command.stdout.write("{} users found without actors".format(total)) + command.stdout.write(f"{total} users found without actors") for i, user in enumerate(qs): - command.stdout.write( - "{}/{} creating actor for {}".format(i + 1, total, user.username) - ) + command.stdout.write(f"{i + 1}/{total} creating actor for {user.username}") try: user.actor = create_actor(user) except IntegrityError as e: # somehow, an actor with the the url exists in the database - command.stderr.write("Error while creating actor: {}".format(str(e))) + command.stderr.write(f"Error while creating actor: {str(e)}") continue user.save(update_fields=["actor"]) diff --git a/api/funkwhale_api/common/scripts/create_image_variations.py b/api/funkwhale_api/common/scripts/create_image_variations.py index ac2279cc8..45b1b3880 100644 --- a/api/funkwhale_api/common/scripts/create_image_variations.py +++ b/api/funkwhale_api/common/scripts/create_image_variations.py @@ -13,7 +13,7 @@ MODELS = [ def main(command, **kwargs): for model, attribute, key_set in MODELS: - qs = model.objects.exclude(**{"{}__isnull".format(attribute): True}) + qs = model.objects.exclude(**{f"{attribute}__isnull": True}) qs = qs.exclude(**{attribute: ""}) warmer = VersatileImageFieldWarmer( instance_or_queryset=qs, @@ -21,10 +21,8 @@ def main(command, **kwargs): image_attr=attribute, verbose=True, ) - command.stdout.write( - "Creating images for {} / {}".format(model.__name__, attribute) - ) + command.stdout.write(f"Creating images for {model.__name__} / {attribute}") num_created, failed_to_create = warmer.warm() command.stdout.write( - " {} created, {} in error".format(num_created, len(failed_to_create)) + f" {num_created} created, {len(failed_to_create)} in error" ) diff --git a/api/funkwhale_api/common/scripts/delete_pre_017_federated_uploads.py b/api/funkwhale_api/common/scripts/delete_pre_017_federated_uploads.py index 527b5c7b2..c27a0a5f8 100644 --- a/api/funkwhale_api/common/scripts/delete_pre_017_federated_uploads.py +++ b/api/funkwhale_api/common/scripts/delete_pre_017_federated_uploads.py @@ -10,5 +10,5 @@ def main(command, **kwargs): source__startswith="http", source__contains="/federation/music/file/" ).exclude(source__contains="youtube") total = queryset.count() - command.stdout.write("{} uploads found".format(total)) + command.stdout.write(f"{total} uploads found") queryset.delete() diff --git a/api/funkwhale_api/common/scripts/django_permissions_to_user_permissions.py b/api/funkwhale_api/common/scripts/django_permissions_to_user_permissions.py index 0a07fa7fe..8fb15f06b 100644 --- a/api/funkwhale_api/common/scripts/django_permissions_to_user_permissions.py +++ b/api/funkwhale_api/common/scripts/django_permissions_to_user_permissions.py @@ -23,6 +23,6 @@ def main(command, **kwargs): total = users.count() command.stdout.write( - "Updating {} users with {} permission...".format(total, user_permission) + f"Updating {total} users with {user_permission} permission..." ) - users.update(**{"permission_{}".format(user_permission): True}) + users.update(**{f"permission_{user_permission}": True}) diff --git a/api/funkwhale_api/common/scripts/migrate_to_user_libraries.py b/api/funkwhale_api/common/scripts/migrate_to_user_libraries.py index a387fca80..de6788eb2 100644 --- a/api/funkwhale_api/common/scripts/migrate_to_user_libraries.py +++ b/api/funkwhale_api/common/scripts/migrate_to_user_libraries.py @@ -36,9 +36,7 @@ def create_libraries(open_api, stdout): ) libraries_by_user[library.actor.user.pk] = library.pk if created: - stdout.write( - " * Created library {} for user {}".format(library.pk, a.user.pk) - ) + stdout.write(f" * Created library {library.pk} for user {a.user.pk}") else: stdout.write( " * Found existing library {} for user {}".format( @@ -60,13 +58,9 @@ def update_uploads(libraries_by_user, stdout): ) total = candidates.update(library=library_id, import_status="finished") if total: - stdout.write( - " * Assigned {} uploads to user {}'s library".format(total, user_id) - ) + stdout.write(f" * Assigned {total} uploads to user {user_id}'s library") else: - stdout.write( - " * No uploads to assign to user {}'s library".format(user_id) - ) + stdout.write(f" * No uploads to assign to user {user_id}'s library") def update_orphan_uploads(open_api, stdout): @@ -105,14 +99,12 @@ def update_orphan_uploads(open_api, stdout): def set_fid(queryset, path, stdout): model = queryset.model._meta.label qs = queryset.filter(fid=None) - base_url = "{}{}".format(settings.FUNKWHALE_URL, path) - stdout.write( - "* Assigning federation ids to {} entries (path: {})".format(model, base_url) - ) + base_url = f"{settings.FUNKWHALE_URL}{path}" + stdout.write(f"* Assigning federation ids to {model} entries (path: {base_url})") new_fid = functions.Concat(Value(base_url), F("uuid"), output_field=CharField()) total = qs.update(fid=new_fid) - stdout.write(" * {} entries updated".format(total)) + stdout.write(f" * {total} entries updated") def update_shared_inbox_url(stdout): @@ -123,16 +115,16 @@ def update_shared_inbox_url(stdout): def generate_actor_urls(part, stdout): - field = "{}_url".format(part) - stdout.write("* Update {} for local actors...".format(field)) + field = f"{part}_url" + stdout.write(f"* Update {field} for local actors...") queryset = federation_models.Actor.objects.local().filter(**{field: None}) - base_url = "{}/federation/actors/".format(settings.FUNKWHALE_URL) + base_url = f"{settings.FUNKWHALE_URL}/federation/actors/" new_field = functions.Concat( Value(base_url), F("preferred_username"), - Value("/{}".format(part)), + Value(f"/{part}"), output_field=CharField(), ) diff --git a/api/funkwhale_api/common/search.py b/api/funkwhale_api/common/search.py index a28184d41..4664db462 100644 --- a/api/funkwhale_api/common/search.py +++ b/api/funkwhale_api/common/search.py @@ -72,7 +72,7 @@ def get_fts_query(query_string, fts_fields=["body_text"], model=None): else: query_string = remove_chars(query_string, ['"', "&", "(", ")", "!", "'"]) parts = query_string.replace(":", "").split(" ") - parts = ["{}:*".format(p) for p in parts if p] + parts = [f"{p}:*" for p in parts if p] if not parts: return Q(pk=None) @@ -97,7 +97,7 @@ def get_fts_query(query_string, fts_fields=["body_text"], model=None): ) } ).values_list("pk", flat=True) - new_query = Q(**{"{}__in".format(fk_field_name): list(subquery)}) + new_query = Q(**{f"{fk_field_name}__in": list(subquery)}) else: new_query = Q( **{ @@ -180,7 +180,7 @@ class SearchConfig: except KeyError: # no cleaning to apply value = token["value"] - q = Q(**{"{}__icontains".format(to): value}) + q = Q(**{f"{to}__icontains": value}) if not specific_field_query: specific_field_query = q else: diff --git a/api/funkwhale_api/common/serializers.py b/api/funkwhale_api/common/serializers.py index efb916957..d10969eeb 100644 --- a/api/funkwhale_api/common/serializers.py +++ b/api/funkwhale_api/common/serializers.py @@ -82,14 +82,14 @@ class RelatedField(serializers.RelatedField): ) -class Action(object): +class Action: def __init__(self, name, allow_all=False, qs_filter=None): self.name = name self.allow_all = allow_all self.qs_filter = qs_filter def __repr__(self): - return "".format(self.name) + return f"" class ActionSerializer(serializers.Serializer): @@ -113,7 +113,7 @@ class ActionSerializer(serializers.Serializer): ) for action in self.actions_by_name.keys(): - handler_name = "handle_{}".format(action) + handler_name = f"handle_{action}" assert hasattr(self, handler_name), "{} miss a {} method".format( self.__class__.__name__, handler_name ) @@ -133,9 +133,9 @@ class ActionSerializer(serializers.Serializer): if value == "all": return self.queryset.all().order_by("id") if type(value) in [list, tuple]: - return self.queryset.filter( - **{"{}__in".format(self.pk_field): value} - ).order_by(self.pk_field) + return self.queryset.filter(**{f"{self.pk_field}__in": value}).order_by( + self.pk_field + ) raise serializers.ValidationError( "{} is not a valid value for objects. You must provide either a " @@ -281,7 +281,7 @@ class APIMutationSerializer(serializers.ModelSerializer): def validate_type(self, value): if value not in self.context["registry"]: - raise serializers.ValidationError("Invalid mutation type {}".format(value)) + raise serializers.ValidationError(f"Invalid mutation type {value}") return value @@ -321,7 +321,7 @@ class ContentSerializer(serializers.Serializer): return utils.render_html(o.text, o.content_type) -class NullToEmptDict(object): +class NullToEmptDict: def get_attribute(self, o): attr = super().get_attribute(o) if attr is None: diff --git a/api/funkwhale_api/common/utils.py b/api/funkwhale_api/common/utils.py index b49c6fdd7..63be15464 100644 --- a/api/funkwhale_api/common/utils.py +++ b/api/funkwhale_api/common/utils.py @@ -36,7 +36,7 @@ def rename_file(instance, field_name, new_name, allow_missing_file=False): field = getattr(instance, field_name) current_name, extension = os.path.splitext(field.name) - new_name_with_extension = "{}{}".format(new_name, extension) + new_name_with_extension = f"{new_name}{extension}" try: shutil.move(field.path, new_name_with_extension) except FileNotFoundError: @@ -71,7 +71,7 @@ def set_query_parameter(url, **kwargs): @deconstructible -class ChunkedPath(object): +class ChunkedPath: def sanitize_filename(self, filename): return filename.replace("/", "-") @@ -88,7 +88,7 @@ class ChunkedPath(object): parts = chunks[:3] + [filename] else: ext = os.path.splitext(filename)[1][1:].lower() - new_filename = "".join(chunks[3:]) + ".{}".format(ext) + new_filename = "".join(chunks[3:]) + f".{ext}" parts = chunks[:3] + [new_filename] return os.path.join(self.root, *parts) @@ -227,7 +227,7 @@ def replace_prefix(queryset, field, old, new): on a whole table with a single query. """ - qs = queryset.filter(**{"{}__startswith".format(field): old}) + qs = queryset.filter(**{f"{field}__startswith": old}) # we extract the part after the old prefix, and Concat it with our new prefix update = models.functions.Concat( models.Value(new), @@ -353,7 +353,7 @@ def attach_content(obj, field, content_data): from . import models content_data = content_data or {} - existing = getattr(obj, "{}_id".format(field)) + existing = getattr(obj, f"{field}_id") if existing: if same_content(getattr(obj, field), **content_data): @@ -378,7 +378,7 @@ def attach_content(obj, field, content_data): def attach_file(obj, field, file_data, fetch=False): from . import models, tasks - existing = getattr(obj, "{}_id".format(field)) + existing = getattr(obj, f"{field}_id") if existing: getattr(obj, field).delete() @@ -395,7 +395,7 @@ def attach_file(obj, field, file_data, fetch=False): name = [ getattr(obj, field) for field in name_fields if getattr(obj, field, None) ][0] - filename = "{}-{}.{}".format(field, name, extension) + filename = f"{field}-{name}.{extension}" if "url" in file_data: attachment.url = file_data["url"] else: @@ -487,4 +487,4 @@ def get_file_hash(file, algo=None, chunk_size=None, full_read=False): # sometimes, it's useful to only hash the beginning of the file, e.g # to avoid a lot of I/O when crawling large libraries hash.update(file.read(chunk_size)) - return "{}:{}".format(algo, hash.hexdigest()) + return f"{algo}:{hash.hexdigest()}" diff --git a/api/funkwhale_api/common/validators.py b/api/funkwhale_api/common/validators.py index 78a4b4c7c..93a22075e 100644 --- a/api/funkwhale_api/common/validators.py +++ b/api/funkwhale_api/common/validators.py @@ -72,7 +72,7 @@ class ImageDimensionsValidator: @deconstructible -class FileValidator(object): +class FileValidator: """ Taken from https://gist.github.com/jrosebr1/2140738 Validator for files, checking the size, extension and mimetype. @@ -163,5 +163,5 @@ class DomainValidator(validators.URLValidator): If it fails, we know the domain is not valid. """ - super().__call__("http://{}".format(value)) + super().__call__(f"http://{value}") return value diff --git a/api/funkwhale_api/contrib/__init__.py b/api/funkwhale_api/contrib/__init__.py index 40a96afc6..e69de29bb 100644 --- a/api/funkwhale_api/contrib/__init__.py +++ b/api/funkwhale_api/contrib/__init__.py @@ -1 +0,0 @@ -# -*- coding: utf-8 -*- diff --git a/api/funkwhale_api/contrib/listenbrainz/client.py b/api/funkwhale_api/contrib/listenbrainz/client.py index 88fb1f16b..b2d1f169b 100644 --- a/api/funkwhale_api/contrib/listenbrainz/client.py +++ b/api/funkwhale_api/contrib/listenbrainz/client.py @@ -68,7 +68,7 @@ class Track: } def __repr__(self): - return "Track(%s, %s)" % (self.artist_name, self.track_name) + return f"Track({self.artist_name}, {self.track_name})" class ListenBrainzClient: @@ -127,7 +127,7 @@ class ListenBrainzClient: response_data = response_text self._handle_ratelimit(response) - log_msg = "Response %s: %r" % (response.status, response_data) + log_msg = f"Response {response.status}: {response_data!r}" if response.status == 429 and retry < 5: # Too Many Requests self.logger.warning(log_msg) return self._submit(listen_type, payload, retry + 1) diff --git a/api/funkwhale_api/contrib/scrobbler/scrobbler.py b/api/funkwhale_api/contrib/scrobbler/scrobbler.py index 6a380c586..38a6477ff 100644 --- a/api/funkwhale_api/contrib/scrobbler/scrobbler.py +++ b/api/funkwhale_api/contrib/scrobbler/scrobbler.py @@ -84,16 +84,16 @@ def get_scrobble_payload(track, date, suffix="[0]"): """ upload = track.uploads.filter(duration__gte=0).first() data = { - "a{}".format(suffix): track.artist.name, - "t{}".format(suffix): track.title, - "l{}".format(suffix): upload.duration if upload else 0, - "b{}".format(suffix): (track.album.title if track.album else "") or "", - "n{}".format(suffix): track.position or "", - "m{}".format(suffix): str(track.mbid or ""), - "o{}".format(suffix): "P", # Source: P = chosen by user + f"a{suffix}": track.artist.name, + f"t{suffix}": track.title, + f"l{suffix}": upload.duration if upload else 0, + f"b{suffix}": (track.album.title if track.album else "") or "", + f"n{suffix}": track.position or "", + f"m{suffix}": str(track.mbid or ""), + f"o{suffix}": "P", # Source: P = chosen by user } if date: - data["i{}".format(suffix)] = int(date.timestamp()) + data[f"i{suffix}"] = int(date.timestamp()) return data diff --git a/api/funkwhale_api/contrib/sites/__init__.py b/api/funkwhale_api/contrib/sites/__init__.py index 40a96afc6..e69de29bb 100644 --- a/api/funkwhale_api/contrib/sites/__init__.py +++ b/api/funkwhale_api/contrib/sites/__init__.py @@ -1 +0,0 @@ -# -*- coding: utf-8 -*- diff --git a/api/funkwhale_api/factories.py b/api/funkwhale_api/factories.py index ae7f68071..8a2c6f76f 100644 --- a/api/funkwhale_api/factories.py +++ b/api/funkwhale_api/factories.py @@ -316,16 +316,16 @@ class FunkwhaleProvider(internet_provider.Provider): def federation_url(self, prefix="", local=False): def path_generator(): - return "{}/{}".format(prefix, uuid.uuid4()) + return f"{prefix}/{uuid.uuid4()}" domain = settings.FEDERATION_HOSTNAME if local else self.domain_name() protocol = "https" path = path_generator() - return "{}://{}/{}".format(protocol, domain, path) + return f"{protocol}://{domain}/{path}" def user_name(self): u = super().user_name() - return "{}{}".format(u, random.randint(10, 999)) + return f"{u}{random.randint(10, 999)}" def music_genre(self): return random.choice(TAGS_DATA["genre"]) diff --git a/api/funkwhale_api/favorites/models.py b/api/funkwhale_api/favorites/models.py index a6a80cebd..5cba39f35 100644 --- a/api/funkwhale_api/favorites/models.py +++ b/api/funkwhale_api/favorites/models.py @@ -23,4 +23,4 @@ class TrackFavorite(models.Model): return favorite def get_activity_url(self): - return "{}/favorites/tracks/{}".format(self.user.get_activity_url(), self.pk) + return f"{self.user.get_activity_url()}/favorites/tracks/{self.pk}" diff --git a/api/funkwhale_api/federation/activity.py b/api/funkwhale_api/federation/activity.py index db0de1828..2a41d4b89 100644 --- a/api/funkwhale_api/federation/activity.py +++ b/api/funkwhale_api/federation/activity.py @@ -241,8 +241,8 @@ class InboxRouter(Router): for k in r.keys(): if k in ["object", "target", "related_object"]: update_fields += [ - "{}_id".format(k), - "{}_content_type".format(k), + f"{k}_id", + f"{k}_content_type", ] else: update_fields.append(k) @@ -264,7 +264,7 @@ class InboxRouter(Router): user = ii.actor.get_user() if not user: continue - group = "user.{}.inbox".format(user.pk) + group = f"user.{user.pk}.inbox" channels.group_send( group, { diff --git a/api/funkwhale_api/federation/actors.py b/api/funkwhale_api/federation/actors.py index 7163bd258..86864d591 100644 --- a/api/funkwhale_api/federation/actors.py +++ b/api/funkwhale_api/federation/actors.py @@ -22,7 +22,7 @@ def get_actor_data(actor_url): try: return response.json() except Exception: - raise ValueError("Invalid actor payload: {}".format(response.text)) + raise ValueError(f"Invalid actor payload: {response.text}") def get_actor(fid, skip_cache=False): diff --git a/api/funkwhale_api/federation/api_serializers.py b/api/funkwhale_api/federation/api_serializers.py index 844be0c1a..bee31bbeb 100644 --- a/api/funkwhale_api/federation/api_serializers.py +++ b/api/funkwhale_api/federation/api_serializers.py @@ -216,7 +216,7 @@ class FetchSerializer(serializers.ModelSerializer): except validators.ValidationError: return value - return "webfinger://{}".format(value) + return f"webfinger://{value}" def create(self, validated_data): check_duplicates = not validated_data.get("force", False) diff --git a/api/funkwhale_api/federation/api_views.py b/api/funkwhale_api/federation/api_views.py index 75c414893..6ddca91e8 100644 --- a/api/funkwhale_api/federation/api_views.py +++ b/api/funkwhale_api/federation/api_views.py @@ -190,12 +190,12 @@ class LibraryViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet): ) except requests.exceptions.RequestException as e: return response.Response( - {"detail": "Error while fetching the library: {}".format(str(e))}, + {"detail": f"Error while fetching the library: {str(e)}"}, status=400, ) except serializers.serializers.ValidationError as e: return response.Response( - {"detail": "Invalid data in remote library: {}".format(str(e))}, + {"detail": f"Invalid data in remote library: {str(e)}"}, status=400, ) serializer = self.serializer_class(library) diff --git a/api/funkwhale_api/federation/contexts.py b/api/funkwhale_api/federation/contexts.py index 537d7f736..351b4f7e2 100644 --- a/api/funkwhale_api/federation/contexts.py +++ b/api/funkwhale_api/federation/contexts.py @@ -362,14 +362,14 @@ class NS: def __getattr__(self, key): if key not in self.conf["document"]["@context"]: raise AttributeError( - "{} is not a valid property of context {}".format(key, self.baseUrl) + f"{key} is not a valid property of context {self.baseUrl}" ) return self.baseUrl + key class NoopContext: def __getattr__(self, key): - return "_:{}".format(key) + return f"_:{key}" NOOP = NoopContext() diff --git a/api/funkwhale_api/federation/factories.py b/api/funkwhale_api/federation/factories.py index 61a15c6b4..f6a20990b 100644 --- a/api/funkwhale_api/federation/factories.py +++ b/api/funkwhale_api/federation/factories.py @@ -106,7 +106,7 @@ class ActorFactory(NoUpdateOnCreate, factory.django.DjangoModelFactory): summary = factory.Faker("paragraph") domain = factory.SubFactory(DomainFactory) fid = factory.LazyAttribute( - lambda o: "https://{}/users/{}".format(o.domain.name, o.preferred_username) + lambda o: f"https://{o.domain.name}/users/{o.preferred_username}" ) followers_url = factory.LazyAttribute( lambda o: "https://{}/users/{}followers".format( @@ -142,7 +142,7 @@ class ActorFactory(NoUpdateOnCreate, factory.django.DjangoModelFactory): self.domain = models.Domain.objects.get_or_create( name=settings.FEDERATION_HOSTNAME )[0] - self.fid = "https://{}/actors/{}".format(self.domain, self.preferred_username) + self.fid = f"https://{self.domain}/actors/{self.preferred_username}" self.save(update_fields=["domain", "fid"]) if not create: if extracted and hasattr(extracted, "pk"): @@ -300,13 +300,13 @@ class NoteFactory(factory.Factory): @registry.register(name="federation.AudioMetadata") class AudioMetadataFactory(factory.Factory): recording = factory.LazyAttribute( - lambda o: "https://musicbrainz.org/recording/{}".format(uuid.uuid4()) + lambda o: f"https://musicbrainz.org/recording/{uuid.uuid4()}" ) artist = factory.LazyAttribute( - lambda o: "https://musicbrainz.org/artist/{}".format(uuid.uuid4()) + lambda o: f"https://musicbrainz.org/artist/{uuid.uuid4()}" ) release = factory.LazyAttribute( - lambda o: "https://musicbrainz.org/release/{}".format(uuid.uuid4()) + lambda o: f"https://musicbrainz.org/release/{uuid.uuid4()}" ) bitrate = 42 length = 43 diff --git a/api/funkwhale_api/federation/jsonld.py b/api/funkwhale_api/federation/jsonld.py index 240c410ee..44d4035f2 100644 --- a/api/funkwhale_api/federation/jsonld.py +++ b/api/funkwhale_api/federation/jsonld.py @@ -257,7 +257,7 @@ class JsonLdSerializer(serializers.Serializer): data = expand(data) except ValueError as e: raise serializers.ValidationError( - "{} is not a valid jsonld document: {}".format(data, e) + f"{data} is not a valid jsonld document: {e}" ) try: config = self.Meta.jsonld_mapping diff --git a/api/funkwhale_api/federation/library.py b/api/funkwhale_api/federation/library.py index e084021fa..abd82d097 100644 --- a/api/funkwhale_api/federation/library.py +++ b/api/funkwhale_api/federation/library.py @@ -21,7 +21,7 @@ def get_library_data(library_url, actor): elif scode == 403: return {"errors": ["Permission denied while scanning library"]} elif scode >= 400: - return {"errors": ["Error {} while fetching the library".format(scode)]} + return {"errors": [f"Error {scode} while fetching the library"]} serializer = serializers.LibrarySerializer(data=response.json()) if not serializer.is_valid(): return {"errors": ["Invalid ActivityPub response from remote library"]} diff --git a/api/funkwhale_api/federation/management/commands/fix_federation_ids.py b/api/funkwhale_api/federation/management/commands/fix_federation_ids.py index 0ccf2d208..77bd5c299 100644 --- a/api/funkwhale_api/federation/management/commands/fix_federation_ids.py +++ b/api/funkwhale_api/federation/management/commands/fix_federation_ids.py @@ -67,9 +67,7 @@ class Command(BaseCommand): for kls, fields in MODELS: results[kls] = {} for field in fields: - candidates = kls.objects.filter( - **{"{}__startswith".format(field): old_prefix} - ) + candidates = kls.objects.filter(**{f"{field}__startswith": old_prefix}) results[kls][field] = candidates.count() total = sum([t for k in results.values() for t in k.values()]) @@ -92,9 +90,7 @@ class Command(BaseCommand): ) else: - self.stdout.write( - "No objects found with prefix {}, exiting.".format(old_prefix) - ) + self.stdout.write(f"No objects found with prefix {old_prefix}, exiting.") return if options["dry_run"]: self.stdout.write( @@ -112,9 +108,7 @@ class Command(BaseCommand): for kls, fields in results.items(): for field, count in fields.items(): - self.stdout.write( - "Replacing {} on {} {}…".format(field, count, kls._meta.label) - ) + self.stdout.write(f"Replacing {field} on {count} {kls._meta.label}…") candidates = kls.objects.all() utils.replace_prefix(candidates, field, old=old_prefix, new=new_prefix) self.stdout.write("") diff --git a/api/funkwhale_api/federation/models.py b/api/funkwhale_api/federation/models.py index 2b6a86dc2..8ead384df 100644 --- a/api/funkwhale_api/federation/models.py +++ b/api/funkwhale_api/federation/models.py @@ -80,7 +80,7 @@ class ActorQuerySet(models.QuerySet): ) qs = qs.annotate( **{ - "_usage_{}".format(s): models.Sum( + f"_usage_{s}": models.Sum( "libraries__uploads__size", filter=uploads_query ) } @@ -226,22 +226,22 @@ class Actor(models.Model): verbose_name = "Account" def get_moderation_url(self): - return "/manage/moderation/accounts/{}".format(self.full_username) + return f"/manage/moderation/accounts/{self.full_username}" @property def webfinger_subject(self): - return "{}@{}".format(self.preferred_username, settings.FEDERATION_HOSTNAME) + return f"{self.preferred_username}@{settings.FEDERATION_HOSTNAME}" @property def private_key_id(self): - return "{}#main-key".format(self.fid) + return f"{self.fid}#main-key" @property def full_username(self) -> str: - return "{}@{}".format(self.preferred_username, self.domain_id) + return f"{self.preferred_username}@{self.domain_id}" def __str__(self): - return "{}@{}".format(self.preferred_username, self.domain_id) + return f"{self.preferred_username}@{self.domain_id}" @property def is_local(self) -> bool: @@ -270,14 +270,14 @@ class Actor(models.Model): def get_absolute_url(self): if self.is_local: - return federation_utils.full_url("/@{}".format(self.preferred_username)) + return federation_utils.full_url(f"/@{self.preferred_username}") return self.url or self.fid def get_current_usage(self): actor = self.__class__.objects.filter(pk=self.pk).with_current_usage().get() data = {} for s in ["draft", "pending", "skipped", "errored", "finished"]: - data[s] = getattr(actor, "_usage_{}".format(s)) or 0 + data[s] = getattr(actor, f"_usage_{s}") or 0 data["total"] = sum(data.values()) return data @@ -341,8 +341,8 @@ class Actor(models.Model): # matches, we consider the actor has the permission to manage # the object domain = self.domain_id - return obj.fid.startswith("http://{}/".format(domain)) or obj.fid.startswith( - "https://{}/".format(domain) + return obj.fid.startswith(f"http://{domain}/") or obj.fid.startswith( + f"https://{domain}/" ) @property @@ -498,9 +498,7 @@ class AbstractFollow(models.Model): abstract = True def get_federation_id(self): - return federation_utils.full_url( - "{}#follows/{}".format(self.actor.fid, self.uuid) - ) + return federation_utils.full_url(f"{self.actor.fid}#follows/{self.uuid}") class Follow(AbstractFollow): @@ -594,7 +592,7 @@ class LibraryTrack(models.Model): remote_response.raise_for_status() extension = music_utils.get_ext_from_type(self.audio_mimetype) title = " - ".join([self.title, self.album_title, self.artist_name]) - filename = "{}.{}".format(title, extension) + filename = f"{title}.{extension}" tmp_file = tempfile.TemporaryFile() for chunk in r.iter_content(chunk_size=512): tmp_file.write(chunk) diff --git a/api/funkwhale_api/federation/serializers.py b/api/funkwhale_api/federation/serializers.py index 38cf444ed..c6e586023 100644 --- a/api/funkwhale_api/federation/serializers.py +++ b/api/funkwhale_api/federation/serializers.py @@ -116,7 +116,7 @@ class MediaSerializer(jsonld.JsonLdSerializer): if not is_mimetype(v, self.allowed_mimetypes): raise serializers.ValidationError( - "Invalid mimetype {}. Allowed: {}".format(v, self.allowed_mimetypes) + f"Invalid mimetype {v}. Allowed: {self.allowed_mimetypes}" ) return v @@ -371,7 +371,7 @@ class ActorSerializer(jsonld.JsonLdSerializer): ret["publicKey"] = { "owner": instance.fid, "publicKeyPem": instance.public_key, - "id": "{}#main-key".format(instance.fid), + "id": f"{instance.fid}#main-key", } ret["endpoints"] = {} @@ -453,7 +453,7 @@ class ActorSerializer(jsonld.JsonLdSerializer): actor, rss_url=rss_url, attributed_to_fid=attributed_to, - **self.validated_data + **self.validated_data, ) return actor @@ -736,9 +736,7 @@ class FollowActionSerializer(serializers.Serializer): .get() ) except follow_class.DoesNotExist: - raise serializers.ValidationError( - "No follow to {}".format(self.action_type) - ) + raise serializers.ValidationError(f"No follow to {self.action_type}") return validated_data def to_representation(self, instance): @@ -749,7 +747,7 @@ class FollowActionSerializer(serializers.Serializer): return { "@context": jsonld.get_default_context(), - "id": instance.get_federation_id() + "/{}".format(self.action_type), + "id": instance.get_federation_id() + f"/{self.action_type}", "type": self.action_type.title(), "actor": actor.fid, "object": FollowSerializer(instance).data, @@ -855,7 +853,7 @@ class ActorWebfingerSerializer(serializers.Serializer): def to_representation(self, instance): data = {} - data["subject"] = "acct:{}".format(instance.webfinger_subject) + data["subject"] = f"acct:{instance.webfinger_subject}" data["links"] = [ {"rel": "self", "href": instance.fid, "type": "application/activity+json"} ] @@ -881,7 +879,7 @@ class ActivitySerializer(serializers.Serializer): try: object_serializer = OBJECT_SERIALIZERS[type] except KeyError: - raise serializers.ValidationError("Unsupported type {}".format(type)) + raise serializers.ValidationError(f"Unsupported type {type}") serializer = object_serializer(data=value) serializer.is_valid(raise_exception=True) @@ -1165,7 +1163,7 @@ MUSIC_ENTITY_JSONLD_MAPPING = { def repr_tag(tag_name): - return {"type": "Hashtag", "name": "#{}".format(tag_name)} + return {"type": "Hashtag", "name": f"#{tag_name}"} def include_content(repr, content_obj): @@ -1704,9 +1702,7 @@ class FlagSerializer(jsonld.JsonLdSerializer): try: return utils.get_object_by_fid(v, local=True) except ObjectDoesNotExist: - raise serializers.ValidationError( - "Unknown id {} for reported object".format(v) - ) + raise serializers.ValidationError(f"Unknown id {v} for reported object") def validate_type(self, tags): if tags: @@ -1918,7 +1914,7 @@ class ChannelUploadSerializer(jsonld.JsonLdSerializer): tags = [item.tag.name for item in upload.get_all_tagged_items()] if tags: data["tag"] = [repr_tag(name) for name in sorted(set(tags))] - data["summary"] = " ".join(["#{}".format(name) for name in tags]) + data["summary"] = " ".join([f"#{name}" for name in tags]) if self.context.get("include_ap_context", True): data["@context"] = jsonld.get_default_context() @@ -2039,7 +2035,7 @@ class DeleteSerializer(jsonld.JsonLdSerializer): try: obj = utils.get_object_by_fid(url) except utils.ObjectDoesNotExist: - raise serializers.ValidationError("No object matching {}".format(url)) + raise serializers.ValidationError(f"No object matching {url}") if isinstance(obj, music_models.Upload): obj = obj.track diff --git a/api/funkwhale_api/federation/signing.py b/api/funkwhale_api/federation/signing.py index 1f668e72a..7ab1a5d06 100644 --- a/api/funkwhale_api/federation/signing.py +++ b/api/funkwhale_api/federation/signing.py @@ -31,7 +31,7 @@ def verify_date(raw_date): now = timezone.now() if dt < now - delta or dt > now + delta: raise forms.ValidationError( - "Request Date {} is too far in the future or in the past".format(raw_date) + f"Request Date {raw_date} is too far in the future or in the past" ) return dt @@ -70,10 +70,10 @@ def verify_django(django_request, public_key): signature = headers["Signature"] except KeyError: raise exceptions.MissingSignature - url = "http://noop{}".format(django_request.path) + url = f"http://noop{django_request.path}" query = django_request.META["QUERY_STRING"] if query: - url += "?{}".format(query) + url += f"?{query}" signature_headers = signature.split('headers="')[1].split('",')[0] expected = signature_headers.split(" ") logger.debug("Signature expected headers: %s", expected) diff --git a/api/funkwhale_api/federation/tasks.py b/api/funkwhale_api/federation/tasks.py index f9c7e8456..b7799ab28 100644 --- a/api/funkwhale_api/federation/tasks.py +++ b/api/funkwhale_api/federation/tasks.py @@ -170,7 +170,7 @@ def deliver_to_remote(delivery): def fetch_nodeinfo(domain_name): s = session.get_session() - wellknown_url = "https://{}/.well-known/nodeinfo".format(domain_name) + wellknown_url = f"https://{domain_name}/.well-known/nodeinfo" response = s.get(url=wellknown_url) response.raise_for_status() serializer = serializers.NodeInfoSerializer(data=response.json()) diff --git a/api/funkwhale_api/federation/utils.py b/api/funkwhale_api/federation/utils.py index f39381022..ee4d3834d 100644 --- a/api/funkwhale_api/federation/utils.py +++ b/api/funkwhale_api/federation/utils.py @@ -122,10 +122,8 @@ def get_domain_query_from_url(domain, url_field="fid"): to match objects that have this domain in the given field. """ - query = Q(**{"{}__startswith".format(url_field): "http://{}/".format(domain)}) - query = query | Q( - **{"{}__startswith".format(url_field): "https://{}/".format(domain)} - ) + query = Q(**{f"{url_field}__startswith": f"http://{domain}/"}) + query = query | Q(**{f"{url_field}__startswith": f"https://{domain}/"}) return query @@ -143,9 +141,7 @@ def is_local(url) -> bool: return True d = settings.FEDERATION_HOSTNAME - return url.startswith("http://{}/".format(d)) or url.startswith( - "https://{}/".format(d) - ) + return url.startswith(f"http://{d}/") or url.startswith(f"https://{d}/") def get_actor_data_from_username(username): @@ -164,8 +160,8 @@ def get_actor_from_username_data_query(field, data): if field: return Q( **{ - "{}__preferred_username__iexact".format(field): data["username"], - "{}__domain__name__iexact".format(field): data["domain"], + f"{field}__preferred_username__iexact": data["username"], + f"{field}__domain__name__iexact": data["domain"], } ) else: diff --git a/api/funkwhale_api/federation/views.py b/api/funkwhale_api/federation/views.py index 324fb4568..6a79597fa 100644 --- a/api/funkwhale_api/federation/views.py +++ b/api/funkwhale_api/federation/views.py @@ -68,7 +68,7 @@ class AuthenticatedIfAllowListEnabled(permissions.BasePermission): return bool(request.actor) -class FederationMixin(object): +class FederationMixin: permission_classes = [AuthenticatedIfAllowListEnabled] def dispatch(self, request, *args, **kwargs): @@ -223,9 +223,9 @@ class WellKnownViewSet(viewsets.GenericViewSet): return HttpResponse(status=405) try: resource_type, resource = webfinger.clean_resource(request.GET["resource"]) - cleaner = getattr(webfinger, "clean_{}".format(resource_type)) + cleaner = getattr(webfinger, f"clean_{resource_type}") result = cleaner(resource) - handler = getattr(self, "handler_{}".format(resource_type)) + handler = getattr(self, f"handler_{resource_type}") data = handler(result) except forms.ValidationError as e: return response.Response({"errors": {"resource": e.message}}, status=400) diff --git a/api/funkwhale_api/federation/webfinger.py b/api/funkwhale_api/federation/webfinger.py index 6b735f4f6..1d46961f1 100644 --- a/api/funkwhale_api/federation/webfinger.py +++ b/api/funkwhale_api/federation/webfinger.py @@ -30,7 +30,7 @@ def clean_acct(acct_string, ensure_local=True): raise forms.ValidationError("Invalid format") if ensure_local and hostname.lower() != settings.FEDERATION_HOSTNAME: - raise forms.ValidationError("Invalid hostname {}".format(hostname)) + raise forms.ValidationError(f"Invalid hostname {hostname}") return username, hostname diff --git a/api/funkwhale_api/history/models.py b/api/funkwhale_api/history/models.py index 8da4e67cd..648c16cd8 100644 --- a/api/funkwhale_api/history/models.py +++ b/api/funkwhale_api/history/models.py @@ -22,4 +22,4 @@ class Listening(models.Model): ordering = ("-creation_date",) def get_activity_url(self): - return "{}/listenings/tracks/{}".format(self.user.get_activity_url(), self.pk) + return f"{self.user.get_activity_url()}/listenings/tracks/{self.pk}" diff --git a/api/funkwhale_api/manage/serializers.py b/api/funkwhale_api/manage/serializers.py index 2ea740916..fe8c9adbd 100644 --- a/api/funkwhale_api/manage/serializers.py +++ b/api/funkwhale_api/manage/serializers.py @@ -85,10 +85,8 @@ class ManageUserSerializer(serializers.ModelSerializer): permissions = validated_data.pop("permissions", {}) if permissions: for p, value in permissions.items(): - setattr(instance, "permission_{}".format(p), value) - instance.save( - update_fields=["permission_{}".format(p) for p in permissions.keys()] - ) + setattr(instance, f"permission_{p}", value) + instance.save(update_fields=[f"permission_{p}" for p in permissions.keys()]) return instance @extend_schema_field(OpenApiTypes.OBJECT) diff --git a/api/funkwhale_api/moderation/filters.py b/api/funkwhale_api/moderation/filters.py index eacb7c4b0..288dd86f8 100644 --- a/api/funkwhale_api/moderation/filters.py +++ b/api/funkwhale_api/moderation/filters.py @@ -19,7 +19,7 @@ def get_filtered_content_query(config, user): query = None ids = user.content_filters.values_list(filter_field, flat=True) for model_field in model_fields: - q = Q(**{"{}__in".format(model_field): ids}) + q = Q(**{f"{model_field}__in": ids}) if query: query |= q else: diff --git a/api/funkwhale_api/moderation/management/commands/mrf_check.py b/api/funkwhale_api/moderation/management/commands/mrf_check.py index 1e0e79d17..72594c65c 100644 --- a/api/funkwhale_api/moderation/management/commands/mrf_check.py +++ b/api/funkwhale_api/moderation/management/commands/mrf_check.py @@ -71,7 +71,7 @@ class Command(BaseCommand): ) ) for name in registry.keys(): - self.stdout.write("- {}".format(name)) + self.stdout.write(f"- {name}") return raw_content = None content = None diff --git a/api/funkwhale_api/moderation/mrf_policies.py b/api/funkwhale_api/moderation/mrf_policies.py index 7d388c69e..d6862b9e7 100644 --- a/api/funkwhale_api/moderation/mrf_policies.py +++ b/api/funkwhale_api/moderation/mrf_policies.py @@ -29,13 +29,11 @@ def check_allow_list(payload, **kwargs): utils.recursive_getattr(payload, "object.id", permissive=True), ] - relevant_domains = set( - [ - domain - for domain in [urllib.parse.urlparse(i).hostname for i in relevant_ids if i] - if domain - ] - ) + relevant_domains = { + domain + for domain in [urllib.parse.urlparse(i).hostname for i in relevant_ids if i] + if domain + } if relevant_domains - allowed_domains: diff --git a/api/funkwhale_api/moderation/serializers.py b/api/funkwhale_api/moderation/serializers.py index b3c784d64..382d81aa8 100644 --- a/api/funkwhale_api/moderation/serializers.py +++ b/api/funkwhale_api/moderation/serializers.py @@ -61,7 +61,7 @@ class UserFilterSerializer(serializers.ModelSerializer): state_serializers = persisting_theory.Registry() -class DescriptionStateMixin(object): +class DescriptionStateMixin: def get_description(self, o): if o.description: return o.description.text diff --git a/api/funkwhale_api/moderation/tasks.py b/api/funkwhale_api/moderation/tasks.py index 9c510bf61..a77a06417 100644 --- a/api/funkwhale_api/moderation/tasks.py +++ b/api/funkwhale_api/moderation/tasks.py @@ -64,9 +64,7 @@ def send_new_report_email_to_moderators(report): subject = "[{} moderation - {}] New report from {}".format( settings.FUNKWHALE_HOSTNAME, report.get_type_display(), submitter_repr ) - detail_url = federation_utils.full_url( - "/manage/moderation/reports/{}".format(report.uuid) - ) + detail_url = federation_utils.full_url(f"/manage/moderation/reports/{report.uuid}") unresolved_reports_url = federation_utils.full_url( "/manage/moderation/reports?q=resolved:no" ) @@ -97,7 +95,7 @@ def send_new_report_email_to_moderators(report): body += [ "", - "- To handle this report, please visit {}".format(detail_url), + f"- To handle this report, please visit {detail_url}", "- To view all unresolved reports (currently {}), please visit {}".format( unresolved_reports, unresolved_reports_url ), @@ -173,9 +171,7 @@ def notify_mods_signup_request_pending(obj): subject = "[{} moderation] New sign-up request from {}".format( settings.FUNKWHALE_HOSTNAME, submitter_repr ) - detail_url = federation_utils.full_url( - "/manage/moderation/requests/{}".format(obj.uuid) - ) + detail_url = federation_utils.full_url(f"/manage/moderation/requests/{obj.uuid}") unresolved_requests_url = federation_utils.full_url( "/manage/moderation/requests?q=status:pending" ) @@ -185,7 +181,7 @@ def notify_mods_signup_request_pending(obj): submitter_repr ), "", - "- To handle this request, please visit {}".format(detail_url), + f"- To handle this request, please visit {detail_url}", "- To view all unresolved requests (currently {}), please visit {}".format( unresolved_requests, unresolved_requests_url ), @@ -217,10 +213,10 @@ def notify_submitter_signup_request_approved(user_request): if not submitter_email: logger.warning("User %s has no e-mail address configured", submitter_repr) return - subject = "Welcome to {}, {}!".format(settings.FUNKWHALE_HOSTNAME, submitter_repr) + subject = f"Welcome to {settings.FUNKWHALE_HOSTNAME}, {submitter_repr}!" login_url = federation_utils.full_url("/login") body = [ - "Hi {} and welcome,".format(submitter_repr), + f"Hi {submitter_repr} and welcome,", "", "Our moderation team has approved your account request and you can now start " "using the service. Please visit {} to get started.".format(login_url), @@ -246,7 +242,7 @@ def notify_submitter_signup_request_refused(user_request): settings.FUNKWHALE_HOSTNAME ) body = [ - "Hi {},".format(submitter_repr), + f"Hi {submitter_repr},", "", "You recently submitted an account request on our service. However, our " "moderation team has refused it, and as a result, you won't be able to use " diff --git a/api/funkwhale_api/music/importers.py b/api/funkwhale_api/music/importers.py index add3993c8..14b63a55a 100644 --- a/api/funkwhale_api/music/importers.py +++ b/api/funkwhale_api/music/importers.py @@ -6,7 +6,7 @@ def load(model, *args, **kwargs): EXCLUDE_VALIDATION = {"Track": ["artist"]} -class Importer(object): +class Importer: def __init__(self, model): self.model = model @@ -22,7 +22,7 @@ class Importer(object): return m -class Mapping(object): +class Mapping: """Cast musicbrainz data to funkwhale data and vice-versa""" def __init__(self, musicbrainz_mapping): diff --git a/api/funkwhale_api/music/licenses.py b/api/funkwhale_api/music/licenses.py index dc0494100..2332f0908 100644 --- a/api/funkwhale_api/music/licenses.py +++ b/api/funkwhale_api/music/licenses.py @@ -70,7 +70,7 @@ def match(*values): value, ) if not urls: - logger.debug('Impossible to guess license from string "{}"'.format(value)) + logger.debug(f'Impossible to guess license from string "{value}"') continue url = urls[0] if _cache: @@ -122,7 +122,7 @@ def get_cc_license(version, perks, country=None, country_name=None): ) if country: code_parts.append(country) - name += " {}".format(country_name) + name += f" {country_name}" url += country + "/" data = { "name": name, diff --git a/api/funkwhale_api/music/management/commands/check_inplace_files.py b/api/funkwhale_api/music/management/commands/check_inplace_files.py index 514b9a838..6754a2592 100644 --- a/api/funkwhale_api/music/management/commands/check_inplace_files.py +++ b/api/funkwhale_api/music/management/commands/check_inplace_files.py @@ -13,7 +13,7 @@ def progress(buffer, count, total, status=""): bar = "=" * filled_len + "-" * (bar_len - filled_len) - buffer.write("[%s] %s/%s ...%s\r" % (bar, count, total, status)) + buffer.write(f"[{bar}] {count}/{total} ...{status}\r") buffer.flush() @@ -43,7 +43,7 @@ class Command(BaseCommand): candidates = models.Upload.objects.filter(source__startswith="file://") candidates = candidates.filter(audio_file__in=["", None]) total = candidates.count() - self.stdout.write("Checking {} in-place imported files…".format(total)) + self.stdout.write(f"Checking {total} in-place imported files…") missing = [] for i, row in enumerate(candidates.values("id", "source").iterator()): @@ -54,7 +54,7 @@ class Command(BaseCommand): if missing: for path, _ in missing: - self.stdout.write(" {}".format(path)) + self.stdout.write(f" {path}") self.stdout.write( "The previous {} paths are referenced in database, but not found on disk!".format( len(missing) @@ -71,5 +71,5 @@ class Command(BaseCommand): "Nothing was deleted, rerun this command with --no-dry-run to apply the changes" ) else: - self.stdout.write("Deleting {} uploads…".format(to_delete.count())) + self.stdout.write(f"Deleting {to_delete.count()} uploads…") to_delete.delete() diff --git a/api/funkwhale_api/music/management/commands/check_licenses.py b/api/funkwhale_api/music/management/commands/check_licenses.py index 0746d6b8b..9fe3c7179 100644 --- a/api/funkwhale_api/music/management/commands/check_licenses.py +++ b/api/funkwhale_api/music/management/commands/check_licenses.py @@ -21,7 +21,7 @@ class Command(BaseCommand): errored.append((data, response)) if errored: - self.stdout.write("{} licenses were not reachable!".format(len(errored))) + self.stdout.write(f"{len(errored)} licenses were not reachable!") for row, response in errored: self.stdout.write( "- {}: error {} at url {}".format( diff --git a/api/funkwhale_api/music/management/commands/fix_uploads.py b/api/funkwhale_api/music/management/commands/fix_uploads.py index 02f3d2232..68661a446 100644 --- a/api/funkwhale_api/music/management/commands/fix_uploads.py +++ b/api/funkwhale_api/music/management/commands/fix_uploads.py @@ -73,13 +73,11 @@ class Command(BaseCommand): Q(source__startswith="file://") | Q(source__startswith="upload://") ).exclude(mimetype__startswith="audio/") total = matching.count() - self.stdout.write( - "[mimetypes] {} entries found with bad or no mimetype".format(total) - ) + self.stdout.write(f"[mimetypes] {total} entries found with bad or no mimetype") if not total: return for extension, mimetype in utils.EXTENSION_TO_MIMETYPE.items(): - qs = matching.filter(source__endswith=".{}".format(extension)) + qs = matching.filter(source__endswith=f".{extension}") self.stdout.write( "[mimetypes] setting {} {} files to {}".format( qs.count(), extension, mimetype @@ -95,9 +93,7 @@ class Command(BaseCommand): Q(bitrate__isnull=True) | Q(duration__isnull=True) ) total = matching.count() - self.stdout.write( - "[bitrate/length] {} entries found with missing values".format(total) - ) + self.stdout.write(f"[bitrate/length] {total} entries found with missing values") if dry_run: return @@ -135,7 +131,7 @@ class Command(BaseCommand): self.stdout.write("Fixing missing size...") matching = models.Upload.objects.filter(size__isnull=True) total = matching.count() - self.stdout.write("[size] {} entries found with missing values".format(total)) + self.stdout.write(f"[size] {total} entries found with missing values") if dry_run: return @@ -148,16 +144,12 @@ class Command(BaseCommand): for upload in chunk: handled += 1 - self.stdout.write( - "[size] {}/{} fixing file #{}".format(handled, total, upload.pk) - ) + self.stdout.write(f"[size] {handled}/{total} fixing file #{upload.pk}") try: upload.size = upload.get_file_size() except Exception as e: - self.stderr.write( - "[size] error with file #{}: {}".format(upload.pk, str(e)) - ) + self.stderr.write(f"[size] error with file #{upload.pk}: {str(e)}") else: updated.append(upload) @@ -170,9 +162,7 @@ class Command(BaseCommand): & (Q(audio_file__isnull=False) | Q(source__startswith="file://")) ) total = matching.count() - self.stdout.write( - "[checksum] {} entries found with missing values".format(total) - ) + self.stdout.write(f"[checksum] {total} entries found with missing values") if dry_run: return chunks = common_utils.chunk_queryset( @@ -184,7 +174,7 @@ class Command(BaseCommand): for upload in chunk: handled += 1 self.stdout.write( - "[checksum] {}/{} fixing file #{}".format(handled, total, upload.pk) + f"[checksum] {handled}/{total} fixing file #{upload.pk}" ) try: @@ -193,7 +183,7 @@ class Command(BaseCommand): ) except Exception as e: self.stderr.write( - "[checksum] error with file #{}: {}".format(upload.pk, str(e)) + f"[checksum] error with file #{upload.pk}: {str(e)}" ) else: updated.append(upload) diff --git a/api/funkwhale_api/music/management/commands/import_files.py b/api/funkwhale_api/music/management/commands/import_files.py index 1d6542a27..d60e13c86 100644 --- a/api/funkwhale_api/music/management/commands/import_files.py +++ b/api/funkwhale_api/music/management/commands/import_files.py @@ -31,7 +31,7 @@ def crawl_dir(dir, extensions, recursive=True, ignored=[]): try: scanner = os.scandir(dir) except Exception as e: - m = "Error while reading {}: {} {}\n".format(dir, e.__class__.__name__, e) + m = f"Error while reading {dir}: {e.__class__.__name__} {e}\n" sys.stderr.write(m) return try: @@ -39,7 +39,7 @@ def crawl_dir(dir, extensions, recursive=True, ignored=[]): try: if entry.is_file(): for e in extensions: - if entry.name.lower().endswith(".{}".format(e.lower())): + if entry.name.lower().endswith(f".{e.lower()}"): if entry.path not in ignored: yield entry.path elif recursive and entry.is_dir(): @@ -260,7 +260,7 @@ class Command(BaseCommand): raise CommandError("Invalid library id") if not library.actor.get_user(): - raise CommandError("Library {} is not a local library".format(library.uuid)) + raise CommandError(f"Library {library.uuid} is not a local library") if options["in_place"]: self.stdout.write( @@ -282,7 +282,7 @@ class Command(BaseCommand): "Culprit: {}".format(p, import_path) ) - reference = options["reference"] or "cli-{}".format(timezone.now().isoformat()) + reference = options["reference"] or f"cli-{timezone.now().isoformat()}" import_url = "{}://{}/library/{}/upload?{}" import_url = import_url.format( @@ -393,10 +393,10 @@ class Command(BaseCommand): message.format(total - len(errors), int(time.time() - start_time)) ) if len(errors) > 0: - self.stderr.write("{} tracks could not be imported:".format(len(errors))) + self.stderr.write(f"{len(errors)} tracks could not be imported:") for path, error in errors: - self.stderr.write("- {}: {}".format(path, error)) + self.stderr.write(f"- {path}: {error}") self.stdout.write( "For details, please refer to import reference '{}' or URL {}".format( @@ -485,12 +485,12 @@ class Command(BaseCommand): return errors def filter_matching(self, matching, library): - sources = ["file://{}".format(p) for p in matching] + sources = [f"file://{p}" for p in matching] # we skip reimport for path that are already found # as a Upload.source existing = library.uploads.filter(source__in=sources, import_status="finished") existing = existing.values_list("source", flat=True) - existing = set([p.replace("file://", "", 1) for p in existing]) + existing = {p.replace("file://", "", 1) for p in existing} skipped = set(matching) & existing result = { "initial": matching, @@ -530,7 +530,7 @@ class Command(BaseCommand): path, e.__class__.__name__, e ) self.stderr.write(m) - errors.append((path, "{} {}".format(e.__class__.__name__, e))) + errors.append((path, f"{e.__class__.__name__} {e}")) return errors def setup_watcher(self, path, extensions, recursive, **kwargs): @@ -544,7 +544,7 @@ class Command(BaseCommand): worker.start() # setup watchdog to monitor directory for trigger files - patterns = ["*.{}".format(e) for e in extensions] + patterns = [f"*.{e}" for e in extensions] event_handler = Watcher( stdout=self.stdout, queue=watchdog_queue, @@ -556,9 +556,7 @@ class Command(BaseCommand): try: while True: - self.stdout.write( - "Watching for changes at {}…".format(path), ending="\r" - ) + self.stdout.write(f"Watching for changes at {path}…", ending="\r") time.sleep(10) if kwargs["prune"] and GLOBAL["need_pruning"]: self.stdout.write("Some files were deleted, pruning library…") @@ -728,7 +726,7 @@ def handle_modified(event, stdout, library, in_place, **kwargs): try: tasks.update_track_metadata(audio_metadata, to_update.track) except serializers.ValidationError as e: - stdout.write(" Invalid metadata: {}".format(e)) + stdout.write(f" Invalid metadata: {e}") else: to_update.checksum = checksum to_update.save(update_fields=["checksum"]) @@ -765,7 +763,7 @@ def handle_moved(event, stdout, library, in_place, **kwargs): existing_candidates = existing_candidates.in_place().filter(source=old_source) existing = existing_candidates.first() if existing: - stdout.write(" Updating path of existing file #{}".format(existing.pk)) + stdout.write(f" Updating path of existing file #{existing.pk}") existing.source = new_source existing.save(update_fields=["source"]) @@ -794,15 +792,14 @@ def check_updates(stdout, library, extensions, paths, batch_size): for path in paths: for ext in extensions: queries.append( - Q(source__startswith="file://{}".format(path)) - & Q(source__endswith=".{}".format(ext)) + Q(source__startswith=f"file://{path}") & Q(source__endswith=f".{ext}") ) query, remainder = queries[0], queries[1:] for q in remainder: query = q | query existing = existing.filter(query) total = existing.count() - stdout.write("Found {} files to check in database!".format(total)) + stdout.write(f"Found {total} files to check in database!") uploads = existing.order_by("source") for i, rows in enumerate(batch(uploads.iterator(), batch_size)): stdout.write( @@ -849,7 +846,7 @@ def check_upload(stdout, upload): try: tasks.update_track_metadata(upload.get_metadata(), track) except serializers.ValidationError as e: - stdout.write(" Invalid metadata: {}".format(e)) + stdout.write(f" Invalid metadata: {e}") return except IntegrityError: stdout.write( diff --git a/api/funkwhale_api/music/management/commands/prune_library.py b/api/funkwhale_api/music/management/commands/prune_library.py index c0a2ebe97..512afe875 100644 --- a/api/funkwhale_api/music/management/commands/prune_library.py +++ b/api/funkwhale_api/music/management/commands/prune_library.py @@ -101,11 +101,9 @@ class Command(BaseCommand): pruned_total = prunable.count() total = models.Track.objects.count() if options["dry_run"]: - self.stdout.write( - "Would prune {}/{} tracks".format(pruned_total, total) - ) + self.stdout.write(f"Would prune {pruned_total}/{total} tracks") else: - self.stdout.write("Deleting {}/{} tracks…".format(pruned_total, total)) + self.stdout.write(f"Deleting {pruned_total}/{total} tracks…") prunable.delete() if options["prune_albums"]: @@ -113,11 +111,9 @@ class Command(BaseCommand): pruned_total = prunable.count() total = models.Album.objects.count() if options["dry_run"]: - self.stdout.write( - "Would prune {}/{} albums".format(pruned_total, total) - ) + self.stdout.write(f"Would prune {pruned_total}/{total} albums") else: - self.stdout.write("Deleting {}/{} albums…".format(pruned_total, total)) + self.stdout.write(f"Deleting {pruned_total}/{total} albums…") prunable.delete() if options["prune_artists"]: @@ -125,11 +121,9 @@ class Command(BaseCommand): pruned_total = prunable.count() total = models.Artist.objects.count() if options["dry_run"]: - self.stdout.write( - "Would prune {}/{} artists".format(pruned_total, total) - ) + self.stdout.write(f"Would prune {pruned_total}/{total} artists") else: - self.stdout.write("Deleting {}/{} artists…".format(pruned_total, total)) + self.stdout.write(f"Deleting {pruned_total}/{total} artists…") prunable.delete() self.stdout.write("") diff --git a/api/funkwhale_api/music/metadata.py b/api/funkwhale_api/music/metadata.py index 792179ee5..4e909fe8a 100644 --- a/api/funkwhale_api/music/metadata.py +++ b/api/funkwhale_api/music/metadata.py @@ -355,15 +355,15 @@ class Metadata(Mapping): def __init__(self, filething, kind=mutagen.File): self._file = kind(filething) if self._file is None: - raise ValueError("Cannot parse metadata from {}".format(filething)) + raise ValueError(f"Cannot parse metadata from {filething}") if len(self._file) == 0: - raise ValueError("No tags found in {}".format(filething)) + raise ValueError(f"No tags found in {filething}") self.fallback = self.load_fallback(filething, self._file) ft = self.get_file_type(self._file) try: self._conf = CONF[ft] except KeyError: - raise ValueError("Unsupported format {}".format(ft)) + raise ValueError(f"Unsupported format {ft}") def get_file_type(self, f): return f.__class__.__name__ @@ -420,7 +420,7 @@ class Metadata(Mapping): try: field_conf = self._conf["fields"][key] except KeyError: - raise UnsupportedTag("{} is not supported for this file format".format(key)) + raise UnsupportedTag(f"{key} is not supported for this file format") real_key = field_conf.get("field", key) try: getter = field_conf.get("getter", self._conf["getter"]) @@ -467,8 +467,7 @@ class Metadata(Mapping): return 1 def __iter__(self): - for field in self._conf["fields"]: - yield field + yield from self._conf["fields"] class ArtistField(serializers.Field): diff --git a/api/funkwhale_api/music/models.py b/api/funkwhale_api/music/models.py index fb05c5694..9543d743a 100644 --- a/api/funkwhale_api/music/models.py +++ b/api/funkwhale_api/music/models.py @@ -85,9 +85,7 @@ class APIModelMixin(models.Model): cls.musicbrainz_model ] else: - raw_data = cls.api.search(**kwargs)[ - "{0}-list".format(cls.musicbrainz_model) - ][0] + raw_data = cls.api.search(**kwargs)[f"{cls.musicbrainz_model}-list"][0] cleaned_data = cls.clean_musicbrainz_data(raw_data) return importers.load(cls, cleaned_data, raw_data, cls.import_hooks) @@ -116,7 +114,7 @@ class APIModelMixin(models.Model): return federation_utils.full_url( reverse( - "federation:music:{}-detail".format(self.federation_namespace), + f"federation:music:{self.federation_namespace}-detail", kwargs={"uuid": self.uuid}, ) ) @@ -252,10 +250,10 @@ class Artist(APIModelMixin): return self.name def get_absolute_url(self): - return "/library/artists/{}".format(self.pk) + return f"/library/artists/{self.pk}" def get_moderation_url(self): - return "/manage/library/artists/{}".format(self.pk) + return f"/manage/library/artists/{self.pk}" @classmethod def get_or_create_from_name(cls, name, **kwargs): @@ -396,10 +394,10 @@ class Album(APIModelMixin): return self.title def get_absolute_url(self): - return "/library/albums/{}".format(self.pk) + return f"/library/albums/{self.pk}" def get_moderation_url(self): - return "/manage/library/albums/{}".format(self.pk) + return f"/manage/library/albums/{self.pk}" @classmethod def get_or_create_from_title(cls, title, **kwargs): @@ -557,10 +555,10 @@ class Track(APIModelMixin): return self.title def get_absolute_url(self): - return "/library/tracks/{}".format(self.pk) + return f"/library/tracks/{self.pk}" def get_moderation_url(self): - return "/manage/library/tracks/{}".format(self.pk) + return f"/manage/library/tracks/{self.pk}" def save(self, **kwargs): try: @@ -572,9 +570,9 @@ class Track(APIModelMixin): @property def full_name(self): try: - return "{} - {} - {}".format(self.artist.name, self.album.title, self.title) + return f"{self.artist.name} - {self.album.title} - {self.title}" except AttributeError: - return "{} - {}".format(self.artist.name, self.title) + return f"{self.artist.name} - {self.title}" @property def cover(self): @@ -582,8 +580,8 @@ class Track(APIModelMixin): def get_activity_url(self): if self.mbid: - return "https://musicbrainz.org/recording/{}".format(self.mbid) - return settings.FUNKWHALE_URL + "/tracks/{}".format(self.pk) + return f"https://musicbrainz.org/recording/{self.mbid}" + return settings.FUNKWHALE_URL + f"/tracks/{self.pk}" @classmethod def get_or_create_from_title(cls, title, **kwargs): @@ -643,7 +641,7 @@ class Track(APIModelMixin): @property def listen_url(self) -> str: # Not using reverse because this is slow - return "/api/v1/listen/{}/".format(self.uuid) + return f"/api/v1/listen/{self.uuid}/" @property def local_license(self): @@ -807,7 +805,7 @@ class Upload(models.Model): title_parts.append(self.track.artist.name) title = " - ".join(title_parts) - filename = "{}.{}".format(title, extension) + filename = f"{title}.{extension}" tmp_file = tempfile.TemporaryFile() for chunk in r.iter_content(chunk_size=512): tmp_file.write(chunk) @@ -824,7 +822,7 @@ class Upload(models.Model): @property def filename(self) -> str: - return "{}.{}".format(self.track.full_name, self.extension) + return f"{self.track.full_name}.{self.extension}" @property def extension(self): @@ -900,12 +898,12 @@ class Upload(models.Model): @property def listen_url(self) -> str: - return self.track.listen_url + "?upload={}".format(self.uuid) + return self.track.listen_url + f"?upload={self.uuid}" def get_listen_url(self, to=None, download=True) -> str: url = self.listen_url if to: - url += "&to={}".format(to) + url += f"&to={to}" if not download: url += "&download=false" @@ -946,9 +944,9 @@ class Upload(models.Model): bitrate = min(bitrate or 320000, self.bitrate or 320000) version = self.versions.create(mimetype=mimetype, bitrate=bitrate, size=0) # we keep the same name, but we update the extension - new_name = os.path.splitext(os.path.basename(self.audio_file.name))[ - 0 - ] + ".{}".format(format) + new_name = ( + os.path.splitext(os.path.basename(self.audio_file.name))[0] + f".{format}" + ) version.audio_file.save(new_name, f) utils.transcode_audio( audio=self.get_audio_segment(), @@ -1091,9 +1089,7 @@ class ImportBatch(models.Model): tasks.import_batch_notify_followers.delay(import_batch_id=self.pk) def get_federation_id(self): - return federation_utils.full_url( - "/federation/music/import/batch/{}".format(self.uuid) - ) + return federation_utils.full_url(f"/federation/music/import/batch/{self.uuid}") class ImportJob(models.Model): @@ -1204,7 +1200,7 @@ class Library(federation_models.FederationMixin): return self.name def get_moderation_url(self) -> str: - return "/manage/library/libraries/{}".format(self.uuid) + return f"/manage/library/libraries/{self.uuid}" def get_federation_id(self) -> str: return federation_utils.full_url( @@ -1212,7 +1208,7 @@ class Library(federation_models.FederationMixin): ) def get_absolute_url(self) -> str: - return "/library/{}".format(self.uuid) + return f"/library/{self.uuid}" def save(self, **kwargs): if not self.pk and not self.fid and self.actor.is_local: diff --git a/api/funkwhale_api/music/serializers.py b/api/funkwhale_api/music/serializers.py index d352da8d3..46a118817 100644 --- a/api/funkwhale_api/music/serializers.py +++ b/api/funkwhale_api/music/serializers.py @@ -40,7 +40,7 @@ class CoverField(common_serializers.AttachmentSerializer): cover_field = CoverField() -class OptionalDescriptionMixin(object): +class OptionalDescriptionMixin: def to_representation(self, obj): repr = super().to_representation(obj) if self.context.get("description", False): @@ -579,7 +579,7 @@ class TrackActivitySerializer(activity_serializers.ModelSerializer): def get_embed_url(type, id): - return settings.FUNKWHALE_EMBED_URL + "?type={}&id={}".format(type, id) + return settings.FUNKWHALE_EMBED_URL + f"?type={type}&id={id}" class OembedSerializer(serializers.Serializer): @@ -619,7 +619,7 @@ class OembedSerializer(serializers.Serializer): ) embed_type = "track" embed_id = track.pk - data["title"] = "{} by {}".format(track.title, track.artist.name) + data["title"] = f"{track.title} by {track.artist.name}" if track.attachment_cover: data[ "thumbnail_url" @@ -658,8 +658,8 @@ class OembedSerializer(serializers.Serializer): ] = album.attachment_cover.download_url_medium_square_crop data["thumbnail_width"] = 200 data["thumbnail_height"] = 200 - data["title"] = "{} by {}".format(album.title, album.artist.name) - data["description"] = "{} by {}".format(album.title, album.artist.name) + data["title"] = f"{album.title} by {album.artist.name}" + data["description"] = f"{album.title} by {album.artist.name}" data["author_name"] = album.artist.name data["height"] = 400 data["author_url"] = federation_utils.full_url( diff --git a/api/funkwhale_api/music/spa_views.py b/api/funkwhale_api/music/spa_views.py index 4ddebcdf5..3102d8635 100644 --- a/api/funkwhale_api/music/spa_views.py +++ b/api/funkwhale_api/music/spa_views.py @@ -109,7 +109,7 @@ def library_track(request, pk, redirect_to_ap): "type": "application/json+oembed", "href": ( utils.join_url(settings.FUNKWHALE_URL, reverse("api:v1:oembed")) - + "?format=json&url={}".format(urllib.parse.quote_plus(track_url)) + + f"?format=json&url={urllib.parse.quote_plus(track_url)}" ), } ) @@ -181,7 +181,7 @@ def library_album(request, pk, redirect_to_ap): "type": "application/json+oembed", "href": ( utils.join_url(settings.FUNKWHALE_URL, reverse("api:v1:oembed")) - + "?format=json&url={}".format(urllib.parse.quote_plus(album_url)) + + f"?format=json&url={urllib.parse.quote_plus(album_url)}" ), } ) @@ -245,7 +245,7 @@ def library_artist(request, pk, redirect_to_ap): "type": "application/json+oembed", "href": ( utils.join_url(settings.FUNKWHALE_URL, reverse("api:v1:oembed")) - + "?format=json&url={}".format(urllib.parse.quote_plus(artist_url)) + + f"?format=json&url={urllib.parse.quote_plus(artist_url)}" ), } ) @@ -297,7 +297,7 @@ def library_playlist(request, pk, redirect_to_ap): "type": "application/json+oembed", "href": ( utils.join_url(settings.FUNKWHALE_URL, reverse("api:v1:oembed")) - + "?format=json&url={}".format(urllib.parse.quote_plus(obj_url)) + + f"?format=json&url={urllib.parse.quote_plus(obj_url)}" ), } ) diff --git a/api/funkwhale_api/music/tasks.py b/api/funkwhale_api/music/tasks.py index 3d3840895..89fc7fa5e 100644 --- a/api/funkwhale_api/music/tasks.py +++ b/api/funkwhale_api/music/tasks.py @@ -66,7 +66,7 @@ def get_cover_from_fs(dir_path): if os.path.exists(dir_path): for name in FOLDER_IMAGE_NAMES: for e, m in IMAGE_TYPES: - cover_path = os.path.join(dir_path, "{}.{}".format(name, e)) + cover_path = os.path.join(dir_path, f"{name}.{e}") if not os.path.exists(cover_path): logger.debug("Cover %s does not exists", cover_path) continue @@ -764,7 +764,7 @@ def broadcast_import_status_update_to_owner(old_status, new_status, upload, **kw from . import serializers - group = "user.{}.imports".format(user.pk) + group = f"user.{user.pk}.imports" channels.group_send( group, { @@ -788,7 +788,7 @@ def clean_transcoding_cache(): limit = timezone.now() - datetime.timedelta(minutes=delay) candidates = ( models.UploadVersion.objects.filter( - (Q(accessed_date__lt=limit) | Q(accessed_date=None)) + Q(accessed_date__lt=limit) | Q(accessed_date=None) ) .only("audio_file", "id") .order_by("id") diff --git a/api/funkwhale_api/music/utils.py b/api/funkwhale_api/music/utils.py index be75cab89..a81e2cff0 100644 --- a/api/funkwhale_api/music/utils.py +++ b/api/funkwhale_api/music/utils.py @@ -67,9 +67,7 @@ AUDIO_EXTENSIONS_AND_MIMETYPE = [ EXTENSION_TO_MIMETYPE = {ext: mt for ext, mt in AUDIO_EXTENSIONS_AND_MIMETYPE} MIMETYPE_TO_EXTENSION = {mt: ext for ext, mt in AUDIO_EXTENSIONS_AND_MIMETYPE} -SUPPORTED_EXTENSIONS = list( - sorted(set([ext for ext, _ in AUDIO_EXTENSIONS_AND_MIMETYPE])) -) +SUPPORTED_EXTENSIONS = list(sorted({ext for ext, _ in AUDIO_EXTENSIONS_AND_MIMETYPE})) def get_ext_from_type(mimetype): diff --git a/api/funkwhale_api/music/views.py b/api/funkwhale_api/music/views.py index c5c183240..20a1956ff 100644 --- a/api/funkwhale_api/music/views.py +++ b/api/funkwhale_api/music/views.py @@ -101,7 +101,7 @@ def refetch_obj(obj, queryset): return obj -class HandleInvalidSearch(object): +class HandleInvalidSearch: def list(self, *args, **kwargs): try: return super().list(*args, **kwargs) @@ -532,8 +532,8 @@ def should_transcode(upload, format, max_bitrate=None): def get_content_disposition(filename): - filename = "filename*=UTF-8''{}".format(urllib.parse.quote(filename)) - return "attachment; {}".format(filename) + filename = f"filename*=UTF-8''{urllib.parse.quote(filename)}" + return f"attachment; {filename}" def record_downloads(f): diff --git a/api/funkwhale_api/musicbrainz/client.py b/api/funkwhale_api/musicbrainz/client.py index 8fdf90322..5e96346d7 100644 --- a/api/funkwhale_api/musicbrainz/client.py +++ b/api/funkwhale_api/musicbrainz/client.py @@ -16,10 +16,10 @@ def clean_artist_search(query, **kwargs): return _api.search_artists(query, **cleaned_kwargs) -class API(object): +class API: _api = _api - class artists(object): + class artists: search = cache_memoize( settings.MUSICBRAINZ_CACHE_DURATION, prefix="memoize:musicbrainz:clean_artist_search", @@ -29,13 +29,13 @@ class API(object): prefix="memoize:musicbrainz:get_artist_by_id", )(_api.get_artist_by_id) - class images(object): + class images: get_front = cache_memoize( settings.MUSICBRAINZ_CACHE_DURATION, prefix="memoize:musicbrainz:get_image_front", )(_api.get_image_front) - class recordings(object): + class recordings: search = cache_memoize( settings.MUSICBRAINZ_CACHE_DURATION, prefix="memoize:musicbrainz:search_recordings", @@ -45,7 +45,7 @@ class API(object): prefix="memoize:musicbrainz:get_recording_by_id", )(_api.get_recording_by_id) - class releases(object): + class releases: search = cache_memoize( settings.MUSICBRAINZ_CACHE_DURATION, prefix="memoize:musicbrainz:search_releases", @@ -60,7 +60,7 @@ class API(object): )(_api.browse_releases) # get_image_front = _api.get_image_front - class release_groups(object): + class release_groups: search = cache_memoize( settings.MUSICBRAINZ_CACHE_DURATION, prefix="memoize:musicbrainz:search_release_groups", diff --git a/api/funkwhale_api/playlists/models.py b/api/funkwhale_api/playlists/models.py index af9190e1c..74172e8b6 100644 --- a/api/funkwhale_api/playlists/models.py +++ b/api/funkwhale_api/playlists/models.py @@ -82,7 +82,7 @@ class Playlist(models.Model): return self.name def get_absolute_url(self): - return "/library/playlists/{}".format(self.pk) + return f"/library/playlists/{self.pk}" @transaction.atomic def insert(self, plt, index=None, allow_duplicates=True): @@ -151,7 +151,7 @@ class Playlist(models.Model): max_tracks = preferences.get("playlists__max_tracks") if existing.count() + len(tracks) > max_tracks: raise exceptions.ValidationError( - "Playlist would reach the maximum of {} tracks".format(max_tracks) + f"Playlist would reach the maximum of {max_tracks} tracks" ) if not allow_duplicates: diff --git a/api/funkwhale_api/radios/filters.py b/api/funkwhale_api/radios/filters.py index 23ac8dba1..114236ee0 100644 --- a/api/funkwhale_api/radios/filters.py +++ b/api/funkwhale_api/radios/filters.py @@ -66,7 +66,7 @@ def clean_config(filter_config): return f.clean_config(filter_config) -class RadioFilter(object): +class RadioFilter: help_text = None label = None fields = [] @@ -114,7 +114,7 @@ class GroupFilter(RadioFilter): elif operator == "or": final_query |= query else: - raise ValueError('Invalid query operator "{}"'.format(operator)) + raise ValueError(f'Invalid query operator "{operator}"') return final_query def validate(self, config): @@ -171,7 +171,7 @@ class ArtistFilter(RadioFilter): except KeyError: raise ValidationError("You must provide an id") except AssertionError: - raise ValidationError('No artist matching ids "{}"'.format(diff)) + raise ValidationError(f'No artist matching ids "{diff}"') @registry.register @@ -226,7 +226,7 @@ class TagFilter(RadioFilter): except KeyError: raise ValidationError("You must provide a name") except AssertionError: - raise ValidationError('No tag matching names "{}"'.format(diff)) + raise ValidationError(f'No tag matching names "{diff}"') @registry.register diff --git a/api/funkwhale_api/radios/radios.py b/api/funkwhale_api/radios/radios.py index 361502da7..58ac8a2cc 100644 --- a/api/funkwhale_api/radios/radios.py +++ b/api/funkwhale_api/radios/radios.py @@ -20,7 +20,7 @@ from .registries import registry logger = logging.getLogger(__name__) -class SimpleRadio(object): +class SimpleRadio: related_object_field = None def clean(self, instance): diff --git a/api/funkwhale_api/subsonic/renderers.py b/api/funkwhale_api/subsonic/renderers.py index 54c4a4063..f11940222 100644 --- a/api/funkwhale_api/subsonic/renderers.py +++ b/api/funkwhale_api/subsonic/renderers.py @@ -20,7 +20,7 @@ ET._original_serialize_xml = ET._serialize_xml def _serialize_xml(write, elem, qnames, namespaces, **kwargs): if elem.tag == "![CDATA[": - write("<%s%s]]>" % (elem.tag, elem.text)) + write(f"<{elem.tag}{elem.text}]]>") return return ET._original_serialize_xml(write, elem, qnames, namespaces, **kwargs) diff --git a/api/funkwhale_api/subsonic/serializers.py b/api/funkwhale_api/subsonic/serializers.py index 2b3bae2e1..5a615126b 100644 --- a/api/funkwhale_api/subsonic/serializers.py +++ b/api/funkwhale_api/subsonic/serializers.py @@ -39,7 +39,7 @@ def get_track_path(track, suffix): parts.append(get_valid_filepart(track.album.title)) track_part = get_valid_filepart(track.title) + "." + suffix if track.position: - track_part = "{} - {}".format(track.position, track_part) + track_part = f"{track.position} - {track_part}" parts.append(track_part) return "/".join(parts) @@ -84,7 +84,7 @@ class GetArtistSerializer(serializers.Serializer): "album": [], } if artist.attachment_cover_id: - payload["coverArt"] = "ar-{}".format(artist.id) + payload["coverArt"] = f"ar-{artist.id}" for album in albums: album_data = { "id": album.id, @@ -95,7 +95,7 @@ class GetArtistSerializer(serializers.Serializer): "songCount": len(album.tracks.all()), } if album.attachment_cover_id: - album_data["coverArt"] = "al-{}".format(album.id) + album_data["coverArt"] = f"al-{album.id}" if album.release_date: album_data["year"] = album.release_date.year payload["album"].append(album_data) @@ -128,7 +128,7 @@ def get_track_data(album, track, upload): "type": "music", } if album and album.attachment_cover_id: - data["coverArt"] = "al-{}".format(album.id) + data["coverArt"] = f"al-{album.id}" if upload.bitrate: data["bitrate"] = int(upload.bitrate / 1000) if upload.size: @@ -151,7 +151,7 @@ def get_album2_data(album): "playCount": album.tracks.aggregate(l=Count("listenings"))["l"] or 0, } if album.attachment_cover_id: - payload["coverArt"] = "al-{}".format(album.id) + payload["coverArt"] = f"al-{album.id}" if album.tagged_items: # exposes only first genre since the specification uses singular noun first_genre = album.tagged_items.first() @@ -308,7 +308,7 @@ def get_channel_data(channel, uploads): "description": channel.artist.description.as_plain_text if channel.artist.description else "", - "coverArt": "at-{}".format(channel.artist.attachment_cover.uuid) + "coverArt": f"at-{channel.artist.attachment_cover.uuid}" if channel.artist.attachment_cover else "", "originalImageUrl": channel.artist.attachment_cover.url @@ -333,7 +333,7 @@ def get_channel_episode_data(upload, channel_id): "description": upload.track.description.as_plain_text if upload.track.description else "", - "coverArt": "at-{}".format(upload.track.attachment_cover.uuid) + "coverArt": f"at-{upload.track.attachment_cover.uuid}" if upload.track.attachment_cover else "", "isDir": "false", diff --git a/api/funkwhale_api/subsonic/views.py b/api/funkwhale_api/subsonic/views.py index 84ef96fa5..6674a5e7c 100644 --- a/api/funkwhale_api/subsonic/views.py +++ b/api/funkwhale_api/subsonic/views.py @@ -67,7 +67,7 @@ def find_object( { "error": { "code": 0, - "message": 'For input string "{}"'.format(raw_value), + "message": f'For input string "{raw_value}"', } } ) @@ -86,7 +86,7 @@ def find_object( { "error": { "code": 70, - "message": "{} not found".format(qs.model.__name__), + "message": f"{qs.model.__name__} not found", } } ) @@ -904,7 +904,7 @@ class SubsonicViewSet(viewsets.GenericViewSet): { "error": { "code": 0, - "message": "Error while fetching url: {}".format(e), + "message": f"Error while fetching url: {e}", } } ) diff --git a/api/funkwhale_api/tags/serializers.py b/api/funkwhale_api/tags/serializers.py index 3b7df6aea..7e4325120 100644 --- a/api/funkwhale_api/tags/serializers.py +++ b/api/funkwhale_api/tags/serializers.py @@ -14,7 +14,7 @@ class TagNameField(serializers.CharField): def to_internal_value(self, value): value = super().to_internal_value(value) if not models.TAG_REGEX.match(value): - raise serializers.ValidationError('Invalid tag "{}"'.format(value)) + raise serializers.ValidationError(f'Invalid tag "{value}"') return value diff --git a/api/funkwhale_api/tags/tasks.py b/api/funkwhale_api/tags/tasks.py index 13ced9d2d..4bc6d59ba 100644 --- a/api/funkwhale_api/tags/tasks.py +++ b/api/funkwhale_api/tags/tasks.py @@ -14,16 +14,14 @@ def get_tags_from_foreign_key( """ data = {} objs = foreign_key_model.objects.filter( - **{"{}__pk__in".format(foreign_key_attr): ids} + **{f"{foreign_key_attr}__pk__in": ids} ).order_by("-id") - objs = objs.only("id", "{}_id".format(foreign_key_attr)).prefetch_related( - tagged_items_attr - ) + objs = objs.only("id", f"{foreign_key_attr}_id").prefetch_related(tagged_items_attr) for obj in objs.iterator(): # loop on all objects, store the objs tags + counter on the corresponding foreign key row_data = data.setdefault( - getattr(obj, "{}_id".format(foreign_key_attr)), + getattr(obj, f"{foreign_key_attr}_id"), {"total_objs": 0, "tags": []}, ) row_data["total_objs"] += 1 diff --git a/api/funkwhale_api/taskapp/celery.py b/api/funkwhale_api/taskapp/celery.py index 728181041..c271fe20d 100644 --- a/api/funkwhale_api/taskapp/celery.py +++ b/api/funkwhale_api/taskapp/celery.py @@ -1,5 +1,3 @@ -from __future__ import absolute_import - import functools import logging import os @@ -22,7 +20,7 @@ app = celery.Celery("funkwhale_api") @celery.signals.task_failure.connect def process_failure(sender, task_id, exception, args, kwargs, traceback, einfo, **kw): - print("[celery] Error during task {}: {}".format(task_id, einfo.exception)) + print(f"[celery] Error during task {task_id}: {einfo.exception}") tb.print_exc() diff --git a/api/funkwhale_api/users/__init__.py b/api/funkwhale_api/users/__init__.py index 40a96afc6..e69de29bb 100644 --- a/api/funkwhale_api/users/__init__.py +++ b/api/funkwhale_api/users/__init__.py @@ -1 +0,0 @@ -# -*- coding: utf-8 -*- diff --git a/api/funkwhale_api/users/admin.py b/api/funkwhale_api/users/admin.py index 4d6d519bb..b63cf6b59 100644 --- a/api/funkwhale_api/users/admin.py +++ b/api/funkwhale_api/users/admin.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, unicode_literals - from django import forms from django.contrib.auth.admin import UserAdmin as AuthUserAdmin from django.contrib.auth.forms import UserChangeForm, UserCreationForm diff --git a/api/funkwhale_api/users/authentication.py b/api/funkwhale_api/users/authentication.py index 85fa2580d..542335450 100644 --- a/api/funkwhale_api/users/authentication.py +++ b/api/funkwhale_api/users/authentication.py @@ -9,7 +9,7 @@ from .oauth import scopes as available_scopes def generate_scoped_token(user_id, user_secret, scopes): if set(scopes) & set(available_scopes.SCOPES_BY_ID) != set(scopes): - raise ValueError("{} contains invalid scopes".format(scopes)) + raise ValueError(f"{scopes} contains invalid scopes") return signing.dumps( { diff --git a/api/funkwhale_api/users/factories.py b/api/funkwhale_api/users/factories.py index c039a4854..d60abc0d2 100644 --- a/api/funkwhale_api/users/factories.py +++ b/api/funkwhale_api/users/factories.py @@ -10,7 +10,7 @@ from . import models @registry.register class GroupFactory(NoUpdateOnCreate, factory.django.DjangoModelFactory): - name = factory.Sequence(lambda n: "group-{0}".format(n)) + name = factory.Sequence(lambda n: f"group-{n}") class Meta: model = "auth.Group" diff --git a/api/funkwhale_api/users/models.py b/api/funkwhale_api/users/models.py index e5ac8bfb6..55dd3906f 100644 --- a/api/funkwhale_api/users/models.py +++ b/api/funkwhale_api/users/models.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, unicode_literals - import datetime import os import random @@ -33,7 +30,7 @@ def get_token(length=5): wordlist_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), "wordlist.txt" ) - with open(wordlist_path, "r") as f: + with open(wordlist_path) as f: words = f.readlines() phrase = "".join(random.choice(words) for i in range(length)) return phrase.replace("\n", "-").rstrip("-") @@ -201,11 +198,7 @@ class User(AbstractUser): defaults = defaults or preferences.get("users__default_permissions") perms = {} for p in PERMISSIONS: - v = ( - self.is_superuser - or getattr(self, "permission_{}".format(p)) - or p in defaults - ) + v = self.is_superuser or getattr(self, f"permission_{p}") or p in defaults perms[p] = v return perms @@ -226,7 +219,7 @@ class User(AbstractUser): def has_permissions(self, *perms, **kwargs): operator = kwargs.pop("operator", "and") if operator not in ["and", "or"]: - raise ValueError("Invalid operator {}".format(operator)) + raise ValueError(f"Invalid operator {operator}") permissions = self.get_permissions() checker = all if operator == "and" else any return checker([permissions[p] for p in perms]) @@ -249,7 +242,7 @@ class User(AbstractUser): self.update_subsonic_api_token() def get_activity_url(self): - return settings.FUNKWHALE_URL + "/@{}".format(self.username) + return settings.FUNKWHALE_URL + f"/@{self.username}" def record_activity(self): """ @@ -292,16 +285,16 @@ class User(AbstractUser): def get_channels_groups(self): groups = ["imports", "inbox"] - groups = ["user.{}.{}".format(self.pk, g) for g in groups] + groups = [f"user.{self.pk}.{g}" for g in groups] for permission, value in self.all_permissions.items(): if value: - groups.append("admin.{}".format(permission)) + groups.append(f"admin.{permission}") return groups def full_username(self) -> str: - return "{}@{}".format(self.username, settings.FEDERATION_HOSTNAME) + return f"{self.username}@{settings.FEDERATION_HOSTNAME}" def get_avatar(self): if not self.actor: diff --git a/api/funkwhale_api/users/oauth/permissions.py b/api/funkwhale_api/users/oauth/permissions.py index 54a3ff0f2..49d4af892 100644 --- a/api/funkwhale_api/users/oauth/permissions.py +++ b/api/funkwhale_api/users/oauth/permissions.py @@ -55,12 +55,12 @@ class ScopePermission(permissions.BasePermission): anonymous_policy = getattr(view, "anonymous_policy", False) if anonymous_policy not in [True, False, "setting"]: raise ImproperlyConfigured( - "{} is not a valid value for anonymous_policy".format(anonymous_policy) + f"{anonymous_policy} is not a valid value for anonymous_policy" ) if isinstance(scope_config, str): scope_config = { - "read": "read:{}".format(scope_config), - "write": "write:{}".format(scope_config), + "read": f"read:{scope_config}", + "write": f"write:{scope_config}", } action = METHOD_SCOPE_MAPPING[request.method.lower()] required_scope = scope_config[action] diff --git a/api/funkwhale_api/users/oauth/scopes.py b/api/funkwhale_api/users/oauth/scopes.py index b3afd14ae..d8ea4bcfd 100644 --- a/api/funkwhale_api/users/oauth/scopes.py +++ b/api/funkwhale_api/users/oauth/scopes.py @@ -5,7 +5,7 @@ class Scope: self.children = children or [] def copy(self, prefix): - return Scope("{}:{}".format(prefix, self.id)) + return Scope(f"{prefix}:{self.id}") BASE_SCOPES = [ diff --git a/api/tests/audio/test_serializers.py b/api/tests/audio/test_serializers.py index 319770c40..2c88283df 100644 --- a/api/tests/audio/test_serializers.py +++ b/api/tests/audio/test_serializers.py @@ -665,7 +665,7 @@ def test_rss_feed_item_serializer_create(factories): expected_uuid = uuid.uuid3( uuid.NAMESPACE_URL, - "rss://{}-16f66fff-41ae-4a1c-9101-2746218c4f32".format(channel.pk), + f"rss://{channel.pk}-16f66fff-41ae-4a1c-9101-2746218c4f32", ) assert upload.library == channel.library assert upload.import_status == "finished" @@ -692,7 +692,7 @@ def test_rss_feed_item_serializer_update(factories): channel = factories["audio.Channel"](rss_url=rss_url, external=True) expected_uuid = uuid.uuid3( uuid.NAMESPACE_URL, - "rss://{}-16f66fff-41ae-4a1c-9101-2746218c4f32".format(channel.pk), + f"rss://{channel.pk}-16f66fff-41ae-4a1c-9101-2746218c4f32", ) upload = factories["music.Upload"]( track__uuid=expected_uuid, diff --git a/api/tests/audio/test_spa_views.py b/api/tests/audio/test_spa_views.py index 341210e69..e95e4bc0b 100644 --- a/api/tests/audio/test_spa_views.py +++ b/api/tests/audio/test_spa_views.py @@ -14,8 +14,8 @@ def test_channel_detail(attribute, spa_html, no_api_auth, client, factories, set library__privacy_level="everyone", artist__with_cover=True ) factories["music.Upload"](playable=True, library=channel.library) - url = "/channels/{}".format(utils.recursive_getattr(channel, attribute)) - detail_url = "/channels/{}".format(channel.actor.full_username) + url = f"/channels/{utils.recursive_getattr(channel, attribute)}" + detail_url = f"/channels/{channel.actor.full_username}" response = client.get(url) @@ -44,7 +44,7 @@ def test_channel_detail(attribute, spa_html, no_api_auth, client, factories, set "rel": "alternate", "type": "application/rss+xml", "href": channel.get_rss_url(), - "title": "{} - RSS Podcast Feed".format(channel.artist.name), + "title": f"{channel.artist.name} - RSS Podcast Feed", }, { "tag": "link", @@ -81,8 +81,8 @@ def test_oembed_channel(factories, no_api_auth, api_client, settings): channel = factories["audio.Channel"](artist__with_cover=True) artist = channel.artist url = reverse("api:v1:oembed") - obj_url = "https://test.com/channels/{}".format(channel.uuid) - iframe_src = "http://embed?type=channel&id={}".format(channel.uuid) + obj_url = f"https://test.com/channels/{channel.uuid}" + iframe_src = f"http://embed?type=channel&id={channel.uuid}" expected = { "version": "1.0", "type": "rich", diff --git a/api/tests/audio/test_views.py b/api/tests/audio/test_views.py index 28f38ed5d..1efd80eb8 100644 --- a/api/tests/audio/test_views.py +++ b/api/tests/audio/test_views.py @@ -442,7 +442,7 @@ def test_can_filter_channels_through_api_scope(factories, logged_in_api_client): factories["audio.Channel"]() url = reverse("api:v1:channels-list") response = logged_in_api_client.get( - url, {"scope": "actor:{}".format(channel.attributed_to.full_username)} + url, {"scope": f"actor:{channel.attributed_to.full_username}"} ) assert response.status_code == 200 diff --git a/api/tests/common/test_authentication.py b/api/tests/common/test_authentication.py index be3f7b99c..9faa465c1 100644 --- a/api/tests/common/test_authentication.py +++ b/api/tests/common/test_authentication.py @@ -34,7 +34,7 @@ def test_should_verify_email( def test_app_token_authentication(factories, api_request): user = factories["users.User"]() app = factories["users.Application"](user=user, scope="read write") - request = api_request.get("/", HTTP_AUTHORIZATION="Bearer {}".format(app.token)) + request = api_request.get("/", HTTP_AUTHORIZATION=f"Bearer {app.token}") auth = authentication.ApplicationTokenAuthentication() assert auth.authenticate(request)[0] == app.user diff --git a/api/tests/common/test_fields.py b/api/tests/common/test_fields.py index 2cc07f1b2..0fdf74cae 100644 --- a/api/tests/common/test_fields.py +++ b/api/tests/common/test_fields.py @@ -101,5 +101,5 @@ def test_generic_relation_filter_target_type_and_id(factories): } }, ) - qs = f.filter(note.__class__.objects.all(), "user:{}".format(user.username)) + qs = f.filter(note.__class__.objects.all(), f"user:{user.username}") assert list(qs) == [note] diff --git a/api/tests/common/test_filters.py b/api/tests/common/test_filters.py index bc155ac8c..57ef25666 100644 --- a/api/tests/common/test_filters.py +++ b/api/tests/common/test_filters.py @@ -31,9 +31,7 @@ def test_mutation_filter_is_approved(value, expected, factories): qs = mutations[True].__class__.objects.all() - filterset = filters.MutationFilter( - {"q": "is_approved:{}".format(value)}, queryset=qs - ) + filterset = filters.MutationFilter({"q": f"is_approved:{value}"}, queryset=qs) assert list(filterset.qs) == [mutations[expected]] diff --git a/api/tests/common/test_middleware.py b/api/tests/common/test_middleware.py index 63d6d3cfb..2a7251ab8 100644 --- a/api/tests/common/test_middleware.py +++ b/api/tests/common/test_middleware.py @@ -129,7 +129,7 @@ def test_get_spa_html_from_http(local_cache, r_mock, mocker, settings): assert middleware.get_spa_html("http://test") == "hello world" cache_set.assert_called_once_with( - "spa-file:{}:index.html".format(url), + f"spa-file:{url}:index.html", "hello world", settings.FUNKWHALE_SPA_HTML_CACHE_DURATION, ) diff --git a/api/tests/common/test_scripts.py b/api/tests/common/test_scripts.py index 930c502a3..35368dcc7 100644 --- a/api/tests/common/test_scripts.py +++ b/api/tests/common/test_scripts.py @@ -20,7 +20,7 @@ def command(): ], ) def test_script_command_list(command, script_name, mocker): - mocked = mocker.patch("funkwhale_api.common.scripts.{}.main".format(script_name)) + mocked = mocker.patch(f"funkwhale_api.common.scripts.{script_name}.main") command.handle(script_name=script_name, interactive=False) @@ -168,7 +168,7 @@ def test_migrate_to_user_libraries_update_actors_shared_inbox_url(factories, std def test_migrate_to_user_libraries_generate_actor_urls( factories, part, settings, stdout ): - field = "{}_url".format(part) + field = f"{part}_url" ok = factories["users.User"]().create_actor() local = factories["federation.Actor"](local=True, **{field: None}) remote = factories["federation.Actor"](local=False, **{field: None}) diff --git a/api/tests/common/test_serializers.py b/api/tests/common/test_serializers.py index a5c9f69c5..15b0f7140 100644 --- a/api/tests/common/test_serializers.py +++ b/api/tests/common/test_serializers.py @@ -155,7 +155,7 @@ def test_track_fields_for_update(mocker): on_updated_fields = mocker.stub() - class Obj(object): + class Obj: field1 = "value1" field2 = "value2" diff --git a/api/tests/common/test_views.py b/api/tests/common/test_views.py index 876252a84..7b08e50b4 100644 --- a/api/tests/common/test_views.py +++ b/api/tests/common/test_views.py @@ -88,9 +88,7 @@ def test_can_approve_reject_mutation_with_perm( has_perm = mocker.patch( "funkwhale_api.common.mutations.registry.has_perm", return_value=True ) - url = reverse( - "api:v1:mutations-{}".format(endpoint), kwargs={"uuid": mutation.uuid} - ) + url = reverse(f"api:v1:mutations-{endpoint}", kwargs={"uuid": mutation.uuid}) response = logged_in_api_client.post(url) @@ -126,9 +124,7 @@ def test_cannot_approve_reject_applied_mutation( target=track, type="update", payload={}, is_applied=True ) mocker.patch("funkwhale_api.common.mutations.registry.has_perm", return_value=True) - url = reverse( - "api:v1:mutations-{}".format(endpoint), kwargs={"uuid": mutation.uuid} - ) + url = reverse(f"api:v1:mutations-{endpoint}", kwargs={"uuid": mutation.uuid}) response = logged_in_api_client.post(url) @@ -150,9 +146,7 @@ def test_cannot_approve_reject_without_perm( track = factories["music.Track"]() mutation = factories["common.Mutation"](target=track, type="update", payload={}) mocker.patch("funkwhale_api.common.mutations.registry.has_perm", return_value=False) - url = reverse( - "api:v1:mutations-{}".format(endpoint), kwargs={"uuid": mutation.uuid} - ) + url = reverse(f"api:v1:mutations-{endpoint}", kwargs={"uuid": mutation.uuid}) response = logged_in_api_client.post(url) @@ -218,7 +212,7 @@ def test_attachment_proxy_dont_crash_on_long_filename( ): long_filename = "a" * 400 attachment = factories["common.Attachment"]( - file=None, url="https://domain/{}.jpg".format(long_filename) + file=None, url=f"https://domain/{long_filename}.jpg" ) avatar_content = avatar.read() diff --git a/api/tests/favorites/test_activity.py b/api/tests/favorites/test_activity.py index e4c040b20..f6a17d4db 100644 --- a/api/tests/favorites/test_activity.py +++ b/api/tests/favorites/test_activity.py @@ -6,7 +6,7 @@ from funkwhale_api.users.serializers import UserActivitySerializer def test_get_favorite_activity_url(settings, factories): favorite = factories["favorites.TrackFavorite"]() user_url = favorite.user.get_activity_url() - expected = "{}/favorites/tracks/{}".format(user_url, favorite.pk) + expected = f"{user_url}/favorites/tracks/{favorite.pk}" assert favorite.get_activity_url() == expected diff --git a/api/tests/federation/test_activity.py b/api/tests/federation/test_activity.py index 859c00045..996843688 100644 --- a/api/tests/federation/test_activity.py +++ b/api/tests/federation/test_activity.py @@ -352,7 +352,7 @@ def test_inbox_routing_send_to_channel(factories, mocker): ii.refresh_from_db() group_send.assert_called_once_with( - "user.{}.inbox".format(ii.actor.user.pk), + f"user.{ii.actor.user.pk}.inbox", { "type": "event.send", "text": "", @@ -455,10 +455,10 @@ def test_outbox_router_dispatch_allow_list(mocker, factories, preferences, now): router.connect({"type": "Noop"}, handler) router.dispatch({"type": "Noop"}, {"summary": "hello"}) prepare_deliveries_and_inbox_items.assert_any_call( - [r1], "to", allowed_domains=set([r1.domain_id]) + [r1], "to", allowed_domains={r1.domain_id} ) prepare_deliveries_and_inbox_items.assert_any_call( - [r2], "cc", allowed_domains=set([r1.domain_id]) + [r2], "cc", allowed_domains={r1.domain_id} ) @@ -579,7 +579,7 @@ def test_prepare_deliveries_and_inbox_items_allow_list(factories, preferences): recipients = [remote_actor1, remote_actor2] inbox_items, deliveries, urls = activity.prepare_deliveries_and_inbox_items( - recipients, "to", allowed_domains=set([remote_actor1.domain_id]) + recipients, "to", allowed_domains={remote_actor1.domain_id} ) expected_inbox_items = [] diff --git a/api/tests/federation/test_api_views.py b/api/tests/federation/test_api_views.py index 3d61984c7..508b8b576 100644 --- a/api/tests/federation/test_api_views.py +++ b/api/tests/federation/test_api_views.py @@ -93,7 +93,7 @@ def test_user_cannot_edit_someone_else_library_follow( logged_in_api_client.user.create_actor() follow = factories["federation.LibraryFollow"]() url = reverse( - "api:v1:federation:library-follows-{}".format(action), + f"api:v1:federation:library-follows-{action}", kwargs={"uuid": follow.uuid}, ) response = logged_in_api_client.post(url) @@ -111,7 +111,7 @@ def test_user_can_accept_or_reject_own_follows( actor = logged_in_api_client.user.create_actor() follow = factories["federation.LibraryFollow"](target__actor=actor) url = reverse( - "api:v1:federation:library-follows-{}".format(action), + f"api:v1:federation:library-follows-{action}", kwargs={"uuid": follow.uuid}, ) response = logged_in_api_client.post(url) diff --git a/api/tests/federation/test_authentication.py b/api/tests/federation/test_authentication.py index cc2ccf8cb..981b44ec7 100644 --- a/api/tests/federation/test_authentication.py +++ b/api/tests/federation/test_authentication.py @@ -37,7 +37,7 @@ def test_authenticate(factories, mocker, api_request): **{ "HTTP_DATE": prepared.headers["date"], "HTTP_SIGNATURE": prepared.headers["signature"], - } + }, ) authenticator = authentication.SignatureAuthentication() user, _ = authenticator.authenticate(django_request) @@ -52,7 +52,7 @@ def test_authenticate(factories, mocker, api_request): def test_authenticate_skips_blocked_domain(factories, api_request): policy = factories["moderation.InstancePolicy"](block_all=True, for_domain=True) private, public = keys.get_key_pair() - actor_url = "https://{}/actor".format(policy.target_domain.name) + actor_url = f"https://{policy.target_domain.name}/actor" signed_request = factories["federation.SignedRequest"]( auth__key=private, auth__key_id=actor_url + "#main-key", auth__headers=["date"] @@ -63,7 +63,7 @@ def test_authenticate_skips_blocked_domain(factories, api_request): **{ "HTTP_DATE": prepared.headers["date"], "HTTP_SIGNATURE": prepared.headers["signature"], - } + }, ) authenticator = authentication.SignatureAuthentication() @@ -85,7 +85,7 @@ def test_authenticate_skips_blocked_actor(factories, api_request): **{ "HTTP_DATE": prepared.headers["date"], "HTTP_SIGNATURE": prepared.headers["signature"], - } + }, ) authenticator = authentication.SignatureAuthentication() @@ -98,7 +98,7 @@ def test_authenticate_ignore_inactive_policy(factories, api_request, mocker): block_all=True, for_domain=True, is_active=False ) private, public = keys.get_key_pair() - actor_url = "https://{}/actor".format(policy.target_domain.name) + actor_url = f"https://{policy.target_domain.name}/actor" signed_request = factories["federation.SignedRequest"]( auth__key=private, auth__key_id=actor_url + "#main-key", auth__headers=["date"] @@ -126,7 +126,7 @@ def test_authenticate_ignore_inactive_policy(factories, api_request, mocker): **{ "HTTP_DATE": prepared.headers["date"], "HTTP_SIGNATURE": prepared.headers["signature"], - } + }, ) authenticator = authentication.SignatureAuthentication() authenticator.authenticate(django_request) @@ -169,7 +169,7 @@ def test_autenthicate_supports_blind_key_rotation(factories, mocker, api_request **{ "HTTP_DATE": prepared.headers["date"], "HTTP_SIGNATURE": prepared.headers["signature"], - } + }, ) authenticator = authentication.SignatureAuthentication() user, _ = authenticator.authenticate(django_request) @@ -186,7 +186,7 @@ def test_authenticate_checks_signature_with_allow_list( preferences["moderation__allow_list_enabled"] = True domain = factories["federation.Domain"](allowed=False) private, public = keys.get_key_pair() - actor_url = "https://{}/actor".format(domain.name) + actor_url = f"https://{domain.name}/actor" signed_request = factories["federation.SignedRequest"]( auth__key=private, auth__key_id=actor_url + "#main-key", auth__headers=["date"] @@ -197,7 +197,7 @@ def test_authenticate_checks_signature_with_allow_list( **{ "HTTP_DATE": prepared.headers["date"], "HTTP_SIGNATURE": prepared.headers["signature"], - } + }, ) authenticator = authentication.SignatureAuthentication() diff --git a/api/tests/federation/test_decorators.py b/api/tests/federation/test_decorators.py index 478fedfc3..2db0d39a4 100644 --- a/api/tests/federation/test_decorators.py +++ b/api/tests/federation/test_decorators.py @@ -39,9 +39,7 @@ def test_fetches_route_create(factories, api_request, mocker): def test_fetches_route_create_local(factories, api_request, mocker, settings): user = factories["users.User"]() user.create_actor() - track = factories["music.Track"]( - fid="https://{}/test".format(settings.FEDERATION_HOSTNAME) - ) + track = factories["music.Track"](fid=f"https://{settings.FEDERATION_HOSTNAME}/test") view = V.as_view({"post": "fetches"}) request = api_request.post("/", format="json") diff --git a/api/tests/federation/test_models.py b/api/tests/federation/test_models.py index 6f722c6e8..4a5f032e3 100644 --- a/api/tests/federation/test_models.py +++ b/api/tests/federation/test_models.py @@ -23,7 +23,7 @@ def test_cannot_duplicate_follow(factories): def test_follow_federation_url(factories): follow = factories["federation.Follow"](local=True) - expected = "{}#follows/{}".format(follow.actor.fid, follow.uuid) + expected = f"{follow.actor.fid}#follows/{follow.uuid}" assert follow.get_federation_id() == expected @@ -179,7 +179,7 @@ def test_actor_can_manage_attributed_to(mocker, factories): def test_actor_can_manage_domain_not_service_actor(mocker, factories): actor = factories["federation.Actor"]() - obj = mocker.Mock(fid="https://{}/hello".format(actor.domain_id)) + obj = mocker.Mock(fid=f"https://{actor.domain_id}/hello") assert actor.can_manage(obj) is False @@ -188,7 +188,7 @@ def test_actor_can_manage_domain_service_actor(mocker, factories): actor = factories["federation.Actor"]() actor.domain.service_actor = actor actor.domain.save() - obj = mocker.Mock(fid="https://{}/hello".format(actor.domain_id)) + obj = mocker.Mock(fid=f"https://{actor.domain_id}/hello") assert actor.can_manage(obj) is True diff --git a/api/tests/federation/test_routes.py b/api/tests/federation/test_routes.py index 108ca41b8..6cf8f12cd 100644 --- a/api/tests/federation/test_routes.py +++ b/api/tests/federation/test_routes.py @@ -42,7 +42,7 @@ def test_inbox_routes(route, handler): matching = [ handler for r, handler in routes.inbox.routes if activity.match_route(r, route) ] - assert len(matching) == 1, "Inbox route {} not found".format(route) + assert len(matching) == 1, f"Inbox route {route} not found" assert matching[0] == handler @@ -88,7 +88,7 @@ def test_outbox_routes(route, handler): matching = [ handler for r, handler in routes.outbox.routes if activity.match_route(r, route) ] - assert len(matching) == 1, "Outbox route {} not found".format(route) + assert len(matching) == 1, f"Outbox route {route} not found" assert matching[0] == handler diff --git a/api/tests/federation/test_serializers.py b/api/tests/federation/test_serializers.py index 4312e26f5..117873c7e 100644 --- a/api/tests/federation/test_serializers.py +++ b/api/tests/federation/test_serializers.py @@ -1940,7 +1940,7 @@ def test_report_serializer_to_ap(factories): "actor": actors.get_service_actor().fid, "content": report.summary, "object": [report.target.fid], - "tag": [{"type": "Hashtag", "name": "#{}".format(report.type)}], + "tag": [{"type": "Hashtag", "name": f"#{report.type}"}], } serializer = serializers.FlagSerializer(report) assert serializer.data == expected diff --git a/api/tests/federation/test_spa_views.py b/api/tests/federation/test_spa_views.py index f72841996..e7a4719be 100644 --- a/api/tests/federation/test_spa_views.py +++ b/api/tests/federation/test_spa_views.py @@ -4,7 +4,7 @@ from funkwhale_api.common import utils def test_channel_detail(spa_html, no_api_auth, client, factories, settings): icon = factories["common.Attachment"]() actor = factories["federation.Actor"](local=True, attachment_icon=icon) - url = "/@{}".format(actor.preferred_username) + url = f"/@{actor.preferred_username}" response = client.get(url) diff --git a/api/tests/federation/test_tasks.py b/api/tests/federation/test_tasks.py index 5dacdcee9..388ab5440 100644 --- a/api/tests/federation/test_tasks.py +++ b/api/tests/federation/test_tasks.py @@ -214,7 +214,7 @@ def test_update_domain_nodeinfo(factories, mocker, now, service_actor): def test_update_domain_nodeinfo_error(factories, r_mock, now): domain = factories["federation.Domain"](nodeinfo_fetch_date=None) - wellknown_url = "https://{}/.well-known/nodeinfo".format(domain.name) + wellknown_url = f"https://{domain.name}/.well-known/nodeinfo" r_mock.get(wellknown_url, status_code=500) @@ -225,7 +225,7 @@ def test_update_domain_nodeinfo_error(factories, r_mock, now): assert domain.nodeinfo_fetch_date == now assert domain.nodeinfo == { "status": "error", - "error": "500 Server Error: None for url: {}".format(wellknown_url), + "error": f"500 Server Error: None for url: {wellknown_url}", } @@ -406,14 +406,12 @@ def test_fetch_success(factories, r_mock, mocker): def test_fetch_webfinger(factories, r_mock, mocker): actor = factories["federation.Actor"]() - fetch = factories["federation.Fetch"]( - url="webfinger://{}".format(actor.full_username) - ) + fetch = factories["federation.Fetch"](url=f"webfinger://{actor.full_username}") payload = serializers.ActorSerializer(actor).data init = mocker.spy(serializers.ActorSerializer, "__init__") save = mocker.spy(serializers.ActorSerializer, "save") webfinger_payload = { - "subject": "acct:{}".format(actor.full_username), + "subject": f"acct:{actor.full_username}", "aliases": ["https://test.webfinger"], "links": [ {"rel": "self", "type": "application/activity+json", "href": actor.fid} @@ -542,7 +540,7 @@ def test_fetch_honor_instance_policy_domain(factories): domain = factories["moderation.InstancePolicy"]( block_all=True, for_domain=True ).target_domain - fid = "https://{}/test".format(domain.name) + fid = f"https://{domain.name}/test" fetch = factories["federation.Fetch"](url=fid) tasks.fetch(fetch_id=fetch.pk) @@ -588,7 +586,7 @@ def test_fetch_honor_instance_policy_different_url_and_id(r_mock, factories): block_all=True, for_domain=True ).target_domain fid = "https://ok/test" - r_mock.get(fid, json={"id": "http://{}/test".format(domain.name)}) + r_mock.get(fid, json={"id": f"http://{domain.name}/test"}) fetch = factories["federation.Fetch"](url=fid) tasks.fetch(fetch_id=fetch.pk) fetch.refresh_from_db() diff --git a/api/tests/federation/test_utils.py b/api/tests/federation/test_utils.py index ff52372fa..876d38e4a 100644 --- a/api/tests/federation/test_utils.py +++ b/api/tests/federation/test_utils.py @@ -67,7 +67,7 @@ def test_retrieve_ap_object_honor_instance_policy_domain(factories): domain = factories["moderation.InstancePolicy"]( block_all=True, for_domain=True ).target_domain - fid = "https://{}/test".format(domain.name) + fid = f"https://{domain.name}/test" with pytest.raises(exceptions.BlockedActorOrDomain): utils.retrieve_ap_object(fid, actor=None) @@ -106,7 +106,7 @@ def test_retrieve_ap_object_honor_instance_policy_different_url_and_id( block_all=True, for_domain=True ).target_domain fid = "https://ok/test" - r_mock.get(fid, json={"id": "http://{}/test".format(domain.name)}) + r_mock.get(fid, json={"id": f"http://{domain.name}/test"}) with pytest.raises(exceptions.BlockedActorOrDomain): utils.retrieve_ap_object(fid, actor=None) diff --git a/api/tests/federation/test_views.py b/api/tests/federation/test_views.py index e7cd736f4..3227ec720 100644 --- a/api/tests/federation/test_views.py +++ b/api/tests/federation/test_views.py @@ -164,7 +164,7 @@ def test_wellknown_webfinger_local(factories, api_client, settings, mocker): url = reverse("federation:well-known-webfinger") response = api_client.get( url, - data={"resource": "acct:{}".format(user.actor.webfinger_subject)}, + data={"resource": f"acct:{user.actor.webfinger_subject}"}, HTTP_ACCEPT="application/jrd+json", ) serializer = serializers.ActorWebfingerSerializer(user.actor) @@ -327,10 +327,8 @@ def test_music_library_retrieve_page_follow( def test_music_local_entity_detail( factories, api_client, factory, serializer_class, namespace, settings ): - obj = factories[factory](fid="http://{}/1".format(settings.FEDERATION_HOSTNAME)) - url = reverse( - "federation:music:{}-detail".format(namespace), kwargs={"uuid": obj.uuid} - ) + obj = factories[factory](fid=f"http://{settings.FEDERATION_HOSTNAME}/1") + url = reverse(f"federation:music:{namespace}-detail", kwargs={"uuid": obj.uuid}) response = api_client.get(url) assert response.status_code == 200 @@ -345,9 +343,7 @@ def test_music_non_local_entity_detail( factories, api_client, factory, namespace, settings ): obj = factories[factory](fid="http://wrong-domain/1") - url = reverse( - "federation:music:{}-detail".format(namespace), kwargs={"uuid": obj.uuid} - ) + url = reverse(f"federation:music:{namespace}-detail", kwargs={"uuid": obj.uuid}) response = api_client.get(url) assert response.status_code == 404 @@ -539,7 +535,7 @@ def test_artist_retrieve_redirects_to_html_if_header_set( @pytest.mark.parametrize("index", ["channels", "libraries"]) def test_public_index_disabled(index, api_client, preferences): preferences["federation__public_index"] = False - url = reverse("federation:index:index-{}".format(index)) + url = reverse(f"federation:index:index-{index}") response = api_client.get(url) assert response.status_code == 405 diff --git a/api/tests/federation/test_webfinger.py b/api/tests/federation/test_webfinger.py index 0608df3e2..1ca7402ca 100644 --- a/api/tests/federation/test_webfinger.py +++ b/api/tests/federation/test_webfinger.py @@ -60,7 +60,7 @@ def test_webfinger_get_resource(r_mock): ], } r_mock.get( - "https://test.webfinger/.well-known/webfinger?resource={}".format(resource), + f"https://test.webfinger/.well-known/webfinger?resource={resource}", json=payload, ) diff --git a/api/tests/history/test_activity.py b/api/tests/history/test_activity.py index f3ada5052..5b048cda6 100644 --- a/api/tests/history/test_activity.py +++ b/api/tests/history/test_activity.py @@ -6,7 +6,7 @@ from funkwhale_api.users.serializers import UserActivitySerializer def test_get_listening_activity_url(settings, factories): listening = factories["history.Listening"]() user_url = listening.user.get_activity_url() - expected = "{}/listenings/tracks/{}".format(user_url, listening.pk) + expected = f"{user_url}/listenings/tracks/{listening.pk}" assert listening.get_activity_url() == expected diff --git a/api/tests/instance/test_stats.py b/api/tests/instance/test_stats.py index 5c45f8a75..2fa40cd70 100644 --- a/api/tests/instance/test_stats.py +++ b/api/tests/instance/test_stats.py @@ -59,10 +59,7 @@ def test_get(mocker): "music_duration", "downloads", ] - [ - mocker.patch.object(stats, "get_{}".format(k), return_value=i) - for i, k in enumerate(keys) - ] + [mocker.patch.object(stats, f"get_{k}", return_value=i) for i, k in enumerate(keys)] expected = {k: i for i, k in enumerate(keys)} diff --git a/api/tests/loadtesting/library.py b/api/tests/loadtesting/library.py index 6413a161f..4402ade2c 100644 --- a/api/tests/loadtesting/library.py +++ b/api/tests/loadtesting/library.py @@ -9,7 +9,7 @@ DATA = {"playable": True} HEADERS = {} if JWT_TOKEN: print("Starting authenticated session") - HEADERS["authorization"] = "JWT {}".format(JWT_TOKEN) + HEADERS["authorization"] = f"JWT {JWT_TOKEN}" class WebsiteTasks(TaskSet): diff --git a/api/tests/manage/test_views.py b/api/tests/manage/test_views.py index 92f9b9ceb..42ccf28c2 100644 --- a/api/tests/manage/test_views.py +++ b/api/tests/manage/test_views.py @@ -216,9 +216,7 @@ def test_album_list(factories, superuser_api_client, settings): album = factories["music.Album"]() factories["music.Album"]() url = reverse("api:v1:manage:library:albums-list") - response = superuser_api_client.get( - url, {"q": 'artist:"{}"'.format(album.artist.name)} - ) + response = superuser_api_client.get(url, {"q": f'artist:"{album.artist.name}"'}) assert response.status_code == 200 diff --git a/api/tests/moderation/test_tasks.py b/api/tests/moderation/test_tasks.py index 2f968c68b..48e445c15 100644 --- a/api/tests/moderation/test_tasks.py +++ b/api/tests/moderation/test_tasks.py @@ -23,9 +23,7 @@ def test_report_created_signal_sends_email_to_mods(factories, mailoutbox, settin tasks.send_new_report_email_to_moderators(report_id=report.pk) - detail_url = federation_utils.full_url( - "/manage/moderation/reports/{}".format(report.uuid) - ) + detail_url = federation_utils.full_url(f"/manage/moderation/reports/{report.uuid}") unresolved_reports_url = federation_utils.full_url( "/manage/moderation/reports?q=resolved:no" ) @@ -56,7 +54,7 @@ def test_signup_request_pending_sends_email_to_mods(factories, mailoutbox, setti tasks.user_request_handle(user_request_id=signup_request.pk, new_status="pending") detail_url = federation_utils.full_url( - "/manage/moderation/requests/{}".format(signup_request.uuid) + f"/manage/moderation/requests/{signup_request.uuid}" ) unresolved_requests_url = federation_utils.full_url( "/manage/moderation/requests?q=status:pending" diff --git a/api/tests/music/test_activity.py b/api/tests/music/test_activity.py index 6cf060f42..813b49599 100644 --- a/api/tests/music/test_activity.py +++ b/api/tests/music/test_activity.py @@ -3,13 +3,13 @@ from funkwhale_api.music import serializers, signals def test_get_track_activity_url_mbid(factories): track = factories["music.Track"]() - expected = "https://musicbrainz.org/recording/{}".format(track.mbid) + expected = f"https://musicbrainz.org/recording/{track.mbid}" assert track.get_activity_url() == expected def test_get_track_activity_url_no_mbid(settings, factories): track = factories["music.Track"](mbid=None) - expected = settings.FUNKWHALE_URL + "/tracks/{}".format(track.pk) + expected = settings.FUNKWHALE_URL + f"/tracks/{track.pk}" assert track.get_activity_url() == expected @@ -23,7 +23,7 @@ def test_upload_import_status_updated_broadcast(factories, mocker): sender=None, upload=upload, old_status="pending", new_status="finished" ) group_send.assert_called_once_with( - "user.{}.imports".format(user.pk), + f"user.{user.pk}.imports", { "type": "event.send", "text": "", diff --git a/api/tests/music/test_commands.py b/api/tests/music/test_commands.py index 04e95d55f..adee497b6 100644 --- a/api/tests/music/test_commands.py +++ b/api/tests/music/test_commands.py @@ -62,14 +62,14 @@ def test_fix_uploads_mimetype(factories, mocker): ogg_path = os.path.join(DATA_DIR, "test.ogg") upload1 = factories["music.Upload"]( audio_file__from_path=mp3_path, - source="file://{}".format(mp3_path), + source=f"file://{mp3_path}", mimetype="application/x-empty", ) # this one already has a mimetype set, to it should not be updated upload2 = factories["music.Upload"]( audio_file__from_path=ogg_path, - source="file://{}".format(ogg_path), + source=f"file://{ogg_path}", mimetype="audio/something", ) c = fix_uploads.Command() @@ -179,7 +179,7 @@ def test_prune_library(factories, mocker): def test_check_inplace_files_dry_run(factories, tmpfile): prunable = factories["music.Upload"](source="file:///notfound", audio_file=None) not_prunable = factories["music.Upload"]( - source="file://{}".format(tmpfile.name), audio_file=None + source=f"file://{tmpfile.name}", audio_file=None ) c = check_inplace_files.Command() c.handle(dry_run=True) @@ -192,9 +192,7 @@ def test_check_inplace_files_dry_run(factories, tmpfile): def test_check_inplace_files_no_dry_run(factories, tmpfile): prunable = factories["music.Upload"](source="file:///notfound", audio_file=None) not_prunable = [ - factories["music.Upload"]( - source="file://{}".format(tmpfile.name), audio_file=None - ), + factories["music.Upload"](source=f"file://{tmpfile.name}", audio_file=None), factories["music.Upload"](source="upload://"), factories["music.Upload"](source="https://"), ] diff --git a/api/tests/music/test_models.py b/api/tests/music/test_models.py index 3ba04934b..ecccb2c62 100644 --- a/api/tests/music/test_models.py +++ b/api/tests/music/test_models.py @@ -193,7 +193,7 @@ def test_track_get_file_size(factories): def test_track_get_file_size_in_place(factories): name = "test.mp3" path = os.path.join(DATA_DIR, name) - upload = factories["music.Upload"](in_place=True, source="file://{}".format(path)) + upload = factories["music.Upload"](in_place=True, source=f"file://{path}") assert upload.get_file_size() == 297745 @@ -435,14 +435,14 @@ def test_artist_playable_by_anonymous(privacy_level, expected, factories): def test_upload_listen_url(factories): upload = factories["music.Upload"]() - expected = upload.track.listen_url + "?upload={}".format(upload.uuid) + expected = upload.track.listen_url + f"?upload={upload.uuid}" assert upload.listen_url == expected def test_upload_listen_url_no_download(factories): upload = factories["music.Upload"]() - expected = upload.track.listen_url + "?upload={}&download=false".format(upload.uuid) + expected = upload.track.listen_url + f"?upload={upload.uuid}&download=false" assert upload.listen_url_no_download == expected diff --git a/api/tests/music/test_music.py b/api/tests/music/test_music.py index 79402b47c..15fab39d4 100644 --- a/api/tests/music/test_music.py +++ b/api/tests/music/test_music.py @@ -17,7 +17,7 @@ def test_can_create_artist_from_api(artists, mocker, db): assert artist.mbid, data["id"] assert artist.name, "Adhesive Wombat" assert artist.fid == federation_utils.full_url( - "/federation/music/artists/{}".format(artist.uuid) + f"/federation/music/artists/{artist.uuid}" ) @@ -42,7 +42,7 @@ def test_can_create_album_from_api(artists, albums, mocker, db): assert album.artist.name, "System of a Down" assert album.artist.mbid, data["artist-credit"][0]["artist"]["id"] assert album.fid == federation_utils.full_url( - "/federation/music/albums/{}".format(album.uuid) + f"/federation/music/albums/{album.uuid}" ) @@ -70,7 +70,7 @@ def test_can_create_track_from_api(artists, albums, tracks, mocker, db): assert str(track.album.mbid) == "a50d2a81-2a50-484d-9cb4-b9f6833f583e" assert track.album.title == "Marsupial Madness" assert track.fid == federation_utils.full_url( - "/federation/music/tracks/{}".format(track.uuid) + f"/federation/music/tracks/{track.uuid}" ) diff --git a/api/tests/music/test_spa_views.py b/api/tests/music/test_spa_views.py index 9a3195f03..391b5cc2e 100644 --- a/api/tests/music/test_spa_views.py +++ b/api/tests/music/test_spa_views.py @@ -14,7 +14,7 @@ def test_library_track(spa_html, no_api_auth, client, factories, settings): track__album__with_cover=True, ) track = upload.track - url = "/library/tracks/{}".format(track.pk) + url = f"/library/tracks/{track.pk}" response = client.get(url) @@ -100,7 +100,7 @@ def test_library_album(spa_html, no_api_auth, client, factories, settings): playable=True, track__disc_number=1, track__album__with_cover=True ).track album = track.album - url = "/library/albums/{}".format(album.pk) + url = f"/library/albums/{album.pk}" response = client.get(url) @@ -167,7 +167,7 @@ def test_library_artist(spa_html, no_api_auth, client, factories, settings): album = factories["music.Album"](with_cover=True) factories["music.Upload"](playable=True, track__album=album) artist = album.artist - url = "/library/artists/{}".format(artist.pk) + url = f"/library/artists/{artist.pk}" response = client.get(url) @@ -224,7 +224,7 @@ def test_library_playlist(spa_html, no_api_auth, client, factories, settings): ).track playlist.insert_many([track]) - url = "/library/playlists/{}".format(playlist.pk) + url = f"/library/playlists/{playlist.pk}" response = client.get(url) @@ -271,7 +271,7 @@ def test_library_playlist(spa_html, no_api_auth, client, factories, settings): def test_library_playlist_empty(spa_html, no_api_auth, client, factories, settings): playlist = factories["playlists.Playlist"](privacy_level="everyone") - url = "/library/playlists/{}".format(playlist.pk) + url = f"/library/playlists/{playlist.pk}" response = client.get(url) @@ -293,7 +293,7 @@ def test_library_playlist_empty(spa_html, no_api_auth, client, factories, settin def test_library_library(spa_html, no_api_auth, client, factories, settings): library = factories["music.Library"]() - url = "/library/{}".format(library.uuid) + url = f"/library/{library.uuid}" response = client.get(url) diff --git a/api/tests/music/test_tasks.py b/api/tests/music/test_tasks.py index abe19c2f5..43bb87dd3 100644 --- a/api/tests/music/test_tasks.py +++ b/api/tests/music/test_tasks.py @@ -390,7 +390,7 @@ def test_upload_import_in_place(factories, mocker): upload = factories["music.Upload"]( track=None, audio_file=None, - source="file://{}".format(path), + source=f"file://{path}", import_metadata={"funkwhale": {"track": {"uuid": track.uuid}}}, ) @@ -564,7 +564,7 @@ def test_populate_album_cover_file_cover_separate_file( ext, mimetype, factories, mocker ): mocker.patch("funkwhale_api.music.tasks.IMAGE_TYPES", [(ext, mimetype)]) - image_path = os.path.join(DATA_DIR, "cover.{}".format(ext)) + image_path = os.path.join(DATA_DIR, f"cover.{ext}") with open(image_path, "rb") as f: image_content = f.read() album = factories["music.Album"](attachment_cover=None, mbid=None) @@ -775,7 +775,7 @@ def test_scan_page_fetches_page_and_creates_tracks(now, mocker, factories, r_moc scan = factories["music.LibraryScan"](status="scanning", total_files=5) uploads = [ factories["music.Upload"]( - fid="https://track.test/{}".format(i), + fid=f"https://track.test/{i}", size=42, bitrate=66, duration=99, @@ -947,7 +947,7 @@ def test_update_library_entity(factories, mocker): ], ) def test_get_cover_from_fs(name, ext, mimetype, tmpdir): - cover_path = os.path.join(tmpdir, "{}.{}".format(name, ext)) + cover_path = os.path.join(tmpdir, f"{name}.{ext}") content = "Hello" with open(cover_path, "w") as f: f.write(content) @@ -1064,7 +1064,7 @@ def test_process_channel_upload_forces_artist_and_attributed_to( get_track_from_import_metadata.assert_called_once_with( expected_final_metadata, attributed_to=channel.attributed_to, - **expected_forced_values + **expected_forced_values, ) assert upload.track.description.content_type == "text/markdown" diff --git a/api/tests/music/test_views.py b/api/tests/music/test_views.py index af0c0fdc7..1e347f4b5 100644 --- a/api/tests/music/test_views.py +++ b/api/tests/music/test_views.py @@ -459,7 +459,7 @@ def test_stream(factories, logged_in_api_client, mocker, settings): reverse("api:v1:stream-detail", kwargs={"uuid": str(upload.track.uuid)}) + ".mp3" ) - assert url.endswith("/{}.mp3".format(upload.track.uuid)) + assert url.endswith(f"/{upload.track.uuid}.mp3") response = logged_in_api_client.get(url) assert response.status_code == 200 @@ -978,7 +978,7 @@ def test_can_get_libraries_for_music_entities( library=channel.library, playable=True, track=upload.track ) - url = reverse("api:v1:{}s-libraries".format(entity), kwargs={"pk": data[entity].pk}) + url = reverse(f"api:v1:{entity}s-libraries", kwargs={"pk": data[entity].pk}) response = api_client.get(url) expected = federation_api_serializers.LibrarySerializer(library).data @@ -1026,8 +1026,8 @@ def test_oembed_track(factories, no_api_auth, api_client, settings): settings.FUNKWHALE_EMBED_URL = "http://embed" track = factories["music.Track"](album__with_cover=True) url = reverse("api:v1:oembed") - track_url = "https://test.com/library/tracks/{}".format(track.pk) - iframe_src = "http://embed?type=track&id={}".format(track.pk) + track_url = f"https://test.com/library/tracks/{track.pk}" + iframe_src = f"http://embed?type=track&id={track.pk}" expected = { "version": "1.0", "type": "rich", @@ -1035,7 +1035,7 @@ def test_oembed_track(factories, no_api_auth, api_client, settings): "provider_url": settings.FUNKWHALE_URL, "height": 150, "width": 600, - "title": "{} by {}".format(track.title, track.artist.name), + "title": f"{track.title} by {track.artist.name}", "description": track.full_name, "thumbnail_url": federation_utils.full_url( track.album.attachment_cover.file.crop["200x200"].url @@ -1062,8 +1062,8 @@ def test_oembed_album(factories, no_api_auth, api_client, settings): track = factories["music.Track"](album__with_cover=True) album = track.album url = reverse("api:v1:oembed") - album_url = "https://test.com/library/albums/{}".format(album.pk) - iframe_src = "http://embed?type=album&id={}".format(album.pk) + album_url = f"https://test.com/library/albums/{album.pk}" + iframe_src = f"http://embed?type=album&id={album.pk}" expected = { "version": "1.0", "type": "rich", @@ -1071,8 +1071,8 @@ def test_oembed_album(factories, no_api_auth, api_client, settings): "provider_url": settings.FUNKWHALE_URL, "height": 400, "width": 600, - "title": "{} by {}".format(album.title, album.artist.name), - "description": "{} by {}".format(album.title, album.artist.name), + "title": f"{album.title} by {album.artist.name}", + "description": f"{album.title} by {album.artist.name}", "thumbnail_url": federation_utils.full_url( album.attachment_cover.file.crop["200x200"].url ), @@ -1099,8 +1099,8 @@ def test_oembed_artist(factories, no_api_auth, api_client, settings): album = track.album artist = track.artist url = reverse("api:v1:oembed") - artist_url = "https://test.com/library/artists/{}".format(artist.pk) - iframe_src = "http://embed?type=artist&id={}".format(artist.pk) + artist_url = f"https://test.com/library/artists/{artist.pk}" + iframe_src = f"http://embed?type=artist&id={artist.pk}" expected = { "version": "1.0", "type": "rich", @@ -1138,8 +1138,8 @@ def test_oembed_playlist(factories, no_api_auth, api_client, settings): ).track playlist.insert_many([track]) url = reverse("api:v1:oembed") - playlist_url = "https://test.com/library/playlists/{}".format(playlist.pk) - iframe_src = "http://embed?type=playlist&id={}".format(playlist.pk) + playlist_url = f"https://test.com/library/playlists/{playlist.pk}" + iframe_src = f"http://embed?type=playlist&id={playlist.pk}" expected = { "version": "1.0", "type": "rich", diff --git a/api/tests/subsonic/test_serializers.py b/api/tests/subsonic/test_serializers.py index 183599e53..bb419e61d 100644 --- a/api/tests/subsonic/test_serializers.py +++ b/api/tests/subsonic/test_serializers.py @@ -89,13 +89,13 @@ def test_get_artists_serializer(factories): "id": artist1.pk, "name": artist1.name, "albumCount": 3, - "coverArt": "ar-{}".format(artist1.id), + "coverArt": f"ar-{artist1.id}", }, { "id": artist2.pk, "name": artist2.name, "albumCount": 2, - "coverArt": "ar-{}".format(artist2.id), + "coverArt": f"ar-{artist2.id}", }, ], }, @@ -106,7 +106,7 @@ def test_get_artists_serializer(factories): "id": artist3.pk, "name": artist3.name, "albumCount": 0, - "coverArt": "ar-{}".format(artist3.id), + "coverArt": f"ar-{artist3.id}", } ], }, @@ -129,11 +129,11 @@ def test_get_artist_serializer(factories): "id": artist.pk, "name": artist.name, "albumCount": 1, - "coverArt": "ar-{}".format(artist.id), + "coverArt": f"ar-{artist.id}", "album": [ { "id": album.pk, - "coverArt": "al-{}".format(album.id), + "coverArt": f"al-{album.id}", "artistId": artist.pk, "name": album.title, "artist": artist.name, @@ -159,7 +159,7 @@ def test_get_artist_serializer(factories): def test_get_track_data_content_type(mimetype, extension, expected, factories): upload = factories["music.Upload"]() upload.mimetype = mimetype - upload.audio_file = "test.{}".format(extension) + upload.audio_file = f"test.{extension}" data = serializers.get_track_data( album=upload.track.album, track=upload.track, upload=upload @@ -182,7 +182,7 @@ def test_get_album_serializer(factories): "songCount": 1, "created": serializers.to_subsonic_date(album.creation_date), "year": album.release_date.year, - "coverArt": "al-{}".format(album.id), + "coverArt": f"al-{album.id}", "genre": tagged_item.tag.name, "duration": 43, "playCount": album.tracks.aggregate(l=Count("listenings"))["l"] or 0, @@ -191,7 +191,7 @@ def test_get_album_serializer(factories): "id": track.pk, "isDir": "false", "title": track.title, - "coverArt": "al-{}".format(album.id), + "coverArt": f"al-{album.id}", "album": album.title, "artist": artist.name, "track": track.position, @@ -308,7 +308,7 @@ def test_channel_serializer(factories): "url": channel.rss_url, "title": channel.artist.name, "description": description.as_plain_text, - "coverArt": "at-{}".format(channel.artist.attachment_cover.uuid), + "coverArt": f"at-{channel.artist.attachment_cover.uuid}", "originalImageUrl": channel.artist.attachment_cover.url, "status": "completed", "episode": [serializers.get_channel_episode_data(upload, channel.uuid)], @@ -333,7 +333,7 @@ def test_channel_episode_serializer(factories): "streamId": upload.track.id, "title": track.title, "description": description.as_plain_text, - "coverArt": "at-{}".format(track.attachment_cover.uuid), + "coverArt": f"at-{track.attachment_cover.uuid}", "isDir": "false", "year": track.creation_date.year, "created": track.creation_date.isoformat(), diff --git a/api/tests/subsonic/test_views.py b/api/tests/subsonic/test_views.py index ca969ba7f..f11f863fa 100644 --- a/api/tests/subsonic/test_views.py +++ b/api/tests/subsonic/test_views.py @@ -775,7 +775,7 @@ def test_get_cover_art_album(factories, logged_in_api_client): url = reverse("api:subsonic:subsonic-get_cover_art") assert url.endswith("getCoverArt") is True album = factories["music.Album"](with_cover=True) - response = logged_in_api_client.get(url, {"id": "al-{}".format(album.pk)}) + response = logged_in_api_client.get(url, {"id": f"al-{album.pk}"}) assert response.status_code == 200 assert response["Content-Type"] == "" @@ -788,7 +788,7 @@ def test_get_cover_art_attachment(factories, logged_in_api_client): attachment = factories["common.Attachment"]() url = reverse("api:subsonic:subsonic-get_cover_art") assert url.endswith("getCoverArt") is True - response = logged_in_api_client.get(url, {"id": "at-{}".format(attachment.uuid)}) + response = logged_in_api_client.get(url, {"id": f"at-{attachment.uuid}"}) assert response.status_code == 200 assert response["Content-Type"] == "" diff --git a/api/tests/test_import_audio_file.py b/api/tests/test_import_audio_file.py index 87fdd4cf6..398b7aaa1 100644 --- a/api/tests/test_import_audio_file.py +++ b/api/tests/test_import_audio_file.py @@ -52,9 +52,9 @@ def test_import_files_stores_proper_data(factories, mocker, now, path): "import_files", str(library.uuid), path, async_=False, interactive=False ) upload = library.uploads.last() - assert upload.import_reference == "cli-{}".format(now.isoformat()) + assert upload.import_reference == f"cli-{now.isoformat()}" assert upload.import_status == "pending" - assert upload.source == "file://{}".format(path) + assert upload.source == f"file://{path}" assert upload.import_metadata == { "funkwhale": { "config": {"replace": False, "dispatch_outbox": False, "broadcast": False} @@ -131,7 +131,7 @@ def test_import_files_skip_if_path_already_imported(factories, mocker): # existing one with same source factories["music.Upload"]( - library=library, import_status="finished", source="file://{}".format(path) + library=library, import_status="finished", source=f"file://{path}" ) call_command( @@ -165,7 +165,7 @@ def test_storage_rename_utf_8_files(factories): @pytest.mark.parametrize("name", ["modified", "moved", "created", "deleted"]) def test_handle_event(name, mocker): - handler = mocker.patch.object(import_files, "handle_{}".format(name)) + handler = mocker.patch.object(import_files, f"handle_{name}") event = {"type": name} stdout = mocker.Mock() @@ -374,5 +374,5 @@ def test_import_files(factories, capsys): imported = library.uploads.filter(import_status="finished").count() assert imported > 0 - assert "Successfully imported {} new tracks".format(imported) in captured.out + assert f"Successfully imported {imported} new tracks" in captured.out assert "For details, please refer to import reference" in captured.out diff --git a/api/tests/users/oauth/test_views.py b/api/tests/users/oauth/test_views.py index 81a87e1ce..fa81054cb 100644 --- a/api/tests/users/oauth/test_views.py +++ b/api/tests/users/oauth/test_views.py @@ -327,7 +327,7 @@ def test_token_view_post(api_client, factories): # Now check we can use the token for auth response = api_client.get( - reverse("api:v1:users:users-me"), HTTP_AUTHORIZATION="Bearer {}".format(token) + reverse("api:v1:users:users-me"), HTTP_AUTHORIZATION=f"Bearer {token}" ) assert response.status_code == 200 @@ -434,7 +434,7 @@ def test_token_auth( settings.ACCOUNT_EMAIL_VERIFICATION = setting_value response = api_client.get( reverse("api:v1:users:users-me"), - HTTP_AUTHORIZATION="Bearer {}".format(token.token), + HTTP_AUTHORIZATION=f"Bearer {token.token}", ) assert response.status_code == expected_status_code diff --git a/api/tests/users/test_models.py b/api/tests/users/test_models.py index 367b05b57..ef4244597 100644 --- a/api/tests/users/test_models.py +++ b/api/tests/users/test_models.py @@ -179,8 +179,8 @@ def test_get_channels_groups(factories): user = factories["users.User"](permission_library=True) assert user.get_channels_groups() == [ - "user.{}.imports".format(user.pk), - "user.{}.inbox".format(user.pk), + f"user.{user.pk}.imports", + f"user.{user.pk}.inbox", "admin.library", ] diff --git a/api/tests/utils.py b/api/tests/utils.py index bed666a67..c1b476a61 100644 --- a/api/tests/utils.py +++ b/api/tests/utils.py @@ -10,4 +10,4 @@ def to_api_date(value): if isinstance(value, datetime.date): f = rest_fields.DateField() return f.to_representation(value) - raise ValueError("Invalid value: {}".format(value)) + raise ValueError(f"Invalid value: {value}") diff --git a/docs/conf.py b/docs/conf.py index 1dfbff8f3..095e5042d 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- # # funkwhale documentation build configuration file, created by # sphinx-quickstart on Sun Jun 25 18:49:23 2017. @@ -85,7 +84,7 @@ myst_heading_anchors = 3 # General information about the project. year = datetime.datetime.now().year project = "funkwhale" -copyright = "{}, The Funkwhale Collective".format(year) +copyright = f"{year}, The Funkwhale Collective" author = "The Funkwhale Collective" # The version info for the project you're documenting, acts as replacement for @@ -214,7 +213,7 @@ texinfo_documents = [ # Define list of redirect files to be build in the Sphinx build process redirect_list = [] -with open("redirects.txt", "r") as fp: +with open("redirects.txt") as fp: data_list = [tuple(line.strip().split(",")) for line in fp] # Generate redirect template diff --git a/front/scripts/contextualize.py b/front/scripts/contextualize.py index af1640299..b94d844c3 100755 --- a/front/scripts/contextualize.py +++ b/front/scripts/contextualize.py @@ -57,7 +57,7 @@ def contextualize(old_po, new_po, edit=False): ) matches = match(missing, old) found = [m for m in matches if m[1] is not None] - print("Found {} matching entries".format(len(found))) + print(f"Found {len(found)} matching entries") if edit: print("Applying changes") for matched, matching in found: diff --git a/front/scripts/fix-fomantic-css.py b/front/scripts/fix-fomantic-css.py index 4ea40f1b4..4e0a2e40a 100755 --- a/front/scripts/fix-fomantic-css.py +++ b/front/scripts/fix-fomantic-css.py @@ -866,8 +866,8 @@ def set_vars(component_name, rules): replacements = conf[m] for line in rule["lines"]: for property, new_value in replacements: - if line.strip().startswith("{}:".format(property)): - new_property = "{}: {};".format(property, new_value) + if line.strip().startswith(f"{property}:"): + new_property = f"{property}: {new_value};" indentation = " " * (len(line) - len(line.lstrip(" "))) line = indentation + new_property break @@ -944,7 +944,7 @@ def iter_components(dir): def replace_vars(source, dest): components = list(sorted(iter_components(os.path.join(source, "components")))) for c in components: - with open(c, "r") as f: + with open(c) as f: text = f.read() for s, r in GLOBAL_REPLACES: @@ -955,7 +955,7 @@ def replace_vars(source, dest): name = c.split("/")[-1].split(".")[0] updated_rules = set_vars(name, rules) text = serialize_rules(updated_rules) - with open(os.path.join(dest, "{}.css".format(name)), "w") as f: + with open(os.path.join(dest, f"{name}.css"), "w") as f: f.write(text) diff --git a/front/scripts/print-duplicates-source.py b/front/scripts/print-duplicates-source.py index 036187ba8..8d8d28d13 100755 --- a/front/scripts/print-duplicates-source.py +++ b/front/scripts/print-duplicates-source.py @@ -15,13 +15,13 @@ def print_duplicates(path): count = collections.Counter([e.msgid for e in pofile]) duplicates = [(k, v) for k, v in count.items() if v > 1] for k, v in sorted(duplicates, key=lambda r: r[1], reverse=True): - print("{} entries - {}:".format(v, k)) + print(f"{v} entries - {k}:") for ctx in contexts_by_id[k]: - print(" - {}".format(ctx)) + print(f" - {ctx}") print() total_duplicates = sum([v - 1 for _, v in duplicates]) - print("{} total duplicates".format(total_duplicates)) + print(f"{total_duplicates} total duplicates") if __name__ == "__main__": diff --git a/scripts/clean-unused-artifacts.py b/scripts/clean-unused-artifacts.py index ff3f63bc7..fce68193b 100755 --- a/scripts/clean-unused-artifacts.py +++ b/scripts/clean-unused-artifacts.py @@ -28,5 +28,5 @@ for job in jobs: "name": job.attributes["name"], "created_at": job.attributes["created_at"], } - print("Deleting job {}!".format(job.id), relevant) + print(f"Deleting job {job.id}!", relevant) job.erase() diff --git a/scripts/is-docker-latest.py b/scripts/is-docker-latest.py index f2f266e33..f95e12bac 100755 --- a/scripts/is-docker-latest.py +++ b/scripts/is-docker-latest.py @@ -10,7 +10,7 @@ def main(current, releases_json): try: version = StrictVersion(current) except ValueError: - print("Version number '{}' isn't valid".format(current)) + print(f"Version number '{current}' isn't valid") sys.exit(1) releases = json.loads(releases_json) @@ -23,7 +23,7 @@ def main(current, releases_json): ) ) sys.exit(1) - print("Version number '{}' is latest release!".format(current)) + print(f"Version number '{current}' is latest release!") if __name__ == "__main__":