Skip to content

Commit

Permalink
Adds type checking for templatetags
Browse files Browse the repository at this point in the history
  • Loading branch information
mouse-reeve committed Aug 28, 2024
1 parent ef30c7c commit c23917a
Show file tree
Hide file tree
Showing 18 changed files with 95 additions and 68 deletions.
8 changes: 6 additions & 2 deletions bookwyrm/models/book.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
""" database schema for books and shelves """
from __future__ import annotations

from itertools import chain
import re
from typing import Any, Dict, Optional, Iterable
from typing import Any, Dict, Optional, Iterable, TYPE_CHECKING
from typing_extensions import Self

from django.contrib.postgres.search import SearchVectorField
Expand Down Expand Up @@ -33,6 +34,9 @@
from .base_model import BookWyrmModel
from . import fields

if TYPE_CHECKING:
from bookwyrm.models import Author


class BookDataModel(ObjectMixin, BookWyrmModel):
"""fields shared between editable book data (books, works, authors)"""
Expand Down Expand Up @@ -415,7 +419,7 @@ def default_edition(self):
"""in case the default edition is not set"""
return self.editions.order_by("-edition_rank").first()

def author_edition(self, author):
def author_edition(self, author: Author) -> Any:
"""in case the default edition doesn't have the required author"""
return self.editions.filter(authors=author).order_by("-edition_rank").first()

Expand Down
12 changes: 8 additions & 4 deletions bookwyrm/templatetags/book_display_tags.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
""" template filters """
from typing import Any
from django import template
from django.db.models import QuerySet
from bookwyrm import models


register = template.Library()


@register.filter(name="review_count")
def get_review_count(book):
def get_review_count(book: models.Edition) -> int:
"""how many reviews?"""
return models.Review.objects.filter(deleted=False, book=book).count()


@register.filter(name="book_description")
def get_book_description(book):
def get_book_description(book: models.Edition) -> Any:
"""use the work's text if the book doesn't have it"""
if book.description:
return book.description
Expand All @@ -24,12 +26,14 @@ def get_book_description(book):


@register.simple_tag(takes_context=False)
def get_book_file_links(book):
def get_book_file_links(book: models.Edition) -> QuerySet[models.FileLink]:
"""links for a book"""
return book.file_links.filter(domain__status="approved")


@register.filter(name="author_edition")
def get_author_edition(book, author):
def get_author_edition(
book: models.Work, author: models.Author
) -> Any:
"""default edition for a book on the author page"""
return book.author_edition(author)
6 changes: 3 additions & 3 deletions bookwyrm/templatetags/celery_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@


@register.filter(name="uptime")
def uptime(seconds):
def uptime(seconds: float) -> str:
"""Seconds uptime to a readable format"""
return str(datetime.timedelta(seconds=seconds))


@register.filter(name="runtime")
def runtime(timestamp):
def runtime(timestamp: float) -> datetime.timedelta:
"""How long has it been?"""
return datetime.datetime.now() - datetime.datetime.fromtimestamp(timestamp)


@register.filter(name="shortname")
def shortname(name):
def shortname(name: str) -> str:
"""removes bookwyrm.celery..."""
return ".".join(name.split(".")[-2:])
4 changes: 3 additions & 1 deletion bookwyrm/templatetags/date_ext.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
""" additional formatting of dates """
from typing import Any

from django import template
from django.template import defaultfilters
from django.contrib.humanize.templatetags.humanize import naturalday
Expand All @@ -9,7 +11,7 @@


@register.filter(expects_localtime=True)
def naturalday_partial(date, arg=None):
def naturalday_partial(date: Any, arg: Any = None) -> str | None:
"""chooses appropriate precision if date is a PartialDate object
If arg is a Django-defined format such as "DATE_FORMAT", it will be adjusted
Expand Down
6 changes: 4 additions & 2 deletions bookwyrm/templatetags/feed_page_tags.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
""" tags used on the feed pages """
from typing import Any
from django import template
from bookwyrm.views.feed import get_suggested_books
from bookwyrm import models


register = template.Library()


@register.filter(name="load_subclass")
def load_subclass(status):
def load_subclass(status: models.Status) -> models.Status:
"""sometimes you didn't select_subclass"""
if hasattr(status, "quotation"):
return status.quotation
Expand All @@ -21,7 +23,7 @@ def load_subclass(status):


