Top

nflgame.update_sched module

from __future__ import absolute_import, division, print_function
import argparse
import time
import json
import os
import sys
import urllib2
from collections import OrderedDict
import xml.dom.minidom as xml

import nflgame


def year_phase_week(year=None, phase=None, week=None):
    cur_year, _ = nflgame.live.current_year_and_week()
    season_types = (
        ('PRE', xrange(0, 4 + 1)),
        ('REG', xrange(1, 17 + 1)),
        ('POST', xrange(1, 4 + 1)),
    )
    for y in range(2009, cur_year+1):
        if year is not None and year != y:
            continue
        for p, weeks in season_types:
            if phase is not None and phase != p:
                continue
            for w in weeks:
                if week is not None and week != w:
                    continue
                yield y, p, w


def schedule_url(year, stype, week):
    """
    Returns the NFL.com XML schedule URL. `year` should be an
    integer, `stype` should be one of the strings `PRE`, `REG` or
    `POST`, and `gsis_week` should be a value in the range
    `[0, 17]`.
    """
    xmlurl = 'http://www.nfl.com/ajax/scorestrip?'
    if stype == 'POST':
        week += 17
        if week == 21:  # NFL.com you so silly
            week += 1
    return '%sseason=%d&seasonType=%s&week=%d' % (xmlurl, year, stype, week)


def week_schedule(year, stype, week):
    """
    Returns a list of dictionaries with information about each game in
    the week specified. The games are ordered by gsis_id. `year` should
    be an integer, `stype` should be one of the strings `PRE`, `REG` or
    `POST`, and `gsis_week` should be a value in the range `[1, 17]`.
    """
    url = schedule_url(year, stype, week)
    try:
        dom = xml.parse(urllib2.urlopen(url))
    except urllib2.HTTPError:
        print >> sys.stderr, 'Could not load %s' % url
        return []

    games = []
    for g in dom.getElementsByTagName("g"):
        gsis_id = g.getAttribute('eid')
        games.append({
            'eid': gsis_id,
            'wday': g.getAttribute('d'),
            'year': year,
            'month': int(gsis_id[4:6]),
            'day': int(gsis_id[6:8]),
            'time': g.getAttribute('t'),
            'meridiem': None,
            'season_type': stype,
            'week': week,
            'home': g.getAttribute('h'),
            'away': g.getAttribute('v'),
            'gamekey': g.getAttribute('gsis'),
        })

    for game in games:
        h = int(game['time'].split(':')[0])
        m = int(game['time'].split(':')[1])
        if 0 < h <= 5:  # All games before "6:00" are PM until proven otherwise
            game['meridiem'] = 'PM'

        if game['meridiem'] is None:

            days_games = [g for g in games if g['wday'] == game['wday']]
            preceeding = [g for g in days_games if g['eid'] < game['eid']]
            proceeding = [g for g in days_games if g['eid'] > game['eid']]

            # If any games *after* this one are AM then so is this
            if any(g['meridiem'] == 'AM' for g in proceeding):
                game['meridiem'] = 'AM'
            # If any games *before* this one are PM then so is this one
            elif any(g['meridiem'] == 'PM' for g in preceeding):
                game['meridiem'] = 'PM'
            # If any games *after* this one have an "earlier" start it's AM
            elif any(h > t for t in [int(g['time'].split(':')[0]) for g in proceeding]):
                game['meridiem'] = 'AM'
            # If any games *before* this one have a "later" start time it's PM
            elif any(h < t for t in [int(g['time'].split(':')[0]) for g in preceeding]):
                game['meridiem'] = 'PM'

        if game['meridiem'] is None:
            if game['wday'] not in ['Sat', 'Sun']:
                game['meridiem'] = 'PM'
            if game['season_type'] == 'POST':
                game['meridiem'] = 'PM'

    return games


def new_schedule():
    """
    Builds an entire schedule from scratch.
    """
    sched = OrderedDict()
    for year, stype, week in year_phase_week():
        update_week(sched, year, stype, week)
    return sched


def update_week(sched, year, stype, week):
    """
    Updates the schedule for the given week in place. `year` should be
    an integer year, `stype` should be one of the strings `PRE`, `REG`
    or `POST`, and `week` should be an integer in the range `[1, 17]`.

    Returns:
        bool: True if at least one game was returned from week_schedule().
        False otherwise.
    """
    games = week_schedule(year, stype, week)
    if not games:
        return False

    for game in games:
        sched[game['eid']] = game

    return True


def write_schedule(fpath, sched):
    alist = []
    for gsis_id in sorted(sched):
        alist.append([gsis_id, sched[gsis_id]])
    json.dump({'time': time.time(), 'games': alist},
              open(fpath, 'w+'), indent=1, sort_keys=True,
              separators=(',', ': '))


