Skip to content

Commit

Permalink
Add game summary for NCAAB boxscores
Browse files Browse the repository at this point in the history
A game summary including a half-by-half score should be included as an
attribute to the NCAAB Boxscores class, which returns a dictionary of
both the home and away team's score per half, including any overtime
results.

Signed-Off-By: Robert Clark <robdclark@outlook.com>
  • Loading branch information
roclark committed Dec 24, 2019
1 parent ed82faf commit 22206d4
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 0 deletions.
62 changes: 62 additions & 0 deletions sportsreference/ncaab/boxscore.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ def __init__(self, uri):
self._losing_name = None
self._losing_abbr = None
self._pace = None
self._summary = None
self._away_ranking = None
self._away_record = None
self._away_minutes_played = None
Expand Down Expand Up @@ -568,6 +569,48 @@ def _find_players(self, boxscore):
away_players, home_players = self._instantiate_players(player_dict)
return away_players, home_players

def _parse_summary(self, boxscore):
"""
Find the game summary including score in each quarter.
The game summary provides further information on the points scored
during each half, including the final score and any overtimes if
applicable. The final output will be in a dictionary with two keys,
'away' and 'home'. The value of each key will be a list for each
respective team's score by order of the half, with the first element
belonging to the first half, similar to the following:
{
'away': [22, 31],
'home': [40, 41]
}
Parameters
----------
boxscore : PyQuery object
A PyQuery object containing all of the HTML from the boxscore.
Returns
-------
dict
Returns a ``dictionary`` representing the score for each team in
each quarter of the game.
"""
team = ['away', 'home']
summary = {'away': [], 'home': []}
game_summary = boxscore(BOXSCORE_SCHEME['summary'])
for ind, team_info in enumerate(game_summary('tr').items()):
# Only pull the first N-1 items as the last element is the final
# score for each team which is already stored in an attribute, and
# shouldn't be duplicated.
for half in list(team_info('td[class="right"]').items())[:-1]:
ind = ind % 2
try:
summary[team[ind]].append(int(half.text()))
except ValueError:
summary[team[ind]].append(None)
return summary

def _parse_game_data(self, uri):
"""
Parses a value for every attribute.
Expand Down Expand Up @@ -615,6 +658,10 @@ def _parse_game_data(self, uri):
value = self._parse_ranking(short_field, boxscore)
setattr(self, field, value)
continue
if short_field == 'summary':
value = self._parse_summary(boxscore)
setattr(self, field, value)
continue
index = 0
if short_field in BOXSCORE_ELEMENT_INDEX.keys():
index = BOXSCORE_ELEMENT_INDEX[short_field]
Expand Down Expand Up @@ -780,6 +827,21 @@ def location(self):
"""
return self._location

@property
def summary(self):
"""
Returns a ``dictionary`` with two keys, 'away' and 'home'. The value of
each key will be a list for each respective team's score by order of
the half, with the first element belonging to the first half, similar
to the following:
{
'away': [22, 31],
'home': [40, 41]
}
"""
return self._summary

@property
def winner(self):
"""
Expand Down
1 change: 1 addition & 0 deletions sportsreference/ncaab/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
'winning_abbr': '',
'losing_name': '',
'losing_abbr': '',
'summary': 'table#line-score',
'pace': 'td[data-stat="pace"]:first',
'away_record': 'div#boxes div[class="section_heading"] h2',
'away_minutes_played': 'tfoot td[data-stat="mp"]',
Expand Down
4 changes: 4 additions & 0 deletions tests/integration/boxscore/test_ncaab_boxscore.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ def setup_method(self, *args, **kwargs):
def test_ncaab_boxscore_returns_requested_boxscore(self):
for attribute, value in self.results.items():
assert getattr(self.boxscore, attribute) == value
assert getattr(self.boxscore, 'summary') == {
'away': [33, 31],
'home': [50, 39]
}

def test_invalid_url_yields_empty_class(self):
flexmock(Boxscore) \
Expand Down
21 changes: 21 additions & 0 deletions tests/unit/test_ncaab_boxscore.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,27 @@ def test_invalid_home_record_returns_default_losses(self):

assert self.boxscore.home_losses == 0

def test_game_summary_with_no_scores_returns_none(self):
result = Boxscore(None)._parse_summary(pq(
"""<table id="line-score">
<tbody>
<tr>
<td class="right"></td>
<td class="right"></td>
</tr>
<tr>
<td class="right"></td>
<td class="right"></td>
</tr>
</tbody>
</table>"""
))

assert result == {
'away': [None],
'home': [None]
}

def test_invalid_url_returns_none(self):
result = Boxscore(None)._retrieve_html_page('')

Expand Down

0 comments on commit 22206d4

Please sign in to comment.