diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml index 2a81eaa3e..1b14149f2 100644 --- a/.github/workflows/pylint.yml +++ b/.github/workflows/pylint.yml @@ -24,5 +24,5 @@ jobs: pip install pylint - name: Analysing the code with pylint run: | - pylint bookwyrm/ --ignore=migrations,tests --disable=E1101,E1135,E1136,R0903,R0901,R0902,W0707,W0511,W0406,R0401,R0801,C0209 + pylint bookwyrm/ --ignore=migrations,tests --disable=E1101,E1135,E1136,R0903,R0901,R0902,W0707,W0511,W0406,R0401,R0801 diff --git a/bookwyrm/connectors/abstract_connector.py b/bookwyrm/connectors/abstract_connector.py index ffacffdf0..902ccd6c4 100644 --- a/bookwyrm/connectors/abstract_connector.py +++ b/bookwyrm/connectors/abstract_connector.py @@ -43,7 +43,7 @@ class AbstractMinimalConnector(ABC): params["min_confidence"] = min_confidence data = self.get_search_data( - "%s%s" % (self.search_url, query), + f"{self.search_url}{query}", params=params, timeout=timeout, ) @@ -57,7 +57,7 @@ class AbstractMinimalConnector(ABC): """isbn search""" params = {} data = self.get_search_data( - "%s%s" % (self.isbn_search_url, query), + f"{self.isbn_search_url}{query}", params=params, ) results = [] @@ -131,7 +131,7 @@ class AbstractConnector(AbstractMinimalConnector): work_data = data if not work_data or not edition_data: - raise ConnectorException("Unable to load book data: %s" % remote_id) + raise ConnectorException(f"Unable to load book data: {remote_id}") with transaction.atomic(): # create activitypub object @@ -223,7 +223,7 @@ def get_data(url, params=None, timeout=10): # check if the url is blocked if models.FederatedServer.is_blocked(url): raise ConnectorException( - "Attempting to load data from blocked url: {:s}".format(url) + f"Attempting to load data from blocked url: {url}" ) try: @@ -283,6 +283,7 @@ class SearchResult: confidence: int = 1 def __repr__(self): + # pylint: disable=consider-using-f-string return "".format( self.key, self.title, self.author ) diff --git a/bookwyrm/connectors/connector_manager.py b/bookwyrm/connectors/connector_manager.py index 1d9588d6b..b676e9aa5 100644 --- a/bookwyrm/connectors/connector_manager.py +++ b/bookwyrm/connectors/connector_manager.py @@ -109,10 +109,10 @@ def get_or_create_connector(remote_id): connector_info = models.Connector.objects.create( identifier=identifier, connector_file="bookwyrm_connector", - base_url="https://%s" % identifier, - books_url="https://%s/book" % identifier, - covers_url="https://%s/images/covers" % identifier, - search_url="https://%s/search?q=" % identifier, + base_url=f"https://{identifier}", + books_url=f"https://{identifier}/book", + covers_url=f"https://{identifier}/images/covers", + search_url=f"https://{identifier}/search?q=", priority=2, ) @@ -131,7 +131,7 @@ def load_more_data(connector_id, book_id): def load_connector(connector_info): """instantiate the connector class""" connector = importlib.import_module( - "bookwyrm.connectors.%s" % connector_info.connector_file + f"bookwyrm.connectors.{connector_info.connector_file}" ) return connector.Connector(connector_info.identifier) @@ -141,4 +141,4 @@ def load_connector(connector_info): def create_connector(sender, instance, created, *args, **kwargs): """create a connector to an external bookwyrm server""" if instance.application_type == "bookwyrm": - get_or_create_connector("https://{:s}".format(instance.server_name)) + get_or_create_connector(f"https://{instance.server_name}") diff --git a/bookwyrm/connectors/inventaire.py b/bookwyrm/connectors/inventaire.py index d2a7b9faa..b23a7d527 100644 --- a/bookwyrm/connectors/inventaire.py +++ b/bookwyrm/connectors/inventaire.py @@ -59,7 +59,7 @@ class Connector(AbstractConnector): def get_remote_id(self, value): """convert an id/uri into a url""" - return "{:s}?action=by-uris&uris={:s}".format(self.books_url, value) + return f"{self.books_url}?action=by-uris&uris={value}" def get_book_data(self, remote_id): data = get_data(remote_id) @@ -88,7 +88,7 @@ class Connector(AbstractConnector): def format_search_result(self, search_result): images = search_result.get("image") cover = ( - "{:s}/img/entities/{:s}".format(self.covers_url, images[0]) + f"{self.covers_url}/img/entities/{images[0]}" if images else None ) @@ -99,9 +99,7 @@ class Connector(AbstractConnector): title=search_result.get("label"), key=self.get_remote_id(search_result.get("uri")), author=search_result.get("description"), - view_link="{:s}/entity/{:s}".format( - self.base_url, search_result.get("uri") - ), + view_link=f"{self.base_url}/entity/{search_result.get('uri')}", cover=cover, confidence=confidence, connector=self, @@ -123,9 +121,7 @@ class Connector(AbstractConnector): title=title[0], key=self.get_remote_id(search_result.get("uri")), author=search_result.get("description"), - view_link="{:s}/entity/{:s}".format( - self.base_url, search_result.get("uri") - ), + view_link=f"{self.base_url}/entity/{search_result.get('uri')}", cover=self.get_cover_url(search_result.get("image")), connector=self, ) @@ -136,9 +132,7 @@ class Connector(AbstractConnector): def load_edition_data(self, work_uri): """get a list of editions for a work""" url = ( - "{:s}?action=reverse-claims&property=wdt:P629&value={:s}&sort=true".format( - self.books_url, work_uri - ) + f"{self.books_url}?action=reverse-claims&property=wdt:P629&value={work_uri}&sort=true" ) return get_data(url) @@ -195,7 +189,7 @@ class Connector(AbstractConnector): # cover may or may not be an absolute url already if re.match(r"^http", cover_id): return cover_id - return "%s%s" % (self.covers_url, cover_id) + return f"{self.covers_url}{cover_id}" def resolve_keys(self, keys): """cool, it's "wd:Q3156592" now what the heck does that mean""" @@ -213,9 +207,7 @@ class Connector(AbstractConnector): link = links.get("enwiki") if not link: return "" - url = "{:s}/api/data?action=wp-extract&lang=en&title={:s}".format( - self.base_url, link - ) + url = f"{self.base_url}/api/data?action=wp-extract&lang=en&title={link}" try: data = get_data(url) except ConnectorException: diff --git a/bookwyrm/connectors/openlibrary.py b/bookwyrm/connectors/openlibrary.py index e58749c13..fca5d0f71 100644 --- a/bookwyrm/connectors/openlibrary.py +++ b/bookwyrm/connectors/openlibrary.py @@ -71,7 +71,7 @@ class Connector(AbstractConnector): key = data["key"] except KeyError: raise ConnectorException("Invalid book data") - return "%s%s" % (self.books_url, key) + return f"{self.books_url}{key}" def is_work_data(self, data): return bool(re.match(r"^[\/\w]+OL\d+W$", data["key"])) @@ -81,7 +81,7 @@ class Connector(AbstractConnector): key = data["key"] except KeyError: raise ConnectorException("Invalid book data") - url = "%s%s/editions" % (self.books_url, key) + url = f"{self.books_url}{key}/editions" data = self.get_book_data(url) edition = pick_default_edition(data["entries"]) if not edition: @@ -93,7 +93,7 @@ class Connector(AbstractConnector): key = data["works"][0]["key"] except (IndexError, KeyError): raise ConnectorException("No work found for edition") - url = "%s%s" % (self.books_url, key) + url = f"{self.books_url}{key}" return self.get_book_data(url) def get_authors_from_data(self, data): @@ -102,7 +102,7 @@ class Connector(AbstractConnector): author_blob = author_blob.get("author", author_blob) # this id is "/authors/OL1234567A" author_id = author_blob["key"] - url = "%s%s" % (self.base_url, author_id) + url = f"{self.base_url}{author_id}" author = self.get_or_create_author(url) if not author: continue @@ -113,8 +113,8 @@ class Connector(AbstractConnector): if not cover_blob: return None cover_id = cover_blob[0] - image_name = "%s-%s.jpg" % (cover_id, size) - return "%s/b/id/%s" % (self.covers_url, image_name) + image_name = f"{cover_id}-{size}.jpg" + return f"{self.covers_url}/b/id/{image_name}" def parse_search_data(self, data): return data.get("docs") @@ -152,7 +152,7 @@ class Connector(AbstractConnector): def load_edition_data(self, olkey): """query openlibrary for editions of a work""" - url = "%s/works/%s/editions" % (self.books_url, olkey) + url = f"{self.books_url}/works/{olkey}/editions" return self.get_book_data(url) def expand_book_data(self, book): diff --git a/bookwyrm/connectors/self_connector.py b/bookwyrm/connectors/self_connector.py index 8d5a7614e..cdb586cb3 100644 --- a/bookwyrm/connectors/self_connector.py +++ b/bookwyrm/connectors/self_connector.py @@ -71,7 +71,7 @@ class Connector(AbstractConnector): def format_search_result(self, search_result): cover = None if search_result.cover: - cover = "%s%s" % (self.covers_url, search_result.cover) + cover = f"{self.covers_url}{search_result.cover}" return SearchResult( title=search_result.title, diff --git a/bookwyrm/importers/importer.py b/bookwyrm/importers/importer.py index caa137ecb..a10b4060c 100644 --- a/bookwyrm/importers/importer.py +++ b/bookwyrm/importers/importer.py @@ -127,6 +127,7 @@ def handle_imported_book(source, user, item, include_reviews, privacy): # but "now" is a bad guess published_date_guess = item.date_read or item.date_added if item.review: + # pylint: disable=consider-using-f-string review_title = ( "Review of {!r} on {!r}".format( item.book.title, diff --git a/bookwyrm/models/activitypub_mixin.py b/bookwyrm/models/activitypub_mixin.py index ed51158bc..3a88c5249 100644 --- a/bookwyrm/models/activitypub_mixin.py +++ b/bookwyrm/models/activitypub_mixin.py @@ -266,7 +266,7 @@ class ObjectMixin(ActivitypubMixin): signed_message = signer.sign(SHA256.new(content.encode("utf8"))) signature = activitypub.Signature( - creator="%s#main-key" % user.remote_id, + creator=f"{user.remote_id}#main-key", created=activity_object.published, signatureValue=b64encode(signed_message).decode("utf8"), ) @@ -285,16 +285,16 @@ class ObjectMixin(ActivitypubMixin): return activitypub.Delete( id=self.remote_id + "/activity", actor=user.remote_id, - to=["%s/followers" % user.remote_id], + to=[f"{user.remote_id}/followers"], cc=["https://www.w3.org/ns/activitystreams#Public"], object=self, ).serialize() def to_update_activity(self, user): """wrapper for Updates to an activity""" - activity_id = "%s#update/%s" % (self.remote_id, uuid4()) + uuid = uuid4() return activitypub.Update( - id=activity_id, + id=f"{self.remote_id}#update/{uuid}", actor=user.remote_id, to=["https://www.w3.org/ns/activitystreams#Public"], object=self, @@ -337,8 +337,8 @@ class OrderedCollectionPageMixin(ObjectMixin): paginated = Paginator(queryset, PAGE_LENGTH) # add computed fields specific to orderd collections activity["totalItems"] = paginated.count - activity["first"] = "%s?page=1" % remote_id - activity["last"] = "%s?page=%d" % (remote_id, paginated.num_pages) + activity["first"] = f"{remote_id}?page=1" + activity["last"] = f"{remote_id}?page={paginated.num_pages}" return serializer(**activity) @@ -420,7 +420,7 @@ class CollectionItemMixin(ActivitypubMixin): """AP for shelving a book""" collection_field = getattr(self, self.collection_field) return activitypub.Add( - id="{:s}#add".format(collection_field.remote_id), + id=f"{collection_field.remote_id}#add", actor=user.remote_id, object=self.to_activity_dataclass(), target=collection_field.remote_id, @@ -430,7 +430,7 @@ class CollectionItemMixin(ActivitypubMixin): """AP for un-shelving a book""" collection_field = getattr(self, self.collection_field) return activitypub.Remove( - id="{:s}#remove".format(collection_field.remote_id), + id=f"{collection_field.remote_id}#remove", actor=user.remote_id, object=self.to_activity_dataclass(), target=collection_field.remote_id, @@ -458,7 +458,7 @@ class ActivityMixin(ActivitypubMixin): """undo an action""" user = self.user if hasattr(self, "user") else self.user_subject return activitypub.Undo( - id="%s#undo" % self.remote_id, + id=f"{self.remote_id}#undo", actor=user.remote_id, object=self, ).serialize() @@ -555,11 +555,11 @@ def to_ordered_collection_page( prev_page = next_page = None if activity_page.has_next(): - next_page = "%s?page=%d" % (remote_id, activity_page.next_page_number()) + next_page = f"{remote_id}?page={activity_page.next_page_number()}" if activity_page.has_previous(): - prev_page = "%s?page=%d" % (remote_id, activity_page.previous_page_number()) + prev_page = f"{remote_id}?page=%d{activity_page.previous_page_number()}" return activitypub.OrderedCollectionPage( - id="%s?page=%s" % (remote_id, page), + id=f"{remote_id}?page={page}", partOf=remote_id, orderedItems=items, next=next_page, diff --git a/bookwyrm/models/author.py b/bookwyrm/models/author.py index 6da80b176..53cf94ff4 100644 --- a/bookwyrm/models/author.py +++ b/bookwyrm/models/author.py @@ -35,7 +35,7 @@ class Author(BookDataModel): def get_remote_id(self): """editions and works both use "book" instead of model_name""" - return "https://%s/author/%s" % (DOMAIN, self.id) + return f"https://{DOMAIN}/author/{self.id}" activity_serializer = activitypub.Author diff --git a/bookwyrm/models/base_model.py b/bookwyrm/models/base_model.py index 0ac2061a9..aa174a143 100644 --- a/bookwyrm/models/base_model.py +++ b/bookwyrm/models/base_model.py @@ -32,11 +32,11 @@ class BookWyrmModel(models.Model): def get_remote_id(self): """generate a url that resolves to the local object""" - base_path = "https://%s" % DOMAIN + base_path = f"https://{DOMAIN}" if hasattr(self, "user"): - base_path = "%s%s" % (base_path, self.user.local_path) + base_path = f"{base_path}{self.user.local_path}" model_name = type(self).__name__.lower() - return "%s/%s/%d" % (base_path, model_name, self.id) + return f"{base_path}/{model_name}/{self.id}" class Meta: """this is just here to provide default fields for other models""" @@ -46,7 +46,7 @@ class BookWyrmModel(models.Model): @property def local_path(self): """how to link to this object in the local app""" - return self.get_remote_id().replace("https://%s" % DOMAIN, "") + return self.get_remote_id().replace(f"https://{DOMAIN}", "") def visible_to_user(self, viewer): """is a user authorized to view an object?""" diff --git a/bookwyrm/models/book.py b/bookwyrm/models/book.py index ec1c14ec0..ac7c42f62 100644 --- a/bookwyrm/models/book.py +++ b/bookwyrm/models/book.py @@ -164,9 +164,9 @@ class Book(BookDataModel): @property def alt_text(self): """image alt test""" - text = "%s" % self.title + text = self.title if self.edition_info: - text += " (%s)" % self.edition_info + text += f" ({self.edition_info})" return text def save(self, *args, **kwargs): @@ -177,9 +177,10 @@ class Book(BookDataModel): def get_remote_id(self): """editions and works both use "book" instead of model_name""" - return "https://%s/book/%d" % (DOMAIN, self.id) + return f"https://{DOMAIN}/book/{self.id}" def __repr__(self): + # pylint: disable=consider-using-f-string return "<{} key={!r} title={!r}>".format( self.__class__, self.openlibrary_key, @@ -216,7 +217,7 @@ class Work(OrderedCollectionPageMixin, Book): """an ordered collection of editions""" return self.to_ordered_collection( self.editions.order_by("-edition_rank").all(), - remote_id="%s/editions" % self.remote_id, + remote_id=f"{self.remote_id}/editions", **kwargs, ) diff --git a/bookwyrm/models/connector.py b/bookwyrm/models/connector.py index 17ba31489..9d2c6aeb3 100644 --- a/bookwyrm/models/connector.py +++ b/bookwyrm/models/connector.py @@ -29,7 +29,4 @@ class Connector(BookWyrmModel): isbn_search_url = models.CharField(max_length=255, null=True, blank=True) def __str__(self): - return "{} ({})".format( - self.identifier, - self.id, - ) + return f"{self.identifier} ({self.id})" diff --git a/bookwyrm/models/fields.py b/bookwyrm/models/fields.py index cc5a7bb55..8555e06fd 100644 --- a/bookwyrm/models/fields.py +++ b/bookwyrm/models/fields.py @@ -308,7 +308,7 @@ class ManyToManyField(ActivitypubFieldMixin, models.ManyToManyField): def field_to_activity(self, value): if self.link_only: - return "%s/%s" % (value.instance.remote_id, self.name) + return f"{value.instance.remote_id}/{self.name}" return [i.remote_id for i in value.all()] def field_from_activity(self, value): @@ -388,7 +388,7 @@ def image_serializer(value, alt): else: return None if not url[:4] == "http": - url = "https://{:s}{:s}".format(DOMAIN, url) + url = f"https://{DOMAIN}{url}" return activitypub.Document(url=url, name=alt) @@ -448,7 +448,7 @@ class ImageField(ActivitypubFieldMixin, models.ImageField): image_content = ContentFile(response.content) extension = imghdr.what(None, image_content.read()) or "" - image_name = "{:s}.{:s}".format(str(uuid4()), extension) + image_name = f"{uuid4()}.{extension}" return [image_name, image_content] def formfield(self, **kwargs): diff --git a/bookwyrm/models/import_job.py b/bookwyrm/models/import_job.py index 7d8ce9e30..4f495f14f 100644 --- a/bookwyrm/models/import_job.py +++ b/bookwyrm/models/import_job.py @@ -198,7 +198,9 @@ class ImportItem(models.Model): return [] def __repr__(self): + # pylint: disable=consider-using-f-string return "<{!r}Item {!r}>".format(self.data["import_source"], self.data["Title"]) def __str__(self): + # pylint: disable=consider-using-f-string return "{} by {}".format(self.data["Title"], self.data["Author"]) diff --git a/bookwyrm/models/list.py b/bookwyrm/models/list.py index bbad5ba9b..49fb53757 100644 --- a/bookwyrm/models/list.py +++ b/bookwyrm/models/list.py @@ -42,7 +42,7 @@ class List(OrderedCollectionMixin, BookWyrmModel): def get_remote_id(self): """don't want the user to be in there in this case""" - return "https://%s/list/%d" % (DOMAIN, self.id) + return f"https://{DOMAIN}/list/{self.id}" @property def collection_queryset(self): diff --git a/bookwyrm/models/relationship.py b/bookwyrm/models/relationship.py index edb89d13c..fc7a9df83 100644 --- a/bookwyrm/models/relationship.py +++ b/bookwyrm/models/relationship.py @@ -53,7 +53,7 @@ class UserRelationship(BookWyrmModel): def get_remote_id(self): """use shelf identifier in remote_id""" base_path = self.user_subject.remote_id - return "%s#follows/%d" % (base_path, self.id) + return f"{base_path}#follows/{self.id}" class UserFollows(ActivityMixin, UserRelationship): @@ -144,7 +144,8 @@ class UserFollowRequest(ActivitypubMixin, UserRelationship): """get id for sending an accept or reject of a local user""" base_path = self.user_object.remote_id - return "%s#%s/%d" % (base_path, status, self.id or 0) + status_id = self.id or 0 + return f"{base_path}#{status}/{status_id}" def accept(self, broadcast_only=False): """turn this request into the real deal""" diff --git a/bookwyrm/models/shelf.py b/bookwyrm/models/shelf.py index c4e907d27..6f1344022 100644 --- a/bookwyrm/models/shelf.py +++ b/bookwyrm/models/shelf.py @@ -44,7 +44,7 @@ class Shelf(OrderedCollectionMixin, BookWyrmModel): def get_identifier(self): """custom-shelf-123 for the url""" slug = re.sub(r"[^\w]", "", self.name).lower() - return "{:s}-{:d}".format(slug, self.id) + return f"{slug}-{self.id}" @property def collection_queryset(self): @@ -55,7 +55,7 @@ class Shelf(OrderedCollectionMixin, BookWyrmModel): """shelf identifier instead of id""" base_path = self.user.remote_id identifier = self.identifier or self.get_identifier() - return "%s/books/%s" % (base_path, identifier) + return f"{base_path}/books/{identifier}" class Meta: """user/shelf unqiueness""" diff --git a/bookwyrm/models/site.py b/bookwyrm/models/site.py index ee69a507f..03d6f5fe2 100644 --- a/bookwyrm/models/site.py +++ b/bookwyrm/models/site.py @@ -81,7 +81,7 @@ class SiteInvite(models.Model): @property def link(self): """formats the invite link""" - return "https://{}/invite/{}".format(DOMAIN, self.code) + return f"https://{DOMAIN}/invite/{self.code}" class InviteRequest(BookWyrmModel): @@ -121,7 +121,7 @@ class PasswordReset(models.Model): @property def link(self): """formats the invite link""" - return "https://{}/password-reset/{}".format(DOMAIN, self.code) + return "https://{DOMAIN}/password-reset/{self.code}" # pylint: disable=unused-argument diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py index d0f094d22..0b6e49e2a 100644 --- a/bookwyrm/models/status.py +++ b/bookwyrm/models/status.py @@ -179,7 +179,7 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel): """helper function for loading AP serialized replies to a status""" return self.to_ordered_collection( self.replies(self), - remote_id="%s/replies" % self.remote_id, + remote_id=f"{self.remote_id}/replies", collection_only=True, **kwargs ).serialize() @@ -226,10 +226,10 @@ class GeneratedNote(Status): """indicate the book in question for mastodon (or w/e) users""" message = self.content books = ", ".join( - '"%s"' % (book.remote_id, book.title) + f'"{book.title}"' for book in self.mention_books.all() ) - return "%s %s %s" % (self.user.display_name, message, books) + return f"{self.user.display_name} {message} {books}" activity_serializer = activitypub.GeneratedNote pure_type = "Note" @@ -277,11 +277,7 @@ class Comment(BookStatus): @property def pure_content(self): """indicate the book in question for mastodon (or w/e) users""" - return '%s

