def doAwardInsights(self, year): """ Calculate award insights for a given year. Returns a list of Insights. """ # Get all Blue Banner, Division Finalist, and Championship Finalist awards blue_banner_award_keys_future = Award.query( Award.year == year, Award.award_type_enum.IN(AwardType.BLUE_BANNER_AWARDS), Award.event_type_enum.IN({ EventType.REGIONAL, EventType.DISTRICT, EventType.DISTRICT_CMP_DIVISION, EventType.DISTRICT_CMP, EventType.CMP_DIVISION, EventType.CMP_FINALS, EventType.FOC })).fetch_async(10000, keys_only=True) cmp_finalist_award_keys_future = Award.query( Award.year == year, Award.award_type_enum == AwardType.FINALIST, Award.event_type_enum.IN( {EventType.CMP_DIVISION, EventType.CMP_FINALS})).fetch_async(10000, keys_only=True) award_futures = ndb.get_multi_async( set(blue_banner_award_keys_future.get_result()).union( set(cmp_finalist_award_keys_future.get_result()))) insights = [] insights += self._calculateBlueBanners(award_futures, year) insights += self._calculateChampionshipStats(award_futures, year) insights += self._calculateRegionalStats(award_futures, year) insights += self._calculateSuccessfulElimTeamups(award_futures, year) return insights
def test_awards_update(self): self.awards_auth.put() awards = [{'name_str': 'Winner', 'team_key': 'frc254'}, {'name_str': 'Winner', 'team_key': 'frc604'}, {'name_str': 'Volunteer Blahblah', 'team_key': 'frc1', 'awardee': 'Bob Bobby'}] request_body = json.dumps(awards) request_path = '/api/trusted/v1/event/2014casj/awards/update' sig = md5.new('{}{}{}'.format('321tEsTsEcReT', request_path, request_body)).hexdigest() response = self.testapp.post(request_path, request_body, headers={'X-TBA-Auth-Id': 'tEsT_id_4', 'X-TBA-Auth-Sig': sig}, expect_errors=True) self.assertEqual(response.status_code, 200) db_awards = Award.query(Award.event == self.event.key).fetch(None) self.assertEqual(len(db_awards), 2) self.assertTrue('2014casj_1' in [a.key.id() for a in db_awards]) self.assertTrue('2014casj_5' in [a.key.id() for a in db_awards]) awards = [{'name_str': 'Winner', 'team_key': 'frc254'}, {'name_str': 'Winner', 'team_key': 'frc604'}] request_body = json.dumps(awards) sig = md5.new('{}{}{}'.format('321tEsTsEcReT', request_path, request_body)).hexdigest() response = self.testapp.post(request_path, request_body, headers={'X-TBA-Auth-Id': 'tEsT_id_4', 'X-TBA-Auth-Sig': sig}, expect_errors=True) self.assertEqual(response.status_code, 200) db_awards = Award.query(Award.event == self.event.key).fetch(None) self.assertEqual(len(db_awards), 1) self.assertTrue('2014casj_1' in [a.key.id() for a in db_awards])
def doAwardInsights(self, year): """ Calculate award insights for a given year. Returns a list of Insights. """ # Get all Blue Banner, Division Finalist, and Championship Finalist awards blue_banner_award_keys_future = Award.query( Award.year == year, Award.award_type_enum.IN(AwardType.BLUE_BANNER_AWARDS), Award.event_type_enum.IN({EventType.REGIONAL, EventType.DISTRICT, EventType.DISTRICT_CMP, EventType.CMP_DIVISION, EventType.CMP_FINALS}) ).fetch_async(10000, keys_only=True) cmp_finalist_award_keys_future = Award.query( Award.year == year, Award.award_type_enum == AwardType.FINALIST, Award.event_type_enum.IN({EventType.CMP_DIVISION, EventType.CMP_FINALS}) ).fetch_async(10000, keys_only=True) award_futures = ndb.get_multi_async( set(blue_banner_award_keys_future.get_result()).union( set(cmp_finalist_award_keys_future.get_result())) ) insights = [] insights += self._calculateBlueBanners(award_futures, year) insights += self._calculateChampionshipStats(award_futures, year) insights += self._calculateRegionalStats(award_futures, year) insights += self._calculateSuccessfulElimTeamups(award_futures, year) return insights
def getAwards(self, keys, year=None): awards = [] for key in keys: if year == None: awards += Award.query(Award.name == key) else: awards += Award.query(Award.name == key, Award.year == year) return awards
def _render(self, team_key, event_key): award_keys_future = Award.query(Award.team_list == ndb.Key(Team, self.team_key), Award.event == ndb.Key(Event, event_key)).fetch_async(None, keys_only=True) awards = ndb.get_multi(award_keys_future.get_result()) awards_dicts = [ModelToDict.awardConverter(award) for award in AwardHelper.organizeAwards(awards)] return json.dumps(awards_dicts, ensure_ascii=True)
def _process_request(self, request, event_key): event = Event.get_by_id(event_key) awards = [] for award in JSONAwardsParser.parse(request.body, event_key): awards.append(Award( id=Award.render_key_name(event.key_name, award['award_type_enum']), name_str=award['name_str'], award_type_enum=award['award_type_enum'], year=event.year, event=event.key, event_type_enum=event.event_type_enum, team_list=[ndb.Key(Team, team_key) for team_key in award['team_key_list']], recipient_json_list=award['recipient_json_list'] )) # it's easier to clear all awards and add new ones than try to find the difference old_award_keys = Award.query(Award.event == event.key).fetch(None, keys_only=True) AwardManipulator.delete_keys(old_award_keys) if event.remap_teams: EventHelper.remapteams_awards(awards, event.remap_teams) AwardManipulator.createOrUpdate(awards) self.response.out.write(json.dumps({'Success': "Awards successfully updated"}))
def _render(self, *args, **kw): awards_future = Award.query( Award.award_type_enum == AwardType.CHAIRMANS, Award.event_type_enum == EventType.CMP_FINALS).fetch_async() teams_by_year = defaultdict(list) for award in awards_future.get_result(): for team_key in award.team_list: teams_by_year[award.year].append(( team_key.get_async(), award.event.get_async(), award, media_query.TeamTagMediasQuery( team_key.id(), MediaTag.CHAIRMANS_VIDEO).fetch_async(), media_query.TeamTagMediasQuery( team_key.id(), MediaTag.CHAIRMANS_PRESENTATION).fetch_async(), media_query.TeamTagMediasQuery( team_key.id(), MediaTag.CHAIRMANS_ESSAY).fetch_async(), )) teams_by_year = sorted(teams_by_year.items(), key=lambda (k, v): -k) for _, tea in teams_by_year: tea.sort(key=lambda x: x[1].get_result().start_date) self.template_values.update({ 'teams_by_year': teams_by_year, }) return jinja2_engine.render('hof.html', self.template_values)
def _query_async(self): team_key = self._query_args[0] event_key = self._query_args[1] awards = yield Award.query( Award.team_list == ndb.Key(Team, team_key), Award.event == ndb.Key(Event, event_key)).fetch_async() raise ndb.Return(awards)
def _query_async(self): team_key = self._query_args[0] year = self._query_args[1] awards = yield Award.query( Award.team_list == ndb.Key(Team, team_key), Award.year == year).fetch_async() raise ndb.Return(awards)
def _render(self, team_number): team = Team.get_by_id("frc" + team_number) if not team: return self.redirect("/error/404") event_team_keys_future = EventTeam.query(EventTeam.team == team.key).fetch_async(1000, keys_only=True) award_keys_future = Award.query(Award.team == team.key).fetch_async(1000, keys_only=True) event_teams_futures = ndb.get_multi_async(event_team_keys_future.get_result()) awards_futures = ndb.get_multi_async(award_keys_future.get_result()) event_keys = [event_team_future.get_result().event for event_team_future in event_teams_futures] events_futures = ndb.get_multi_async(event_keys) awards_by_event = {} for award_future in awards_futures: award = award_future.get_result() if award.event.id() not in awards_by_event: awards_by_event[award.event.id()] = [award] else: awards_by_event[award.event.id()].append(award) event_awards = [] current_event = None matches_upcoming = None short_cache = False for event_future in events_futures: event = event_future.get_result() if event.now: current_event = event team_matches_future = Match.query(Match.event == event.key, Match.team_key_names == team.key_name)\ .fetch_async(500, keys_only=True) matches = ndb.get_multi(team_matches_future.get_result()) matches_upcoming = MatchHelper.upcomingMatches(matches) if event.within_a_day: short_cache = True if event.key_name in awards_by_event: sorted_awards = AwardHelper.organizeAwards(awards_by_event[event.key_name])['list'] else: sorted_awards = [] event_awards.append((event, sorted_awards)) event_awards = sorted(event_awards, key=lambda (e, _): e.start_date if e.start_date else datetime.datetime(e.year, 12, 31)) years = sorted(set([et.get_result().year for et in event_teams_futures if et.get_result().year != None])) template_values = {'team': team, 'event_awards': event_awards, 'years': years, 'current_event': current_event, 'matches_upcoming': matches_upcoming} if short_cache: self._cache_expiration = self.SHORT_CACHE_EXPIRATION path = os.path.join(os.path.dirname(__file__), '../templates/team_history.html') return template.render(path, template_values)
def _render(self, *args, **kw): awards_future = Award.query( Award.award_type_enum==AwardType.CHAIRMANS, Award.event_type_enum==EventType.CMP_FINALS).fetch_async() teams_by_year = defaultdict(list) for award in awards_future.get_result(): for team_key in award.team_list: teams_by_year[award.year].append(( team_key.get_async(), award.event.get_async(), award, media_query.TeamTagMediasQuery(team_key.id(), MediaTag.CHAIRMANS_VIDEO).fetch_async(), media_query.TeamTagMediasQuery(team_key.id(), MediaTag.CHAIRMANS_PRESENTATION).fetch_async(), media_query.TeamTagMediasQuery(team_key.id(), MediaTag.CHAIRMANS_ESSAY).fetch_async(), )) teams_by_year = sorted(teams_by_year.items(), key=lambda (k, v): -k) for _, tea in teams_by_year: tea.sort(key=lambda x: x[1].get_result().start_date) self.template_values.update({ 'teams_by_year': teams_by_year, }) return jinja2_engine.render('hof.html', self.template_values)
def _process_request(self, request, event_key): event = Event.get_by_id(event_key) awards = [] for award in JSONAwardsParser.parse(request.body, event_key): awards.append( Award(id=Award.render_key_name(event.key_name, award['award_type_enum']), name_str=award['name_str'], award_type_enum=award['award_type_enum'], year=event.year, event=event.key, event_type_enum=event.event_type_enum, team_list=[ ndb.Key(Team, team_key) for team_key in award['team_key_list'] ], recipient_json_list=award['recipient_json_list'])) # it's easier to clear all awards and add new ones than try to find the difference old_award_keys = Award.query(Award.event == event.key).fetch( None, keys_only=True) AwardManipulator.delete_keys(old_award_keys) if event.remap_teams: EventHelper.remapteams_awards(awards, event.remap_teams) AwardManipulator.createOrUpdate(awards) self.response.out.write( json.dumps({'Success': "Awards successfully updated"}))
def _query_async(self): team_key = self._query_args[0] event_key = self._query_args[1] awards = yield Award.query(Award.team_list == ndb.Key( Team, team_key), Award.event == ndb.Key(Event, event_key)).fetch_async() raise ndb.Return(awards)
def update(self, event_key): """ Updates EventTeams for an event. Returns a tuple of (teams, event_teams, event_team_keys_to_delete) An EventTeam is valid iff the team: a) played a match at the event, b) the team received an award at the event, c) or the event has not yet occurred. """ event = Event.get_by_id(event_key) # Add teams from Matches and Awards team_ids = set() match_key_futures = Match.query( Match.event == event.key).fetch_async(1000, keys_only=True) award_key_futures = Award.query( Award.event == event.key).fetch_async(1000, keys_only=True) match_futures = ndb.get_multi_async(match_key_futures.get_result()) award_futures = ndb.get_multi_async(award_key_futures.get_result()) for match_future in match_futures: match = match_future.get_result() for team in match.team_key_names: team_ids.add(team) for award_future in award_futures: award = award_future.get_result() for team_key in award.team_list: team_ids.add(team_key.id()) # Create or update EventTeams teams = [Team(id=team_id, team_number=int(team_id[3:])) for team_id in team_ids] if teams: event_teams = [EventTeam(id=event_key + "_" + team.key.id(), event=event.key, team=team.key, year=event.year) for team in teams] else: event_teams = None # Delete EventTeams for teams who did not participate in the event # Only runs if event is over existing_event_teams_keys = EventTeam.query( EventTeam.event == event.key).fetch(1000, keys_only=True) existing_event_teams = ndb.get_multi(existing_event_teams_keys) existing_team_ids = set() for et in existing_event_teams: existing_team_ids.add(et.team.id()) et_keys_to_delete = set() if event.end_date is not None and event.end_date < datetime.datetime.now(): for team_id in existing_team_ids.difference(team_ids): et_key_name = "{}_{}".format(event.key_name, team_id) et_keys_to_delete.add(ndb.Key(EventTeam, et_key_name)) ndb.delete_multi(et_keys_to_delete) return teams, event_teams, et_keys_to_delete
def get(self): self._require_admin() award_count = Award.query().count() self.template_values.update({"award_count": award_count}) path = os.path.join(os.path.dirname(__file__), '../../templates/admin/award_dashboard.html') self.response.out.write(template.render(path, self.template_values))
def _query_async(self): team_key = self._query_args[0] event_type_enum = self._query_args[1] award_type_enum = self._query_args[2] awards = yield Award.query( Award.team_list == ndb.Key(Team, team_key), Award.event_type_enum == event_type_enum, Award.award_type_enum == award_type_enum).fetch_async() raise ndb.Return(awards)
def get(self): award_count = Award.query().count() template_values = { "award_count": award_count } path = os.path.join(os.path.dirname(__file__), '../../templates/admin/award_dashboard.html') self.response.out.write(template.render(path, template_values))
def get(self): self._require_admin() award_count = Award.query().count() self.template_values.update({ "award_count": award_count }) path = os.path.join(os.path.dirname(__file__), '../../templates/admin/award_dashboard.html') self.response.out.write(template.render(path, self.template_values))
def calculate_event_points(cls, event): match_key_futures = Match.query(Match.event == event.key).fetch_async( None, keys_only=True) award_key_futures = Award.query(Award.event == event.key).fetch_async( None, keys_only=True) match_futures = ndb.get_multi_async(match_key_futures.get_result()) award_futures = ndb.get_multi_async(award_key_futures.get_result()) POINTS_MULTIPLIER = 3 if event.event_type_enum == EventType.DISTRICT_CMP else 1 district_points = { 'points': defaultdict(lambda: { 'qual_points': 0, 'elim_points': 0, 'alliance_points': 0, 'award_points': 0, 'total': 0, }), 'tiebreakers': defaultdict(lambda: { # for tiebreaker stats that can't be calculated with 'points' 'qual_wins': 0, 'highest_qual_scores': [], }), } # match points elim_num_wins = defaultdict(lambda: defaultdict(int)) elim_alliances = defaultdict(lambda: defaultdict(list)) for match_future in match_futures: match = match_future.get_result() if not match.has_been_played: continue if match.comp_level == 'qm': if match.winning_alliance == '': for team in match.team_key_names: district_points['points'][team][ 'qual_points'] += 1 * POINTS_MULTIPLIER else: for team in match.alliances[ match.winning_alliance]['teams']: district_points['points'][team][ 'qual_points'] += 2 * POINTS_MULTIPLIER district_points['tiebreakers'][team]['qual_wins'] += 1 for color in ['red', 'blue']: for team in match.alliances[color]['teams']: score = match.alliances[color]['score'] district_points['tiebreakers'][team][ 'highest_qual_scores'] = heapq.nlargest( 3, district_points['tiebreakers'][team] ['highest_qual_scores'] + [score]) else: if match.winning_alliance == '': continue match_set_key = '{}_{}{}'.format(match.event.id(), match.comp_level, match.set_number) elim_num_wins[match_set_key][match.winning_alliance] += 1 elim_alliances[match_set_key][ match.winning_alliance] += match.alliances[ match.winning_alliance]['teams'] if elim_num_wins[match_set_key][match.winning_alliance] >= 2: for team in elim_alliances[match_set_key][ match.winning_alliance]: district_points['points'][team][ 'elim_points'] += 5 * POINTS_MULTIPLIER # alliance points if event.alliance_selections: selection_points = EventHelper.alliance_selections_to_points( event.alliance_selections) for team, points in selection_points.items(): district_points['points'][team][ 'alliance_points'] += points * POINTS_MULTIPLIER else: logging.warning( "Event {} has no alliance selection district_points!".format( event.key.id())) # award points for award_future in award_futures: award = award_future.get_result() if award.award_type_enum not in AwardType.NON_JUDGED_NON_TEAM_AWARDS: if award.award_type_enum == AwardType.CHAIRMANS: point_value = 10 elif award.award_type_enum in { AwardType.ENGINEERING_INSPIRATION, AwardType.ROOKIE_ALL_STAR }: point_value = 8 else: point_value = 5 for team in award.team_list: district_points['points'][team.id( )]['award_points'] += point_value * POINTS_MULTIPLIER for team, point_breakdown in district_points['points'].items(): for p in point_breakdown.values(): district_points['points'][team]['total'] += p return district_points
def update(self, event_key): """ Updates EventTeams for an event. Returns a tuple of (teams, event_teams, event_team_keys_to_delete) An EventTeam is valid iff the team: a) played a match at the event, b) the team received an award at the event, c) the event has not yet occurred, d) the team is on an alliance e) the winning alliance of one of this event's divisions f) or the event is not from the current year. (This is to make sure we don't delete old data we may no longer be able to scrape) """ event = Event.get_by_id(event_key) cur_year = datetime.datetime.now().year # Add teams from Matches and Awards team_ids = set() match_key_futures = Match.query( Match.event == event.key).fetch_async(1000, keys_only=True) award_key_futures = Award.query( Award.event == event.key).fetch_async(1000, keys_only=True) match_futures = ndb.get_multi_async(match_key_futures.get_result()) award_futures = ndb.get_multi_async(award_key_futures.get_result()) division_futures = ndb.get_multi_async(event.divisions) if event.divisions else [] division_matches_futures = [Match.query( Match.event == division).fetch_async(1000) for division in event.divisions] if event.divisions else [] for match_future in match_futures: match = match_future.get_result() for team in match.team_key_names: team_ids.add(team) for award_future in award_futures: award = award_future.get_result() for team_key in award.team_list: team_ids.add(team_key.id()) # Add teams from Alliances for team in event.alliance_teams: team_ids.add(team) # Add teams from division winners if division_futures and division_matches_futures: for division_future, matches_future in zip(division_futures, division_matches_futures): division_winners = self.get_event_winners(division_future.get_result(), matches_future.get_result()) team_ids = team_ids.union(division_winners) # Create or update EventTeams teams = [Team(id=team_id, team_number=int(team_id[3:])) for team_id in team_ids if team_id[3:].isdigit()] if teams: event_teams = [EventTeam(id=event_key + "_" + team.key.id(), event=event.key, team=team.key, year=event.year) for team in teams] else: event_teams = None # Delete EventTeams for teams who did not participate in the event # Only runs if event is over existing_event_teams_keys = EventTeam.query( EventTeam.event == event.key).fetch(1000, keys_only=True) existing_event_teams = ndb.get_multi(existing_event_teams_keys) existing_team_ids = set() for et in existing_event_teams: existing_team_ids.add(et.team.id()) et_keys_to_delete = set() if event.year == cur_year and event.end_date is not None and event.end_date < datetime.datetime.now(): for team_id in existing_team_ids.difference([team.key.id() for team in teams]): et_key_name = "{}_{}".format(event.key_name, team_id) et_keys_to_delete.add(ndb.Key(EventTeam, et_key_name)) return teams, event_teams, et_keys_to_delete
def _query_async(self): team_key = self._query_args[0] year = self._query_args[1] awards = yield Award.query(Award.team_list == ndb.Key(Team, team_key), Award.year == year).fetch_async() raise ndb.Return(awards)
def _query_async(self): event_key = self._query_args[0] awards = yield Award.query( Award.event == ndb.Key(Event, event_key)).fetch_async() raise ndb.Return(awards)
def calculate_event_points(cls, event): match_key_futures = Match.query(Match.event == event.key).fetch_async(None, keys_only=True) award_key_futures = Award.query(Award.event == event.key).fetch_async(None, keys_only=True) district_team_key_futures = DistrictTeam.query(DistrictTeam.district == event.event_district_enum, DistrictTeam.year == event.year).fetch_async(None, keys_only=True) match_futures = ndb.get_multi_async(match_key_futures.get_result()) award_futures = ndb.get_multi_async(award_key_futures.get_result()) district_team_futures = ndb.get_multi_async(district_team_key_futures.get_result()) # Typically 3 for District CMP, 1 otherwise POINTS_MULTIPLIER = DistrictPointValues.DISTRICT_CMP_MULTIPLIER.get(event.year, DistrictPointValues.DISTRICT_CMP_MULIPLIER_DEFAULT) if event.event_type_enum == EventType.DISTRICT_CMP else DistrictPointValues.STANDARD_MULTIPLIER district_points = { 'points': defaultdict(lambda: { 'qual_points': 0, 'elim_points': 0, 'alliance_points': 0, 'award_points': 0, 'total': 0, }), 'tiebreakers': defaultdict(lambda: { # for tiebreaker stats that can't be calculated with 'points' 'qual_wins': 0, 'highest_qual_scores': [], }), } single_district_points = district_points.copy() # match points if event.year >= 2015: # Switched to ranking-based points for 2015 and onward cls.calc_rank_based_match_points(event, district_points, match_futures, POINTS_MULTIPLIER) else: cls.calc_wlt_based_match_points(district_points, match_futures, POINTS_MULTIPLIER) # alliance points if event.alliance_selections: selection_points = EventHelper.alliance_selections_to_points(event.key_name, POINTS_MULTIPLIER, event.alliance_selections) for team, points in selection_points.items(): district_points['points'][team]['alliance_points'] += points else: logging.warning("Event {} has no alliance selection district_points!".format(event.key.id())) # award points for award_future in award_futures: award = award_future.get_result() point_value = 0 if event.year >= 2014: if award.award_type_enum not in AwardType.NON_JUDGED_NON_TEAM_AWARDS: if award.award_type_enum == AwardType.CHAIRMANS: point_value = DistrictPointValues.CHAIRMANS.get(event.year, DistrictPointValues.CHAIRMANS_DEFAULT) elif award.award_type_enum in {AwardType.ENGINEERING_INSPIRATION, AwardType.ROOKIE_ALL_STAR}: point_value = DistrictPointValues.EI_AND_RAS_DEFAULT else: point_value = DistrictPointValues.OTHER_AWARD_DEFAULT else: # Legacy awards if award.award_type_enum in DistrictPointValues.LEGACY_5_PT_AWARDS.get(event.year, []): point_value = 5 elif award.award_type_enum in DistrictPointValues.LEGACY_2_PT_AWARDS.get(event.year, []): point_value = 2 # Add award points to all teams who won for team in award.team_list: district_points['points'][team.id()]['award_points'] += point_value * POINTS_MULTIPLIER # Filter out teams not in this district (only keep those with a DistrictTeam present for this district) for district_team_future in district_team_futures: district_team = district_team_future.get_result() team_key = district_team.team.id() if team_key in district_points['points']: single_district_points['points'][team_key] = district_points['points'][team_key] if team_key in district_points['tiebreakers']: single_district_points['tiebreakers'][team_key] = district_points['tiebreakers'][team_key] for team, point_breakdown in single_district_points['points'].items(): for p in point_breakdown.values(): single_district_points['points'][team]['total'] += p return single_district_points
def get_awards_async(self): from models.award import Award award_keys = yield Award.query(Award.event == self.key).fetch_async(500, keys_only=True) self._awards = yield ndb.get_multi_async(award_keys)
def render_team_history(cls, handler, team, is_canonical): event_team_keys_future = EventTeam.query( EventTeam.team == team.key).fetch_async(1000, keys_only=True) award_keys_future = Award.query( Award.team_list == team.key).fetch_async(1000, keys_only=True) event_teams_futures = ndb.get_multi_async( event_team_keys_future.get_result()) awards_futures = ndb.get_multi_async(award_keys_future.get_result()) event_keys = [ event_team_future.get_result().event for event_team_future in event_teams_futures ] events_futures = ndb.get_multi_async(event_keys) awards_by_event = {} for award_future in awards_futures: award = award_future.get_result() if award.event.id() not in awards_by_event: awards_by_event[award.event.id()] = [award] else: awards_by_event[award.event.id()].append(award) event_awards = [] current_event = None matches_upcoming = None short_cache = False for event_future in events_futures: event = event_future.get_result() if event.now: current_event = event team_matches_future = Match.query(Match.event == event.key, Match.team_key_names == team.key_name)\ .fetch_async(500, keys_only=True) matches = ndb.get_multi(team_matches_future.get_result()) matches_upcoming = MatchHelper.upcomingMatches(matches) if event.within_a_day: short_cache = True if event.key_name in awards_by_event: sorted_awards = AwardHelper.organizeAwards( awards_by_event[event.key_name]) else: sorted_awards = [] event_awards.append((event, sorted_awards)) event_awards = sorted( event_awards, key=lambda (e, _): e.start_date if e.start_date else datetime.datetime(e.year, 12, 31)) years = sorted( set([ et.get_result().year for et in event_teams_futures if et.get_result().year is not None ])) handler.template_values.update({ 'is_canonical': is_canonical, 'team': team, 'event_awards': event_awards, 'years': years, 'current_event': current_event, 'matches_upcoming': matches_upcoming }) if short_cache: handler._cache_expiration = handler.SHORT_CACHE_EXPIRATION path = os.path.join(os.path.dirname(__file__), '../templates/team_history.html') return template.render(path, handler.template_values)
def _render(self, team_number, year=None, explicit_year=False): team = Team.get_by_id("frc" + team_number) if not team: return self.redirect("/error/404") event_teams = EventTeam.query(EventTeam.team == team.key).fetch(1000) event_keys = [event_team.event for event_team in event_teams if event_team.year == year] events = ndb.get_multi(event_keys) for event in events: if not event.start_date: event.start_date = datetime.datetime(year, 12, 31) #unknown goes last events = sorted(events, key=lambda event: event.start_date) years = sorted(set([a.year for a in event_teams if a.year != None])) awards_future = Award.query(Award.year == year, Award.team == team.key).fetch_async(500) for e in events: e.team_matches_future = Match.query(Match.event == e.key, Match.team_key_names == team.key_name).fetch_async(500) # Return an array of event names and a list of matches from that event that the # team was a participant in. participation = list() year_wlt_list = list() current_event = None matches_upcoming = None short_cache = False for e in events: awards = AwardHelper.organizeAwards([award for award in awards_future.get_result() if award.event == e.key]) matches = e.team_matches_future.get_result() matches_organized = MatchHelper.organizeMatches(matches) if e.now: current_event = e matches_upcoming = MatchHelper.upcomingMatches(matches) if event.within_a_day: short_cache = True wlt = EventHelper.calculateTeamWLTFromMatches(team.key_name, matches) year_wlt_list.append(wlt) if wlt["win"] + wlt["loss"] + wlt["tie"] == 0: display_wlt = None else: display_wlt = wlt team_rank = None if e.rankings: for element in e.rankings: if element[1] == team_number: team_rank = element[0] break participation.append({ 'event' : e, 'matches' : matches_organized, 'wlt': display_wlt, 'rank': team_rank, 'awards': awards }) year_wlt = {"win": 0, "loss": 0, "tie": 0} for wlt in year_wlt_list: year_wlt["win"] += wlt["win"] year_wlt["loss"] += wlt["loss"] year_wlt["tie"] += wlt["tie"] if year_wlt["win"] + year_wlt["loss"] + year_wlt["tie"] == 0: year_wlt = None template_values = { "explicit_year": explicit_year, "team": team, "participation": participation, "year": year, "years": years, "year_wlt": year_wlt, "current_event": current_event, "matches_upcoming": matches_upcoming } if short_cache: self._cache_expiration = self.SHORT_CACHE_EXPIRATION path = os.path.join(os.path.dirname(__file__), '../templates/team_details.html') return template.render(path, template_values)
def _render(self, team_key): self._set_team(team_key) award_keys_future = Award.query(Award.team_list == self.team.key).fetch_async(1000, keys_only=True) awards_futures = ndb.get_multi_async(award_keys_future.get_result()) awards_list = [ModelToDict.awardConverter(award_future.get_result()) for award_future in awards_futures] return json.dumps(awards_list, ensure_ascii=True)
def _query_async(self): event_key = self._query_args[0] awards = yield Award.query(Award.event == ndb.Key(Event, event_key)).fetch_async() raise ndb.Return(awards)
def get_awards_async(): award_keys = yield Award.query( Award.year == year, Award.team_list == team.key).fetch_async(500, keys_only=True) awards = yield ndb.get_multi_async(award_keys) raise ndb.Return(awards)
def prepAwards(self): from models.award import Award if self._awards_future is None: self._awards_future = Award.query(Award.event == self.key).fetch_async(500)
def get_awards_async(self): from models.award import Award award_keys = yield Award.query(Award.event == self.key).fetch_async( 500, keys_only=True) self._awards = yield ndb.get_multi_async(award_keys)
def calculate_event_points(cls, event): match_key_futures = Match.query(Match.event == event.key).fetch_async(None, keys_only=True) award_key_futures = Award.query(Award.event == event.key).fetch_async(None, keys_only=True) match_futures = ndb.get_multi_async(match_key_futures.get_result()) award_futures = ndb.get_multi_async(award_key_futures.get_result()) POINTS_MULTIPLIER = 3 if event.event_type_enum == EventType.DISTRICT_CMP else 1 district_points = { 'points': defaultdict(lambda: { 'qual_points': 0, 'elim_points': 0, 'alliance_points': 0, 'award_points': 0, 'total': 0, }), 'tiebreakers': defaultdict(lambda: { # for tiebreaker stats that can't be calculated with 'points' 'qual_wins': 0, 'highest_qual_scores': [], }), } # match points elim_num_wins = defaultdict(lambda: defaultdict(int)) elim_alliances = defaultdict(lambda: defaultdict(list)) for match_future in match_futures: match = match_future.get_result() if not match.has_been_played: continue if match.comp_level == 'qm': if match.winning_alliance == '': for team in match.team_key_names: district_points['points'][team]['qual_points'] += 1 * POINTS_MULTIPLIER else: for team in match.alliances[match.winning_alliance]['teams']: district_points['points'][team]['qual_points'] += 2 * POINTS_MULTIPLIER district_points['tiebreakers'][team]['qual_wins'] += 1 for color in ['red', 'blue']: for team in match.alliances[color]['teams']: score = match.alliances[color]['score'] district_points['tiebreakers'][team]['highest_qual_scores'] = heapq.nlargest(3, district_points['tiebreakers'][team]['highest_qual_scores'] + [score]) else: if match.winning_alliance == '': continue match_set_key = '{}_{}{}'.format(match.event.id(), match.comp_level, match.set_number) elim_num_wins[match_set_key][match.winning_alliance] += 1 elim_alliances[match_set_key][match.winning_alliance] += match.alliances[match.winning_alliance]['teams'] if elim_num_wins[match_set_key][match.winning_alliance] >= 2: for team in elim_alliances[match_set_key][match.winning_alliance]: district_points['points'][team]['elim_points'] += 5* POINTS_MULTIPLIER # alliance points if event.alliance_selections: selection_points = EventHelper.alliance_selections_to_points(event.alliance_selections) for team, points in selection_points.items(): district_points['points'][team]['alliance_points'] += points * POINTS_MULTIPLIER else: logging.warning("Event {} has no alliance selection district_points!".format(event.key.id())) # award points for award_future in award_futures: award = award_future.get_result() if award.award_type_enum not in AwardType.NON_JUDGED_NON_TEAM_AWARDS: if award.award_type_enum == AwardType.CHAIRMANS: point_value = 10 elif award.award_type_enum in {AwardType.ENGINEERING_INSPIRATION, AwardType.ROOKIE_ALL_STAR}: point_value = 8 else: point_value = 5 for team in award.team_list: district_points['points'][team.id()]['award_points'] += point_value * POINTS_MULTIPLIER for team, point_breakdown in district_points['points'].items(): for p in point_breakdown.values(): district_points['points'][team]['total'] += p return district_points
def calculate_event_points(cls, event): match_key_futures = Match.query(Match.event == event.key).fetch_async(None, keys_only=True) award_key_futures = Award.query(Award.event == event.key).fetch_async(None, keys_only=True) match_futures = ndb.get_multi_async(match_key_futures.get_result()) award_futures = ndb.get_multi_async(award_key_futures.get_result()) POINTS_MULTIPLIER = 3 if event.event_type_enum == EventType.DISTRICT_CMP else 1 district_points = { 'points': defaultdict(lambda: { 'qual_points': 0, 'elim_points': 0, 'alliance_points': 0, 'award_points': 0, 'total': 0, }), 'tiebreakers': defaultdict(lambda: { # for tiebreaker stats that can't be calculated with 'points' 'qual_wins': 0, 'highest_qual_scores': [], }), } # match points if event.year == 2015: from helpers.match_helper import MatchHelper # circular import issue # qual match points are calculated by rank if event.rankings and len(event.rankings) > 1: rankings = event.rankings[1:] # skip title row num_teams = len(rankings) alpha = 1.07 for row in rankings: rank = int(row[0]) team = 'frc{}'.format(row[1]) qual_points = int(np.ceil(cls.inverf(float(num_teams - 2 * rank + 2) / (alpha * num_teams)) * (10.0 / cls.inverf(1.0 / alpha)) + 12)) district_points['points'][team]['qual_points'] = qual_points * POINTS_MULTIPLIER else: logging.warning("Event {} has no rankings for qual_points calculations!".format(event.key.id())) matches = MatchHelper.organizeMatches([mf.get_result() for mf in match_futures]) # qual match calculations. only used for tiebreaking for match in matches['qm']: for color in ['red', 'blue']: for team in match.alliances[color]['teams']: score = match.alliances[color]['score'] district_points['tiebreakers'][team]['highest_qual_scores'] = heapq.nlargest(3, district_points['tiebreakers'][team]['highest_qual_scores'] + [score]) # elim match point calculations # count number of matches played per team per comp level num_played = defaultdict(lambda: defaultdict(int)) for level in ['qf', 'sf']: for match in matches[level]: if not match.has_been_played: continue for color in ['red', 'blue']: for team in match.alliances[color]['teams']: num_played[level][team] += 1 # qf and sf points advancement = MatchHelper.generatePlayoffAdvancement2015(matches) for last_level, level in [('qf', 'sf'), ('sf', 'f')]: for (teams, _, _) in advancement[last_level]: teams = ['frc{}'.format(t) for t in teams] done = False for match in matches[level]: for color in ['red', 'blue']: if set(teams).intersection(set(match.alliances[color]['teams'])) != set(): for team in teams: points = 5.0 if last_level == 'qf' else 3.3 district_points['points'][team]['elim_points'] += int(np.ceil(points * num_played[last_level][team])) * POINTS_MULTIPLIER done = True break if done: break if done: break # final points num_wins = {'red': 0, 'blue': 0} team_matches_played = {'red': [], 'blue': []} for match in matches['f']: if not match.has_been_played or match.winning_alliance == '': continue num_wins[match.winning_alliance] += 1 for team in match.alliances[match.winning_alliance]['teams']: team_matches_played[match.winning_alliance].append(team) if num_wins[match.winning_alliance] >= 2: for team in team_matches_played[match.winning_alliance]: district_points['points'][team]['elim_points'] += 5 * POINTS_MULTIPLIER else: elim_num_wins = defaultdict(lambda: defaultdict(int)) elim_alliances = defaultdict(lambda: defaultdict(list)) for match_future in match_futures: match = match_future.get_result() if not match.has_been_played: continue if match.comp_level == 'qm': if match.winning_alliance == '': for team in match.team_key_names: district_points['points'][team]['qual_points'] += 1 * POINTS_MULTIPLIER else: for team in match.alliances[match.winning_alliance]['teams']: district_points['points'][team]['qual_points'] += 2 * POINTS_MULTIPLIER district_points['tiebreakers'][team]['qual_wins'] += 1 for color in ['red', 'blue']: for team in match.alliances[color]['teams']: score = match.alliances[color]['score'] district_points['tiebreakers'][team]['highest_qual_scores'] = heapq.nlargest(3, district_points['tiebreakers'][team]['highest_qual_scores'] + [score]) else: if match.winning_alliance == '': continue match_set_key = '{}_{}{}'.format(match.event.id(), match.comp_level, match.set_number) elim_num_wins[match_set_key][match.winning_alliance] += 1 elim_alliances[match_set_key][match.winning_alliance] += match.alliances[match.winning_alliance]['teams'] if elim_num_wins[match_set_key][match.winning_alliance] >= 2: for team in elim_alliances[match_set_key][match.winning_alliance]: district_points['points'][team]['elim_points'] += 5* POINTS_MULTIPLIER # alliance points if event.alliance_selections: selection_points = EventHelper.alliance_selections_to_points(event.alliance_selections) for team, points in selection_points.items(): district_points['points'][team]['alliance_points'] += points * POINTS_MULTIPLIER else: logging.warning("Event {} has no alliance selection district_points!".format(event.key.id())) # award points for award_future in award_futures: award = award_future.get_result() if award.award_type_enum not in AwardType.NON_JUDGED_NON_TEAM_AWARDS: if award.award_type_enum == AwardType.CHAIRMANS: point_value = 10 elif award.award_type_enum in {AwardType.ENGINEERING_INSPIRATION, AwardType.ROOKIE_ALL_STAR}: point_value = 8 else: point_value = 5 for team in award.team_list: district_points['points'][team.id()]['award_points'] += point_value * POINTS_MULTIPLIER for team, point_breakdown in district_points['points'].items(): for p in point_breakdown.values(): district_points['points'][team]['total'] += p return district_points
def get_awards_async(): award_keys = yield Award.query(Award.year == year, Award.team_list == team.key).fetch_async(500, keys_only=True) awards = yield ndb.get_multi_async(award_keys) raise ndb.Return(awards)
def update(self, event_key): """ Updates EventTeams for an event. Returns a tuple of (teams, event_teams, event_team_keys_to_delete) An EventTeam is valid iff the team: a) played a match at the event, b) the team received an award at the event, c) the event has not yet occurred, d) or the event is not from the current year. (This is to make sure we don't delete old data we may no longer be able to scrape) """ event = Event.get_by_id(event_key) cur_year = datetime.datetime.now().year # Add teams from Matches and Awards team_ids = set() match_key_futures = Match.query( Match.event == event.key).fetch_async(1000, keys_only=True) award_key_futures = Award.query( Award.event == event.key).fetch_async(1000, keys_only=True) match_futures = ndb.get_multi_async(match_key_futures.get_result()) award_futures = ndb.get_multi_async(award_key_futures.get_result()) for match_future in match_futures: match = match_future.get_result() for team in match.team_key_names: team_ids.add(team) for award_future in award_futures: award = award_future.get_result() for team_key in award.team_list: team_ids.add(team_key.id()) # Create or update EventTeams teams = [Team(id=team_id, team_number=int(team_id[3:])) for team_id in team_ids] if teams: event_teams = [EventTeam(id=event_key + "_" + team.key.id(), event=event.key, team=team.key, year=event.year) for team in teams] else: event_teams = None # Delete EventTeams for teams who did not participate in the event # Only runs if event is over existing_event_teams_keys = EventTeam.query( EventTeam.event == event.key).fetch(1000, keys_only=True) existing_event_teams = ndb.get_multi(existing_event_teams_keys) existing_team_ids = set() for et in existing_event_teams: existing_team_ids.add(et.team.id()) et_keys_to_delete = set() if event.year == cur_year and event.end_date is not None and event.end_date < datetime.datetime.now(): for team_id in existing_team_ids.difference(team_ids): et_key_name = "{}_{}".format(event.key_name, team_id) et_keys_to_delete.add(ndb.Key(EventTeam, et_key_name)) return teams, event_teams, et_keys_to_delete