from__future__importannotationsimportdatetimefromtypingimportIterable,Optional,Protocol,TYPE_CHECKING,_ProtocolMetafromdjango.db.modelsimportBooleanField,CharField,QuerySetfromdjango.db.models.baseimportModelBasefromdjango.utilsimporttimezonefrom.utilsimportmemoizeifTYPE_CHECKING:from.modelsimportUserBadge,Vote,Show,Track,Profile,TwitterUser,UserWebsite# to check to see that their VoterProtocol implementations are complete:Profile()TwitterUser()
self,)->tuple[Optional[TwitterUser],Optional[Profile]]:...@propertydefusername(self)->str:...@propertydefvoter_id(self)->tuple[Optional[int],Optional[int]]:""" A unique identifier that will be the same for TwitterUser and Profile instances that represent the same accounts. """twu,pr=self._twitter_user_and_profile()return(NoneiftwuisNoneelsetwu.pk,NoneifprisNoneelsepr.pk)@property@memoizedefbadges(self)->QuerySet[UserBadge]:from.modelsimportUserBadgereturnUserBadge.for_voter(self)
[docs]@memoizedefvotes_with_liberal_preselection(self)->QuerySet[Vote]:returnself.votes().prefetch_related('show','show__play_set','show__play_set__track',# doesn't actually appear to work :<)
[docs]def_batting_average(self,cutoff:Optional[datetime.datetime]=None,minimum_weight:float=1,)->Optional[float]:from.modelsimportShowdefba(pk:int,current_show_pk:int,cutoff:Optional[datetime.datetime])->tuple[float,float]:score:float=0weight:float=0forvoteinself.votes().filter(date__gt=cutoff).prefetch_related('tracks'):success=vote.success()ifsuccessisnotNone:score+=success*vote.weight()weight+=vote.weight()return(score,weight)score,weight=ba(self.pk,Show.current().pk,cutoff)ifweight>=minimum_weight:returnscore/weightelse:# there were no worthwhile votesreturnNonereturnscore
[docs]@memoizedefbatting_average(self,minimum_weight:float=1)->Optional[float]:""" Return a user's batting average for the past six months. """from.modelsimportShowreturnself._batting_average(cutoff=Show.at(timezone.now()-datetime.timedelta(days=31*6)).end,minimum_weight=minimum_weight,)