(comment on "%s")

' % ( - self.content, - self.book.remote_id, - self.book.title, - ) + return f'{self.content}

(comment on "{self.book.title}")

' activity_serializer = activitypub.Comment @@ -306,12 +302,7 @@ class Quotation(BookStatus): """indicate the book in question for mastodon (or w/e) users""" quote = re.sub(r"^

", '

"', self.quote) quote = re.sub(r"

$", '"

', quote) - return '%s

-- "%s"

%s' % ( - quote, - self.book.remote_id, - self.book.title, - self.content, - ) + return f'{quote}

-- "{self.book.title}"

{self.content}' activity_serializer = activitypub.Quotation diff --git a/bookwyrm/templatetags/utilities.py b/bookwyrm/templatetags/utilities.py index fe83278ac..76b4cd3f6 100644 --- a/bookwyrm/templatetags/utilities.py +++ b/bookwyrm/templatetags/utilities.py @@ -12,7 +12,7 @@ register = template.Library() @register.filter(name="uuid") def get_uuid(identifier): """for avoiding clashing ids when there are many forms""" - return "%s%s" % (identifier, uuid4()) + return f"{identifier}{uuid4()}" @register.filter(name="username") @@ -50,7 +50,7 @@ def truncatepath(value, arg): length = int(arg) except ValueError: # invalid literal for int() return path_list[-1] # Fail silently. - return "%s/…%s" % (path_list[0], path_list[-1][-length:]) + return f"{path_list[0]}/…{path_list[-1][-length:]}" @register.simple_tag(takes_context=False) @@ -60,7 +60,7 @@ def get_book_cover_thumbnail(book, size="medium", ext="jpg"): if size == "": size = "medium" try: - cover_thumbnail = getattr(book, "cover_bw_book_%s_%s" % (size, ext)) + cover_thumbnail = getattr(book, f"cover_bw_book_{size}_{ext}") return cover_thumbnail.url except OSError: return static("images/no_cover.jpg") diff --git a/bookwyrm/utils/regex.py b/bookwyrm/utils/regex.py index 3ac5a0ffd..f0c442459 100644 --- a/bookwyrm/utils/regex.py +++ b/bookwyrm/utils/regex.py @@ -3,8 +3,8 @@ DOMAIN = r"[\w_\-\.]+\.[a-z]{2,}" LOCALNAME = r"@?[a-zA-Z_\-\.0-9]+" STRICT_LOCALNAME = r"@[a-zA-Z_\-\.0-9]+" -USERNAME = r"%s(@%s)?" % (LOCALNAME, DOMAIN) -STRICT_USERNAME = r"\B%s(@%s)?\b" % (STRICT_LOCALNAME, DOMAIN) -FULL_USERNAME = r"%s@%s\b" % (LOCALNAME, DOMAIN) +USERNAME = rf"{LOCALNAME}(@{DOMAIN})?" +STRICT_USERNAME = rf"\B{STRICT_LOCALNAME}(@{DOMAIN})?\b" +FULL_USERNAME = rf"{LOCALNAME}@{DOMAIN}\b" # should match (BookWyrm/1.0.0; or (BookWyrm/99.1.2; BOOKWYRM_USER_AGENT = r"\(BookWyrm/[0-9]+\.[0-9]+\.[0-9]+;" diff --git a/bookwyrm/views/author.py b/bookwyrm/views/author.py index e51dc7d83..e1e9247de 100644 --- a/bookwyrm/views/author.py +++ b/bookwyrm/views/author.py @@ -55,4 +55,4 @@ class EditAuthor(View): return TemplateResponse(request, "author/edit_author.html", data) author = form.save() - return redirect("/author/%s" % author.id) + return redirect(f"/author/{author.id}") diff --git a/bookwyrm/views/edit_user.py b/bookwyrm/views/edit_user.py index b97f27374..4026a5319 100644 --- a/bookwyrm/views/edit_user.py +++ b/bookwyrm/views/edit_user.py @@ -79,7 +79,7 @@ def save_user_form(form): # set the name to a hash extension = form.files["avatar"].name.split(".")[-1] - filename = "%s.%s" % (uuid4(), extension) + filename = f"{uuid4()}.{extension}" user.avatar.save(filename, image, save=False) user.save() return user diff --git a/bookwyrm/views/editions.py b/bookwyrm/views/editions.py index 7615c497c..d044f17cd 100644 --- a/bookwyrm/views/editions.py +++ b/bookwyrm/views/editions.py @@ -96,4 +96,4 @@ def switch_edition(request): readthrough.book = new_edition readthrough.save() - return redirect("/book/%d" % new_edition.id) + return redirect(f"/book/{new_edition.id}") diff --git a/bookwyrm/views/feed.py b/bookwyrm/views/feed.py index d17de8f96..98a1c836c 100644 --- a/bookwyrm/views/feed.py +++ b/bookwyrm/views/feed.py @@ -42,7 +42,7 @@ class Feed(View): "tab": tab, "streams": STREAMS, "goal_form": forms.GoalForm(), - "path": "/%s" % tab["key"], + "path": f"/{tab['key']}", }, } return TemplateResponse(request, "feed/feed.html", data) diff --git a/bookwyrm/views/follow.py b/bookwyrm/views/follow.py index c3336a94a..0710a70c5 100644 --- a/bookwyrm/views/follow.py +++ b/bookwyrm/views/follow.py @@ -86,4 +86,4 @@ def delete_follow_request(request): return HttpResponseBadRequest() follow_request.delete() - return redirect("/user/%s" % request.user.localname) + return redirect(f"/user/{request.user.localname}") diff --git a/bookwyrm/views/helpers.py b/bookwyrm/views/helpers.py index b1e5f68c7..e6db1487a 100644 --- a/bookwyrm/views/helpers.py +++ b/bookwyrm/views/helpers.py @@ -113,7 +113,7 @@ def handle_remote_webfinger(query): try: user = models.User.objects.get(username__iexact=query) except models.User.DoesNotExist: - url = "https://%s/.well-known/webfinger?resource=acct:%s" % (domain, query) + url = f"https://{domain}/.well-known/webfinger?resource=acct:{query}" try: data = get_data(url) except (ConnectorException, HTTPError): diff --git a/bookwyrm/views/import_data.py b/bookwyrm/views/import_data.py index 634940a07..2232e39c2 100644 --- a/bookwyrm/views/import_data.py +++ b/bookwyrm/views/import_data.py @@ -68,7 +68,7 @@ class Import(View): importer.start_import(job) - return redirect("/import/%d" % job.id) + return redirect(f"/import/{job.id}") return HttpResponseBadRequest() @@ -112,4 +112,4 @@ class ImportStatus(View): items, ) importer.start_import(job) - return redirect("/import/%d" % job.id) + return redirect(f"/import/{job.id}") diff --git a/bookwyrm/views/inbox.py b/bookwyrm/views/inbox.py index e255b4fa2..ff01cfb2f 100644 --- a/bookwyrm/views/inbox.py +++ b/bookwyrm/views/inbox.py @@ -71,7 +71,7 @@ def is_blocked_user_agent(request): user_agent = request.headers.get("User-Agent") if not user_agent: return False - url = re.search(r"https?://{:s}/?".format(regex.DOMAIN), user_agent) + url = re.search(rf"https?://{regex.DOMAIN}/?", user_agent) if not url: return False url = url.group() diff --git a/bookwyrm/views/list.py b/bookwyrm/views/list.py index af99e9f55..8faadb305 100644 --- a/bookwyrm/views/list.py +++ b/bookwyrm/views/list.py @@ -322,7 +322,7 @@ def add_book(request): path = reverse("list", args=[book_list.id]) params = request.GET.copy() params["updated"] = True - return redirect("{:s}?{:s}".format(path, urlencode(params))) + return redirect(f"{path}?{urlencode(params)}") @require_POST @@ -396,7 +396,7 @@ def set_book_position(request, list_item_id): def increment_order_in_reverse( book_list_id: int, start: int, end: Optional[int] = None ): - """increase the order nu,ber for every item in a list""" + """increase the order number for every item in a list""" try: book_list = models.List.objects.get(id=book_list_id) except models.List.DoesNotExist: diff --git a/bookwyrm/views/login.py b/bookwyrm/views/login.py index 97d541690..6c40e4cef 100644 --- a/bookwyrm/views/login.py +++ b/bookwyrm/views/login.py @@ -46,7 +46,7 @@ class Login(View): except models.User.DoesNotExist: # maybe it's a full username? username = localname else: - username = "%s@%s" % (localname, DOMAIN) + username = f"{localname}@{DOMAIN}" password = login_form.data["password"] # perform authentication diff --git a/bookwyrm/views/password.py b/bookwyrm/views/password.py index 6d202ce24..baf1b3ff4 100644 --- a/bookwyrm/views/password.py +++ b/bookwyrm/views/password.py @@ -38,7 +38,7 @@ class PasswordResetRequest(View): # create a new reset code code = models.PasswordReset.objects.create(user=user) password_reset_email(code) - data = {"message": _("A password reset link sent to %s" % email)} + data = {"message": _(f"A password reset link sent to {email}")} return TemplateResponse(request, "password_reset_request.html", data) diff --git a/bookwyrm/views/register.py b/bookwyrm/views/register.py index 1a0615ac0..1e0dd1d53 100644 --- a/bookwyrm/views/register.py +++ b/bookwyrm/views/register.py @@ -64,7 +64,7 @@ class Register(View): return TemplateResponse(request, "invite.html", data) return TemplateResponse(request, "login.html", data) - username = "%s@%s" % (localname, DOMAIN) + username = f"{localname}@{DOMAIN}" user = models.User.objects.create_user( username, email, diff --git a/bookwyrm/views/search.py b/bookwyrm/views/search.py index cdea86631..d8abdce5b 100644 --- a/bookwyrm/views/search.py +++ b/bookwyrm/views/search.py @@ -63,7 +63,7 @@ class Search(View): data["results"] = paginated data["remote"] = search_remote - return TemplateResponse(request, "search/{:s}.html".format(search_type), data) + return TemplateResponse(request, f"search/{search_type}.html", data) def book_search(query, _, min_confidence, search_remote=False): diff --git a/bookwyrm/views/status.py b/bookwyrm/views/status.py index 0ead2d014..c8131f657 100644 --- a/bookwyrm/views/status.py +++ b/bookwyrm/views/status.py @@ -36,7 +36,7 @@ class CreateStatus(View): status_type = status_type[0].upper() + status_type[1:] try: - form = getattr(forms, "%sForm" % status_type)(request.POST) + form = getattr(forms, f"{status_type}Form")(request.POST) except AttributeError: return HttpResponseBadRequest() if not form.is_valid(): @@ -58,8 +58,8 @@ class CreateStatus(View): # turn the mention into a link content = re.sub( - r"%s([^@]|$)" % mention_text, - r'%s\g<1>' % (mention_user.remote_id, mention_text), + rf"{mention_text}([^@]|$)", + rf'{mention_text}\g<1>', content, ) # add reply parent to mentions @@ -182,7 +182,7 @@ def format_links(content): if url.fragment != "": link += "#" + url.fragment - formatted_content += '%s' % (potential_link, link) + formatted_content += f'{link}' except (ValidationError, UnicodeError): formatted_content += potential_link diff --git a/bookwyrm/views/wellknown.py b/bookwyrm/views/wellknown.py index c981eb69e..660a45244 100644 --- a/bookwyrm/views/wellknown.py +++ b/bookwyrm/views/wellknown.py @@ -26,7 +26,7 @@ def webfinger(request): return JsonResponse( { - "subject": "acct:%s" % (user.username), + "subject": f"acct:{user.username}", "links": [ { "rel": "self", @@ -46,7 +46,7 @@ def nodeinfo_pointer(_): "links": [ { "rel": "http://nodeinfo.diaspora.software/ns/schema/2.0", - "href": "https://%s/nodeinfo/2.0" % DOMAIN, + "href": f"https://{DOMAIN}/nodeinfo/2.0", } ] }