diff options
author | MichaĆ Klichowicz <emkael@tlen.pl> | 2018-10-17 20:02:57 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-10-17 20:02:57 +0200 |
commit | 984540cd2dfba29c1dc9cbc43ab6fa4c85c7727b (patch) | |
tree | d03e49f564cec7c3eec7ce7c98fae530ec1544e0 /jfr_playoff/matchinfo.py | |
parent | 9a5f06ee9cddd38e11f49a2f934de202d34e63e2 (diff) | |
parent | 31fc51ce22e7c5197ed367cadd14d8a258f8fd65 (diff) |
Merge pull request #28 from emkael/develv1.2.0
v1.2
Diffstat (limited to 'jfr_playoff/matchinfo.py')
-rw-r--r-- | jfr_playoff/matchinfo.py | 185 |
1 files changed, 154 insertions, 31 deletions
diff --git a/jfr_playoff/matchinfo.py b/jfr_playoff/matchinfo.py index 5924564..ab742d4 100644 --- a/jfr_playoff/matchinfo.py +++ b/jfr_playoff/matchinfo.py @@ -5,6 +5,7 @@ import jfr_playoff.sql as p_sql from jfr_playoff.dto import Match, Team from jfr_playoff.remote import RemoteUrl as p_remote from jfr_playoff.tournamentinfo import TournamentInfo +from jfr_playoff.logger import PlayoffLogger class MatchInfo: @@ -36,10 +37,15 @@ class MatchInfo: def __fetch_match_link(self): if 'link' in self.config: self.info.link = self.config['link'] + PlayoffLogger.get('matchinfo').info( + 'match #%d link pre-defined: %s', self.info.id, self.info.link) elif ('round' in self.config) and ('database' in self.config): event_info = TournamentInfo(self.config, self.database) self.info.link = event_info.get_results_link( 'runda%d.html' % (self.config['round'])) + PlayoffLogger.get('matchinfo').info( + 'match #%d link fetched: %s', self.info.id, self.info.link) + PlayoffLogger.get('matchinfo').info('match #%d link empty', self.info.id) def __get_predefined_scores(self): teams = [Team(), Team()] @@ -62,6 +68,9 @@ class MatchInfo: if i == 2: break scores_fetched = True + PlayoffLogger.get('matchinfo').info( + 'pre-defined scores for match #%d: %s', + self.info.id, teams) return scores_fetched, teams_fetched, teams def __get_db_teams(self, teams, fetch_scores): @@ -77,6 +86,8 @@ class MatchInfo: teams[0].score += row[2] else: teams[1].score -= row[2] + PlayoffLogger.get('matchinfo').info( + 'db scores for match #%d: %s', self.info.id, teams) return teams def __find_table_row(self, url): @@ -84,7 +95,13 @@ class MatchInfo: for row in html_content.select('tr tr'): for cell in row.select('td.t1'): if cell.text.strip() == str(self.config['table']): + PlayoffLogger.get('matchinfo.html').debug( + 'HTML row for table %d found: %s', + self.config['table'], row) return row + PlayoffLogger.get('matchinfo.html').debug( + 'HTML row for table %d not found', + self.config['table']) return None def __get_html_teams(self, teams, fetch_score): @@ -93,17 +110,48 @@ class MatchInfo: row = self.__find_table_row(self.info.link) if row is None: raise ValueError('table row not found') - score_cell = row.select('td.bdc')[-1] - scores = [ - float(text) for text - in score_cell.contents - if isinstance(text, unicode)] + try: + scores = [ + float(text) for text + in row.select('td.bdc')[-1].contents + if isinstance(text, unicode)] + except ValueError: + # single-segment match + try: + # running single-segment + scores = [ + float(text.strip()) for text + in row.select('td.bdcg a')[-1].contents + if isinstance(text, unicode)] + except IndexError: + try: + # static single-segment + scores = [ + float(text.strip()) for text + in row.select('td.bdc a')[-1].contents + if isinstance(text, unicode)] + except IndexError: + # toweled single-segment + scores = [0.0, 0.0] + # carry-over + carry_over = [ + float(text.strip()) if len(text.strip()) > 0 else 0.0 for text + in row.select('td.bdc')[0].contents + if isinstance(text, unicode)] + if len(carry_over) < 2: + # no carry-over, possibly no carry-over cells or empty + carry_over = [0.0, 0.0] + for i in range(0, 2): + scores[i] += carry_over[i] team_names = [[text for text in link.contents if isinstance(text, unicode)][0].strip(u'\xa0') for link in row.select('a[onmouseover]')] for i in range(0, 2): teams[i].name = team_names[i] teams[i].score = scores[i] + PlayoffLogger.get('matchinfo').info( + 'HTML scores for match #%d: %s', + self.info.id, teams) return teams def __get_config_teams(self, teams): @@ -133,15 +181,17 @@ class MatchInfo: else '??' for team in match_teams]) else: teams[i].name = '' + PlayoffLogger.get('matchinfo').info( + 'config scores for match #%d: %s', + self.info.id, teams) return teams def __fetch_teams_with_scores(self): (scores_fetched, teams_fetched, self.info.teams) = self.__get_predefined_scores() if scores_fetched: - if 'running' in self.config: - self.info.running = int(self.config['running']) - else: - self.info.running = -1 + PlayoffLogger.get('matchinfo').info( + 'pre-defined scores for match #%d fetched', self.info.id) + self.info.running = int(self.config.get('running', -1)) if not teams_fetched: try: try: @@ -151,10 +201,16 @@ class MatchInfo: raise KeyError('database not configured') self.info.teams = self.__get_db_teams( self.info.teams, not scores_fetched) - except (IOError, TypeError, IndexError, KeyError): + except (IOError, TypeError, IndexError, KeyError) as e: + PlayoffLogger.get('matchinfo').warning( + 'fetching DB scores for match #%d failed: %s(%s)', + self.info.id, type(e).__name__, str(e)) self.info.teams = self.__get_html_teams( self.info.teams, not scores_fetched) - except (TypeError, IndexError, KeyError, IOError, ValueError): + except (TypeError, IndexError, KeyError, IOError, ValueError) as e: + PlayoffLogger.get('matchinfo').warning( + 'fetching HTML scores for match #%d failed: %s(%s)', + self.info.id, type(e).__name__, str(e)) self.info.teams = self.__get_config_teams(self.info.teams) def __get_db_board_count(self): @@ -170,6 +226,9 @@ class MatchInfo: boards_played = max(int(row[1]), 0) if boards_to_play > 0: boards_played += int(towels[0]) + PlayoffLogger.get('matchinfo').info( + 'DB board count for match #%d: %d/%d', + self.info.id, boards_played, boards_to_play) return boards_played, boards_to_play def __has_segment_link(self, cell): @@ -183,6 +242,15 @@ class MatchInfo: def __get_html_running_boards(self, cell): return int(cell.contents[-1].strip()) + def __get_html_segment_board_count(self, segment_url): + segment_content = p_remote.fetch(segment_url) + board_rows = [row for row in segment_content.find_all('tr') if len(row.select('td.bdcc a.zb')) > 0] + board_count = len(board_rows) + played_boards = len([ + row for row in board_rows if len( + ''.join([cell.text.strip() for cell in row.select('td.bdc')])) > 0]) + return played_boards, board_count + def __get_finished_info(self, cell): segment_link = cell.select('a[href]') if len(segment_link) > 0: @@ -190,14 +258,15 @@ class MatchInfo: r'\.htm$', '.html', urljoin(self.info.link, segment_link[0]['href'])) try: - segment_content = p_remote.fetch(segment_url) - board_rows = [row for row in segment_content.find_all('tr') if len(row.select('td.bdcc a.zb')) > 0] - board_count = len(board_rows) - played_boards = len([ - row for row in board_rows if len( - ''.join([cell.text.strip() for cell in row.select('td.bdc')])) > 0]) + played_boards, board_count = self.__get_html_segment_board_count(segment_url) + PlayoffLogger.get('matchinfo').info( + 'HTML played boards count for segment: %d/%d', + played_boards, board_count) return board_count, played_boards >= board_count - except IOError: + except IOError as e: + PlayoffLogger.get('matchinfo').info( + 'cannot fetch HTML played boards count for segment: %s(%s)', + self.info.id, type(e).__name__, str(e)) return 0, False return 0, False @@ -207,14 +276,22 @@ class MatchInfo: row = self.__find_table_row(self.info.link) if row is None: raise ValueError('table row not found') - cells = row.select('td.bdc') - segments = [cell for cell in cells if self.__has_segment_link(cell)] - towels = [cell for cell in cells if self.__has_towel_image(cell)] - if len(segments) == 0: - if len(towels) > 0: - return 1, 1 # entire match is toweled, so mark as finished + for selector in ['td.bdc', 'td.bdcg']: + cells = row.select(selector) + segments = [cell for cell in cells if self.__has_segment_link(cell)] + towels = [cell for cell in cells if self.__has_towel_image(cell)] + if len(segments) == 0: + # in single-segment match, there are no td.bdc cells with segment links + # but maybe it's a multi-segment match with towels + if len(towels) > 0: + PlayoffLogger.get('matchinfo').info( + 'HTML board count for match #%d: all towels', self.info.id) + return 1, 1 # entire match is toweled, so mark as finished else: - raise ValueError('segments not found') + # not a single-segment match, no need to look for td.bdcg cells + break + if len(segments) == 0: + raise ValueError('segments not found') running_segments = row.select('td.bdca') running_boards = sum([self.__get_html_running_boards(segment) for segment in running_segments]) finished_segments = [] @@ -226,8 +303,18 @@ class MatchInfo: finished_segments.append(segment) if boards_in_segment is None and boards > 0: boards_in_segment = boards - total_boards = (len(segments) + len(towels) + len(running_segments)) * boards_in_segment + if 'bdcg' in segments[0]['class']: + # only a single-segment match will yield td.bdcg cells with segment scores + total_boards = boards_in_segment + else: + PlayoffLogger.get('matchinfo').info( + 'HTML board count for match #%d, found: %d finished segments, %d towels, %d boards per segment and %d boards in running segment', + self.info.id, len(finished_segments), len(towels), boards_in_segment, running_boards) + total_boards = (len(segments) + len(towels) + len(running_segments)) * boards_in_segment played_boards = (len(towels) + len(finished_segments)) * boards_in_segment + running_boards + PlayoffLogger.get('matchinfo').info( + 'HTML board count for match #%d: %d/%d', + self.info.id, played_boards, total_boards) return played_boards, total_boards def __fetch_board_count(self): @@ -237,10 +324,16 @@ class MatchInfo: if self.database is None: raise KeyError('database not configured') boards_played, boards_to_play = self.__get_db_board_count() - except (IOError, TypeError, IndexError, KeyError): + except (IOError, TypeError, IndexError, KeyError) as e: + PlayoffLogger.get('matchinfo').warning( + 'fetching board count from DB for match #%d failed: %s(%s)', + self.info.id, type(e).__name__, str(e)) try: boards_played, boards_to_play = self.__get_html_board_count() - except (TypeError, IndexError, KeyError, IOError, ValueError): + except (TypeError, IndexError, KeyError, IOError, ValueError) as e: + PlayoffLogger.get('matchinfo').warning( + 'fetching board count from HTML for match #%d failed: %s(%s)', + self.info.id, type(e).__name__, str(e)) pass if boards_played > 0: self.info.running = -1 \ @@ -260,6 +353,9 @@ class MatchInfo: current_segment = int( self.database.fetch( self.config['database'], p_sql.CURRENT_SEGMENT, ())[0]) + PlayoffLogger.get('matchinfo').info( + 'fetched running segment from DB for match #%d: %d', + self.info.id, current_segment) return '%s%st%d-%d.html' % ( prefix, round_no, self.config['table'], current_segment) @@ -270,11 +366,15 @@ class MatchInfo: running_link = row.select('td.bdcg a[href]') if len(running_link) == 0: raise ValueError('running link not found') + PlayoffLogger.get('matchinfo').info( + 'fetched running link from HTML for match #%d: %s', + self.info.id, running_link) return urljoin(self.info.link, running_link[0]['href']) def __determine_running_link(self): if self.info.link is None: return + match_link = self.info.link link_match = re.match(r'^(.*)runda(\d+)\.html$', self.info.link) if link_match: try: @@ -282,11 +382,31 @@ class MatchInfo: raise KeyError('database not configured') self.info.link = self.__get_db_running_link( link_match.group(1), link_match.group(2)) - except (IOError, TypeError, IndexError, KeyError): + except (IOError, TypeError, IndexError, KeyError) as e: + PlayoffLogger.get('matchinfo').warning( + 'cannot determine running link from DB for match #%d: %s(%s)', + self.info.id, type(e).__name__, str(e)) try: self.info.link = self.__get_html_running_link() - except (TypeError, IndexError, KeyError, IOError, ValueError): - pass + except (TypeError, IndexError, KeyError, IOError, ValueError) as e: + PlayoffLogger.get('matchinfo').warning( + 'cannot determine running link from HTML for match #%d: %s(%s)', + self.info.id, type(e).__name__, str(e)) + if self.info.link != match_link: + # we've detected a running segment link + # we should check if the segment's uploaded live + try: + boards_played, board_count = self.__get_html_segment_board_count(re.sub('\.htm$', '.html', self.info.link)) + except IOError as e: + PlayoffLogger.get('matchinfo').warning( + 'cannot determine running link (%s) board count for match #%d: %s(%s)', + self.info.link, self.info.id, type(e).__name__, str(e)) + boards_played = 0 + if not boards_played: + PlayoffLogger.get('matchinfo').warning( + 'running link (%s) for match #%d is not live, reverting to match link (%s)', + self.info.link, self.info.id, match_link) + self.info.link = match_link def set_phase_link(self, phase_link): if self.info.link is None: @@ -294,6 +414,9 @@ class MatchInfo: else: if self.info.link != '#': self.info.link = urljoin(phase_link, self.info.link) + PlayoffLogger.get('matchinfo').info( + 'applying phase link %s to match #%d: %s', + phase_link, self.info.id, self.info.link) def get_info(self): self.__fetch_teams_with_scores() |