@register.simple_tag(takes_context=True)
def suggested_books(context):
def suggested_books(context: dict[str, Any]) -> Any:
"""get books for suggested books panel"""
# this happens here instead of in the view so that the template snippet can
# be cached in the template
Expand Down
6 changes: 3 additions & 3 deletions bookwyrm/templatetags/group_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,21 @@


@register.filter(name="has_groups")
def has_groups(user):
def has_groups(user: models.User) -> bool:
"""whether or not the user has a pending invitation to join this group"""

return models.GroupMember.objects.filter(user=user).exists()


@register.filter(name="is_member")
def is_member(group, user):
def is_member(group: models.Group, user: models.User) -> bool:
"""whether or not the user is a member of this group"""

return models.GroupMember.objects.filter(group=group, user=user).exists()


@register.filter(name="is_invited")
def is_invited(group, user):
def is_invited(group: models.Group, user: models.User) -> bool:
"""whether or not the user has a pending invitation to join this group"""

return models.GroupMemberInvitation.objects.filter(group=group, user=user).exists()
13 changes: 8 additions & 5 deletions bookwyrm/templatetags/interaction.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
""" template filters for status interaction buttons """
from typing import Any
from django import template

from bookwyrm import models
Expand All @@ -9,7 +10,7 @@


@register.filter(name="liked")
def get_user_liked(user, status):
def get_user_liked(user: models.User, status: models.Status) -> Any:
"""did the given user fav a status?"""
return get_or_set(
f"fav-{user.id}-{status.id}",
Expand All @@ -21,7 +22,7 @@ def get_user_liked(user, status):


@register.filter(name="boosted")
def get_user_boosted(user, status):
def get_user_boosted(user: models.User, status: models.Status) -> Any:
"""did the given user fav a status?"""
return get_or_set(
f"boost-{user.id}-{status.id}",
Expand All @@ -32,13 +33,13 @@ def get_user_boosted(user, status):


@register.filter(name="saved")
def get_user_saved_lists(user, book_list):
def get_user_saved_lists(user: models.User, book_list: models.List) -> bool:
"""did the user save a list"""
return user.saved_lists.filter(id=book_list.id).exists()


@register.simple_tag(takes_context=True)
def get_relationship(context, user_object):
def get_relationship(context: dict[str, Any], user_object: models.User) -> Any:
"""caches the relationship between the logged in user and another user"""
user = context["request"].user
return get_or_set(
Expand All @@ -50,7 +51,9 @@ def get_relationship(context, user_object):
)


def get_relationship_name(user, user_object):
def get_relationship_name(
user: models.User, user_object: models.User
) -> dict[str, bool]:
"""returns the relationship type"""
types = {
"is_following": False,
Expand Down
7 changes: 4 additions & 3 deletions bookwyrm/templatetags/landing_page_tags.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
""" template filters """
from typing import Optional
from django import template
from django.db.models import Avg, StdDev, Count, F, Q
from django.db.models import Avg, StdDev, Count, F, Q, QuerySet

from bookwyrm import models

register = template.Library()


@register.simple_tag(takes_context=False)
def get_book_superlatives():
def get_book_superlatives() -> dict[str, Optional[models.Work]]:
"""get book stats for the about page"""
total_ratings = models.Review.objects.filter(local=True, deleted=False).count()
data = {}
Expand Down Expand Up @@ -67,7 +68,7 @@ def get_book_superlatives():


@register.simple_tag(takes_context=False)
def get_landing_books():
def get_landing_books() -> list[QuerySet[models.Edition]]:
"""list of books for the landing page"""
return list(
set(
Expand Down
2 changes: 1 addition & 1 deletion bookwyrm/templatetags/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@


@register.simple_tag(takes_context=False)
def get_lang():
def get_lang() -> str:
"""get current language, strip to the first two letters"""
language = utils.translation.get_language()
return language[0 : language.find("-")]
3 changes: 2 additions & 1 deletion bookwyrm/templatetags/markdown.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
""" template filters """
from typing import Any
from django import template
from bookwyrm.views.status import to_markdown

Expand All @@ -7,7 +8,7 @@


@register.filter(name="to_markdown")
def get_markdown(content):
def get_markdown(content: str) -> Any:
"""convert markdown to html"""
if content:
return to_markdown(content)
Expand Down
6 changes: 4 additions & 2 deletions bookwyrm/templatetags/notification_page_tags.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
""" tags used on the feed pages """
from typing import Optional
from django import template
from bookwyrm import models
from bookwyrm.templatetags.feed_page_tags import load_subclass


register = template.Library()


@register.simple_tag(takes_context=False)
def related_status(notification):
def related_status(notification: models.Notification) -> Optional[models.Status]:
"""for notifications"""
if not notification.related_status:
return None
return load_subclass(notification.related_status)


@register.simple_tag(takes_context=False)
def get_related_users(notification):
def get_related_users(notification: models.Notification) -> list[models.User]:
"""Who actually was it who liked your post"""
return list(reversed(list(notification.related_users.distinct())))[:10]
5 changes: 3 additions & 2 deletions bookwyrm/templatetags/rating_tags.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
""" template filters """
from typing import Any
from django import template
from django.db.models import Avg

Expand All @@ -10,7 +11,7 @@


@register.filter(name="rating")
def get_rating(book, user):
def get_rating(book: models.Edition, user: models.User) -> Any:
"""get the overall rating of a book"""
# this shouldn't happen, but it CAN
if not book.parent_work:
Expand All @@ -29,7 +30,7 @@ def get_rating(book, user):


@register.filter(name="user_rating")
def get_user_rating(book, user):
def get_user_rating(book: models.Edition, user: models.User) -> Any:
"""get a user's rating of a book"""
rating = (
models.Review.objects.filter(
Expand Down
12 changes: 7 additions & 5 deletions bookwyrm/templatetags/shelf_tags.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
""" Filters and tags related to shelving books """
from typing import Any
from django import template
from django.utils.translation import gettext_lazy as _
from django_stubs_ext import StrPromise

from bookwyrm import models
from bookwyrm.utils import cache
Expand All @@ -19,7 +21,7 @@


@register.filter(name="is_book_on_shelf")
def get_is_book_on_shelf(book, shelf):
def get_is_book_on_shelf(book: models.Edition, shelf: models.Shelf) -> Any:
"""is a book on a shelf"""
return cache.get_or_set(
f"book-on-shelf-{book.id}-{shelf.id}",
Expand All @@ -31,7 +33,7 @@ def get_is_book_on_shelf(book, shelf):


@register.filter(name="next_shelf")
def get_next_shelf(current_shelf):
def get_next_shelf(current_shelf: str) -> str:
"""shelf you'd use to update reading progress"""
if current_shelf == "to-read":
return "reading"
Expand All @@ -45,7 +47,7 @@ def get_next_shelf(current_shelf):


@register.filter(name="translate_shelf_name")
def get_translated_shelf_name(shelf):
def get_translated_shelf_name(shelf: models.Shelf | dict[str, str]) -> str | StrPromise:
"""produce translated shelf identifiername"""
if not shelf:
return ""
Expand All @@ -59,7 +61,7 @@ def get_translated_shelf_name(shelf):


@register.simple_tag(takes_context=True)
def active_shelf(context, book):
def active_shelf(context: dict[str, Any], book: models.Edition) -> Any:
"""check what shelf a user has a book on, if any"""
user = context["request"].user
return cache.get_or_set(
Expand All @@ -78,7 +80,7 @@ def active_shelf(context, book):


@register.simple_tag(takes_context=False)
def latest_read_through(book, user):
def latest_read_through(book: models.Edition, user: models.User) -> Any:
"""the most recent read activity"""
return cache.get_or_set(
f"latest_read_through-{user.id}-{book.id}",
Expand Down
2 changes: 1 addition & 1 deletion bookwyrm/templatetags/stars.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@


@register.filter(name="half_star")
def get_half_star(value):
def get_half_star(value: str) -> str:
"""one of those things that's weirdly hard with templates"""
return f"{value}.5"
Loading

0 comments on commit c23917a

Please sign in to comment.