From 6b1b17bb85bf60e06b7bb4ffafaa8e9c768d7743 Mon Sep 17 00:00:00 2001 From: Kiran Jonnalagadda Date: Wed, 3 Jan 2024 20:59:21 +0530 Subject: [PATCH] Resolved membership model typing issues --- funnel/models/account.py | 7 +- funnel/models/account_membership.py | 4 +- funnel/models/comment.py | 2 +- funnel/models/commentset_membership.py | 4 +- funnel/models/membership_mixin.py | 219 +++++++++--------- funnel/models/project_membership.py | 6 +- funnel/models/proposal.py | 4 +- funnel/models/proposal_membership.py | 13 +- funnel/models/reorder_mixin.py | 48 ++-- funnel/models/site_membership.py | 8 +- funnel/models/sponsor_membership.py | 20 +- funnel/views/search.py | 2 +- ...8b_complement_email_md5sum_with_blake2b.py | 6 +- .../1c9cbf3a1e5e_add_commenset_memberships.py | 18 +- ...c10efdbce_deprecate_session_speaker_bio.py | 2 +- ...7_uuid_columns_for_proposal_and_session.py | 4 +- ...321b11b6a413_add_participant_uuid_field.py | 2 +- ..._drop_support_for_128_bit_blake2b_hash_.py | 4 +- .../63c44675b6cd_migrate_to_phonenumber.py | 8 +- .../versions/69c2ced88981_team_org_uuid.py | 4 +- .../versions/7f8114c73092_add_rsvp_uuid.py | 2 +- .../887db555cca9_adding_uuid_to_commentset.py | 2 +- .../ad5013552ec6_simplify_proposal_fields.py | 2 +- .../ae075a249493_migrate_email_addresses.py | 16 +- .../aebd5a9e5af1_project_timestamps.py | 2 +- ...d_columns_for_project_profile_user_team.py | 14 +- .../c3069d33419a_comment_uuid_field.py | 2 +- ...populate_usersession_geonameid_from_ip_.py | 2 +- ...2b28adfa135_add_proposal_suuid_redirect.py | 2 +- .../e2be4ab896d3_migrate_old_labels.py | 4 +- ...9_move_participant_to_emailaddressmixin.py | 4 +- .../versions/eec2fad0f3e9_venue_uuid_field.py | 2 +- ...a05ebecbc0f_populate_proposalmembership.py | 2 +- 33 files changed, 221 insertions(+), 220 deletions(-) diff --git a/funnel/models/account.py b/funnel/models/account.py index a33907d42..0f08e688a 100644 --- a/funnel/models/account.py +++ b/funnel/models/account.py @@ -1428,7 +1428,10 @@ def do_delete(self): # 2. Revoke all active memberships for membership in self.active_memberships(): - membership = membership.freeze_member_attribution(self) + if callable( + freeze := getattr(membership, 'freeze_member_attribution', None) + ): + membership = freeze(self) if membership.revoke_on_member_delete: membership.revoke(actor=self) # TODO: freeze fullname in unrevoked memberships (pending title column there) @@ -1498,7 +1501,7 @@ def uuid_zbase32(self) -> str: @classmethod def _uuid_zbase32_comparator(cls) -> ZBase32Comparator: """Return SQL comparator for :prop:`uuid_zbase32`.""" - return ZBase32Comparator(cls.uuid) + return ZBase32Comparator(cls.uuid) # type: ignore[arg-type] @classmethod def name_is(cls, name: str) -> ColumnElement: diff --git a/funnel/models/account_membership.py b/funnel/models/account_membership.py index 53c30ffab..d9f91aeda 100644 --- a/funnel/models/account_membership.py +++ b/funnel/models/account_membership.py @@ -8,12 +8,12 @@ from . import Mapped, Model, relationship, sa, sa_orm from .account import Account -from .membership_mixin import ImmutableUserMembershipMixin +from .membership_mixin import ImmutableMembershipMixin __all__ = ['AccountMembership'] -class AccountMembership(ImmutableUserMembershipMixin, Model): +class AccountMembership(ImmutableMembershipMixin, Model): """ An account can be a member of another account as an owner, admin or follower. diff --git a/funnel/models/comment.py b/funnel/models/comment.py index 3cedcb03f..fff72671b 100644 --- a/funnel/models/comment.py +++ b/funnel/models/comment.py @@ -416,7 +416,7 @@ def posted_by(self) -> Account | DuckTypeAccount: def _posted_by_setter(self, value: Account | None) -> None: self._posted_by = value - @posted_by.inplace.expression + @posted_by.inplace.expression # type: ignore[arg-type] @classmethod def _posted_by_expression(cls) -> sa_orm.InstrumentedAttribute[Account | None]: """Return SQL Expression.""" diff --git a/funnel/models/commentset_membership.py b/funnel/models/commentset_membership.py index 00e123b4b..c4b8683d1 100644 --- a/funnel/models/commentset_membership.py +++ b/funnel/models/commentset_membership.py @@ -9,7 +9,7 @@ from . import Mapped, Model, Query, relationship, sa, sa_orm from .account import Account -from .membership_mixin import ImmutableUserMembershipMixin +from .membership_mixin import ImmutableMembershipMixin from .project import Project from .proposal import Proposal from .update import Update @@ -17,7 +17,7 @@ __all__ = ['CommentsetMembership'] -class CommentsetMembership(ImmutableUserMembershipMixin, Model): +class CommentsetMembership(ImmutableMembershipMixin, Model): """Membership roles for users who are commentset users and subscribers.""" __tablename__ = 'commentset_membership' diff --git a/funnel/models/membership_mixin.py b/funnel/models/membership_mixin.py index f906716d2..c5d32f136 100644 --- a/funnel/models/membership_mixin.py +++ b/funnel/models/membership_mixin.py @@ -19,7 +19,6 @@ from . import ( BaseMixin, Mapped, - Model, UuidMixin, db, declarative_mixin, @@ -31,7 +30,7 @@ ) from .account import Account from .helpers import IntTitle -from .reorder_mixin import ReorderProtoMixin +from .reorder_mixin import ReorderMixin # Export only symbols needed in views. __all__ = [ @@ -47,15 +46,37 @@ class MembershipMixinProtocol(Protocol): - _title: declared_attr[str | None] + member_id: Mapped[int] member: declared_attr[Account] _local_data_only: bool + parent_id_column: ClassVar[str] def replace(self, actor: Account, **data: Any) -> Self: ... +class FrozenAttributionSubclassProtocol(MembershipMixinProtocol, Protocol): + _title: declared_attr[str | None] + + +class ReorderSubclassProtocol(Protocol): + seq: Mapped[Any] + parent_id: Mapped[Any] + parent: Mapped[Any] + is_active: hybrid_property[bool] + + @property + def parent_scoped_reorder_query_filter( + self: ReorderSubclassProtocol, + ) -> ColumnElement[bool]: + ... + + MembershipMixinType = TypeVar('MembershipMixinType', bound=MembershipMixinProtocol) +FrozenAttributionType = TypeVar( + 'FrozenAttributionType', bound=FrozenAttributionSubclassProtocol +) + # --- Enum ----------------------------------------------------------------------------- @@ -98,22 +119,80 @@ class MembershipRecordTypeError(MembershipError): class ImmutableMembershipMixin(UuidMixin, BaseMixin[UUID, Account]): """Support class for immutable memberships.""" - #: Can granted_by be null? Only in memberships based on legacy data - __null_granted_by__: ClassVar[bool] = False - #: List of columns that will be copied into a new row when a membership is amended - __data_columns__: ClassVar[Iterable[str]] = () - #: Name of the parent id column, used in SQL constraints - parent_id_column: ClassVar[str | None] if TYPE_CHECKING: #: Subclass has a table name __tablename__: str #: Parent column (declare as synonym of 'profile_id' or 'project_id' in #: subclasses) - parent_id: Mapped[int] | None + parent_id: Mapped[Any] | None #: Parent object - parent: Mapped[Model] | None - #: Subject of this membership (subclasses must define) - member: declared_attr[Account] + parent: Mapped[Any] | None + + #: Can granted_by be null? Only in memberships based on legacy data + __null_granted_by__: ClassVar[bool] = False + #: List of columns that will be copied into a new row when a membership is amended + __data_columns__: ClassVar[Iterable[str]] = () + #: Name of the parent id column, used in SQL constraints + parent_id_column: ClassVar[str] + #: Foreign key column to account table + member_id: Mapped[int] = sa_orm.mapped_column( + sa.ForeignKey('account.id', ondelete='CASCADE'), + default=None, + nullable=False, + index=True, + ) + + @classmethod + def __member(cls) -> Mapped[Account]: + """Member in this membership record.""" + return relationship(Account, foreign_keys=[cls.member_id]) + + member = with_roles( + declared_attr(__member), + read={'member', 'editor'}, + grants_via={None: {'admin': 'member'}}, + ) + del __member + + @declared_attr + @classmethod + def user(cls) -> Mapped[Account]: + """Legacy alias for member in this membership record.""" + return sa_orm.synonym('member') + + __table_args__: tuple # pyright: ignore[reportGeneralTypeIssues] + + @declared_attr.directive # type: ignore[no-redef] + @classmethod + def __table_args__(cls) -> tuple: + """Table arguments for SQLAlchemy.""" + try: + args = list(super().__table_args__) # type: ignore[misc] + except AttributeError: + args = [] + kwargs = args.pop(-1) if args and isinstance(args[-1], dict) else None + if cls.parent_id_column: + args.append( + sa.Index( + 'ix_' + cls.__tablename__ + '_active', + cls.parent_id_column, + 'member_id', + unique=True, + postgresql_where='revoked_at IS NULL', + ), + ) + else: + args.append( + sa.Index( + 'ix_' + cls.__tablename__ + '_active', + 'member_id', + unique=True, + postgresql_where='revoked_at IS NULL', + ), + ) + if kwargs: + args.append(kwargs) + return tuple(args) #: Should an active membership record be revoked when the member is soft-deleted? #: (Hard deletes will cascade and also delete all membership records.) @@ -257,10 +336,6 @@ def revoke(self, actor: Account) -> None: self.revoked_at = sa.func.utcnow() self.revoked_by = actor - def copy_template(self, **kwargs) -> Self: - """Make a copy of self for customization.""" - raise NotImplementedError("Subclasses must implement copy_template") - @with_roles(call={'editor'}) def replace(self, actor: Account, _accept: bool = False, **data: Any) -> Self: """Replace this membership record with changes to role columns.""" @@ -366,74 +441,6 @@ def accept(self, actor: Account) -> Self: raise ValueError("Invite must be accepted by the invited user") return self.replace(actor, _accept=True) - @with_roles(call={'owner', 'member'}) - def freeze_member_attribution(self, actor: Account) -> Self: - """ - Freeze member attribution and return a replacement record. - - Subclasses that support member attribution must override this method. The - default implementation returns `self`. - """ - return self - - -@declarative_mixin -class ImmutableUserMembershipMixin(ImmutableMembershipMixin): - """Support class for immutable memberships for users.""" - - #: Foreign key column to account table - member_id: Mapped[int] = sa_orm.mapped_column( - sa.ForeignKey('account.id', ondelete='CASCADE'), - default=None, - nullable=False, - index=True, - ) - - @with_roles(read={'member', 'editor'}, grants_via={None: {'admin': 'member'}}) - @declared_attr - @classmethod - def member(cls) -> Mapped[Account]: - """Member in this membership record.""" - return relationship(Account, foreign_keys=[cls.member_id]) - - @declared_attr - @classmethod - def user(cls) -> Mapped[Account]: - """Legacy alias for member in this membership record.""" - return sa_orm.synonym('member') - - @declared_attr.directive - @classmethod - def __table_args__(cls) -> tuple: - """Table arguments for SQLAlchemy.""" - try: - args = list(super().__table_args__) # type: ignore[misc] - except AttributeError: - args = [] - kwargs = args.pop(-1) if args and isinstance(args[-1], dict) else None - if cls.parent_id_column is not None: - args.append( - sa.Index( - 'ix_' + cls.__tablename__ + '_active', - cls.parent_id_column, - 'member_id', - unique=True, - postgresql_where='revoked_at IS NULL', - ), - ) - else: - args.append( - sa.Index( - 'ix_' + cls.__tablename__ + '_active', - 'member_id', - unique=True, - postgresql_where='revoked_at IS NULL', - ), - ) - if kwargs: - args.append(kwargs) - return tuple(args) - @hybrid_property def is_self_granted(self) -> bool: """Return True if the member in this record is also the granting actor.""" @@ -453,6 +460,7 @@ def is_self_revoked(self) -> bool: with_roles(is_self_revoked, read={'member', 'editor'}) def copy_template(self, **kwargs) -> Self: + """Make a copy of self for customization.""" return self.__class__(member=self.member, **kwargs) # type: ignore[call-arg] @classmethod @@ -508,14 +516,9 @@ def migrate_account(cls, old_account: Account, new_account: Account) -> None: @declarative_mixin -class ReorderMembershipProtoMixin(ReorderProtoMixin): +class ReorderMembershipMixin(ImmutableMembershipMixin, ReorderMixin): """Customizes ReorderMixin for membership models.""" - if TYPE_CHECKING: - parent_id_column: ClassVar[str] - parent: Any - is_active: hybrid_property[bool] - #: Sequence number. Not immutable, and may be overwritten by ReorderMixin as a #: side-effect of reordering other records. This is not considered a revision. #: However, it can be argued that relocating a sponsor in the list constitutes a @@ -523,19 +526,21 @@ class ReorderMembershipProtoMixin(ReorderProtoMixin): #: on `seq` being mutable in a future iteration. seq: Mapped[int] = sa_orm.mapped_column(nullable=False) - @declared_attr.directive + __table_args__: tuple # pyright: ignore[reportGeneralTypeIssues] + + @declared_attr.directive # type: ignore[no-redef] @classmethod - def __table_args__(cls) -> tuple: + def __table_args__(cls) -> tuple: # type: ignore[override] """Table arguments.""" try: - args = list(super().__table_args__) # type: ignore[misc] + args = list(super().__table_args__) except AttributeError: args = [] kwargs = args.pop(-1) if args and isinstance(args[-1], dict) else None # Add unique constraint on :attr:`seq` for active records args.append( sa.Index( - 'ix_' + cls.__tablename__ + '_seq', # type: ignore[attr-defined] + 'ix_' + cls.__tablename__ + '_seq', cls.parent_id_column, 'seq', unique=True, @@ -546,18 +551,20 @@ def __table_args__(cls) -> tuple: args.append(kwargs) return tuple(args) - def __init__(self, **kwargs) -> None: + def __init__(self: ReorderSubclassProtocol, **kwargs) -> None: super().__init__(**kwargs) # Assign a default value to `seq` if self.seq is None: # Will be None until first commit - self.seq = ( # type: ignore[unreachable] + self.seq = ( sa.select(sa.func.coalesce(sa.func.max(self.__class__.seq) + 1, 1)) .where(self.parent_scoped_reorder_query_filter) .scalar_subquery() ) @property - def parent_scoped_reorder_query_filter(self) -> ColumnElement: + def parent_scoped_reorder_query_filter( + self: ReorderSubclassProtocol, + ) -> ColumnElement[bool]: """ Return a query filter that includes a scope limitation to active records. @@ -583,9 +590,8 @@ def parent_scoped_reorder_query_filter(self) -> ColumnElement: class FrozenAttributionMixin: """Provides a `title` data column and support method to freeze it.""" - @declared_attr @classmethod - def _title(cls) -> Mapped[str | None]: + def __title(cls) -> Mapped[str | None]: """Create optional attribution title for this membership record.""" return immutable( sa_orm.mapped_column( @@ -593,8 +599,11 @@ def _title(cls) -> Mapped[str | None]: ) ) + _title = declared_attr(__title) + del __title + @property - def title(self: MembershipMixinProtocol) -> str: + def title(self: FrozenAttributionSubclassProtocol) -> str: """Attribution title for this record.""" if self._local_data_only: # self._title may be None when returning local data @@ -609,14 +618,14 @@ def title(self, value: str | None) -> None: self._title = value or None # Don't set empty string @property - def pickername(self: MembershipMixinProtocol) -> str: + def pickername(self: FrozenAttributionSubclassProtocol) -> str: """Return member's pickername, but only if attribution isn't frozen.""" return self._title if self._title else self.member.pickername @with_roles(call={'owner', 'member'}) def freeze_member_attribution( - self: MembershipMixinType, actor: Account - ) -> MembershipMixinType: + self: FrozenAttributionType, actor: Account + ) -> FrozenAttributionType: """Freeze member attribution and return a replacement record.""" if self._title is None: membership = self.replace(actor=actor, title=self.member.title) @@ -695,7 +704,7 @@ def _confirm_enumerated_mixins(_mapper: Any, cls: type[Account]) -> None: """Confirm that the membership collection attributes actually exist.""" expected_class = ImmutableMembershipMixin if issubclass(cls, Account): - expected_class = ImmutableUserMembershipMixin + expected_class = ImmutableMembershipMixin for source in ( cls.__active_membership_attrs__, cls.__noninvite_membership_attrs__, diff --git a/funnel/models/project_membership.py b/funnel/models/project_membership.py index 8ba8e0fa7..60a146bc6 100644 --- a/funnel/models/project_membership.py +++ b/funnel/models/project_membership.py @@ -7,7 +7,7 @@ from coaster.sqlalchemy import immutable, with_roles from . import Mapped, Model, declared_attr, relationship, sa, sa_orm -from .membership_mixin import ImmutableUserMembershipMixin +from .membership_mixin import ImmutableMembershipMixin from .project import Project __all__ = ['ProjectMembership', 'project_child_role_map', 'project_child_role_set'] @@ -35,7 +35,7 @@ ) -class ProjectMembership(ImmutableUserMembershipMixin, Model): +class ProjectMembership(ImmutableMembershipMixin, Model): """Users can be crew members of projects, with specified access rights.""" __tablename__ = 'project_membership' @@ -137,7 +137,7 @@ class ProjectMembership(ImmutableUserMembershipMixin, Model): @declared_attr.directive @classmethod - def __table_args__(cls) -> tuple: + def __table_args__(cls) -> tuple: # type: ignore[override] """Table arguments.""" try: args = list(super().__table_args__) diff --git a/funnel/models/proposal.py b/funnel/models/proposal.py index 8775374ac..6ba4d64db 100644 --- a/funnel/models/proposal.py +++ b/funnel/models/proposal.py @@ -42,7 +42,7 @@ from .label import Label, ProposalLabelProxy, proposal_label from .project import Project from .project_membership import project_child_role_map -from .reorder_mixin import ReorderProtoMixin +from .reorder_mixin import ReorderMixin from .video_mixin import VideoMixin __all__ = ['PROPOSAL_STATE', 'Proposal', 'ProposalSuuidRedirect'] @@ -127,7 +127,7 @@ class PROPOSAL_STATE(LabeledEnum): # noqa: N801 # --- Models ------------------------------------------------------------------ -class Proposal(UuidMixin, BaseScopedIdNameMixin, VideoMixin, ReorderProtoMixin, Model): +class Proposal(UuidMixin, BaseScopedIdNameMixin, VideoMixin, ReorderMixin, Model): __tablename__ = 'proposal' created_by_id: Mapped[int] = sa_orm.mapped_column( diff --git a/funnel/models/proposal_membership.py b/funnel/models/proposal_membership.py index 91d938e7c..3d01df05b 100644 --- a/funnel/models/proposal_membership.py +++ b/funnel/models/proposal_membership.py @@ -9,22 +9,13 @@ from coaster.sqlalchemy import immutable, with_roles from . import Mapped, Model, relationship, sa, sa_orm -from .membership_mixin import ( - FrozenAttributionMixin, - ImmutableUserMembershipMixin, - ReorderMembershipProtoMixin, -) +from .membership_mixin import FrozenAttributionMixin, ReorderMembershipMixin from .proposal import Proposal __all__ = ['ProposalMembership'] -class ProposalMembership( # type: ignore[misc] # FIXME - FrozenAttributionMixin, - ImmutableUserMembershipMixin, - ReorderMembershipProtoMixin, - Model, -): +class ProposalMembership(FrozenAttributionMixin, ReorderMembershipMixin, Model): """Users can be presenters or reviewers on proposals.""" __tablename__ = 'proposal_membership' diff --git a/funnel/models/reorder_mixin.py b/funnel/models/reorder_mixin.py index 0d3006391..055554cf6 100644 --- a/funnel/models/reorder_mixin.py +++ b/funnel/models/reorder_mixin.py @@ -2,41 +2,43 @@ from __future__ import annotations -from datetime import datetime -from typing import TYPE_CHECKING, Any, ClassVar, TypeVar +from typing import Any, Protocol, TypeVar -from . import Mapped, QueryProperty, db, declarative_mixin, declared_attr, sa, sa_orm +from . import Mapped, db, declarative_mixin, sa, sa_orm +from .typing import ModelIdProtocol -__all__ = ['ReorderProtoMixin'] +__all__ = ['ReorderMixin'] # Use of TypeVar for subclasses of ReorderMixin as defined in these mypy tickets: # https://github.com/python/mypy/issues/1212 # https://github.com/python/mypy/issues/7191 -Reorderable = TypeVar('Reorderable', bound='ReorderProtoMixin') + + +class ReorderSubclassProtocol(ModelIdProtocol, Protocol): + parent_id: Mapped[Any] + parent: Mapped[Any] + seq: Mapped[Any] + + @property + def parent_scoped_reorder_query_filter(self) -> sa.ColumnElement[bool]: + ... + + def reorder_item(self: Reorderable, other: Reorderable, before: bool) -> None: + ... + + +Reorderable = TypeVar('Reorderable', bound='ReorderSubclassProtocol') @declarative_mixin -class ReorderProtoMixin: +class ReorderMixin: """Adds support for re-ordering sequences within a parent container.""" - if TYPE_CHECKING: - #: Subclasses must have a created_at column - created_at: declared_attr[datetime] - #: Subclass must have a primary key that is int or uuid - id_: declared_attr[Any] - #: Subclass must declare a parent_id synonym to the parent model fkey column - parent_id: Mapped[Any] - #: Subclass must declare a seq column or synonym, holding a sequence id. It - #: need not be unique, but reordering is meaningless when both items have the - #: same number - seq: Mapped[int] - - #: Subclass must offer a SQLAlchemy query (this is standard from base classes) - query: ClassVar[QueryProperty] - @property - def parent_scoped_reorder_query_filter(self) -> sa.ColumnElement[bool]: + def parent_scoped_reorder_query_filter( + self: ReorderSubclassProtocol, + ) -> sa.ColumnElement[bool]: """ Return a query filter that includes a scope limitation to the parent. @@ -100,7 +102,7 @@ def reorder_item(self: Reorderable, other: Reorderable, before: bool) -> None: new_seq_number = self.seq # Temporarily give self an out-of-bounds number - self.seq = ( + self.seq: Mapped[int] = ( sa.select(sa.func.coalesce(sa.func.max(cls.seq) + 1, 1)) .where(self.parent_scoped_reorder_query_filter) .scalar_subquery() diff --git a/funnel/models/site_membership.py b/funnel/models/site_membership.py index ecf3d6819..7d8eb6663 100644 --- a/funnel/models/site_membership.py +++ b/funnel/models/site_membership.py @@ -5,12 +5,12 @@ from werkzeug.utils import cached_property from . import Mapped, Model, declared_attr, sa, sa_orm -from .membership_mixin import ImmutableUserMembershipMixin +from .membership_mixin import ImmutableMembershipMixin __all__ = ['SiteMembership'] -class SiteMembership(ImmutableUserMembershipMixin, Model): +class SiteMembership(ImmutableMembershipMixin, Model): """Membership roles for users who are site administrators.""" __tablename__ = 'site_membership' @@ -38,7 +38,7 @@ class SiteMembership(ImmutableUserMembershipMixin, Model): #: SiteMembership doesn't have a container limiting its scope parent_id = None - parent_id_column = None + parent_id_column = '' # Must be of type str, not None parent = None # Site admin roles (at least one must be True): @@ -54,7 +54,7 @@ class SiteMembership(ImmutableUserMembershipMixin, Model): @declared_attr.directive @classmethod - def __table_args__(cls) -> tuple: + def __table_args__(cls) -> tuple: # type: ignore[override] """Table arguments.""" try: args = list(super().__table_args__) diff --git a/funnel/models/sponsor_membership.py b/funnel/models/sponsor_membership.py index 87b491f1e..563d3fa81 100644 --- a/funnel/models/sponsor_membership.py +++ b/funnel/models/sponsor_membership.py @@ -9,23 +9,14 @@ from coaster.sqlalchemy import immutable from . import Mapped, Model, relationship, sa, sa_orm -from .membership_mixin import ( - FrozenAttributionMixin, - ImmutableUserMembershipMixin, - ReorderMembershipProtoMixin, -) +from .membership_mixin import FrozenAttributionMixin, ReorderMembershipMixin from .project import Project from .proposal import Proposal __all__ = ['ProjectSponsorMembership', 'ProposalSponsorMembership'] -class ProjectSponsorMembership( # type: ignore[misc] # FIXME - FrozenAttributionMixin, - ImmutableUserMembershipMixin, - ReorderMembershipProtoMixin, - Model, -): +class ProjectSponsorMembership(FrozenAttributionMixin, ReorderMembershipMixin, Model): """Sponsor of a project.""" __tablename__ = 'project_sponsor_membership' @@ -116,12 +107,7 @@ def offered_roles(self) -> set[str]: # FIXME: Replace this with existing proposal collaborator as they're now both related # to "account" -class ProposalSponsorMembership( # type: ignore[misc] # FIXME - FrozenAttributionMixin, - ImmutableUserMembershipMixin, - ReorderMembershipProtoMixin, - Model, -): +class ProposalSponsorMembership(FrozenAttributionMixin, ReorderMembershipMixin, Model): """Sponsor of a proposal.""" __tablename__ = 'proposal_sponsor_membership' diff --git a/funnel/views/search.py b/funnel/views/search.py index ae54d8ff1..86bd71765 100644 --- a/funnel/views/search.py +++ b/funnel/views/search.py @@ -231,7 +231,7 @@ def all_query(self, tsquery: sa.Function) -> Query[Project]: def all_count(self, tsquery: sa.Function) -> int: """Return count of matching projects across the entire site.""" return ( - db.session.query(sa.func.count('*')) + db.session.query(sa.func.count(sa.text('*'))) .select_from(Project) .join(Account, Project.account) .filter( diff --git a/migrations/versions/047ebdac558b_complement_email_md5sum_with_blake2b.py b/migrations/versions/047ebdac558b_complement_email_md5sum_with_blake2b.py index 4c9045d76..45383fdd2 100644 --- a/migrations/versions/047ebdac558b_complement_email_md5sum_with_blake2b.py +++ b/migrations/versions/047ebdac558b_complement_email_md5sum_with_blake2b.py @@ -59,7 +59,7 @@ def upgrade() -> None: # Add blake2b column to UserEmail op.add_column('user_email', sa.Column('blake2b', sa.LargeBinary(), nullable=True)) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(user_email)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(user_email)) progress = get_progressbar("Emails", count) progress.start() items = conn.execute(sa.select(user_email.c.id, user_email.c.email)) @@ -85,7 +85,9 @@ def upgrade() -> None: op.add_column( 'user_email_claim', sa.Column('blake2b', sa.LargeBinary(), nullable=True) ) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(user_email_claim)) + count = conn.scalar( + sa.select(sa.func.count(sa.text('*'))).select_from(user_email_claim) + ) progress = get_progressbar("Email claims", count) progress.start() items = conn.execute(sa.select(user_email_claim.c.id, user_email_claim.c.email)) diff --git a/migrations/versions/1c9cbf3a1e5e_add_commenset_memberships.py b/migrations/versions/1c9cbf3a1e5e_add_commenset_memberships.py index 1c982cac6..f612ca46a 100644 --- a/migrations/versions/1c9cbf3a1e5e_add_commenset_memberships.py +++ b/migrations/versions/1c9cbf3a1e5e_add_commenset_memberships.py @@ -129,7 +129,7 @@ def downgrade(engine_name=''): def upgrade_(): conn = op.get_bind() - count = conn.scalar(sa.select(sa.func.count('*')).select_from(project)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(project)) progress = get_progressbar("Projects", count) progress.start() @@ -139,7 +139,7 @@ def upgrade_(): for counter, project_item in enumerate(projects): # Create membership for existing RSVP rsvp_count = conn.scalar( - sa.select(sa.func.count('*')) + sa.select(sa.func.count(sa.text('*'))) .where(rsvp.c.project_id == project_item.id) .select_from(rsvp) ) @@ -157,7 +157,7 @@ def upgrade_(): for rsvp_item in rsvps: existing_counter = conn.scalar( - sa.select(sa.func.count('*')) + sa.select(sa.func.count(sa.text('*'))) .where( commentset_membership.c.commentset_id == project_item.commentset_id ) @@ -196,7 +196,7 @@ def upgrade_(): for crew in crews: existing_counter = conn.scalar( - sa.select(sa.func.count('*')) + sa.select(sa.func.count(sa.text('*'))) .where( commentset_membership.c.commentset_id == project_item.commentset_id ) @@ -225,7 +225,9 @@ def upgrade_(): progress.finish() # Create commentset membership for existing proposal memberships - count = conn.scalar(sa.select(sa.func.count('*')).select_from(proposal_membership)) + count = conn.scalar( + sa.select(sa.func.count(sa.text('*'))).select_from(proposal_membership) + ) progress = get_progressbar("Proposals", count) progress.start() @@ -243,7 +245,7 @@ def upgrade_(): ) for counter, proposal_item in enumerate(proposals): existing_counter = conn.scalar( - sa.select(sa.func.count('*')) + sa.select(sa.func.count(sa.text('*'))) .where(commentset_membership.c.commentset_id == proposal_item.commentset_id) .where(commentset_membership.c.user_id == proposal_item.user_id) .where(commentset_membership.c.revoked_at.is_(None)) @@ -273,7 +275,7 @@ def upgrade_(): def downgrade_(): conn = op.get_bind() - count = conn.scalar(sa.select(sa.func.count('*')).select_from(project)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(project)) progress = get_progressbar("Projects", count) progress.start() @@ -294,7 +296,7 @@ def downgrade_(): progress.update(counter) progress.finish() - count = conn.scalar(sa.select(sa.func.count('*')).select_from(proposal)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(proposal)) progress = get_progressbar("Proposals", count) progress.start() diff --git a/migrations/versions/284c10efdbce_deprecate_session_speaker_bio.py b/migrations/versions/284c10efdbce_deprecate_session_speaker_bio.py index 149ff54a7..e61746248 100644 --- a/migrations/versions/284c10efdbce_deprecate_session_speaker_bio.py +++ b/migrations/versions/284c10efdbce_deprecate_session_speaker_bio.py @@ -58,7 +58,7 @@ def session_description(row): def upgrade() -> None: conn = op.get_bind() - count = conn.scalar(sa.select(sa.func.count('*')).select_from(session)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(session)) progress = get_progressbar("Sessions", count) progress.start() items = conn.execute(session.select()) diff --git a/migrations/versions/2cbfbcca4737_uuid_columns_for_proposal_and_session.py b/migrations/versions/2cbfbcca4737_uuid_columns_for_proposal_and_session.py index 227e8ab52..085c9ed92 100644 --- a/migrations/versions/2cbfbcca4737_uuid_columns_for_proposal_and_session.py +++ b/migrations/versions/2cbfbcca4737_uuid_columns_for_proposal_and_session.py @@ -43,7 +43,7 @@ def upgrade() -> None: conn = op.get_bind() op.add_column('proposal', sa.Column('uuid', sa.Uuid(), nullable=True)) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(proposal)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(proposal)) progress = get_progressbar("Proposals", count) progress.start() items = conn.execute(sa.select(proposal.c.id)) @@ -57,7 +57,7 @@ def upgrade() -> None: op.create_unique_constraint('proposal_uuid_key', 'proposal', ['uuid']) op.add_column('session', sa.Column('uuid', sa.Uuid(), nullable=True)) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(session)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(session)) progress = get_progressbar("Sessions", count) progress.start() items = conn.execute(sa.select(session.c.id)) diff --git a/migrations/versions/321b11b6a413_add_participant_uuid_field.py b/migrations/versions/321b11b6a413_add_participant_uuid_field.py index 5df001c4e..feac414db 100644 --- a/migrations/versions/321b11b6a413_add_participant_uuid_field.py +++ b/migrations/versions/321b11b6a413_add_participant_uuid_field.py @@ -44,7 +44,7 @@ def upgrade() -> None: op.add_column('participant', sa.Column('uuid', sa.Uuid(), nullable=True)) # migrate past participants - count = conn.scalar(sa.select(sa.func.count('*')).select_from(participant)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(participant)) progress = get_progressbar("Participants", count) progress.start() items = conn.execute(sa.select(participant.c.id)) diff --git a/migrations/versions/5f1ab3e04f73_drop_support_for_128_bit_blake2b_hash_.py b/migrations/versions/5f1ab3e04f73_drop_support_for_128_bit_blake2b_hash_.py index 25cdb531c..eee61ac8d 100644 --- a/migrations/versions/5f1ab3e04f73_drop_support_for_128_bit_blake2b_hash_.py +++ b/migrations/versions/5f1ab3e04f73_drop_support_for_128_bit_blake2b_hash_.py @@ -63,7 +63,9 @@ def downgrade() -> None: sa.Column('blake2b', postgresql.BYTEA(), autoincrement=False, nullable=True), ) # Recalculate blake2b hashes - count = conn.scalar(sa.select(sa.func.count('*')).select_from(user_email_claim)) + count = conn.scalar( + sa.select(sa.func.count(sa.text('*'))).select_from(user_email_claim) + ) progress = get_progressbar("Email claims", count) progress.start() items = conn.execute( diff --git a/migrations/versions/63c44675b6cd_migrate_to_phonenumber.py b/migrations/versions/63c44675b6cd_migrate_to_phonenumber.py index 959b3dc0b..a6c634290 100644 --- a/migrations/versions/63c44675b6cd_migrate_to_phonenumber.py +++ b/migrations/versions/63c44675b6cd_migrate_to_phonenumber.py @@ -110,7 +110,7 @@ def upgrade_() -> None: op.add_column( 'user_phone', sa.Column('phone_number_id', sa.Integer(), nullable=True) ) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(user_phone)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(user_phone)) items = conn.execute( sa.select( user_phone.c.id, @@ -181,7 +181,7 @@ def upgrade_() -> None: rows_to_delete = set() - count = conn.scalar(sa.select(sa.func.count('*')).select_from(sms_message)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(sms_message)) items = conn.execute( sa.select( sms_message.c.id, @@ -325,7 +325,7 @@ def downgrade_() -> None: nullable=True, ), ) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(sms_message)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(sms_message)) items = conn.execute( sa.select(sms_message.c.id, phone_number.c.number).where( sms_message.c.phone_number_id == phone_number.c.id @@ -359,7 +359,7 @@ def downgrade_() -> None: op.add_column( 'user_phone', sa.Column('phone', sa.TEXT(), autoincrement=False, nullable=True) ) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(user_phone)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(user_phone)) items = conn.execute( sa.select(user_phone.c.id, phone_number.c.number).where( user_phone.c.phone_number_id == phone_number.c.id diff --git a/migrations/versions/69c2ced88981_team_org_uuid.py b/migrations/versions/69c2ced88981_team_org_uuid.py index 42ad39f46..7feb122dc 100644 --- a/migrations/versions/69c2ced88981_team_org_uuid.py +++ b/migrations/versions/69c2ced88981_team_org_uuid.py @@ -46,7 +46,7 @@ def upgrade() -> None: conn = op.get_bind() op.add_column('team', sa.Column('org_uuid', sa.Uuid(), nullable=True)) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(team)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(team)) progress = get_progressbar("Teams", count) progress.start() items = conn.execute(sa.select(team.c.id, team.c.orgid)) @@ -70,7 +70,7 @@ def downgrade() -> None: op.add_column( 'team', sa.Column('orgid', sa.String(22), autoincrement=False, nullable=True) ) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(team)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(team)) progress = get_progressbar("Teams", count) progress.start() items = conn.execute(sa.select(team.c.id, team.c.org_uuid)) diff --git a/migrations/versions/7f8114c73092_add_rsvp_uuid.py b/migrations/versions/7f8114c73092_add_rsvp_uuid.py index 4836eb1a2..7fced4679 100644 --- a/migrations/versions/7f8114c73092_add_rsvp_uuid.py +++ b/migrations/versions/7f8114c73092_add_rsvp_uuid.py @@ -49,7 +49,7 @@ def upgrade() -> None: conn = op.get_bind() op.add_column('rsvp', sa.Column('uuid', sa.Uuid(), nullable=True)) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(rsvp)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(rsvp)) progress = get_progressbar("Rsvps", count) progress.start() diff --git a/migrations/versions/887db555cca9_adding_uuid_to_commentset.py b/migrations/versions/887db555cca9_adding_uuid_to_commentset.py index 7702f2e50..3e4291924 100644 --- a/migrations/versions/887db555cca9_adding_uuid_to_commentset.py +++ b/migrations/versions/887db555cca9_adding_uuid_to_commentset.py @@ -45,7 +45,7 @@ def upgrade() -> None: op.add_column('commentset', sa.Column('uuid', sa.Uuid(), nullable=True)) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(commentset)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(commentset)) progress = get_progressbar("Commentsets", count) progress.start() items = conn.execute(sa.select(commentset.c.id)) diff --git a/migrations/versions/ad5013552ec6_simplify_proposal_fields.py b/migrations/versions/ad5013552ec6_simplify_proposal_fields.py index 1551e0219..4fa98c8a6 100644 --- a/migrations/versions/ad5013552ec6_simplify_proposal_fields.py +++ b/migrations/versions/ad5013552ec6_simplify_proposal_fields.py @@ -87,7 +87,7 @@ def upgrade() -> None: op.add_column('proposal', sa.Column('body_html', sa.UnicodeText(), nullable=True)) op.add_column('proposal', sa.Column('description', sa.Unicode(), nullable=True)) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(proposal)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(proposal)) progress = get_progressbar("Proposals", count) progress.start() items = conn.execute(proposal.select()) diff --git a/migrations/versions/ae075a249493_migrate_email_addresses.py b/migrations/versions/ae075a249493_migrate_email_addresses.py index a6ea10cff..dd639e74f 100644 --- a/migrations/versions/ae075a249493_migrate_email_addresses.py +++ b/migrations/versions/ae075a249493_migrate_email_addresses.py @@ -167,7 +167,7 @@ def upgrade() -> None: 'user_email', sa.Column('email_address_id', sa.Integer(), nullable=True) ) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(user_email)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(user_email)) progress = get_progressbar("Emails", count) progress.start() items = conn.execute( @@ -259,7 +259,9 @@ def upgrade() -> None: ondelete='SET NULL', ) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(user_email_claim)) + count = conn.scalar( + sa.select(sa.func.count(sa.text('*'))).select_from(user_email_claim) + ) progress = get_progressbar("Email claims", count) progress.start() items = conn.execute( @@ -348,7 +350,7 @@ def upgrade() -> None: ) count = conn.scalar( - sa.select(sa.func.count('*')) + sa.select(sa.func.count(sa.text('*'))) .select_from(proposal) .where(proposal.c.email.is_not(None)) ) @@ -413,7 +415,7 @@ def downgrade() -> None: ) count = conn.scalar( - sa.select(sa.func.count('*')) + sa.select(sa.func.count(sa.text('*'))) .select_from(proposal) .where(proposal.c.email_address_id.is_not(None)) ) @@ -449,7 +451,9 @@ def downgrade() -> None: sa.Column('email', sa.VARCHAR(length=254), autoincrement=False, nullable=True), ) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(user_email_claim)) + count = conn.scalar( + sa.select(sa.func.count(sa.text('*'))).select_from(user_email_claim) + ) progress = get_progressbar("Email claims", count) progress.start() items = conn.execute( @@ -519,7 +523,7 @@ def downgrade() -> None: sa.Column('blake2b', postgresql.BYTEA(), autoincrement=False, nullable=True), ) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(user_email)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(user_email)) progress = get_progressbar("Emails", count) progress.start() items = conn.execute( diff --git a/migrations/versions/aebd5a9e5af1_project_timestamps.py b/migrations/versions/aebd5a9e5af1_project_timestamps.py index 804c56f03..5e9e44797 100644 --- a/migrations/versions/aebd5a9e5af1_project_timestamps.py +++ b/migrations/versions/aebd5a9e5af1_project_timestamps.py @@ -88,7 +88,7 @@ def upgrade() -> None: # Update project start_at/end_at timestamps where sessions exist conn = op.get_bind() - count = conn.scalar(sa.select(sa.func.count('*')).select_from(project)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(project)) progress = get_progressbar("Projects", count) progress.start() project_ids = conn.execute(sa.select(project.c.id)) diff --git a/migrations/versions/b34aa62af7fc_uuid_columns_for_project_profile_user_team.py b/migrations/versions/b34aa62af7fc_uuid_columns_for_project_profile_user_team.py index 1ecfc660c..0cb59af67 100644 --- a/migrations/versions/b34aa62af7fc_uuid_columns_for_project_profile_user_team.py +++ b/migrations/versions/b34aa62af7fc_uuid_columns_for_project_profile_user_team.py @@ -65,7 +65,7 @@ def upgrade() -> None: # --- Project op.add_column('project', sa.Column('uuid', sa.Uuid(), nullable=True)) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(project)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(project)) progress = get_progressbar("Projects", count) progress.start() items = conn.execute(sa.select(project.c.id)) @@ -80,7 +80,7 @@ def upgrade() -> None: # --- Profile op.add_column('profile', sa.Column('uuid', sa.Uuid(), nullable=True)) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(profile)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(profile)) progress = get_progressbar("Profiles", count) progress.start() items = conn.execute(sa.select(profile.c.id, profile.c.userid)) @@ -99,7 +99,7 @@ def upgrade() -> None: # --- Team op.add_column('team', sa.Column('uuid', sa.Uuid(), nullable=True)) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(team)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(team)) progress = get_progressbar("Teams", count) progress.start() items = conn.execute(sa.select(team.c.id, team.c.userid)) @@ -118,7 +118,7 @@ def upgrade() -> None: # --- User op.add_column('user', sa.Column('uuid', sa.Uuid(), nullable=True)) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(user)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(user)) progress = get_progressbar("Users", count) progress.start() items = conn.execute(sa.select(user.c.id, user.c.userid)) @@ -142,7 +142,7 @@ def downgrade() -> None: # --- User op.add_column('user', sa.Column('userid', sa.String(22), nullable=True)) op.create_unique_constraint('user_userid_key', 'user', ['userid']) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(user)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(user)) progress = get_progressbar("Users", count) progress.start() items = conn.execute(sa.select(user.c.id, user.c.uuid)) @@ -161,7 +161,7 @@ def downgrade() -> None: # --- Team op.add_column('team', sa.Column('userid', sa.String(22), nullable=True)) op.create_unique_constraint('team_userid_key', 'team', ['userid']) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(team)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(team)) progress = get_progressbar("Teams", count) progress.start() items = conn.execute(sa.select(team.c.id, team.c.uuid)) @@ -180,7 +180,7 @@ def downgrade() -> None: # --- Profile op.add_column('profile', sa.Column('userid', sa.String(22), nullable=True)) op.create_unique_constraint('profile_userid_key', 'profile', ['userid']) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(profile)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(profile)) progress = get_progressbar("Profiles", count) progress.start() items = conn.execute(sa.select(profile.c.id, profile.c.uuid)) diff --git a/migrations/versions/c3069d33419a_comment_uuid_field.py b/migrations/versions/c3069d33419a_comment_uuid_field.py index b873631f1..34fbd17a1 100644 --- a/migrations/versions/c3069d33419a_comment_uuid_field.py +++ b/migrations/versions/c3069d33419a_comment_uuid_field.py @@ -41,7 +41,7 @@ def upgrade() -> None: op.add_column('comment', sa.Column('uuid', sa.Uuid(), nullable=True)) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(comment)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(comment)) progress = get_progressbar("Comments", count) progress.start() items = conn.execute(sa.select(comment.c.id)) diff --git a/migrations/versions/ca578c1b82e8_populate_usersession_geonameid_from_ip_.py b/migrations/versions/ca578c1b82e8_populate_usersession_geonameid_from_ip_.py index 9b7af1fc7..5afb523fe 100644 --- a/migrations/versions/ca578c1b82e8_populate_usersession_geonameid_from_ip_.py +++ b/migrations/versions/ca578c1b82e8_populate_usersession_geonameid_from_ip_.py @@ -72,7 +72,7 @@ def upgrade() -> None: if geoip_city is not None or geoip_asn is not None: conn = op.get_bind() count = conn.scalar( - sa.select(sa.func.count('*')) + sa.select(sa.func.count(sa.text('*'))) .select_from(user_session) .where( sa.or_( diff --git a/migrations/versions/e2b28adfa135_add_proposal_suuid_redirect.py b/migrations/versions/e2b28adfa135_add_proposal_suuid_redirect.py index c72feedf5..5b67d654d 100644 --- a/migrations/versions/e2b28adfa135_add_proposal_suuid_redirect.py +++ b/migrations/versions/e2b28adfa135_add_proposal_suuid_redirect.py @@ -74,7 +74,7 @@ def upgrade() -> None: ) conn = op.get_bind() - count = conn.scalar(sa.select(sa.func.count('*')).select_from(proposal)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(proposal)) progress = get_progressbar("Proposals", count) progress.start() items = conn.execute(sa.select(proposal.c.id, proposal.c.uuid)) diff --git a/migrations/versions/e2be4ab896d3_migrate_old_labels.py b/migrations/versions/e2be4ab896d3_migrate_old_labels.py index 8eadf602d..830676efb 100644 --- a/migrations/versions/e2be4ab896d3_migrate_old_labels.py +++ b/migrations/versions/e2be4ab896d3_migrate_old_labels.py @@ -71,7 +71,7 @@ def upgrade() -> None: sec_count = cast( int, conn.scalar( - sa.select(sa.func.count('*')) + sa.select(sa.func.count(sa.text('*'))) .select_from(section) .where(section.c.project_id == proj.id) ), @@ -236,7 +236,7 @@ def upgrade() -> None: duplicate_count = cast( int, conn.scalar( - sa.select(sa.func.count('*')) + sa.select(sa.func.count(sa.text('*'))) .select_from(label) .where(label.c.name == st_name) .where(label.c.project_id == proj.id) diff --git a/migrations/versions/e3b3ccbca3b9_move_participant_to_emailaddressmixin.py b/migrations/versions/e3b3ccbca3b9_move_participant_to_emailaddressmixin.py index 906475372..38e9cbe06 100644 --- a/migrations/versions/e3b3ccbca3b9_move_participant_to_emailaddressmixin.py +++ b/migrations/versions/e3b3ccbca3b9_move_participant_to_emailaddressmixin.py @@ -139,7 +139,7 @@ def upgrade() -> None: ondelete='SET NULL', ) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(participant)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(participant)) progress = get_progressbar("Participants", count) progress.start() items = conn.execute( @@ -244,7 +244,7 @@ def downgrade() -> None: 'participant', sa.Column('email', sa.VARCHAR(length=254), autoincrement=False, nullable=True), ) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(participant)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(participant)) progress = get_progressbar("Participants", count) progress.start() items = conn.execute( diff --git a/migrations/versions/eec2fad0f3e9_venue_uuid_field.py b/migrations/versions/eec2fad0f3e9_venue_uuid_field.py index f9d951ad7..366d6b5b4 100644 --- a/migrations/versions/eec2fad0f3e9_venue_uuid_field.py +++ b/migrations/versions/eec2fad0f3e9_venue_uuid_field.py @@ -40,7 +40,7 @@ def upgrade() -> None: conn = op.get_bind() op.add_column('venue', sa.Column('uuid', sa.Uuid(), nullable=True)) - count = conn.scalar(sa.select(sa.func.count('*')).select_from(venue)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(venue)) progress = get_progressbar("Venues", count) progress.start() items = conn.execute(sa.select(venue.c.id)) diff --git a/migrations/versions/fa05ebecbc0f_populate_proposalmembership.py b/migrations/versions/fa05ebecbc0f_populate_proposalmembership.py index 025b31446..7bbbe085f 100644 --- a/migrations/versions/fa05ebecbc0f_populate_proposalmembership.py +++ b/migrations/versions/fa05ebecbc0f_populate_proposalmembership.py @@ -87,7 +87,7 @@ def get_progressbar(label, maxval): def upgrade() -> None: # Adapts from `proposal` table to an empty `proposal_membership` table. conn = op.get_bind() - count = conn.scalar(sa.select(sa.func.count('*')).select_from(proposal)) + count = conn.scalar(sa.select(sa.func.count(sa.text('*'))).select_from(proposal)) progress = get_progressbar("Proposals", count) progress.start()