Source code for election_day.models.archived_result

from copy import deepcopy
from onegov.core.orm import Base
from onegov.core.orm import translation_hybrid
from onegov.core.orm.mixins import ContentMixin
from onegov.core.orm.mixins import dict_property
from onegov.core.orm.mixins import meta_property
from onegov.core.orm.mixins import TimestampMixin
from onegov.core.orm.mixins.content import dictionary_based_property_factory
from onegov.core.orm.types import HSTORE
from onegov.core.orm.types import UTCDateTime
from onegov.core.orm.types import UUID
from onegov.election_day.models.election import Election
from onegov.election_day.models.election_compound import ElectionCompound
from onegov.election_day.models.mixins import DomainOfInfluenceMixin
from onegov.election_day.models.mixins import TitleTranslationsMixin
from onegov.election_day.models.vote import Vote
from sqlalchemy import Boolean
from sqlalchemy import Column
from sqlalchemy import Date
from sqlalchemy import Enum
from sqlalchemy import Integer
from sqlalchemy import Text
from uuid import uuid4


from typing import Any
from typing import TYPE_CHECKING
if TYPE_CHECKING:
    import datetime
    import uuid
    from builtins import type as _type
    from collections.abc import Mapping
    from onegov.election_day.request import ElectionDayRequest
    from typing import Literal
    from typing import Self
    from typing import TypeAlias

[docs] ResultType: TypeAlias = Literal['election', 'election_compound', 'vote']
[docs] meta_local_property = dictionary_based_property_factory('local')
[docs] class ArchivedResult(Base, ContentMixin, TimestampMixin, DomainOfInfluenceMixin, TitleTranslationsMixin): """ Stores the result of an election or vote. """
[docs] __tablename__ = 'archived_results'
#: Identifies the result
[docs] id: 'Column[uuid.UUID]' = Column( UUID, # type:ignore[arg-type] primary_key=True, default=uuid4 )
#: The date of the election/vote
[docs] date: 'Column[datetime.date]' = Column(Date, nullable=False)
#: The last change of the results election/vote
[docs] last_modified: 'Column[datetime.datetime | None]' = Column( UTCDateTime, nullable=True )
#: The last change of election/vote
[docs] last_result_change: 'Column[datetime.datetime | None]' = Column( UTCDateTime, nullable=True )
#: Type of the result
[docs] type: 'Column[ResultType]' = Column( Enum( # type:ignore[arg-type] 'vote', 'election', 'election_compound', name='type_of_result' ), nullable=False )
#: Origin of the result
[docs] schema: 'Column[str]' = Column(Text, nullable=False)
#: The name of the principal
[docs] name: 'Column[str]' = Column(Text, nullable=False)
#: Total number of political entities
[docs] total_entities: 'Column[int | None]' = Column(Integer, nullable=True)
#: Number of already counted political entities
[docs] counted_entities: 'Column[int | None]' = Column(Integer, nullable=True)
@property
[docs] def progress(self) -> tuple[int, int]: return self.counted_entities or 0, self.total_entities or 0
#: Number of already counted political entities
[docs] has_results: 'Column[bool | None]' = Column(Boolean, nullable=True)
#: The link to the detailed results
[docs] url: 'Column[str]' = Column(Text, nullable=False)
#: Title of the election/vote
[docs] title_translations: 'Column[Mapping[str, str]]' = Column( HSTORE, nullable=False )
[docs] title = translation_hybrid(title_translations)
[docs] def title_prefix(self, request: 'ElectionDayRequest') -> str: if self.is_fetched(request) and self.domain == 'municipality': return self.name or '' return ''
#: Shortcode for cantons that use it
[docs] shortcode: 'Column[str | None]' = Column(Text, nullable=True)
#: The id of the election/vote.
[docs] external_id: dict_property[str | None] = meta_property('id')
#: The names of the elected candidates.
[docs] elected_candidates: dict_property[list[tuple[str, str]]] = meta_property( 'elected_candidates', default=list )
#: The URLs of the elections (if it is a compound)
[docs] elections: dict_property[list[str]] = meta_property( 'elections', default=list )
#: The answer of a vote (accepted, rejected, counter-proposal).
[docs] answer: dict_property[str] = meta_property('answer', default='')
#: The nays rate of a vote.
[docs] nays_percentage: dict_property[float] = meta_property( 'nays_percentage', default=100.0 )
#: The yeas rate of a vote.
[docs] yeas_percentage: dict_property[float] = meta_property( 'yeas_percentage', default=0.0 )
#: True, if the vote or election has been counted.
[docs] counted: dict_property[bool] = meta_property('counted', default=False)
#: True, if the vote or election has been completed.
[docs] completed: dict_property[bool] = meta_property( 'completed', default=False )
#: Turnout (vote/elections)
[docs] turnout: dict_property[float | None] = meta_property('turnout')
#: True, if this is direct complex vote
[docs] direct: dict_property[bool] = meta_property( 'direct', default=True )
#: The local results (municipal results if fetched from cantonal instance)
[docs] local: dict_property[dict[str, Any] | None] = meta_property('local')
#: The answer if this a fetched cantonal/federal result on a communal #: instance.
[docs] local_answer: dict_property[str] = meta_local_property('answer', '')
#: The nays rate if this a fetched cantonal/federal result on a communal #: instance.
[docs] local_nays_percentage: dict_property[float] = meta_local_property( 'nays_percentage', 100.0 )
#: The yeas rate if this a fetched cantonal/federal result on a communal #: instance.
[docs] local_yeas_percentage: dict_property[float] = meta_local_property( 'yeas_percentage', 0.0 )
@property
[docs] def type_class(self) -> '_type[Election | ElectionCompound | Vote]': if self.type == 'vote': return Vote elif self.type == 'election': return Election elif self.type == 'election_compound': return ElectionCompound raise NotImplementedError
[docs] def is_fetched(self, request: 'ElectionDayRequest') -> bool: """ Returns True, if this results has been fetched from another instance. """ return self.schema != request.app.schema
[docs] def is_fetched_by_municipality( self, request: 'ElectionDayRequest' ) -> bool: """ Returns True, if this results has been fetched from another instance by a communal instance. """ return ( self.is_fetched(request) and request.app.principal.domain == 'municipality' )
[docs] def adjusted_url(self, request: 'ElectionDayRequest') -> str: """ Returns the url adjusted to the current host. Needed if the instance is accessible under different hosts at the same time. """ if self.is_fetched(request): return self.url return request.class_link( self.type_class, {'id': self.external_id} )
[docs] def display_answer(self, request: 'ElectionDayRequest') -> str: """ Returns the answer (depending on the current instance). """ if self.is_fetched_by_municipality(request): return self.local_answer return self.answer
[docs] def display_nays_percentage(self, request: 'ElectionDayRequest') -> float: """ Returns the nays rate (depending on the current instance). """ if self.is_fetched_by_municipality(request): return self.local_nays_percentage return self.nays_percentage
[docs] def display_yeas_percentage(self, request: 'ElectionDayRequest') -> float: """ Returns the yeas rate (depending on the current instance). """ if self.is_fetched_by_municipality(request): return self.local_yeas_percentage return self.yeas_percentage
[docs] def copy_from(self, source: 'Self') -> None: self.date = source.date self.last_modified = source.last_modified self.last_result_change = source.last_result_change self.type = source.type self.schema = source.schema self.name = source.name self.total_entities = source.total_entities self.counted_entities = source.counted_entities self.has_results = source.has_results self.url = source.url self.title_translations = deepcopy(dict(source.title_translations)) self.shortcode = source.shortcode self.domain = source.domain self.meta = deepcopy(dict(source.meta))