Skip to content

Commit

Permalink
Merge 0004468 into cf298c2
Browse files Browse the repository at this point in the history
  • Loading branch information
reddigari committed Mar 2, 2019
2 parents cf298c2 + 0004468 commit cf2682a
Show file tree
Hide file tree
Showing 7 changed files with 323 additions and 20 deletions.
7 changes: 7 additions & 0 deletions mlbgame/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@
import mlbgame.events
import mlbgame.game
import mlbgame.info
import mlbgame.innings
import mlbgame.stats
import mlbgame.version

Expand Down Expand Up @@ -235,6 +236,12 @@ def important_dates(year=None):
return mlbgame.info.ImportantDates(data)


def game_innings(game_id):
"""Return dictionary of game innings for game matching the game id."""
data = mlbgame.innings.game_innings(game_id)
return [mlbgame.innings.Inning(data[x], x) for x in data]


def league():
"""Return Info object that contains league information"""
return mlbgame.info.Info(mlbgame.info.league_info())
Expand Down
10 changes: 10 additions & 0 deletions mlbgame/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
'org_id=1&season={0}')
BCAST_INFO = ('http://mlb.mlb.com/lookup/json/named.mlb_broadcast_info.bam?'
'team_id={}&season={}')
INNINGS_URL = BASE_URL + 'gid_{3}/inning/inning_all.xml'
# Local Directory
PWD = os.path.join(os.path.dirname(__file__))

Expand Down Expand Up @@ -91,6 +92,15 @@ def get_game_events(game_id):
raise ValueError('Could not find a game with that id.')


def get_innings(game_id):
"""Return the innings file of a game with matching id."""
year, month, day = get_date_from_game_id(game_id)
try:
return urlopen(INNINGS_URL.format(year, month, day, game_id))
except HTTPError:
raise ValueError('Could not find a game with that id.')


def get_overview(game_id):
"""Return the linescore file of a game with matching id."""
year, month, day = get_date_from_game_id(game_id)
Expand Down
36 changes: 20 additions & 16 deletions mlbgame/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,26 @@ def __inning_info(inning, part):
# info
info = []
# loop through the half
half = inning.findall(part)[0]
for y in half.xpath('.//atbat | .//action'):
atbat_action = {'tag': y.tag}
# loop through and save info
for i in y.attrib:
atbat_action[i] = y.attrib[i]
# only get pitches for atbat tags
if y.tag == 'atbat':
atbat_action['pitches'] = []
for i in y.findall('pitch'):
pitch = {}
# loop through pitch info
for n in i.attrib:
pitch[n] = i.attrib[n]
atbat_action['pitches'].append(pitch)
info.append(atbat_action)
# Added more robust exception handling to catch final innings'
# with only 1 frame 'top'
try:
half = inning.findall(part)[0]
for y in half.xpath('.//atbat | .//action'):
atbat_action = {'tag': y.tag}
# loop through and save info
for i in y.attrib:
atbat_action[i] = y.attrib[i]
if y.tag == 'atbat':
atbat_action['pitches'] = []
for i in y.findall('pitch'):
pitch = {}
# loop through pitch info
for n in i.attrib:
pitch[n] = i.attrib[n]
atbat_action['pitches'].append(pitch)
info.append(atbat_action)
except IndexError:
pass
return info


Expand Down
110 changes: 110 additions & 0 deletions mlbgame/innings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#!/usr/bin/env python

"""Module that is used for getting the detailed events by inning
that occured throughout games.
"""

import mlbgame.data
import mlbgame.object
import mlbgame.events

import lxml.etree as etree


def game_innings(game_id):
"""Return dictionary of innings for a game with matching id."""
# get data from data module
data = mlbgame.data.get_innings(game_id)
# parse XML
parsed = etree.parse(data)
root = parsed.getroot()
# empty output file
output = {}
# loop through innings
innings = root.findall('inning')
for x in innings:
output[x.attrib['num']] = {
'top': mlbgame.events.__inning_info(x, 'top'),
'bottom': mlbgame.events.__inning_info(x, 'bottom')
}
return output


