From 377a4e1ef1c5fd0664250d4fde76f132d92b6d69 Mon Sep 17 00:00:00 2001
From: Mouse Reeve
Date: Fri, 17 Sep 2021 21:39:18 -0700
Subject: [PATCH 1/8] Updating string format syntax part 1
---
bookwyrm/activitypub/base_activity.py | 12 +++----
bookwyrm/activitystreams.py | 4 +--
bookwyrm/emailing.py | 8 ++---
bookwyrm/forms.py | 2 +-
bookwyrm/models/user.py | 20 ++++++-----
bookwyrm/preview_images.py | 5 +--
bookwyrm/sanitize_html.py | 2 +-
bookwyrm/settings.py | 15 ++++----
bookwyrm/signatures.py | 20 +++++------
bookwyrm/suggested_users.py | 4 +--
bookwyrm/urls.py | 52 ++++++++++++++-------------
11 files changed, 73 insertions(+), 71 deletions(-)
diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py
index 4f7b55d5..24d383ac 100644
--- a/bookwyrm/activitypub/base_activity.py
+++ b/bookwyrm/activitypub/base_activity.py
@@ -101,7 +101,7 @@ class ActivityObject:
except KeyError:
if field.default == MISSING and field.default_factory == MISSING:
raise ActivitySerializerError(
- "Missing required field: %s" % field.name
+ f"Missing required field: {field.name}"
)
value = field.default
setattr(self, field.name, value)
@@ -219,8 +219,8 @@ def set_related_field(
model_name, origin_model_name, related_field_name, related_remote_id, data
):
"""load reverse related fields (editions, attachments) without blocking"""
- model = apps.get_model("bookwyrm.%s" % model_name, require_ready=True)
- origin_model = apps.get_model("bookwyrm.%s" % origin_model_name, require_ready=True)
+ model = apps.get_model(f"bookwyrm.{model_name}", require_ready=True)
+ origin_model = apps.get_model(f"bookwyrm.{origin_model_name}", require_ready=True)
with transaction.atomic():
if isinstance(data, str):
@@ -234,7 +234,7 @@ def set_related_field(
# this must exist because it's the object that triggered this function
instance = origin_model.find_existing_by_remote_id(related_remote_id)
if not instance:
- raise ValueError("Invalid related remote id: %s" % related_remote_id)
+ raise ValueError(f"Invalid related remote id: {related_remote_id}")
# set the origin's remote id on the activity so it will be there when
# the model instance is created
@@ -265,7 +265,7 @@ def get_model_from_type(activity_type):
]
if not model:
raise ActivitySerializerError(
- 'No model found for activity type "%s"' % activity_type
+ f'No model found for activity type "{activity_type}"'
)
return model[0]
@@ -286,7 +286,7 @@ def resolve_remote_id(
data = get_data(remote_id)
except ConnectorException:
raise ActivitySerializerError(
- "Could not connect to host for remote_id in: %s" % (remote_id)
+ f"Could not connect to host for remote_id: {remote_id}"
)
# determine the model implicitly, if not provided
# or if it's a model with subclasses like Status, check again
diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py
index 10149993..13d56f84 100644
--- a/bookwyrm/activitystreams.py
+++ b/bookwyrm/activitystreams.py
@@ -16,11 +16,11 @@ class ActivityStream(RedisStore):
def stream_id(self, user):
"""the redis key for this user's instance of this stream"""
- return "{}-{}".format(user.id, self.key)
+ return f"{user.id}-{self.key}"
def unread_id(self, user):
"""the redis key for this user's unread count for this stream"""
- return "{}-unread".format(self.stream_id(user))
+ return "{}-unread".format(self.stream_id(user)) # pylint: disable=consider-using-f-string
def get_rank(self, obj): # pylint: disable=no-self-use
"""statuses are sorted by date published"""
diff --git a/bookwyrm/emailing.py b/bookwyrm/emailing.py
index 4f43c69e..10db4f13 100644
--- a/bookwyrm/emailing.py
+++ b/bookwyrm/emailing.py
@@ -11,7 +11,7 @@ def email_data():
"""fields every email needs"""
site = models.SiteSettings.objects.get()
if site.logo_small:
- logo_path = "/images/{}".format(site.logo_small.url)
+ logo_path = f"/images/{site.logo_small.url}"
else:
logo_path = "/static/images/logo-small.png"
@@ -49,15 +49,15 @@ def password_reset_email(reset_code):
def format_email(email_name, data):
"""render the email templates"""
subject = (
- get_template("email/{}/subject.html".format(email_name)).render(data).strip()
+ get_template(f"email/{email_name}/subject.html").render(data).strip()
)
html_content = (
- get_template("email/{}/html_content.html".format(email_name))
+ get_template(f"email/{email_name}/html_content.html")
.render(data)
.strip()
)
text_content = (
- get_template("email/{}/text_content.html".format(email_name))
+ get_template(f"email/{email_name}/text_content.html")
.render(data)
.strip()
)
diff --git a/bookwyrm/forms.py b/bookwyrm/forms.py
index b53d0b6a..f20cdd00 100644
--- a/bookwyrm/forms.py
+++ b/bookwyrm/forms.py
@@ -261,7 +261,7 @@ class CreateInviteForm(CustomForm):
),
"use_limit": widgets.Select(
choices=[
- (i, _("%(count)d uses" % {"count": i}))
+ (i, _(f"{i} uses"))
for i in [1, 5, 10, 25, 50, 100]
]
+ [(None, _("Unlimited"))]
diff --git a/bookwyrm/models/user.py b/bookwyrm/models/user.py
index a33daf72..750cfa44 100644
--- a/bookwyrm/models/user.py
+++ b/bookwyrm/models/user.py
@@ -152,12 +152,13 @@ class User(OrderedCollectionPageMixin, AbstractUser):
@property
def following_link(self):
"""just how to find out the following info"""
- return "{:s}/following".format(self.remote_id)
+ return f"{self.remote_id}/following"
@property
def alt_text(self):
"""alt text with username"""
- return "avatar for %s" % (self.localname or self.username)
+ # pylint: disable=consider-using-f-string
+ return "avatar for {:s}".format(self.localname or self.username)
@property
def display_name(self):
@@ -198,7 +199,7 @@ class User(OrderedCollectionPageMixin, AbstractUser):
"""an ordered collection of statuses"""
if filter_type:
filter_class = apps.get_model(
- "bookwyrm.%s" % filter_type, require_ready=True
+ f"bookwyrm.{filter_type}", require_ready=True
)
if not issubclass(filter_class, Status):
raise TypeError(
@@ -223,7 +224,7 @@ class User(OrderedCollectionPageMixin, AbstractUser):
def to_following_activity(self, **kwargs):
"""activitypub following list"""
- remote_id = "%s/following" % self.remote_id
+ remote_id = f"{self.remote_id}/following"
return self.to_ordered_collection(
self.following.order_by("-updated_date").all(),
remote_id=remote_id,
@@ -266,7 +267,7 @@ class User(OrderedCollectionPageMixin, AbstractUser):
if not self.local and not re.match(regex.FULL_USERNAME, self.username):
# generate a username that uses the domain (webfinger format)
actor_parts = urlparse(self.remote_id)
- self.username = "%s@%s" % (self.username, actor_parts.netloc)
+ self.username = f"{self.username}@{actor_parts.netloc}"
# this user already exists, no need to populate fields
if not created:
@@ -320,7 +321,8 @@ class User(OrderedCollectionPageMixin, AbstractUser):
@property
def local_path(self):
"""this model doesn't inherit bookwyrm model, so here we are"""
- return "/user/%s" % (self.localname or self.username)
+ # pylint: disable=consider-using-f-string
+ return "/user/{:s}".format(self.localname or self.username)
def create_shelves(self):
"""default shelves for a new user"""
@@ -361,7 +363,7 @@ class KeyPair(ActivitypubMixin, BookWyrmModel):
def get_remote_id(self):
# self.owner is set by the OneToOneField on User
- return "%s/#main-key" % self.owner.remote_id
+ return f"{self.owner.remote_id}/#main-key"
def save(self, *args, **kwargs):
"""create a key pair"""
@@ -398,7 +400,7 @@ class AnnualGoal(BookWyrmModel):
def get_remote_id(self):
"""put the year in the path"""
- return "{:s}/goal/{:d}".format(self.user.remote_id, self.year)
+ return f"{self.user.remote_id}/goal/{self.year}"
@property
def books(self):
@@ -454,7 +456,7 @@ def get_or_create_remote_server(domain):
pass
try:
- data = get_data("https://%s/.well-known/nodeinfo" % domain)
+ data = get_data(f"https://{domain}/.well-known/nodeinfo")
try:
nodeinfo_url = data.get("links")[0].get("href")
except (TypeError, KeyError):
diff --git a/bookwyrm/preview_images.py b/bookwyrm/preview_images.py
index 900a3e12..c9ef4643 100644
--- a/bookwyrm/preview_images.py
+++ b/bookwyrm/preview_images.py
@@ -315,7 +315,8 @@ def save_and_cleanup(image, instance=None):
"""Save and close the file"""
if not isinstance(instance, (models.Book, models.User, models.SiteSettings)):
return False
- file_name = "%s-%s.jpg" % (str(instance.id), str(uuid4()))
+ uuid = uuid4()
+ file_name = f"{instance.id}-{uuid}.jpg"
image_buffer = BytesIO()
try:
@@ -412,7 +413,7 @@ def generate_user_preview_image_task(user_id):
texts = {
"text_one": user.display_name,
- "text_three": "@{}@{}".format(user.localname, settings.DOMAIN),
+ "text_three": "@{user.localname}@{settings.DOMAIN}"
}
if user.avatar:
diff --git a/bookwyrm/sanitize_html.py b/bookwyrm/sanitize_html.py
index 0be64c58..8b0e3c4c 100644
--- a/bookwyrm/sanitize_html.py
+++ b/bookwyrm/sanitize_html.py
@@ -48,7 +48,7 @@ class InputHtmlParser(HTMLParser): # pylint: disable=abstract-method
return
self.tag_stack = self.tag_stack[:-1]
- self.output.append(("tag", "%s>" % tag))
+ self.output.append(("tag", f"{tag}>"))
def handle_data(self, data):
"""extract the answer, if we're in an answer tag"""
diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py
index 452b8d94..521014a1 100644
--- a/bookwyrm/settings.py
+++ b/bookwyrm/settings.py
@@ -23,7 +23,7 @@ EMAIL_HOST_USER = env("EMAIL_HOST_USER")
EMAIL_HOST_PASSWORD = env("EMAIL_HOST_PASSWORD")
EMAIL_USE_TLS = env.bool("EMAIL_USE_TLS", True)
EMAIL_USE_SSL = env.bool("EMAIL_USE_SSL", False)
-DEFAULT_FROM_EMAIL = "admin@{:s}".format(env("DOMAIN"))
+DEFAULT_FROM_EMAIL = "admin@{:s}".format(env("DOMAIN")) # pylint: disable=consider-using-f-string
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@@ -177,11 +177,8 @@ USE_L10N = True
USE_TZ = True
-USER_AGENT = "%s (BookWyrm/%s; +https://%s/)" % (
- requests.utils.default_user_agent(),
- VERSION,
- DOMAIN,
-)
+agent = requests.utils.default_user_agent()
+USER_AGENT = f"{agent} (BookWyrm/{VERSION}; +https://{DOMAIN}/)"
# Imagekit generated thumbnails
ENABLE_THUMBNAIL_GENERATION = env.bool("ENABLE_THUMBNAIL_GENERATION", False)
@@ -212,11 +209,11 @@ if USE_S3:
AWS_S3_OBJECT_PARAMETERS = {"CacheControl": "max-age=86400"}
# S3 Static settings
STATIC_LOCATION = "static"
- STATIC_URL = "https://%s/%s/" % (AWS_S3_CUSTOM_DOMAIN, STATIC_LOCATION)
+ STATIC_URL = f"https://{AWS_S3_CUSTOM_DOMAIN}/{STATIC_LOCATION}/"
STATICFILES_STORAGE = "bookwyrm.storage_backends.StaticStorage"
# S3 Media settings
MEDIA_LOCATION = "images"
- MEDIA_URL = "https://%s/%s/" % (AWS_S3_CUSTOM_DOMAIN, MEDIA_LOCATION)
+ MEDIA_URL = f"https://{AWS_S3_CUSTOM_DOMAIN}/{MEDIA_LOCATION}/"
MEDIA_FULL_URL = MEDIA_URL
DEFAULT_FILE_STORAGE = "bookwyrm.storage_backends.ImagesStorage"
# I don't know if it's used, but the site crashes without it
@@ -226,5 +223,5 @@ else:
STATIC_URL = "/static/"
STATIC_ROOT = os.path.join(BASE_DIR, env("STATIC_ROOT", "static"))
MEDIA_URL = "/images/"
- MEDIA_FULL_URL = "%s://%s%s" % (PROTOCOL, DOMAIN, MEDIA_URL)
+ MEDIA_FULL_URL = f"{PROTOCOL}://{DOMAIN}{MEDIA_URL}"
MEDIA_ROOT = os.path.join(BASE_DIR, env("MEDIA_ROOT", "images"))
diff --git a/bookwyrm/signatures.py b/bookwyrm/signatures.py
index c8c90028..61cafe71 100644
--- a/bookwyrm/signatures.py
+++ b/bookwyrm/signatures.py
@@ -26,21 +26,21 @@ def make_signature(sender, destination, date, digest):
"""uses a private key to sign an outgoing message"""
inbox_parts = urlparse(destination)
signature_headers = [
- "(request-target): post %s" % inbox_parts.path,
- "host: %s" % inbox_parts.netloc,
- "date: %s" % date,
- "digest: %s" % digest,
+ f"(request-target): post {inbox_parts.path}",
+ f"host: {inbox_parts.netloc}",
+ f"date: {date}",
+ f"digest: {digest}",
]
message_to_sign = "\n".join(signature_headers)
signer = pkcs1_15.new(RSA.import_key(sender.key_pair.private_key))
signed_message = signer.sign(SHA256.new(message_to_sign.encode("utf8")))
signature = {
- "keyId": "%s#main-key" % sender.remote_id,
+ "keyId": f"{sender.remote_id}#main-key",
"algorithm": "rsa-sha256",
"headers": "(request-target) host date digest",
"signature": b64encode(signed_message).decode("utf8"),
}
- return ",".join('%s="%s"' % (k, v) for (k, v) in signature.items())
+ return ",".join(f'{k}="{v}"' for (k, v) in signature.items())
def make_digest(data):
@@ -58,7 +58,7 @@ def verify_digest(request):
elif algorithm == "SHA-512":
hash_function = hashlib.sha512
else:
- raise ValueError("Unsupported hash function: {}".format(algorithm))
+ raise ValueError(f"Unsupported hash function: {algorithm}")
expected = hash_function(request.body).digest()
if b64decode(digest) != expected:
@@ -95,18 +95,18 @@ class Signature:
def verify(self, public_key, request):
"""verify rsa signature"""
if http_date_age(request.headers["date"]) > MAX_SIGNATURE_AGE:
- raise ValueError("Request too old: %s" % (request.headers["date"],))
+ raise ValueError(f"Request too old: {request.headers['date']}")
public_key = RSA.import_key(public_key)
comparison_string = []
for signed_header_name in self.headers.split(" "):
if signed_header_name == "(request-target)":
- comparison_string.append("(request-target): post %s" % request.path)
+ comparison_string.append(f"(request-target): post {request.path}")
else:
if signed_header_name == "digest":
verify_digest(request)
comparison_string.append(
- "%s: %s" % (signed_header_name, request.headers[signed_header_name])
+ f"{signed_header_name}: {request.headers[signed_header_name]}"
)
comparison_string = "\n".join(comparison_string)
diff --git a/bookwyrm/suggested_users.py b/bookwyrm/suggested_users.py
index 88343061..e8f23632 100644
--- a/bookwyrm/suggested_users.py
+++ b/bookwyrm/suggested_users.py
@@ -24,8 +24,8 @@ class SuggestedUsers(RedisStore):
def store_id(self, user): # pylint: disable=no-self-use
"""the key used to store this user's recs"""
if isinstance(user, int):
- return "{:d}-suggestions".format(user)
- return "{:d}-suggestions".format(user.id)
+ return f"{user}-suggestions"
+ return f"{user.id}-suggestions"
def get_counts_from_rank(self, rank): # pylint: disable=no-self-use
"""calculate mutuals count and shared books count from rank"""
diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py
index 6acf75cb..6ff0c183 100644
--- a/bookwyrm/urls.py
+++ b/bookwyrm/urls.py
@@ -7,8 +7,8 @@ from django.views.generic.base import TemplateView
from bookwyrm import settings, views
from bookwyrm.utils import regex
-USER_PATH = r"^user/(?P%s)" % regex.USERNAME
-LOCAL_USER_PATH = r"^user/(?P%s)" % regex.LOCALNAME
+USER_PATH = rf"^user/(?P{regex.USERNAME})"
+LOCAL_USER_PATH = rf"^user/(?P{regex.LOCALNAME})"
status_types = [
"status",
@@ -19,7 +19,9 @@ status_types = [
"boost",
"generatednote",
]
-STATUS_PATH = r"%s/(%s)/(?P\d+)" % (USER_PATH, "|".join(status_types))
+
+status_types_string = "|".join(status_types)
+STATUS_PATH = rf"{USER_PATH}/({status_types_string})/(?P\d+)"
BOOK_PATH = r"^book/(?P\d+)"
@@ -33,8 +35,8 @@ urlpatterns = [
),
# federation endpoints
re_path(r"^inbox/?$", views.Inbox.as_view()),
- re_path(r"%s/inbox/?$" % LOCAL_USER_PATH, views.Inbox.as_view()),
- re_path(r"%s/outbox/?$" % LOCAL_USER_PATH, views.Outbox.as_view()),
+ re_path(rf"{LOCAL_USER_PATH}/inbox/?$", views.Inbox.as_view()),
+ re_path(rf"{LOCAL_USER_PATH}/outbox/?$", views.Outbox.as_view()),
re_path(r"^\.well-known/webfinger/?$", views.webfinger),
re_path(r"^\.well-known/nodeinfo/?$", views.nodeinfo_pointer),
re_path(r"^\.well-known/host-meta/?$", views.host_meta),
@@ -210,12 +212,12 @@ urlpatterns = [
name="get-started-users",
),
# feeds
- re_path(r"^(?P{:s})/?$".format(STREAMS), views.Feed.as_view()),
+ re_path(rf"^(?P{STREAMS})/?$", views.Feed.as_view()),
re_path(
r"^direct-messages/?$", views.DirectMessage.as_view(), name="direct-messages"
),
re_path(
- r"^direct-messages/(?P%s)?$" % regex.USERNAME,
+ rf"^direct-messages/(?P{regex.USERNAME})?$",
views.DirectMessage.as_view(),
name="direct-messages-user",
),
@@ -225,22 +227,22 @@ urlpatterns = [
re_path(r"^import/?$", views.Import.as_view(), name="import"),
re_path(r"^import/(\d+)/?$", views.ImportStatus.as_view(), name="import-status"),
# users
- re_path(r"%s\.json$" % USER_PATH, views.User.as_view()),
- re_path(r"%s/?$" % USER_PATH, views.User.as_view(), name="user-feed"),
- re_path(r"%s/rss" % USER_PATH, views.rss_feed.RssFeed(), name="user-rss"),
+ re_path(rf"{USER_PATH}\.json$", views.User.as_view()),
+ re_path(rf"{USER_PATH}/?$", views.User.as_view(), name="user-feed"),
+ re_path(rf"{USER_PATH}/rss/?$", views.rss_feed.RssFeed(), name="user-rss"),
re_path(
- r"%s/followers(.json)?/?$" % USER_PATH,
+ rf"{USER_PATH}/followers(.json)?/?$",
views.Followers.as_view(),
name="user-followers",
),
re_path(
- r"%s/following(.json)?/?$" % USER_PATH,
+ rf"{USER_PATH}/following(.json)?/?$",
views.Following.as_view(),
name="user-following",
),
re_path(r"^hide-suggestions/?$", views.hide_suggestions, name="hide-suggestions"),
# lists
- re_path(r"%s/lists/?$" % USER_PATH, views.UserLists.as_view(), name="user-lists"),
+ re_path(rf"{USER_PATH}/lists/?$", views.UserLists.as_view(), name="user-lists"),
re_path(r"^list/?$", views.Lists.as_view(), name="lists"),
re_path(r"^list/saved/?$", views.SavedLists.as_view(), name="saved-lists"),
re_path(r"^list/(?P\d+)(.json)?/?$", views.List.as_view(), name="list"),
@@ -262,14 +264,14 @@ urlpatterns = [
re_path(r"^save-list/(?P\d+)/?$", views.save_list, name="list-save"),
re_path(r"^unsave-list/(?P\d+)/?$", views.unsave_list, name="list-unsave"),
# User books
- re_path(r"%s/books/?$" % USER_PATH, views.Shelf.as_view(), name="user-shelves"),
+ re_path(rf"{USER_PATH}/books/?$", views.Shelf.as_view(), name="user-shelves"),
re_path(
- r"^%s/(helf|books)/(?P[\w-]+)(.json)?/?$" % USER_PATH,
+ rf"^{USER_PATH}/(helf|books)/(?P[\w-]+)(.json)?/?$",
views.Shelf.as_view(),
name="shelf",
),
re_path(
- r"^%s/(books|shelf)/(?P[\w-]+)(.json)?/?$" % LOCAL_USER_PATH,
+ rf"^{LOCAL_USER_PATH}/(books|shelf)/(?P[\w-]+)(.json)?/?$",
views.Shelf.as_view(),
name="shelf",
),
@@ -279,7 +281,7 @@ urlpatterns = [
re_path(r"^unshelve/?$", views.unshelve),
# goals
re_path(
- r"%s/goal/(?P\d{4})/?$" % USER_PATH,
+ rf"{USER_PATH}/goal/(?P\d{4})/?$",
views.Goal.as_view(),
name="user-goal",
),
@@ -296,10 +298,10 @@ urlpatterns = [
re_path(r"^block/(?P\d+)/?$", views.Block.as_view()),
re_path(r"^unblock/(?P\d+)/?$", views.unblock),
# statuses
- re_path(r"%s(.json)?/?$" % STATUS_PATH, views.Status.as_view(), name="status"),
- re_path(r"%s/activity/?$" % STATUS_PATH, views.Status.as_view(), name="status"),
+ re_path(rf"{STATUS_PATH}(.json)?/?$", views.Status.as_view(), name="status"),
+ re_path(rf"{STATUS_PATH}/activity/?$", views.Status.as_view(), name="status"),
re_path(
- r"%s/replies(.json)?/?$" % STATUS_PATH, views.Replies.as_view(), name="replies"
+ rf"{STATUS_PATH}/replies(.json)?/?$", views.Replies.as_view(), name="replies"
),
re_path(
r"^post/?$",
@@ -329,17 +331,17 @@ urlpatterns = [
re_path(r"^boost/(?P\d+)/?$", views.Boost.as_view()),
re_path(r"^unboost/(?P\d+)/?$", views.Unboost.as_view()),
# books
- re_path(r"%s(.json)?/?$" % BOOK_PATH, views.Book.as_view(), name="book"),
+ re_path(rf"{BOOK_PATH}(.json)?/?$", views.Book.as_view(), name="book"),
re_path(
- r"%s/(?Preview|comment|quote)/?$" % BOOK_PATH,
+ rf"{BOOK_PATH}/(?Preview|comment|quote)/?$",
views.Book.as_view(),
name="book-user-statuses",
),
- re_path(r"%s/edit/?$" % BOOK_PATH, views.EditBook.as_view(), name="edit-book"),
- re_path(r"%s/confirm/?$" % BOOK_PATH, views.ConfirmEditBook.as_view()),
+ re_path(rf"{BOOK_PATH}/edit/?$", views.EditBook.as_view(), name="edit-book"),
+ re_path(rf"{BOOK_PATH}/confirm/?$", views.ConfirmEditBook.as_view()),
re_path(r"^create-book/?$", views.EditBook.as_view(), name="create-book"),
re_path(r"^create-book/confirm?$", views.ConfirmEditBook.as_view()),
- re_path(r"%s/editions(.json)?/?$" % BOOK_PATH, views.Editions.as_view()),
+ re_path(rf"{BOOK_PATH}/editions(.json)?/?$", views.Editions.as_view()),
re_path(
r"^upload-cover/(?P\d+)/?$", views.upload_cover, name="upload-cover"
),
From acfb1bb3764c7a41c699aebc13da9c61418e239e Mon Sep 17 00:00:00 2001
From: Mouse Reeve
Date: Sat, 18 Sep 2021 11:32:00 -0700
Subject: [PATCH 2/8] Updating string format synatx part 2
---
.github/workflows/pylint.yml | 2 +-
bookwyrm/connectors/abstract_connector.py | 9 +++++----
bookwyrm/connectors/connector_manager.py | 12 ++++++------
bookwyrm/connectors/inventaire.py | 22 +++++++--------------
bookwyrm/connectors/openlibrary.py | 14 ++++++-------
bookwyrm/connectors/self_connector.py | 2 +-
bookwyrm/importers/importer.py | 1 +
bookwyrm/models/activitypub_mixin.py | 24 +++++++++++------------
bookwyrm/models/author.py | 2 +-
bookwyrm/models/base_model.py | 8 ++++----
bookwyrm/models/book.py | 9 +++++----
bookwyrm/models/connector.py | 5 +----
bookwyrm/models/fields.py | 6 +++---
bookwyrm/models/import_job.py | 2 ++
bookwyrm/models/list.py | 2 +-
bookwyrm/models/relationship.py | 5 +++--
bookwyrm/models/shelf.py | 4 ++--
bookwyrm/models/site.py | 4 ++--
bookwyrm/models/status.py | 19 +++++-------------
bookwyrm/templatetags/utilities.py | 6 +++---
bookwyrm/utils/regex.py | 6 +++---
bookwyrm/views/author.py | 2 +-
bookwyrm/views/edit_user.py | 2 +-
bookwyrm/views/editions.py | 2 +-
bookwyrm/views/feed.py | 2 +-
bookwyrm/views/follow.py | 2 +-
bookwyrm/views/helpers.py | 2 +-
bookwyrm/views/import_data.py | 4 ++--
bookwyrm/views/inbox.py | 2 +-
bookwyrm/views/list.py | 4 ++--
bookwyrm/views/login.py | 2 +-
bookwyrm/views/password.py | 2 +-
bookwyrm/views/register.py | 2 +-
bookwyrm/views/search.py | 2 +-
bookwyrm/views/status.py | 8 ++++----
bookwyrm/views/wellknown.py | 4 ++--
36 files changed, 96 insertions(+), 110 deletions(-)
diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml
index 2a81eaa3..1b14149f 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 ffacffdf..902ccd6c 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 1d9588d6..b676e9aa 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 d2a7b9fa..b23a7d52 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 e58749c1..fca5d0f7 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 8d5a7614..cdb586cb 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 caa137ec..a10b4060 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 ed51158b..3a88c524 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 6da80b17..53cf94ff 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 0ac2061a..aa174a14 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 ec1c14ec..ac7c42f6 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 17ba3148..9d2c6aeb 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 cc5a7bb5..8555e06f 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 7d8ce9e3..4f495f14 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 bbad5ba9..49fb5375 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 edb89d13..fc7a9df8 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 c4e907d2..6f134402 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 ee69a507..03d6f5fe 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 d0f094d2..0b6e49e2 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 fe83278a..76b4cd3f 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 3ac5a0ff..f0c44245 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 e51dc7d8..e1e9247d 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 b97f2737..4026a531 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 7615c497..d044f17c 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 d17de8f9..98a1c836 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 c3336a94..0710a70c 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 b1e5f68c..e6db1487 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 634940a0..2232e39c 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 e255b4fa..ff01cfb2 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 af99e9f5..8faadb30 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 97d54169..6c40e4ce 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 6d202ce2..baf1b3ff 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 1a0615ac..1e0dd1d5 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 cdea8663..d8abdce5 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 0ead2d01..c8131f65 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 c981eb69..660a4524 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",
}
]
}
From 08f6a9765379ab96cbf8348024923ea8a24e8254 Mon Sep 17 00:00:00 2001
From: Mouse Reeve
Date: Sat, 18 Sep 2021 11:33:43 -0700
Subject: [PATCH 3/8] Python formatting
---
bookwyrm/activitystreams.py | 4 +++-
bookwyrm/connectors/abstract_connector.py | 4 +---
bookwyrm/connectors/inventaire.py | 10 ++--------
bookwyrm/emailing.py | 12 +++---------
bookwyrm/forms.py | 5 +----
bookwyrm/models/fields.py | 2 +-
bookwyrm/models/status.py | 2 +-
bookwyrm/models/user.py | 4 +---
bookwyrm/preview_images.py | 2 +-
bookwyrm/settings.py | 4 +++-
10 files changed, 17 insertions(+), 32 deletions(-)
diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py
index 13d56f84..c2b3da5e 100644
--- a/bookwyrm/activitystreams.py
+++ b/bookwyrm/activitystreams.py
@@ -20,7 +20,9 @@ class ActivityStream(RedisStore):
def unread_id(self, user):
"""the redis key for this user's unread count for this stream"""
- return "{}-unread".format(self.stream_id(user)) # pylint: disable=consider-using-f-string
+ return "{}-unread".format(
+ self.stream_id(user)
+ ) # pylint: disable=consider-using-f-string
def get_rank(self, obj): # pylint: disable=no-self-use
"""statuses are sorted by date published"""
diff --git a/bookwyrm/connectors/abstract_connector.py b/bookwyrm/connectors/abstract_connector.py
index 902ccd6c..455241cc 100644
--- a/bookwyrm/connectors/abstract_connector.py
+++ b/bookwyrm/connectors/abstract_connector.py
@@ -222,9 +222,7 @@ def get_data(url, params=None, timeout=10):
"""wrapper for request.get"""
# check if the url is blocked
if models.FederatedServer.is_blocked(url):
- raise ConnectorException(
- f"Attempting to load data from blocked url: {url}"
- )
+ raise ConnectorException(f"Attempting to load data from blocked url: {url}")
try:
resp = requests.get(
diff --git a/bookwyrm/connectors/inventaire.py b/bookwyrm/connectors/inventaire.py
index b23a7d52..70455488 100644
--- a/bookwyrm/connectors/inventaire.py
+++ b/bookwyrm/connectors/inventaire.py
@@ -87,11 +87,7 @@ class Connector(AbstractConnector):
def format_search_result(self, search_result):
images = search_result.get("image")
- cover = (
- f"{self.covers_url}/img/entities/{images[0]}"
- if images
- else None
- )
+ cover = f"{self.covers_url}/img/entities/{images[0]}" if images else None
# a deeply messy translation of inventaire's scores
confidence = float(search_result.get("_score", 0.1))
confidence = 0.1 if confidence < 150 else 0.999
@@ -131,9 +127,7 @@ class Connector(AbstractConnector):
def load_edition_data(self, work_uri):
"""get a list of editions for a work"""
- url = (
- f"{self.books_url}?action=reverse-claims&property=wdt:P629&value={work_uri}&sort=true"
- )
+ url = f"{self.books_url}?action=reverse-claims&property=wdt:P629&value={work_uri}&sort=true"
return get_data(url)
def get_edition_from_work_data(self, data):
diff --git a/bookwyrm/emailing.py b/bookwyrm/emailing.py
index 10db4f13..c6a197f2 100644
--- a/bookwyrm/emailing.py
+++ b/bookwyrm/emailing.py
@@ -48,18 +48,12 @@ def password_reset_email(reset_code):
def format_email(email_name, data):
"""render the email templates"""
- subject = (
- get_template(f"email/{email_name}/subject.html").render(data).strip()
- )
+ subject = get_template(f"email/{email_name}/subject.html").render(data).strip()
html_content = (
- get_template(f"email/{email_name}/html_content.html")
- .render(data)
- .strip()
+ get_template(f"email/{email_name}/html_content.html").render(data).strip()
)
text_content = (
- get_template(f"email/{email_name}/text_content.html")
- .render(data)
- .strip()
+ get_template(f"email/{email_name}/text_content.html").render(data).strip()
)
return (subject, html_content, text_content)
diff --git a/bookwyrm/forms.py b/bookwyrm/forms.py
index d8228b7e..23063ff7 100644
--- a/bookwyrm/forms.py
+++ b/bookwyrm/forms.py
@@ -260,10 +260,7 @@ class CreateInviteForm(CustomForm):
]
),
"use_limit": widgets.Select(
- choices=[
- (i, _(f"{i} uses"))
- for i in [1, 5, 10, 25, 50, 100]
- ]
+ choices=[(i, _(f"{i} uses")) for i in [1, 5, 10, 25, 50, 100]]
+ [(None, _("Unlimited"))]
),
}
diff --git a/bookwyrm/models/fields.py b/bookwyrm/models/fields.py
index 8555e06f..ccd669cb 100644
--- a/bookwyrm/models/fields.py
+++ b/bookwyrm/models/fields.py
@@ -56,7 +56,7 @@ class ActivitypubFieldMixin:
activitypub_field=None,
activitypub_wrapper=None,
deduplication_field=False,
- **kwargs
+ **kwargs,
):
self.deduplication_field = deduplication_field
if activitypub_wrapper:
diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py
index 0b6e49e2..e3a3d387 100644
--- a/bookwyrm/models/status.py
+++ b/bookwyrm/models/status.py
@@ -181,7 +181,7 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel):
self.replies(self),
remote_id=f"{self.remote_id}/replies",
collection_only=True,
- **kwargs
+ **kwargs,
).serialize()
def to_activity_dataclass(self, pure=False): # pylint: disable=arguments-differ
diff --git a/bookwyrm/models/user.py b/bookwyrm/models/user.py
index 750cfa44..ad43270c 100644
--- a/bookwyrm/models/user.py
+++ b/bookwyrm/models/user.py
@@ -198,9 +198,7 @@ class User(OrderedCollectionPageMixin, AbstractUser):
def to_outbox(self, filter_type=None, **kwargs):
"""an ordered collection of statuses"""
if filter_type:
- filter_class = apps.get_model(
- f"bookwyrm.{filter_type}", require_ready=True
- )
+ filter_class = apps.get_model(f"bookwyrm.{filter_type}", require_ready=True)
if not issubclass(filter_class, Status):
raise TypeError(
"filter_status_class must be a subclass of models.Status"
diff --git a/bookwyrm/preview_images.py b/bookwyrm/preview_images.py
index c9ef4643..55af3532 100644
--- a/bookwyrm/preview_images.py
+++ b/bookwyrm/preview_images.py
@@ -413,7 +413,7 @@ def generate_user_preview_image_task(user_id):
texts = {
"text_one": user.display_name,
- "text_three": "@{user.localname}@{settings.DOMAIN}"
+ "text_three": "@{user.localname}@{settings.DOMAIN}",
}
if user.avatar:
diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py
index c6a816ed..285d2df8 100644
--- a/bookwyrm/settings.py
+++ b/bookwyrm/settings.py
@@ -23,7 +23,9 @@ EMAIL_HOST_USER = env("EMAIL_HOST_USER")
EMAIL_HOST_PASSWORD = env("EMAIL_HOST_PASSWORD")
EMAIL_USE_TLS = env.bool("EMAIL_USE_TLS", True)
EMAIL_USE_SSL = env.bool("EMAIL_USE_SSL", False)
-DEFAULT_FROM_EMAIL = "admin@{:s}".format(env("DOMAIN")) # pylint: disable=consider-using-f-string
+DEFAULT_FROM_EMAIL = "admin@{:s}".format(
+ env("DOMAIN")
+) # pylint: disable=consider-using-f-string
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
From ea303fb285766e30032a67f8c7bb196d8ef7b0e0 Mon Sep 17 00:00:00 2001
From: Mouse Reeve
Date: Mon, 20 Sep 2021 16:44:59 -0700
Subject: [PATCH 4/8] Updating string format synatx part 3
---
bookwyrm/activitystreams.py | 5 ++---
bookwyrm/models/status.py | 10 ++++++++--
bookwyrm/preview_images.py | 4 +++-
bookwyrm/settings.py | 4 +---
bookwyrm/urls.py | 4 ++--
bookwyrm/views/books.py | 12 ++++++------
6 files changed, 22 insertions(+), 17 deletions(-)
diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py
index c2b3da5e..5e0969e5 100644
--- a/bookwyrm/activitystreams.py
+++ b/bookwyrm/activitystreams.py
@@ -20,9 +20,8 @@ class ActivityStream(RedisStore):
def unread_id(self, user):
"""the redis key for this user's unread count for this stream"""
- return "{}-unread".format(
- self.stream_id(user)
- ) # pylint: disable=consider-using-f-string
+ stream_id = self.stream_id(user)
+ return f"{stream_id}-unread"
def get_rank(self, obj): # pylint: disable=no-self-use
"""statuses are sorted by date published"""
diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py
index e3a3d387..0a51f6a3 100644
--- a/bookwyrm/models/status.py
+++ b/bookwyrm/models/status.py
@@ -277,7 +277,10 @@ class Comment(BookStatus):
@property
def pure_content(self):
"""indicate the book in question for mastodon (or w/e) users"""
- return f'{self.content}(comment on "{self.book.title}")
'
+ return (
+ f'{self.content}(comment on '
+ '"{self.book.title}")
'
+ )
activity_serializer = activitypub.Comment
@@ -302,7 +305,10 @@ 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 f'{quote} -- "{self.book.title}"
{self.content}'
+ return (
+ f'{quote} -- '
+ '"{self.book.title}"
{self.content}'
+ )
activity_serializer = activitypub.Quotation
diff --git a/bookwyrm/preview_images.py b/bookwyrm/preview_images.py
index 55af3532..17377f95 100644
--- a/bookwyrm/preview_images.py
+++ b/bookwyrm/preview_images.py
@@ -220,6 +220,7 @@ def generate_default_inner_img():
# pylint: disable=too-many-locals
+# pylint: disable=too-many-statements
def generate_preview_image(
texts=None, picture=None, rating=None, show_instance_layer=True
):
@@ -237,7 +238,8 @@ def generate_preview_image(
# Color
if BG_COLOR in ["use_dominant_color_light", "use_dominant_color_dark"]:
- image_bg_color = "rgb(%s, %s, %s)" % dominant_color
+ red, green, blue = dominant_color
+ image_bg_color = f"rgb({red}, {green}, {blue})"
# Adjust color
image_bg_color_rgb = [x / 255.0 for x in ImageColor.getrgb(image_bg_color)]
diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py
index 1a05120b..f2c329f0 100644
--- a/bookwyrm/settings.py
+++ b/bookwyrm/settings.py
@@ -23,9 +23,7 @@ EMAIL_HOST_USER = env("EMAIL_HOST_USER")
EMAIL_HOST_PASSWORD = env("EMAIL_HOST_PASSWORD")
EMAIL_USE_TLS = env.bool("EMAIL_USE_TLS", True)
EMAIL_USE_SSL = env.bool("EMAIL_USE_SSL", False)
-DEFAULT_FROM_EMAIL = "admin@{:s}".format(
- env("DOMAIN")
-) # pylint: disable=consider-using-f-string
+DEFAULT_FROM_EMAIL = f"admin@{DOMAIN}"
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py
index 2924bd97..7cf99af3 100644
--- a/bookwyrm/urls.py
+++ b/bookwyrm/urls.py
@@ -20,8 +20,8 @@ status_types = [
"generatednote",
]
-status_types_string = "|".join(status_types)
-STATUS_PATH = rf"{USER_PATH}/({status_types_string})/(?P\d+)"
+STATUS_TYPES_STRING = "|".join(status_types)
+STATUS_PATH = rf"{USER_PATH}/({STATUS_TYPES_STRING})/(?P\d+)"
BOOK_PATH = r"^book/(?P\d+)"
diff --git a/bookwyrm/views/books.py b/bookwyrm/views/books.py
index c2525295..a31a99e7 100644
--- a/bookwyrm/views/books.py
+++ b/bookwyrm/views/books.py
@@ -174,7 +174,7 @@ class EditBook(View):
# check if this is an edition of an existing work
author_text = book.author_text if book else add_author
data["book_matches"] = connector_manager.local_search(
- "%s %s" % (form.cleaned_data.get("title"), author_text),
+ f'{form.cleaned_data.get("title")} {author_text}',
min_confidence=0.5,
raw=True,
)[:5]
@@ -212,7 +212,7 @@ class EditBook(View):
if image:
book.cover.save(*image, save=False)
book.save()
- return redirect("/book/%s" % book.id)
+ return redirect(f"/book/{book.id}")
@method_decorator(login_required, name="dispatch")
@@ -238,14 +238,14 @@ class ConfirmEditBook(View):
# get or create author as needed
for i in range(int(request.POST.get("author-match-count", 0))):
- match = request.POST.get("author_match-%d" % i)
+ match = request.POST.get(f"author_match-{i}")
if not match:
return HttpResponseBadRequest()
try:
# if it's an int, it's an ID
match = int(match)
author = get_object_or_404(
- models.Author, id=request.POST["author_match-%d" % i]
+ models.Author, id=request.POST[f"author_match-{i}"]
)
except ValueError:
# otherwise it's a name
@@ -267,7 +267,7 @@ class ConfirmEditBook(View):
for author_id in request.POST.getlist("remove_authors"):
book.authors.remove(author_id)
- return redirect("/book/%s" % book.id)
+ return redirect(f"/book/{book.id}")
@login_required
@@ -283,7 +283,7 @@ def upload_cover(request, book_id):
if image:
book.cover.save(*image)
- return redirect("{:s}?cover_error=True".format(book.local_path))
+ return redirect(f"{book.local_path}?cover_error=True")
form = forms.CoverForm(request.POST, request.FILES, instance=book)
if not form.is_valid() or not form.files.get("cover"):
From a74141ece4ebb5829734d50e6fbbfc5ff661cdc1 Mon Sep 17 00:00:00 2001
From: Mouse Reeve
Date: Mon, 20 Sep 2021 17:16:14 -0700
Subject: [PATCH 5/8] Adds site models tests
---
bookwyrm/tests/models/test_site.py | 95 ++++++++++++++++++++++++++++++
1 file changed, 95 insertions(+)
create mode 100644 bookwyrm/tests/models/test_site.py
diff --git a/bookwyrm/tests/models/test_site.py b/bookwyrm/tests/models/test_site.py
new file mode 100644
index 00000000..457bdf5e
--- /dev/null
+++ b/bookwyrm/tests/models/test_site.py
@@ -0,0 +1,95 @@
+""" testing models """
+from datetime import timedelta
+from unittest.mock import patch
+
+from django.db import IntegrityError
+from django.test import TestCase
+from django.utils import timezone
+
+from bookwyrm import models, settings
+
+
+class SiteModels(TestCase):
+ """tests for site models"""
+
+ def setUp(self):
+ """we need basic test data and mocks"""
+ with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
+ "bookwyrm.activitystreams.populate_stream_task.delay"
+ ):
+ self.local_user = models.User.objects.create_user(
+ "mouse@local.com",
+ "mouse@mouse.com",
+ "mouseword",
+ local=True,
+ localname="mouse",
+ remote_id="https://example.com/users/mouse",
+ )
+
+ def test_site_settings_absent(self):
+ """create and load site settings"""
+ self.assertFalse(models.SiteSettings.objects.exists())
+ result = models.SiteSettings.get()
+ self.assertTrue(models.SiteSettings.objects.exists())
+ self.assertEqual(result.id, 1)
+ self.assertEqual(result.name, "BookWyrm")
+
+ def test_site_settings_present(self):
+ """load site settings"""
+ models.SiteSettings.objects.create(name="Fish Town")
+ result = models.SiteSettings.get()
+ self.assertEqual(result.id, 1)
+ self.assertEqual(result.name, "Fish Town")
+ self.assertEqual(models.SiteSettings.objects.all().count(), 1)
+
+ def test_site_invite(self):
+ """default invite"""
+ invite = models.SiteInvite.objects.create(
+ user=self.local_user,
+ )
+ self.assertTrue(invite.valid())
+
+ def test_site_invite_with_limit(self):
+ """with use limit"""
+ # valid
+ invite = models.SiteInvite.objects.create(user=self.local_user, use_limit=1)
+ self.assertTrue(invite.valid())
+
+ # invalid
+ invite = models.SiteInvite.objects.create(user=self.local_user, use_limit=0)
+ self.assertFalse(invite.valid())
+ invite = models.SiteInvite.objects.create(
+ user=self.local_user, use_limit=1, times_used=1
+ )
+ self.assertFalse(invite.valid())
+
+ def test_site_invite_with_expiry(self):
+ """with expiration date"""
+ date = timezone.now() + timedelta(days=1)
+ invite = models.SiteInvite.objects.create(user=self.local_user, expiry=date)
+ self.assertTrue(invite.valid())
+
+ date = timezone.now() - timedelta(days=1)
+ invite = models.SiteInvite.objects.create(user=self.local_user, expiry=date)
+ self.assertFalse(invite.valid())
+
+ def test_site_invite_link(self):
+ """invite link generator"""
+ invite = models.SiteInvite.objects.create(user=self.local_user, code="hello")
+ self.assertEqual(invite.link, f"https://{settings.DOMAIN}/invite/hello")
+
+ def test_invite_request(self):
+ """someone wants an invite"""
+ # normal and good
+ request = models.InviteRequest.objects.create(email="mouse.reeve@gmail.com")
+ self.assertIsNone(request.invite)
+
+ # already in use
+ with self.assertRaises(IntegrityError):
+ request = models.InviteRequest.objects.create(email="mouse@mouse.com")
+
+ def test_password_reset(self):
+ """password reset token"""
+ token = models.PasswordReset.objects.create(user=self.local_user, code="hello")
+ self.assertTrue(token.valid())
+ self.assertEqual(token.link, f"https://{settings.DOMAIN}/password-reset/hello")
From 1be33c97a21dc6c104d17a11b280aa45774900de Mon Sep 17 00:00:00 2001
From: Mouse Reeve
Date: Mon, 20 Sep 2021 17:19:26 -0700
Subject: [PATCH 6/8] Fixes string formatting in site model
---
bookwyrm/models/site.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bookwyrm/models/site.py b/bookwyrm/models/site.py
index 72b077f4..8338fff8 100644
--- a/bookwyrm/models/site.py
+++ b/bookwyrm/models/site.py
@@ -127,7 +127,7 @@ class PasswordReset(models.Model):
@property
def link(self):
"""formats the invite link"""
- return "https://{DOMAIN}/password-reset/{self.code}"
+ return f"https://{DOMAIN}/password-reset/{self.code}"
# pylint: disable=unused-argument
From 90c74f00c9df701efd993cc0983ca182f27b3b0a Mon Sep 17 00:00:00 2001
From: Mouse Reeve
Date: Mon, 20 Sep 2021 17:40:59 -0700
Subject: [PATCH 7/8] Fixes missing f format in preview image string
plus a unit test for it
---
bookwyrm/preview_images.py | 2 +-
bookwyrm/tests/test_preview_images.py | 9 +++++++++
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/bookwyrm/preview_images.py b/bookwyrm/preview_images.py
index 17377f95..8224a278 100644
--- a/bookwyrm/preview_images.py
+++ b/bookwyrm/preview_images.py
@@ -415,7 +415,7 @@ def generate_user_preview_image_task(user_id):
texts = {
"text_one": user.display_name,
- "text_three": "@{user.localname}@{settings.DOMAIN}",
+ "text_three": f"@{user.localname}@{settings.DOMAIN}",
}
if user.avatar:
diff --git a/bookwyrm/tests/test_preview_images.py b/bookwyrm/tests/test_preview_images.py
index 760ff4c4..f95e623c 100644
--- a/bookwyrm/tests/test_preview_images.py
+++ b/bookwyrm/tests/test_preview_images.py
@@ -20,6 +20,7 @@ from bookwyrm.preview_images import (
# pylint: disable=unused-argument
# pylint: disable=missing-function-docstring
+# pylint: disable=consider-using-with
class PreviewImages(TestCase):
"""every response to a get request, html or json"""
@@ -120,3 +121,11 @@ class PreviewImages(TestCase):
self.assertEqual(
self.local_user.preview_image.height, settings.PREVIEW_IMG_HEIGHT
)
+
+ def test_generate_user_preview_images_task(self, *args, **kwargs):
+ """test task's external calls"""
+ with patch("bookwyrm.preview_images.generate_preview_image") as generate_mock:
+ generate_user_preview_image_task(self.local_user.id)
+ args = generate_mock.call_args.kwargs
+ self.assertEqual(args["texts"]["text_one"], "possum")
+ self.assertEqual(args["texts"]["text_three"], f"@possum@{settings.DOMAIN}")
From 673f49bf215020530b5a89b64be66acd3565bb3f Mon Sep 17 00:00:00 2001
From: Mouse Reeve
Date: Mon, 20 Sep 2021 18:01:12 -0700
Subject: [PATCH 8/8] Tests fixes
---
bookwyrm/models/status.py | 4 ++--
bookwyrm/tests/models/test_site.py | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py
index 0a51f6a3..c751e859 100644
--- a/bookwyrm/models/status.py
+++ b/bookwyrm/models/status.py
@@ -279,7 +279,7 @@ class Comment(BookStatus):
"""indicate the book in question for mastodon (or w/e) users"""
return (
f'{self.content}(comment on '
- '"{self.book.title}")
'
+ f'"{self.book.title}")'
)
activity_serializer = activitypub.Comment
@@ -307,7 +307,7 @@ class Quotation(BookStatus):
quote = re.sub(r"$", '"', quote)
return (
f'{quote} -- '
- '"{self.book.title}"
{self.content}'
+ f'"{self.book.title}"{self.content}'
)
activity_serializer = activitypub.Quotation
diff --git a/bookwyrm/tests/models/test_site.py b/bookwyrm/tests/models/test_site.py
index 457bdf5e..b7c19c4b 100644
--- a/bookwyrm/tests/models/test_site.py
+++ b/bookwyrm/tests/models/test_site.py
@@ -36,7 +36,7 @@ class SiteModels(TestCase):
def test_site_settings_present(self):
"""load site settings"""
- models.SiteSettings.objects.create(name="Fish Town")
+ models.SiteSettings.objects.create(id=1, name="Fish Town")
result = models.SiteSettings.get()
self.assertEqual(result.id, 1)
self.assertEqual(result.name, "Fish Town")