diff --git a/funnel/models/account.py b/funnel/models/account.py index 9945a9986..57a47c28b 100644 --- a/funnel/models/account.py +++ b/funnel/models/account.py @@ -986,6 +986,7 @@ def ticket_followers(self) -> Query[Account]: 'is_verified', }, } + __json_datasets__ = ('primary', 'related') profile_state.add_conditional_state( 'ACTIVE_AND_PUBLIC', diff --git a/funnel/models/comment.py b/funnel/models/comment.py index 0213ab45e..22507732e 100644 --- a/funnel/models/comment.py +++ b/funnel/models/comment.py @@ -383,6 +383,7 @@ class Comment(UuidMixin, BaseMixin[int, Account], Model): 'json': {'created_at', 'urls', 'uuid_b58', 'absolute_url'}, 'minimal': {'created_at', 'uuid_b58'}, } + __json_datasets__ = ('json',) def __init__(self, **kwargs) -> None: super().__init__(**kwargs) diff --git a/funnel/models/helpers.py b/funnel/models/helpers.py index a94f13109..d8c3a458d 100644 --- a/funnel/models/helpers.py +++ b/funnel/models/helpers.py @@ -140,15 +140,17 @@ class IntTitle(DataclassFromType, int): """Integer value with a title (for enums).""" - title: str + # The empty default is required for Mypy's enum plugin's `Enum.__call__` analysis + title: str = '' @dataclass(frozen=True) class IntNameTitle(DataclassFromType, int): """Integer value with a name and title (for enums).""" - name: str - title: str + # The empty default is required for Mypy's enum plugin's `Enum.__call__` analysis + name: str = '' + title: str = '' @dataclass diff --git a/funnel/models/notification.py b/funnel/models/notification.py index f3df660fa..335b32386 100644 --- a/funnel/models/notification.py +++ b/funnel/models/notification.py @@ -735,7 +735,7 @@ def __init__( # pylint: disable=super-init-not-called self.fragment_uuid = fragment.uuid if fragment is not None else None self.created_at = utcnow() self.created_by = user - self.created_by_id = cast(int, user.id) if user is not None else None + self.created_by_id = user.id if user is not None else None def __getattr__(self, attr: str) -> Any: """Get an attribute.""" diff --git a/funnel/views/notification.py b/funnel/views/notification.py index bfdb9f14a..72a529365 100644 --- a/funnel/views/notification.py +++ b/funnel/views/notification.py @@ -9,7 +9,7 @@ from email.utils import formataddr from functools import wraps from itertools import islice -from typing import Any, ClassVar, Literal +from typing import Any, ClassVar, Literal, cast from uuid import UUID, uuid4 from flask import url_for @@ -319,19 +319,21 @@ def fragments_order_by(self) -> list[sa.UnaryExpression]: ] @property - def fragments_query_options(self) -> list: # TODO: full spec + def fragments_query_options(self) -> Sequence: """Provide a list of SQLAlchemy options for loading fragments.""" return [] @cached_property - def fragments(self) -> list[RoleAccessProxy[ModelUuidProtocol]]: + def fragments( + self, + ) -> list[RoleAccessProxy[ModelUuidProtocol]]: # type: ignore[type-var] # FIXME query = self.notification_recipient.rolledup_fragments() if query is None: return [] query = query.order_by(*self.fragments_order_by) - if self.fragments_query_options: - query = query.options(*self.fragments_query_options) + if query_options := self.fragments_query_options: + query = query.options(*query_options) return [ _f.access_for(actor=self.notification_recipient.recipient) @@ -366,7 +368,7 @@ def web(self) -> str: @property def email_base_url(self) -> str: """Base URL for relative links in email.""" - return self.notification.role_provider_obj.absolute_url + return cast(str, self.notification.role_provider_obj.absolute_url) def email_subject(self) -> str: """ diff --git a/funnel/views/notifications/proposal_notification.py b/funnel/views/notifications/proposal_notification.py index 306e98843..9a13ec1c9 100644 --- a/funnel/views/notifications/proposal_notification.py +++ b/funnel/views/notifications/proposal_notification.py @@ -2,6 +2,8 @@ from __future__ import annotations +from collections.abc import Sequence + from flask import render_template from werkzeug.utils import cached_property @@ -76,7 +78,7 @@ def fragments_order_by(self) -> list[sa.UnaryExpression]: return [Proposal.datetime.desc()] @property - def fragments_query_options(self): + def fragments_query_options(self) -> Sequence: return [ sa_orm.load_only( Proposal.name, Proposal.title, Proposal.project_id, Proposal.uuid