Source code for election_day.models.election_compound.part

from onegov.election_day.models.election_compound.mixins import \
    DerivedAttributesMixin
from onegov.election_day.models.party_result.mixins import \
    HistoricalPartyResultsMixin
from onegov.election_day.models.party_result.mixins import \
    PartyResultsCheckMixin


from typing import Any, Generic, TypeVar, TYPE_CHECKING
if TYPE_CHECKING:
    import datetime
    from onegov.election_day.models import Election
    from onegov.election_day.models import ElectionCompound
    from onegov.election_day.models import ElectionCompoundRelationship
    from onegov.election_day.models import PartyResult
    from onegov.election_day.types import DomainOfInfluence  # noqa: F401
    from onegov.core.orm import SessionManager  # noqa: F401
    from sqlalchemy.orm import Query


[docs] T = TypeVar('T')
[docs] class inherited_attribute(Generic[T]): # noqa: N801
[docs] def __set_name__( self, owner: type[Any], name: str ) -> None: self.name = name
[docs] def __get__( self, # NOTE: Because we mix ElectionCompoundPart with other objects mypy # will complain about inherited_attribute not working on these # other objects, since information is lost during type union # so for now we ignore type safety here, it should be fine instance: Any, owner: type[Any] ) -> T: return getattr(instance.election_compound, self.name)
[docs] class ElectionCompoundPart( DerivedAttributesMixin, PartyResultsCheckMixin, HistoricalPartyResultsMixin ): """ A part of an election compound. Covers a part of an election compound between the domain of the compound and the domain of the elections. There is no database object behind a part of an election compound, all the results are either taken from the compound (parties) or elections (candidates)- """ def __init__( self, election_compound: 'ElectionCompound', domain: str, segment: str ):
[docs] self.election_compound = election_compound
[docs] self.election_compound_id = ( election_compound.id if election_compound else None )
[docs] self.domain = domain
[docs] self.segment = segment
[docs] self.id = segment.replace(' ', '-').lower()
[docs] def __eq__(self, other: object) -> bool: return ( isinstance(other, ElectionCompoundPart) and self.election_compound_id == other.election_compound_id and self.domain == other.domain and self.segment == other.segment )
# NOTE: These top three attributes are a bit ugly due to the mixins # forward declaring these attributes as columns, even though they # can be arbitrary readable attributes, which cannot be expressed # yet using a Protocol, once we can do that, this should become # cleaner
[docs] date: inherited_attribute['datetime.date'] = ( inherited_attribute['datetime.date']()) # type:ignore[assignment]
[docs] completes_manually: inherited_attribute[bool] = ( inherited_attribute[bool]()) # type:ignore[assignment]
[docs] manually_completed: inherited_attribute[bool] = ( inherited_attribute[bool]()) # type:ignore[assignment]
[docs] pukelsheim = inherited_attribute[bool]()
[docs] last_result_change = inherited_attribute['datetime.datetime | None']()
[docs] last_change = inherited_attribute['datetime.datetime | None']()
[docs] last_modified = inherited_attribute['datetime.datetime | None']()
[docs] domain_elections = inherited_attribute['DomainOfInfluence']()
[docs] colors = inherited_attribute[dict[str, str]]()
[docs] voters_counts = inherited_attribute[bool]()
[docs] exact_voters_counts = inherited_attribute[bool]()
[docs] horizontal_party_strengths = inherited_attribute[bool]()
[docs] show_party_strengths = inherited_attribute[bool]()
[docs] use_historical_party_results = inherited_attribute[bool]()
[docs] session_manager = inherited_attribute['SessionManager']()
@property
[docs] def title(self) -> str: return f'{self.election_compound.title} {self.segment}'
@property
[docs] def short_title(self) -> str | None: if not self.election_compound.short_title: return None return f'{self.election_compound.short_title} {self.segment}'
@property
[docs] def title_translations(self) -> dict[str, str]: return { locale: f'{title} {self.segment}' for locale, title in self.election_compound.title_translations.items() }
@property
[docs] def short_title_translations(self) -> dict[str, str]: translations = self.election_compound.short_title_translations or {} return { locale: f'{title} {self.segment}' for locale, title in translations.items() }
@property
[docs] def elections(self) -> list['Election']: return [ election for election in self.election_compound.elections if election.domain_supersegment == self.segment ]
@property
[docs] def progress(self) -> tuple[int, int]: result = [e.completed for e in self.elections] return sum(1 for r in result if r), len(result)
@property
[docs] def party_results(self) -> 'list[PartyResult]': # type:ignore[override] return [ result for result in self.election_compound.party_results if ( result.domain == self.domain and result.domain_segment == self.segment ) ]
@property
[docs] def has_results(self) -> bool: """ Returns True, if the election compound has any results. """ if self.has_party_results: return True for election in self.elections: if election.has_results: return True return False
@property
[docs] def elected_candidates(self) -> list[tuple[str, str]]: """ Returns the first and last names of the elected candidates. """ result = [] for election in self.elections: result.extend(election.elected_candidates) return result
@property
[docs] def relationships_for_historical_party_results( self ) -> 'Query[ElectionCompoundRelationship]': return self.election_compound.related_compounds