def eprint(*args, **kwargs):
    kwargs['file'] = sys.stderr
    print(*args, **kwargs)


def run():
    parser = argparse.ArgumentParser(
        description='Updates nflgame\'s schedule to correspond to the latest '
                    'information.',
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    aa = parser.add_argument
    aa('--json-update-file', type=str, default=None,
       help='When set, the file provided will be updated in place with new '
            'schedule data from NFL.com. If this option is not set, then the '
            '"schedule.json" file that comes with nflgame will be updated '
            'instead.')
    aa('--rebuild', action='store_true',
       help='When set, the entire schedule will be rebuilt.')
    aa('--year', default=None, type=int,
       help='Force the update to a specific year.')
    aa('--phase', default=None, choices=['PRE', 'REG', 'POST'],
       help='Force the update to a specific phase.')
    aa('--week', default=None, type=int,
       help='Force the update to a specific week.')
    args = parser.parse_args()

    if args.json_update_file is None:
        args.json_update_file = nflgame.sched._sched_json_file

    # Before doing anything laborious, make sure we have write access to
    # the JSON database.
    if not os.access(args.json_update_file, os.W_OK):
        eprint('I do not have write access to "%s".' % args.json_update_file)
        eprint('Without write access, I cannot update the schedule.')
        sys.exit(1)

    if args.rebuild:
        sched = new_schedule()
    else:
        sched, last = nflgame.sched._create_schedule(args.json_update_file)
        print('Last updated: %s' % last)

        if (args.year, args.phase, args.week) == (None, None, None):
            year, week = nflgame.live.current_year_and_week()
            phase = nflgame.live._cur_season_phase
            update_week(sched, year, phase, week)
        else:
            for y, p, w in year_phase_week(args.year, args.phase, args.week):
                print('Updating (%d, %s, %d)...' % (y, p, w))
                update_week(sched, y, p, w)
    write_schedule(args.json_update_file, sched)

if __name__ == '__main__':
    run()

Functions

def eprint(

*args, **kwargs)

def eprint(*args, **kwargs):
    kwargs['file'] = sys.stderr
    print(*args, **kwargs)

def new_schedule(

)

Builds an entire schedule from scratch.

def new_schedule():
    """
    Builds an entire schedule from scratch.
    """
    sched = OrderedDict()
    for year, stype, week in year_phase_week():
        update_week(sched, year, stype, week)
    return sched

def run(

)

def run():
    parser = argparse.ArgumentParser(
        description='Updates nflgame\'s schedule to correspond to the latest '
                    'information.',
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    aa = parser.add_argument
    aa('--json-update-file', type=str, default=None,
       help='When set, the file provided will be updated in place with new '
            'schedule data from NFL.com. If this option is not set, then the '
            '"schedule.json" file that comes with nflgame will be updated '
            'instead.')
    aa('--rebuild', action='store_true',
       help='When set, the entire schedule will be rebuilt.')
    aa('--year', default=None, type=int,
       help='Force the update to a specific year.')
    aa('--phase', default=None, choices=['PRE', 'REG', 'POST'],
       help='Force the update to a specific phase.')
    aa('--week', default=None, type=int,
       help='Force the update to a specific week.')
    args = parser.parse_args()

    if args.json_update_file is None:
        args.json_update_file = nflgame.sched._sched_json_file

    # Before doing anything laborious, make sure we have write access to
    # the JSON database.
    if not os.access(args.json_update_file, os.W_OK):
        eprint('I do not have write access to "%s".' % args.json_update_file)
        eprint('Without write access, I cannot update the schedule.')
        sys.exit(1)

    if args.rebuild:
        sched = new_schedule()
    else:
        sched, last = nflgame.sched._create_schedule(args.json_update_file)
        print('Last updated: %s' % last)

        if (args.year, args.phase, args.week) == (None, None, None):
            year, week = nflgame.live.current_year_and_week()
            phase = nflgame.live._cur_season_phase
            update_week(sched, year, phase, week)
        else:
            for y, p, w in year_phase_week(args.year, args.phase, args.week):
                print('Updating (%d, %s, %d)...' % (y, p, w))
                update_week(sched, y, p, w)
    write_schedule(args.json_update_file, sched)

def schedule_url(

year, stype, week)

Returns the NFL.com XML schedule URL. year should be an integer, stype should be one of the strings PRE, REG or POST, and gsis_week should be a value in the range [0, 17].

def schedule_url(year, stype, week):
    """
    Returns the NFL.com XML schedule URL. `year` should be an
    integer, `stype` should be one of the strings `PRE`, `REG` or
    `POST`, and `gsis_week` should be a value in the range
    `[0, 17]`.
    """
    xmlurl = 'http://www.nfl.com/ajax/scorestrip?'
    if stype == 'POST':
        week += 17
        if week == 21:  # NFL.com you so silly
            week += 1
    return '%sseason=%d&seasonType=%s&week=%d' % (xmlurl, year, stype, week)

def update_week(

sched, year, stype, week)

Updates the schedule for the given week in place. year should be an integer year, stype should be one of the strings PRE, REG or POST, and week should be an integer in the range [1, 17].

Returns: bool: True if at least one game was returned from week_schedule(). False otherwise.

def update_week(sched, year, stype, week):
    """
    Updates the schedule for the given week in place. `year` should be
    an integer year, `stype` should be one of the strings `PRE`, `REG`
    or `POST`, and `week` should be an integer in the range `[1, 17]`.

    Returns:
        bool: True if at least one game was returned from week_schedule().
        False otherwise.
    """
    games = week_schedule(year, stype, week)
    if not games:
        return False

    for game in games:
        sched[game['eid']] = game

    return True

def week_schedule(

year, stype, week)

Returns a list of dictionaries with information about each game in the week specified. The games are ordered by gsis_id. year should be an integer, stype should be one of the strings PRE, REG or POST, and gsis_week should be a value in the range [1, 17].

def week_schedule(year, stype, week):
    """
    Returns a list of dictionaries with information about each game in
    the week specified. The games are ordered by gsis_id. `year` should
    be an integer, `stype` should be one of the strings `PRE`, `REG` or
    `POST`, and `gsis_week` should be a value in the range `[1, 17]`.
    """
    url = schedule_url(year, stype, week)
    try:
        dom = xml.parse(urllib2.urlopen(url))
    except urllib2.HTTPError:
        print >> sys.stderr, 'Could not load %s' % url
        return []

    games = []
    for g in dom.getElementsByTagName("g"):
        gsis_id = g.getAttribute('eid')
        games.append({
            'eid': gsis_id,
            'wday': g.getAttribute('d'),
            'year': year,
            'month': int(gsis_id[4:6]),
            'day': int(gsis_id[6:8]),
            'time': g.getAttribute('t'),
            'meridiem': None,
            'season_type': stype,
            'week': week,
            'home': g.getAttribute('h'),
            'away': g.getAttribute('v'),
            'gamekey': g.getAttribute('gsis'),
        })

    for game in games:
        h = int(game['time'].split(':')[0])
        m = int(game['time'].split(':')[1])
        if 0 < h <= 5:  # All games before "6:00" are PM until proven otherwise
            game['meridiem'] = 'PM'

        if game['meridiem'] is None:

            days_games = [g for g in games if g['wday'] == game['wday']]
            preceeding = [g for g in days_games if g['eid'] < game['eid']]
            proceeding = [g for g in days_games if g['eid'] > game['eid']]

            # If any games *after* this one are AM then so is this
            if any(g['meridiem'] == 'AM' for g in proceeding):
                game['meridiem'] = 'AM'
            # If any games *before* this one are PM then so is this one
            elif any(g['meridiem'] == 'PM' for g in preceeding):
                game['meridiem'] = 'PM'
            # If any games *after* this one have an "earlier" start it's AM
            elif any(h > t for t in [int(g['time'].split(':')[0]) for g in proceeding]):
                game['meridiem'] = 'AM'
            # If any games *before* this one have a "later" start time it's PM
            elif any(h < t for t in [int(g['time'].split(':')[0]) for g in preceeding]):
                game['meridiem'] = 'PM'

        if game['meridiem'] is None:
            if game['wday'] not in ['Sat', 'Sun']:
                game['meridiem'] = 'PM'
            if game['season_type'] == 'POST':
                game['meridiem'] = 'PM'

    return games

def write_schedule(

fpath, sched)

def write_schedule(fpath, sched):
    alist = []
    for gsis_id in sorted(sched):
        alist.append([gsis_id, sched[gsis_id]])
    json.dump({'time': time.time(), 'games': alist},
              open(fpath, 'w+'), indent=1, sort_keys=True,
              separators=(',', ': '))

def year_phase_week(

year=None, phase=None, week=None)

def year_phase_week(year=None, phase=None, week=None):
    cur_year, _ = nflgame.live.current_year_and_week()
    season_types = (
        ('PRE', xrange(0, 4 + 1)),
        ('REG', xrange(1, 17 + 1)),
        ('POST', xrange(1, 4 + 1)),
    )
    for y in range(2009, cur_year+1):
        if year is not None and year != y:
            continue
        for p, weeks in season_types:
            if phase is not None and phase != p:
                continue
            for w in weeks:
                if week is not None and week != w:
                    continue
                yield y, p, w