class Inning(mlbgame.events.Inning):
""" Class that inherits from events - Inning
"""

def nice_output(self):
"""Prints basic inning info in a nice way."""
return 'Inning {0}'.format(self.num)

def __str__(self):
return self.nice_output()


class AtBat(mlbgame.events.AtBat):
""" Class that inherits from events - AtBat
"""

def nice_output(self):
"""Prints basic at bat info in a nice way."""
return self.des

def __str__(self):
return self.nice_output()


class Pitch(mlbgame.events.Pitch):
"""Class that inherits from events with more data
Properties:
des
des_e
id
type
code
tfs
tfs_zulu
x
y
event_num
sv_id
play_guid
start_speed
end_speed
sz_top
sz_bot
pfx_x
pfx_z
px
pz
x0
y0
z0
vx0
vy0
vz0
ax
ay
az
break_y
break_angle
break_length
pitch_type
type_confidence
zone
nasty
spin_dir
spin_rate
cc
mt
"""

def nice_output(self):
"""Prints basic event info in a nice way."""
out = 'Pitch: {0} starting at {1}: ending at: {2} Description: {3}'
return out.format(self.pitch_type, self.start_speed,
self.end_speed, self.des)

def __str__(self):
return self.nice_output()
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,6 @@
data_files=[('docs', ['README.md', 'LICENSE', 'description.rst'])],
install_requires=['lxml'],
extras_require={
'dev': ['pytest', 'pytest-cov', 'coveralls']
'dev': ['pytest>=3.6', 'pytest-cov', 'coveralls']
}
)
9 changes: 6 additions & 3 deletions tests/test_game.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,20 @@ def test_day(self):
self.assertEqual(game.date, datetime(2016, 8, 2, 19, 10))
self.assertEqual(game.game_id, '2016_08_02_nyamlb_nynmlb_1')
self.assertEqual(game.game_league, 'AN')
self.assertEqual(game.game_start_time, '7:10PM')
self.assertEqual(game.game_start_time, '07:10 pm')
self.assertEqual(game.game_status, 'FINAL')
self.assertEqual(game.game_tag, 'go_game')
self.assertEqual(game.home_team, 'Mets')
self.assertEqual(game.home_team_errors, 0)
self.assertEqual(game.home_team_hits, 10)
self.assertEqual(game.home_team_runs, 7)
self.assertEqual(game.l_pitcher, 'M. Tanaka')
self.assertEqual(game.l_pitcher, 'Masahiro Tanaka')
self.assertEqual(game.l_pitcher_losses, 4)
self.assertEqual(game.l_pitcher_wins, 7)
self.assertEqual(game.l_team, 'Yankees')
self.assertEqual(game.sv_pitcher, '. ')
self.assertEqual(game.sv_pitcher_saves, 0)
self.assertEqual(game.w_pitcher, 'J. deGrom')
self.assertEqual(game.w_pitcher, 'Jacob deGrom')
self.assertEqual(game.w_pitcher_losses, 5)
self.assertEqual(game.w_pitcher_wins, 7)
self.assertEqual(game.w_team, 'Mets')
Expand Down Expand Up @@ -95,6 +95,9 @@ def test_games(self):
self.assertIsInstance(game.home_team_runs, int)
self.assertIsInstance(game.nice_score(), str)
if game.game_tag == 'go_game':
# skip canceled games, which don't have W/L attributes
if game.home_team_runs == game.away_team_runs == 0:
continue
self.assertIsInstance(game.l_pitcher, str)
self.assertIsInstance(game.l_pitcher_losses, int)
self.assertIsInstance(game.l_pitcher_wins, int)
Expand Down

0 comments on commit cf2682a

Please sign in to comment.