Coverage for bundesliga_tippspiel/utils/collections/Leaderboard.py: 57%
Shortcuts on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""LICENSE
2Copyright 2017 Hermann Krumrey <hermann@krumreyh.com>
4This file is part of bundesliga-tippspiel.
6bundesliga-tippspiel is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
11bundesliga-tippspiel is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
16You should have received a copy of the GNU General Public License
17along with bundesliga-tippspiel. If not, see <http://www.gnu.org/licenses/>.
18LICENSE"""
20from typing import List, Tuple, Dict
21from jerrycan.base import db
22from jerrycan.db.User import User
23from bundesliga_tippspiel.db import SeasonWinner, LeaderboardEntry, \
24 DisplayBotsSettings, MatchdayWinner, UserProfile
27class Leaderboard:
28 """
29 Class that encapsulates a leaderboard
30 """
32 def __init__(
33 self,
34 league: str,
35 season: int,
36 matchday: int,
37 include_bots: bool
38 ):
39 """
40 Initializes the leaerboard object
41 :param league: The league of the leaderboard
42 :param season: The season of the leaderboard
43 :param matchday: The matchday of the leaderboard
44 :param include_bots: Whether or not to include bots
45 """
46 self.league = league
47 self.season = season
48 self.matchday = matchday
49 self.include_bots = include_bots
51 self.season_winners: Dict[int, List[str]] = {}
52 for season_winner in SeasonWinner.query.filter_by(league=league).all(): 52 ↛ 53line 52 didn't jump to line 53, because the loop on line 52 never started
53 user_id = season_winner.user_id
54 winner_season = season_winner.season_string
55 if user_id not in self.season_winners:
56 self.season_winners[user_id] = []
57 self.season_winners[user_id].append(winner_season)
58 self.matchday_winners: Dict[int, List[int]] = {}
59 for matchday_winner in MatchdayWinner.query.filter_by( 59 ↛ 62line 59 didn't jump to line 62, because the loop on line 59 never started
60 league=league, season=season
61 ).all():
62 user_id = matchday_winner.user_id
63 winner_matchday = matchday_winner.matchday
64 if user_id not in self.matchday_winners:
65 self.matchday_winners[user_id] = []
66 self.matchday_winners[user_id].append(winner_matchday)
68 self.ranking: List[LeaderboardEntry] = \
69 LeaderboardEntry.query.filter_by(
70 league=league,
71 season=season,
72 matchday=matchday
73 ).options(db.joinedload(LeaderboardEntry.user)
74 .subqueryload(User.profile)
75 .subqueryload(UserProfile.favourite_team)).all()
76 self.ranking.sort(key=lambda x: x.position) 76 ↛ exitline 76 didn't run the lambda on line 76
77 self.history: List[Tuple[User, List["LeaderboardEntry"]]] \
78 = LeaderboardEntry.load_history(league, season, matchday)
80 if not include_bots: 80 ↛ exitline 80 didn't return from function '__init__', because the condition on line 80 was never false
81 self.ranking = [
82 x for x in self.ranking
83 if DisplayBotsSettings.bot_symbol() not in x.user.username
84 ]
85 self.history = [
86 x for x in self.history
87 if DisplayBotsSettings.bot_symbol() not in x[0].username
88 ]
90 def ranking_to_table_data(self) -> List[Tuple[
91 int, str, str, User, List[str], List[int], int
92 ]]:
93 """
94 Converts the leaderboard into a format that can easily be entered
95 into a HTML table
96 :return: The data as tuple with the following attributes:
97 - position
98 - tendency (example: +2 or -3 etc.)
99 - tendency-class
100 - user
101 - previous season wins
102 - previous matchday wins
103 - points
104 """
105 table_data = []
106 for item in self.ranking: 106 ↛ 107line 106 didn't jump to line 107, because the loop on line 106 never started
107 table_data.append((
108 item.get_position_info(self.include_bots)[0],
109 item.get_tendency(self.include_bots),
110 item.get_tendency_class(self.include_bots),
111 item.user,
112 self.season_winners.get(item.user_id, []),
113 self.matchday_winners.get(item.user_id, []),
114 item.points
115 ))
116 return table_data
118 def matchday_ranking_to_table_data(self) -> List[Tuple[
119 int, None, None, User, List[str], List[int], int
120 ]]:
121 """
122 Calculates the leaderboard ranking to table data for the current
123 matchday only
124 :return: The data as tuple with the following attributes:
125 - position
126 - tendency (None in this case)
127 - tendency-class (None in this case)
128 - user
129 - previous season wins (Empty list in this case)
130 - The matchday wins for the current mtchday only
131 - points on this matchday
132 """
133 table_data: List[Tuple[User, List[int], int]] = []
134 matchday_winners = [
135 user_id for user_id, matchdays in self.matchday_winners.items()
136 if self.matchday in matchdays
137 ]
139 user_histories = dict(self.history)
140 for item in self.ranking: 140 ↛ 141line 140 didn't jump to line 141, because the loop on line 140 never started
141 points = item.points
142 if item.matchday > 1:
143 previous = user_histories[item.user][-2]
144 points -= previous.points
146 table_data.append((
147 item.user,
148 [self.matchday] if item.user_id in matchday_winners else [],
149 points
150 ))
151 table_data.sort(key=lambda x: x[2], reverse=True) 151 ↛ exitline 151 didn't run the lambda on line 151
152 table: List[Tuple[int, None, None, User, List[str], List[int], int]] \
153 = []
155 for i, data in enumerate(table_data): 155 ↛ 156line 155 didn't jump to line 156, because the loop on line 155 never started
156 empty: List[str] = []
157 table.append((
158 i + 1,
159 None,
160 None,
161 data[0],
162 empty,
163 data[1],
164 data[2]
165 ))
166 return table
168 def history_to_chart_data(self) -> List[Tuple[str, str, List[int]]]:
169 """
170 Creates data for the ranking chart
171 :return: The data to be used by the javascript chart
172 """
173 chart_colours = ["red", "blue", "yellow",
174 "green", "purple", "orange",
175 "brown", "black", "gray"]
177 chart_data = []
179 for i, (user, user_history) in enumerate(self.history): 179 ↛ 180line 179 didn't jump to line 180, because the loop on line 179 never started
180 chart_colour = chart_colours[i % len(chart_colours)]
181 user_positions = []
182 for item in user_history:
183 position = item.get_position_info(self.include_bots)[0]
184 user_positions.append(position)
185 chart_data.append((user.username, chart_colour, user_positions))
187 return chart_data