<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals

import argparse
import codecs
import locale
import os
import sys

from jinja2 import Environment, FileSystemLoader

import pytz

try:
    import readline  # NOQA
except ImportError:
    pass

try:
    import tzlocal
    _DEFAULT_TIMEZONE = tzlocal.get_localzone().zone
except ImportError:
    _DEFAULT_TIMEZONE = 'Europe/Paris'

import six

from pelican import __version__

locale.setlocale(locale.LC_ALL, '')
try:
    _DEFAULT_LANGUAGE = locale.getlocale()[0]
except ValueError:
    # Don't fail on macosx: "unknown locale: UTF-8"
    _DEFAULT_LANGUAGE = None
if _DEFAULT_LANGUAGE is None:
    _DEFAULT_LANGUAGE = 'English'
else:
    _DEFAULT_LANGUAGE = _DEFAULT_LANGUAGE.split('_')[0]

_TEMPLATES_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                              "templates")
_jinja_env = Environment(
    loader=FileSystemLoader(_TEMPLATES_DIR),
    trim_blocks=True,
)

_GITHUB_PAGES_BRANCHES = {
    'personal': 'master',
    'project': 'gh-pages'
}

CONF = {
    'pelican': 'pelican',
    'pelicanopts': '',
    'basedir': os.curdir,
    'ftp_host': 'localhost',
    'ftp_user': 'anonymous',
    'ftp_target_dir': '/',
    'ssh_host': 'localhost',
    'ssh_port': 22,
    'ssh_user': 'root',
    'ssh_target_dir': '/var/www',
    's3_bucket': 'my_s3_bucket',
    'cloudfiles_username': 'my_rackspace_username',
    'cloudfiles_api_key': 'my_rackspace_api_key',
    'cloudfiles_container': 'my_cloudfiles_container',
    'dropbox_dir': '~/Dropbox/Public/',
    'github_pages_branch': _GITHUB_PAGES_BRANCHES['project'],
    'default_pagination': 10,
    'siteurl': '',
    'lang': _DEFAULT_LANGUAGE,
    'timezone': _DEFAULT_TIMEZONE
}

# url for list of valid timezones
_TZ_URL = 'http://en.wikipedia.org/wiki/List_of_tz_database_time_zones'

def _input_compat(prompt):
    if six.PY3:
        r = input(prompt)
    else:
        r = raw_input(prompt)
    return r

if six.PY3:
    str_compat = str
else:
    str_compat = unicode

# Create a 'marked' default path, to determine if someone has supplied
# a path on the command-line.
class _DEFAULT_PATH_TYPE(str_compat):
    is_default_path = True

_DEFAULT_PATH = _DEFAULT_PATH_TYPE(os.curdir)

def decoding_strings(f):
    def wrapper(*args, **kwargs):
        out = f(*args, **kwargs)
        if isinstance(out, six.string_types) and not six.PY3:
            # todo: make encoding configurable?
            if six.PY3:
                return out
            else:
                return out.decode(sys.stdin.encoding)
        return out
    return wrapper

@decoding_strings
def ask(question, answer=str_compat, default=None, length=None):
    if answer == str_compat:
        r = ''
        while True:
            if default:
                r = _input_compat('> {0} [{1}] '.format(question, default))
            else:
                r = _input_compat('> {0} '.format(question, default))

            r = r.strip()

            if len(r) <= 0:
                if default:
                    r = default
                    break
                else:
                    print('You must enter something')
            else:
                if length and len(r) != length:
                    print('Entry must be {0} characters long'.format(length))
                else:
                    break

        return r

    elif answer == bool:
        r = None
        while True:
            if default is True:
                r = _input_compat('> {0} (Y/n) '.format(question))
            elif default is False:
                r = _input_compat('> {0} (y/N) '.format(question))
            else:
                r = _input_compat('> {0} (y/n) '.format(question))

            r = r.strip().lower()

            if r in ('y', 'yes'):
                r = True
                break
            elif r in ('n', 'no'):
                r = False
                break
            elif not r:
                r = default
                break
            else:
                print("You must answer 'yes' or 'no'")
        return r
    elif answer == int:
        r = None
        while True:
            if default:
                r = _input_compat('> {0} [{1}] '.format(question, default))
            else:
                r = _input_compat('> {0} '.format(question))

            r = r.strip()

            if not r:
                r = default
                break

            try:
                r = int(r)
                break
            except ValueError:
                print('You must enter an integer')
        return r
    else:
        raise NotImplemented(
            'Argument `answer` must be str_compat, bool, or integer')

def ask_timezone(question, default, tzurl):
    """Prompt for time zone and validate input"""
    lower_tz = [tz.lower() for tz in pytz.all_timezones]
    while True:
        r = ask(question, str_compat, default)
        r = r.strip().replace(' ', '_').lower()
        if r in lower_tz:
            r = pytz.all_timezones[lower_tz.index(r)]
            break
        else:
            print('Please enter a valid time zone:\n'
                  ' (check [{0}])'.format(tzurl))
    return r

def main():
    parser = argparse.ArgumentParser(
        description="A kickstarter for Pelican",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument('-p', '--path', default=_DEFAULT_PATH,
                        help="The path to generate the blog into")
    parser.add_argument('-t', '--title', metavar="title",
                        help='Set the title of the website')
    parser.add_argument('-a', '--author', metavar="author",
                        help='Set the author name of the website')
    parser.add_argument('-l', '--lang', metavar="lang",
                        help='Set the default web site language')

    args = parser.parse_args()

    print('''Welcome to pelican-quickstart v{v}.

This script will help you create a new Pelican-based website.

Please answer the following questions so this script can generate the files
needed by Pelican.

    '''.format(v=__version__))

    project = os.path.join(
        os.environ.get('VIRTUAL_ENV', os.curdir), '.project')
    no_path_was_specified = hasattr(args.path, 'is_default_path')
    if os.path.isfile(project) and no_path_was_specified:
        CONF['basedir'] = open(project, 'r').read().rstrip("\n")
        print('Using project associated with current virtual environment.'
              'Will save to:\n%s\n' % CONF['basedir'])
    else:
        CONF['basedir'] = os.path.abspath(os.path.expanduser(
            ask('Where do you want to create your new web site?',
                answer=str_compat, default=args.path)))

    CONF['sitename'] = ask('What will be the title of this web site?',
                           answer=str_compat, default=args.title)
    CONF['author'] = ask('Who will be the author of this web site?',
                         answer=str_compat, default=args.author)
    CONF['lang'] = ask('What will be the default language of this web site?',
                       str_compat, args.lang or CONF['lang'], 2)

    if ask('Do you want to specify a URL prefix? e.g., https://example.com  ',
           answer=bool, default=True):
        CONF['siteurl'] = ask('What is your URL prefix? (see '
                              'above example; no trailing slash)',
                              str_compat, CONF['siteurl'])

    CONF['with_pagination'] = ask('Do you want to enable article pagination?',
                                  bool, bool(CONF['default_pagination']))

    if CONF['with_pagination']:
        CONF['default_pagination'] = ask('How many articles per page '
                                         'do you want?',
                                         int, CONF['default_pagination'])
    else:
        CONF['default_pagination'] = False

    CONF['timezone'] = ask_timezone('What is your time zone?',
                                    CONF['timezone'], _TZ_URL)

    automation = ask('Do you want to generate a tasks.py/Makefile '
                     'to automate generation and publishing?', bool, True)

    if automation:
        if ask('Do you want to upload your website using FTP?',
               answer=bool, default=False):
            CONF['ftp'] = True,
            CONF['ftp_host'] = ask('What is the hostname of your FTP server?',
                                   str_compat, CONF['ftp_host'])
            CONF['ftp_user'] = ask('What is your username on that server?',
                                   str_compat, CONF['ftp_user'])
            CONF['ftp_target_dir'] = ask('Where do you want to put your '
                                         'web site on that server?',
                                         str_compat, CONF['ftp_target_dir'])
        if ask('Do you want to upload your website using SSH?',
               answer=bool, default=False):
            CONF['ssh'] = True,
            CONF['ssh_host'] = ask('What is the hostname of your SSH server?',
                                   str_compat, CONF['ssh_host'])
            CONF['ssh_port'] = ask('What is the port of your SSH server?',
                                   int, CONF['ssh_port'])
            CONF['ssh_user'] = ask('What is your username on that server?',
                                   str_compat, CONF['ssh_user'])
            CONF['ssh_target_dir'] = ask('Where do you want to put your '
                                         'web site on that server?',
                                         str_compat, CONF['ssh_target_dir'])

        if ask('Do you want to upload your website using Dropbox?',
               answer=bool, default=False):
            CONF['dropbox'] = True,
            CONF['dropbox_dir'] = ask('Where is your Dropbox directory?',
                                      str_compat, CONF['dropbox_dir'])

        if ask('Do you want to upload your website using S3?',
               answer=bool, default=False):
            CONF['s3'] = True,
            CONF['s3_bucket'] = ask('What is the name of your S3 bucket?',
                                    str_compat, CONF['s3_bucket'])

        if ask('Do you want to upload your website using '
               'Rackspace Cloud Files?', answer=bool, default=False):
            CONF['cloudfiles'] = True,
            CONF['cloudfiles_username'] = ask('What is your Rackspace '
                                              'Cloud username?', str_compat,
                                              CONF['cloudfiles_username'])
            CONF['cloudfiles_api_key'] = ask('What is your Rackspace '
                                             'Cloud API key?', str_compat,
                                             CONF['cloudfiles_api_key'])
            CONF['cloudfiles_container'] = ask('What is the name of your '
                                               'Cloud Files container?',
                                               str_compat,
                                               CONF['cloudfiles_container'])

        if ask('Do you want to upload your website using GitHub Pages?',
               answer=bool, default=False):
            CONF['github'] = True,
            if ask('Is this your personal page (username.github.io)?',
                   answer=bool, default=False):
                CONF['github_pages_branch'] = \
                    _GITHUB_PAGES_BRANCHES['personal']
            else:
                CONF['github_pages_branch'] = \
                    _GITHUB_PAGES_BRANCHES['project']

    try:
        os.makedirs(os.path.join(CONF['basedir'], 'content'))
    except OSError as e:
        print('Error: {0}'.format(e))

    try:
        os.makedirs(os.path.join(CONF['basedir'], 'output'))
    except OSError as e:
        print('Error: {0}'.format(e))

    try:
        with codecs.open(os.path.join(CONF['basedir'], 'pelicanconf.py'),
                         'w', 'utf-8') as fd:
            conf_python = dict()
            for key, value in CONF.items():
                conf_python[key] = repr(value)

            _template = _jinja_env.get_template('pelicanconf.py.jinja2')
            fd.write(_template.render(**conf_python))
            fd.close()
    except OSError as e:
        print('Error: {0}'.format(e))

    try:
        with codecs.open(os.path.join(CONF['basedir'], 'publishconf.py'),
                         'w', 'utf-8') as fd:
            _template = _jinja_env.get_template('publishconf.py.jinja2')
            fd.write(_template.render(**CONF))
            fd.close()
    except OSError as e:
        print('Error: {0}'.format(e))

    if automation:
        try:
            with codecs.open(os.path.join(CONF['basedir'], 'tasks.py'),
                             'w', 'utf-8') as fd:
                _template = _jinja_env.get_template('tasks.py.jinja2')
                fd.write(_template.render(**CONF))
                fd.close()
        except OSError as e:
            print('Error: {0}'.format(e))
        try:
            with codecs.open(os.path.join(CONF['basedir'], 'Makefile'),
                             'w', 'utf-8') as fd:
                py_v = 'python'
                if six.PY3:
                    py_v = 'python3'
                _template = _jinja_env.get_template('Makefile.jinja2')
                fd.write(_template.render(py_v=py_v, **CONF))
                fd.close()
        except OSError as e:
            print('Error: {0}'.format(e))

    print('Done. Your new project is available at %s' % CONF['basedir'])

if __name__ == "__main__":
    main()
<commit_msg>Conform to changes in Flake8 v3.6 code style<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals

import argparse
import codecs
import locale
import os
import sys

from jinja2 import Environment, FileSystemLoader

import pytz

try:
    import readline  # NOQA
except ImportError:
    pass

try:
    import tzlocal
    _DEFAULT_TIMEZONE = tzlocal.get_localzone().zone
except ImportError:
    _DEFAULT_TIMEZONE = 'Europe/Paris'

import six

from pelican import __version__

locale.setlocale(locale.LC_ALL, '')
try:
    _DEFAULT_LANGUAGE = locale.getlocale()[0]
except ValueError:
    # Don't fail on macosx: "unknown locale: UTF-8"
    _DEFAULT_LANGUAGE = None
if _DEFAULT_LANGUAGE is None:
    _DEFAULT_LANGUAGE = 'English'
else:
    _DEFAULT_LANGUAGE = _DEFAULT_LANGUAGE.split('_')[0]

_TEMPLATES_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                              "templates")
_jinja_env = Environment(
    loader=FileSystemLoader(_TEMPLATES_DIR),
    trim_blocks=True,
)

_GITHUB_PAGES_BRANCHES = {
    'personal': 'master',
    'project': 'gh-pages'
}

CONF = {
    'pelican': 'pelican',
    'pelicanopts': '',
    'basedir': os.curdir,
    'ftp_host': 'localhost',
    'ftp_user': 'anonymous',
    'ftp_target_dir': '/',
    'ssh_host': 'localhost',
    'ssh_port': 22,
    'ssh_user': 'root',
    'ssh_target_dir': '/var/www',
    's3_bucket': 'my_s3_bucket',
    'cloudfiles_username': 'my_rackspace_username',
    'cloudfiles_api_key': 'my_rackspace_api_key',
    'cloudfiles_container': 'my_cloudfiles_container',
    'dropbox_dir': '~/Dropbox/Public/',
    'github_pages_branch': _GITHUB_PAGES_BRANCHES['project'],
    'default_pagination': 10,
    'siteurl': '',
    'lang': _DEFAULT_LANGUAGE,
    'timezone': _DEFAULT_TIMEZONE
}

# url for list of valid timezones
_TZ_URL = 'http://en.wikipedia.org/wiki/List_of_tz_database_time_zones'

def _input_compat(prompt):
    if six.PY3:
        r = input(prompt)
    else:
        r = raw_input(prompt)
    return r

if six.PY3:
    str_compat = str
else:
    str_compat = unicode

# Create a 'marked' default path, to determine if someone has supplied
# a path on the command-line.
class _DEFAULT_PATH_TYPE(str_compat):
    is_default_path = True

_DEFAULT_PATH = _DEFAULT_PATH_TYPE(os.curdir)

def decoding_strings(f):
    def wrapper(*args, **kwargs):
        out = f(*args, **kwargs)
        if isinstance(out, six.string_types) and not six.PY3:
            # todo: make encoding configurable?
            if six.PY3:
                return out
            else:
                return out.decode(sys.stdin.encoding)
        return out
    return wrapper

@decoding_strings
def ask(question, answer=str_compat, default=None, length=None):
    if answer == str_compat:
        r = ''
        while True:
            if default:
                r = _input_compat('> {0} [{1}] '.format(question, default))
            else:
                r = _input_compat('> {0} '.format(question, default))

            r = r.strip()

            if len(r) <= 0:
                if default:
                    r = default
                    break
                else:
                    print('You must enter something')
            else:
                if length and len(r) != length:
                    print('Entry must be {0} characters long'.format(length))
                else:
                    break

        return r

    elif answer == bool:
        r = None
        while True:
            if default is True:
                r = _input_compat('> {0} (Y/n) '.format(question))
            elif default is False:
                r = _input_compat('> {0} (y/N) '.format(question))
            else:
                r = _input_compat('> {0} (y/n) '.format(question))

            r = r.strip().lower()

            if r in ('y', 'yes'):
                r = True
                break
            elif r in ('n', 'no'):
                r = False
                break
            elif not r:
                r = default
                break
            else:
                print("You must answer 'yes' or 'no'")
        return r
    elif answer == int:
        r = None
        while True:
            if default:
                r = _input_compat('> {0} [{1}] '.format(question, default))
            else:
                r = _input_compat('> {0} '.format(question))

            r = r.strip()

            if not r:
                r = default
                break

            try:
                r = int(r)
                break
            except ValueError:
                print('You must enter an integer')
        return r
    else:
        raise NotImplementedError(
            'Argument `answer` must be str_compat, bool, or integer')

def ask_timezone(question, default, tzurl):
    """Prompt for time zone and validate input"""
    lower_tz = [tz.lower() for tz in pytz.all_timezones]
    while True:
        r = ask(question, str_compat, default)
        r = r.strip().replace(' ', '_').lower()
        if r in lower_tz:
            r = pytz.all_timezones[lower_tz.index(r)]
            break
        else:
            print('Please enter a valid time zone:\n'
                  ' (check [{0}])'.format(tzurl))
    return r

def main():
    parser = argparse.ArgumentParser(
        description="A kickstarter for Pelican",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument('-p', '--path', default=_DEFAULT_PATH,
                        help="The path to generate the blog into")
    parser.add_argument('-t', '--title', metavar="title",
                        help='Set the title of the website')
    parser.add_argument('-a', '--author', metavar="author",
                        help='Set the author name of the website')
    parser.add_argument('-l', '--lang', metavar="lang",
                        help='Set the default web site language')

    args = parser.parse_args()

    print('''Welcome to pelican-quickstart v{v}.

This script will help you create a new Pelican-based website.

Please answer the following questions so this script can generate the files
needed by Pelican.

    '''.format(v=__version__))

    project = os.path.join(
        os.environ.get('VIRTUAL_ENV', os.curdir), '.project')
    no_path_was_specified = hasattr(args.path, 'is_default_path')
    if os.path.isfile(project) and no_path_was_specified:
        CONF['basedir'] = open(project, 'r').read().rstrip("\n")
        print('Using project associated with current virtual environment.'
              'Will save to:\n%s\n' % CONF['basedir'])
    else:
        CONF['basedir'] = os.path.abspath(os.path.expanduser(
            ask('Where do you want to create your new web site?',
                answer=str_compat, default=args.path)))

    CONF['sitename'] = ask('What will be the title of this web site?',
                           answer=str_compat, default=args.title)
    CONF['author'] = ask('Who will be the author of this web site?',
                         answer=str_compat, default=args.author)
    CONF['lang'] = ask('What will be the default language of this web site?',
                       str_compat, args.lang or CONF['lang'], 2)

    if ask('Do you want to specify a URL prefix? e.g., https://example.com  ',
           answer=bool, default=True):
        CONF['siteurl'] = ask('What is your URL prefix? (see '
                              'above example; no trailing slash)',
                              str_compat, CONF['siteurl'])

    CONF['with_pagination'] = ask('Do you want to enable article pagination?',
                                  bool, bool(CONF['default_pagination']))

    if CONF['with_pagination']:
        CONF['default_pagination'] = ask('How many articles per page '
                                         'do you want?',
                                         int, CONF['default_pagination'])
    else:
        CONF['default_pagination'] = False

    CONF['timezone'] = ask_timezone('What is your time zone?',
                                    CONF['timezone'], _TZ_URL)

    automation = ask('Do you want to generate a tasks.py/Makefile '
                     'to automate generation and publishing?', bool, True)

    if automation:
        if ask('Do you want to upload your website using FTP?',
               answer=bool, default=False):
            CONF['ftp'] = True,
            CONF['ftp_host'] = ask('What is the hostname of your FTP server?',
                                   str_compat, CONF['ftp_host'])
            CONF['ftp_user'] = ask('What is your username on that server?',
                                   str_compat, CONF['ftp_user'])
            CONF['ftp_target_dir'] = ask('Where do you want to put your '
                                         'web site on that server?',
                                         str_compat, CONF['ftp_target_dir'])
        if ask('Do you want to upload your website using SSH?',
               answer=bool, default=False):
            CONF['ssh'] = True,
            CONF['ssh_host'] = ask('What is the hostname of your SSH server?',
                                   str_compat, CONF['ssh_host'])
            CONF['ssh_port'] = ask('What is the port of your SSH server?',
                                   int, CONF['ssh_port'])
            CONF['ssh_user'] = ask('What is your username on that server?',
                                   str_compat, CONF['ssh_user'])
            CONF['ssh_target_dir'] = ask('Where do you want to put your '
                                         'web site on that server?',
                                         str_compat, CONF['ssh_target_dir'])

        if ask('Do you want to upload your website using Dropbox?',
               answer=bool, default=False):
            CONF['dropbox'] = True,
            CONF['dropbox_dir'] = ask('Where is your Dropbox directory?',
                                      str_compat, CONF['dropbox_dir'])

        if ask('Do you want to upload your website using S3?',
               answer=bool, default=False):
            CONF['s3'] = True,
            CONF['s3_bucket'] = ask('What is the name of your S3 bucket?',
                                    str_compat, CONF['s3_bucket'])

        if ask('Do you want to upload your website using '
               'Rackspace Cloud Files?', answer=bool, default=False):
            CONF['cloudfiles'] = True,
            CONF['cloudfiles_username'] = ask('What is your Rackspace '
                                              'Cloud username?', str_compat,
                                              CONF['cloudfiles_username'])
            CONF['cloudfiles_api_key'] = ask('What is your Rackspace '
                                             'Cloud API key?', str_compat,
                                             CONF['cloudfiles_api_key'])
            CONF['cloudfiles_container'] = ask('What is the name of your '
                                               'Cloud Files container?',
                                               str_compat,
                                               CONF['cloudfiles_container'])

        if ask('Do you want to upload your website using GitHub Pages?',
               answer=bool, default=False):
            CONF['github'] = True,
            if ask('Is this your personal page (username.github.io)?',
                   answer=bool, default=False):
                CONF['github_pages_branch'] = \
                    _GITHUB_PAGES_BRANCHES['personal']
            else:
                CONF['github_pages_branch'] = \
                    _GITHUB_PAGES_BRANCHES['project']

    try:
        os.makedirs(os.path.join(CONF['basedir'], 'content'))
    except OSError as e:
        print('Error: {0}'.format(e))

    try:
        os.makedirs(os.path.join(CONF['basedir'], 'output'))
    except OSError as e:
        print('Error: {0}'.format(e))

    try:
        with codecs.open(os.path.join(CONF['basedir'], 'pelicanconf.py'),
                         'w', 'utf-8') as fd:
            conf_python = dict()
            for key, value in CONF.items():
                conf_python[key] = repr(value)

            _template = _jinja_env.get_template('pelicanconf.py.jinja2')
            fd.write(_template.render(**conf_python))
            fd.close()
    except OSError as e:
        print('Error: {0}'.format(e))

    try:
        with codecs.open(os.path.join(CONF['basedir'], 'publishconf.py'),
                         'w', 'utf-8') as fd:
            _template = _jinja_env.get_template('publishconf.py.jinja2')
            fd.write(_template.render(**CONF))
            fd.close()
    except OSError as e:
        print('Error: {0}'.format(e))

    if automation:
        try:
            with codecs.open(os.path.join(CONF['basedir'], 'tasks.py'),
                             'w', 'utf-8') as fd:
                _template = _jinja_env.get_template('tasks.py.jinja2')
                fd.write(_template.render(**CONF))
                fd.close()
        except OSError as e:
            print('Error: {0}'.format(e))
        try:
            with codecs.open(os.path.join(CONF['basedir'], 'Makefile'),
                             'w', 'utf-8') as fd:
                py_v = 'python'
                if six.PY3:
                    py_v = 'python3'
                _template = _jinja_env.get_template('Makefile.jinja2')
                fd.write(_template.render(py_v=py_v, **CONF))
                fd.close()
        except OSError as e:
            print('Error: {0}'.format(e))

    print('Done. Your new project is available at %s' % CONF['basedir'])

if __name__ == "__main__":
    main()
<|endoftext|>


<commit_before>import csv, itertools, copy, time, os, re, shutil
from collections import Counter
from selenium import webdriver
from poolReducer import poolReducer

teamNames = {
'LAA' : 'Angels',
'HOU' : 'Astros',
'OAK' : 'Athletics',
'TOR' : 'Blue Jays',
'ATL' : 'Braves',
'MIL' : 'Brewers',
'STL' : 'Cardinals',
'CHC' : 'Cubs',
'ARI' : 'Diamondbacks',
'LOS' : 'Dodgers',
'SFG' : 'Giants',
'CLE' : 'Indians',
'SEA' : 'Mariners',
'MIA' : 'Marlins',
'NYM' : 'Mets',
'WAS' : 'Nationals',
'BAL' : 'Orioles',
'SDP' : 'Padres',
'PHI' : 'Phillies',
'PIT' : 'Pirates',
'TEX' : 'Rangers',
'TAM' : 'Rays',
'BOS' : 'Red Sox',
'CIN' : 'Reds',
'COL' : 'Rockies',
'KAN' : 'Royals',
'DET' : 'Tigers',
'MIN' : 'Twins',
'CWS' : 'White Sox',
'NYY' : 'Yankees'
}

urlBat = 'http://www.fangraphs.com/dailyprojections.aspx?pos=all&stats=bat&type=sabersim&team=0&lg=all&players=0'
urlPit = 'http://www.fangraphs.com/dailyprojections.aspx?pos=all&stats=pit&type=sabersim&team=0&lg=all&players=0'
urlFanDuel = 'https://www.fanduel.com/games/19327/contests/19327-209469721/enter'
# urlFanDuel should be user input on website

batFolderPath = '/Users/RyanRobertson21/Desktop/battersPP-'
pitFolderPath = '/Users/RyanRobertson21/Desktop/pitchersPP-'
fanDuelFolderPath = '/Users/RyanRobertson21/Desktop/fanDuel-'

def downloadData(folderPath, url, linkTextString):
    name = str(time.asctime(time.localtime(time.time()))).replace(':', '_')
    folderPath = folderPath + name
    os.makedirs(folderPath)

    profile = webdriver.FirefoxProfile()
    profile.set_preference('browser.download.folderList', 2)
    profile.set_preference('browser.download.manager.showWhenStarting', False)
    profile.set_preference('browser.download.dir', folderPath)
    profile.set_preference('browser.helperApps.neverAsk.saveToDisk', 'text/csv')

    browser = webdriver.Firefox(profile)
    browser.get(url)
    linkElem = browser.find_element_by_link_text(linkTextString)
    linkElem.click()
    time.sleep(5)
    for file in os.listdir(folderPath):
        filePath = folderPath + '/' + file
    with open(filePath) as spreadSheetFile:
        dataList = list(csv.reader(spreadSheetFile))[1:]
    browser.quit()
    shutil.rmtree(folderPath)
    return dataList

battersPP = downloadData(batFolderPath, urlBat, 'Export Data')
time.sleep(3)
pitchersPP = downloadData(pitFolderPath, urlPit, 'Export Data')
time.sleep(3)
contestLineup = downloadData(fanDuelFolderPath, urlFanDuel, 'Download players list')

# to test when PP is not updated yet
# contestLineup = list(csv.reader(open('/Users/RyanRobertson21/Desktop/FD_5-16.csv')))[1:]
# battersPP = list(csv.reader(open('/Users/RyanRobertson21/Desktop/battersPP-Tue May 16 18_17_23 2017/FanGraphs Leaderboard.csv')))[1:]
# pitchersPP = list(csv.reader(open('/Users/RyanRobertson21/Desktop/pitchersPP-Tue May 16 18_17_56 2017/FanGraphs Leaderboard.csv')))[1:]

def editPlayerName(elementName, rowIndex):
    fullName = elementName[rowIndex].lower().replace(".", "").replace(" jr", "").split(' ', 1)
    firstName = fullName[0]
    if len(firstName) > 2:
        firstName = firstName[:3]
    lastName = fullName[1]
    name = firstName + " " + lastName
    removeInitial = re.compile(r' \w ').search(name)
    if removeInitial:
        name = name.replace(removeInitial.group(), ' ')
    return name

playerNamesToCheck = []
playerDict = {}

for row in contestLineup:
    for ppRow in battersPP:
        fdName = editPlayerName(row, 3)
        ppName = editPlayerName(ppRow, 0)

        if fdName == ppName and row[1] != 'P' and (teamNames[row[9]] == ppRow[1] or ppRow[1] == ''):
            playerList = []
            playerList.append(row[1])
            playerList.append(row[3])
            playerList.append(float(ppRow[-3]))
            playerList.append(int(row[7]))
            playerDict[row[0]] = playerList
            playerNamesToCheck.append(fdName)

for row in contestLineup:
    for ppRow in pitchersPP:
        fdName = editPlayerName(row, 3)
        ppName = editPlayerName(ppRow, 0)

        if fdName == ppName and row[1] == 'P' and (teamNames[row[9]] == ppRow[1] or ppRow[1] == ''):
            playerList = []
            playerList.append(row[1])
            playerList.append(row[3])
            playerList.append(float(ppRow[-3]))
            playerList.append(int(row[7]))
            playerDict[row[0]] = playerList
            playerNamesToCheck.append(fdName)

# Used to test to make sure players are being read in from Fangraphs pitchers and Fangraphs batters spreadsheets, as well
# as FanDuels total lineup spreadsheet. Works best when no games have started yet, otherwise players in games that have started
# are no longer eligibile to be selected for the contest in Fanduel. So while they will appear in the projected poitns spreadsheet
# they wont, and shouldn't appear on fanduel, and thus wont be read in.
# print('\nBatters missing from PP\n')
# for ppRow in battersPP:
#     ppName = editPlayerName(ppRow, 0)
#
#     if ppName not in playerNamesToCheck:
#         print(ppName)
#
# print('\nPitchers missing from PP\n')
# for ppRow in pitchersPP:
#     ppName = editPlayerName(ppRow, 0)
#
#     if ppName not in playerNamesToCheck:
#         print(ppName)
# print('\nPlayer missing from FanDuel\n')
# for row in contestLineup:
#     fdName = editPlayerName(row, 3)
#
#     if fdName not in playerNamesToCheck:
#         print(fdName, row[1])

print('Player Dict Info')
print(len(playerDict))

print('\nFilling in Position Dictionaries...')
pitchers = {}
catchers = {}
firstBase = {}
secondBase = {}
thirdBase = {}
shortStop = {}
outfielders = {}

for ids in playerDict:

    if playerDict[ids][0] == 'P':
        pitchers[ids] = playerDict[ids]

    elif playerDict[ids][0] == 'C':
        catchers[ids] = playerDict[ids]

    elif playerDict[ids][0] == '1B':
        firstBase[ids] = playerDict[ids]

    elif playerDict[ids][0] == '2B':
        secondBase[ids] = playerDict[ids]

    elif playerDict[ids][0] == '3B':
        thirdBase[ids] = playerDict[ids]

    elif playerDict[ids][0] == 'SS':
        shortStop[ids] = playerDict[ids]

    elif playerDict[ids][0] == 'OF':
        outfielders[ids] = playerDict[ids]

print('\nAFTER LOADING IN THE DATA...')
print('Pitchers: ' + str(len(pitchers)))
print('Catchers: ' + str(len(catchers)))
print('FirstBase: ' + str(len(firstBase)))
print('SecondBase: ' + str(len(secondBase)))
print('ThirdBase: ' + str(len(thirdBase)))
print('ShortStop: ' + str(len(shortStop)))
print('Outfielders: ' + str(len(outfielders)))

def positionFilter(positionDict):
    filteredDict = {}
    for player in positionDict:
        if positionDict[player][3] not in filteredDict:
            filteredDict[positionDict[player][3]] = positionDict[player]
            filteredDict[positionDict[player][3]].append(player)
        else:
            if positionDict[player][2] > filteredDict[positionDict[player][3]][2]:
                filteredDict[positionDict[player][3]] = positionDict[player]
                filteredDict[positionDict[player][3]].append(player)
    return filteredDict

def ofPositionFilter(positionDict):
    outfielderSalaries = []
    for of in positionDict:
        outfielderSalaries.append(positionDict[of][3])

    ofSalaryCounts = Counter(outfielderSalaries)

    outfielderSalariesToFilter = {k: v for k, v in ofSalaryCounts.items() if v > 3}

    for salary in outfielderSalariesToFilter:
        playersWithSameSalary = []
        for of in positionDict:
            if positionDict[of][3] == salary:
                playersWithSameSalary.append(positionDict[of][2])

        ofCopy = copy.deepcopy(positionDict)
        for num in range(outfielderSalariesToFilter[salary] - 3):
            lowestPP = min(playersWithSameSalary)
            for of in ofCopy:
                if ofCopy[of][2] == lowestPP and ofCopy[of][3] == salary:
                    del positionDict[of]
                    playersWithSameSalary.remove(lowestPP)

    return positionDict

def filterMoreExpensiveLessPP(positionDict):
    salariesToDelete = set()

    for salary in positionDict:
        for otherSalaries in positionDict:
            if salary < otherSalaries and positionDict[salary][2] >= positionDict[otherSalaries][2]:
                salariesToDelete.add(otherSalaries)

    for item in salariesToDelete:
        del positionDict[item]

    filteredDict = {}
    for key in positionDict:
        filteredDict[positionDict[key][-1]] = positionDict[key]
    return filteredDict

def ofFilterMoreExpensiveLessPP(positionDict):
    outfielderList = []
    for key in positionDict:
        playerEntry = []
        playerEntry.append(key)
        for info in positionDict[key]:
            playerEntry.append(info)
        outfielderList.append(playerEntry)

    outfielderListSalaryOrder = sorted(outfielderList, key=lambda x: (x[4], x[3] * -1))

    lowestSalaryOutfielders = outfielderListSalaryOrder[0:3]
    count = 1
    while 2 + count < len(outfielderListSalaryOrder) - 1:

        minProjectedPoints = min(lowestSalaryOutfielders, key=lambda x: x[3])

        outfieldersToDelete = []
        for of in outfielderListSalaryOrder[2 + count:]:
            if of[3] < minProjectedPoints[3] and of[4] > minProjectedPoints[4]:
                outfieldersToDelete.append(of)

        outfielderListSalaryOrder = [x for x in outfielderListSalaryOrder if x not in outfieldersToDelete]

        lowestSalaryOutfielders.remove(minProjectedPoints)

        try:
            lowestSalaryOutfielders.append(outfielderListSalaryOrder[2 + count])
        except IndexError:
            break

        count += 1

    return outfielderListSalaryOrder

print('\nAFTER FIRST FILTER!')
print('Pitchers: ' + str(len(positionFilter(pitchers))))
print('Catchers: ' + str(len(positionFilter(catchers))))
print('FirstBase: ' + str(len(positionFilter(firstBase))))
print('SecondBase: ' + str(len(positionFilter(secondBase))))
print('ThirdBase: ' + str(len(positionFilter(thirdBase))))
print('ShortStop: ' + str(len(positionFilter(shortStop))))
print('Outfielders: ' + str(len(ofPositionFilter(outfielders))))

pitchers = filterMoreExpensiveLessPP(positionFilter(pitchers))
catchers = filterMoreExpensiveLessPP(positionFilter(catchers))
firstBase = filterMoreExpensiveLessPP(positionFilter(firstBase))
secondBase = filterMoreExpensiveLessPP(positionFilter(secondBase))
thirdBase = filterMoreExpensiveLessPP(positionFilter(thirdBase))
shortStop = filterMoreExpensiveLessPP(positionFilter(shortStop))
outfielders = ofFilterMoreExpensiveLessPP(ofPositionFilter(outfielders))

print('\nAFTER BOTH FILTERS...')
print('Pitchers: ' + str(len(pitchers)))
print('Catchers: ' + str(len(catchers)))
print('FirstBase: ' + str(len(firstBase)))
print('SecondBase: ' + str(len(secondBase)))
print('ThirdBase: ' + str(len(thirdBase)))
print('ShortStop: ' + str(len(shortStop)))
print('Outfielders: ' + str(len(outfielders)))

start = time.time()
outfielderGroups = list(itertools.combinations(outfielders, 3))
print("\nNumber of oufielder combinations: " + str(len(outfielderGroups)))

allLineups = list(itertools.product(pitchers, catchers, firstBase, secondBase, thirdBase, shortStop, outfielderGroups))
print("\nNumber of possibly optimal lineups: " + str(len(allLineups)))
print(allLineups[2])
underCap = {}
count = 1
for lineup in allLineups:
    salary = 0
    for item in lineup:
        if type(item) == tuple:
            for of in item:
                salary += of[4]
        else:
            salary += playerDict[item][3]
    if salary <= 35000:
        underCap[count] = lineup
        count += 1

print("\nNumber of possibly optimal lineups under the cap: " + str(len(underCap))+"\n")

underCapPP = {}
for key in underCap:
    projectedPoints = 0
    for item in underCap[key]:
        if type(item) == tuple:
            for of in item:
                projectedPoints += of[3]
        else:
            projectedPoints += playerDict[item][2]
    underCapPP[projectedPoints] = underCap[key]

pp = max(underCapPP)
optimalLineup = underCapPP[pp]

capUsed = 0
for item in optimalLineup:
    if type(item) == tuple:
        for of in item:
            capUsed += of[4]
            print(of[1] + ": " + of[2] + ' PP: ' + str(round(of[3], 2)) + ' Cost: ' + str(of[4]))
    else:
        capUsed += playerDict[item][3]
        print(playerDict[item][0] + ": " + playerDict[item][1] + ' PP: ' + str(round(playerDict[item][2], 2)) + ' Cost: ' + str(playerDict[item][3]))

print("\nCap Used: $" + str(capUsed))
print("Projected Points: " + str(round(pp, 2)))

end = time.time()
print("\nRuntime from outfielderGroups calculation til end of program: " + str(end-start) + " seconds.")<commit_msg>Add comma separators to print statements<commit_after>import csv, itertools, copy, time, os, re, shutil
from collections import Counter
from selenium import webdriver
from poolReducer import poolReducer

teamNames = {
'LAA' : 'Angels',
'HOU' : 'Astros',
'OAK' : 'Athletics',
'TOR' : 'Blue Jays',
'ATL' : 'Braves',
'MIL' : 'Brewers',
'STL' : 'Cardinals',
'CHC' : 'Cubs',
'ARI' : 'Diamondbacks',
'LOS' : 'Dodgers',
'SFG' : 'Giants',
'CLE' : 'Indians',
'SEA' : 'Mariners',
'MIA' : 'Marlins',
'NYM' : 'Mets',
'WAS' : 'Nationals',
'BAL' : 'Orioles',
'SDP' : 'Padres',
'PHI' : 'Phillies',
'PIT' : 'Pirates',
'TEX' : 'Rangers',
'TAM' : 'Rays',
'BOS' : 'Red Sox',
'CIN' : 'Reds',
'COL' : 'Rockies',
'KAN' : 'Royals',
'DET' : 'Tigers',
'MIN' : 'Twins',
'CWS' : 'White Sox',
'NYY' : 'Yankees'
}

urlBat = 'http://www.fangraphs.com/dailyprojections.aspx?pos=all&stats=bat&type=sabersim&team=0&lg=all&players=0'
urlPit = 'http://www.fangraphs.com/dailyprojections.aspx?pos=all&stats=pit&type=sabersim&team=0&lg=all&players=0'
urlFanDuel = 'https://www.fanduel.com/games/19342/contests/19342-209510202/enter'
# urlFanDuel should be user input on website

batFolderPath = '/Users/RyanRobertson21/Desktop/battersPP-'
pitFolderPath = '/Users/RyanRobertson21/Desktop/pitchersPP-'
fanDuelFolderPath = '/Users/RyanRobertson21/Desktop/fanDuel-'

def downloadData(folderPath, url, linkTextString):
    name = str(time.asctime(time.localtime(time.time()))).replace(':', '_')
    folderPath = folderPath + name
    os.makedirs(folderPath)

    profile = webdriver.FirefoxProfile()
    profile.set_preference('browser.download.folderList', 2)
    profile.set_preference('browser.download.manager.showWhenStarting', False)
    profile.set_preference('browser.download.dir', folderPath)
    profile.set_preference('browser.helperApps.neverAsk.saveToDisk', 'text/csv')

    browser = webdriver.Firefox(profile)
    browser.get(url)
    linkElem = browser.find_element_by_link_text(linkTextString)
    linkElem.click()
    time.sleep(5)
    for file in os.listdir(folderPath):
        filePath = folderPath + '/' + file
    with open(filePath) as spreadSheetFile:
        dataList = list(csv.reader(spreadSheetFile))[1:]
    browser.quit()
    # KEEP FOR NOW TO CHECK DATA shutil.rmtree(folderPath)
    return dataList
s1= time.time()
print('Downloading batters data from FanGraphs...')
battersPP = downloadData(batFolderPath, urlBat, 'Export Data')
e1 = time.time()
print(e1-s1)
time.sleep(3)
s2 = time.time()
print('\nDownloading pitchers data from FanGraphs...')
pitchersPP = downloadData(pitFolderPath, urlPit, 'Export Data')
e2 = time.time()
print(e2-s2)
time.sleep(3)
s3 = time.time()
print('\nDownloading contest data from FanDuel...')
contestLineup = downloadData(fanDuelFolderPath, urlFanDuel, 'Download players list')
e3 = time.time()
print(e3-s3)
# to test when PP is not updated yet
# contestLineup = list(csv.reader(open('/Users/RyanRobertson21/Desktop/FD_5-16.csv')))[1:]
# battersPP = list(csv.reader(open('/Users/RyanRobertson21/Desktop/battersPP-Tue May 16 18_17_23 2017/FanGraphs Leaderboard.csv')))[1:]
# pitchersPP = list(csv.reader(open('/Users/RyanRobertson21/Desktop/pitchersPP-Tue May 16 18_17_56 2017/FanGraphs Leaderboard.csv')))[1:]

def editPlayerName(elementName, rowIndex):
    fullName = elementName[rowIndex].lower().replace(".", "").replace(" jr", "").split(' ', 1)
    firstName = fullName[0]
    if len(firstName) > 2:
        firstName = firstName[:3]
    lastName = fullName[1]
    name = firstName + " " + lastName
    removeInitial = re.compile(r' \w ').search(name)
    if removeInitial:
        name = name.replace(removeInitial.group(), ' ')
    return name

playerNamesToCheck = []
playerDict = {}

for row in contestLineup:
    for ppRow in battersPP:
        fdName = editPlayerName(row, 3)
        ppName = editPlayerName(ppRow, 0)

        if fdName == ppName and row[1] != 'P' and (teamNames[row[9]] == ppRow[1] or ppRow[1] == ''):
            playerList = []
            playerList.append(row[1])
            playerList.append(row[3])
            playerList.append(float(ppRow[-3]))
            playerList.append(int(row[7]))
            playerDict[row[0]] = playerList
            playerNamesToCheck.append(fdName)

for row in contestLineup:
    for ppRow in pitchersPP:
        fdName = editPlayerName(row, 3)
        ppName = editPlayerName(ppRow, 0)

        if fdName == ppName and row[1] == 'P' and (teamNames[row[9]] == ppRow[1] or ppRow[1] == ''):
            playerList = []
            playerList.append(row[1])
            playerList.append(row[3])
            playerList.append(float(ppRow[-3]))
            playerList.append(int(row[7]))
            playerDict[row[0]] = playerList
            playerNamesToCheck.append(fdName)

# Used to test to make sure players are being read in from Fangraphs pitchers and Fangraphs batters spreadsheets, as well
# as FanDuels total lineup spreadsheet. Works best when no games have started yet, otherwise players in games that have started
# are no longer eligibile to be selected for the contest in Fanduel. So while they will appear in the projected poitns spreadsheet
# they wont, and shouldn't appear on fanduel, and thus wont be read in.
# print('\nBatters missing from PP\n')
# for ppRow in battersPP:
#     ppName = editPlayerName(ppRow, 0)
#
#     if ppName not in playerNamesToCheck:
#         print(ppName)
#
# print('\nPitchers missing from PP\n')
# for ppRow in pitchersPP:
#     ppName = editPlayerName(ppRow, 0)
#
#     if ppName not in playerNamesToCheck:
#         print(ppName)
# print('\nPlayer missing from FanDuel\n')
# for row in contestLineup:
#     fdName = editPlayerName(row, 3)
#
#     if fdName not in playerNamesToCheck:
#         print(fdName, row[1])

print('\nPlayer Dict Info')
print(len(playerDict))

print('\nFilling in Position Dictionaries...')
pitchers = {}
catchers = {}
firstBase = {}
secondBase = {}
thirdBase = {}
shortStop = {}
outfielders = {}

for ids in playerDict:

    if playerDict[ids][0] == 'P':
        pitchers[ids] = playerDict[ids]

    elif playerDict[ids][0] == 'C':
        catchers[ids] = playerDict[ids]

    elif playerDict[ids][0] == '1B':
        firstBase[ids] = playerDict[ids]

    elif playerDict[ids][0] == '2B':
        secondBase[ids] = playerDict[ids]

    elif playerDict[ids][0] == '3B':
        thirdBase[ids] = playerDict[ids]

    elif playerDict[ids][0] == 'SS':
        shortStop[ids] = playerDict[ids]

    elif playerDict[ids][0] == 'OF':
        outfielders[ids] = playerDict[ids]

print('\nAFTER LOADING IN THE DATA...')
print('Pitchers: ' + str(len(pitchers)))
print('Catchers: ' + str(len(catchers)))
print('FirstBase: ' + str(len(firstBase)))
print('SecondBase: ' + str(len(secondBase)))
print('ThirdBase: ' + str(len(thirdBase)))
print('ShortStop: ' + str(len(shortStop)))
print('Outfielders: ' + str(len(outfielders)))

def positionFilter(positionDict):
    filteredDict = {}
    for player in positionDict:
        if positionDict[player][3] not in filteredDict:
            filteredDict[positionDict[player][3]] = positionDict[player]
            filteredDict[positionDict[player][3]].append(player)
        else:
            if positionDict[player][2] > filteredDict[positionDict[player][3]][2]:
                filteredDict[positionDict[player][3]] = positionDict[player]
                filteredDict[positionDict[player][3]].append(player)
    return filteredDict

def ofPositionFilter(positionDict):
    outfielderSalaries = []
    for of in positionDict:
        outfielderSalaries.append(positionDict[of][3])

    ofSalaryCounts = Counter(outfielderSalaries)

    outfielderSalariesToFilter = {k: v for k, v in ofSalaryCounts.items() if v > 3}

    for salary in outfielderSalariesToFilter:
        playersWithSameSalary = []
        for of in positionDict:
            if positionDict[of][3] == salary:
                playersWithSameSalary.append(positionDict[of][2])

        ofCopy = copy.deepcopy(positionDict)
        for num in range(outfielderSalariesToFilter[salary] - 3):
            lowestPP = min(playersWithSameSalary)
            for of in ofCopy:
                if ofCopy[of][2] == lowestPP and ofCopy[of][3] == salary:
                    del positionDict[of]
                    playersWithSameSalary.remove(lowestPP)

    return positionDict

def filterMoreExpensiveLessPP(positionDict):
    salariesToDelete = set()

    for salary in positionDict:
        for otherSalaries in positionDict:
            if salary < otherSalaries and positionDict[salary][2] >= positionDict[otherSalaries][2]:
                salariesToDelete.add(otherSalaries)

    for item in salariesToDelete:
        del positionDict[item]

    filteredDict = {}
    for key in positionDict:
        filteredDict[positionDict[key][-1]] = positionDict[key]
    return filteredDict

def ofFilterMoreExpensiveLessPP(positionDict):
    outfielderList = []
    for key in positionDict:
        playerEntry = []
        playerEntry.append(key)
        for info in positionDict[key]:
            playerEntry.append(info)
        outfielderList.append(playerEntry)

    outfielderListSalaryOrder = sorted(outfielderList, key=lambda x: (x[4], x[3] * -1))

    lowestSalaryOutfielders = outfielderListSalaryOrder[0:3]
    count = 1
    while 2 + count < len(outfielderListSalaryOrder) - 1:

        minProjectedPoints = min(lowestSalaryOutfielders, key=lambda x: x[3])

        outfieldersToDelete = []
        for of in outfielderListSalaryOrder[2 + count:]:
            if of[3] < minProjectedPoints[3] and of[4] > minProjectedPoints[4]:
                outfieldersToDelete.append(of)

        outfielderListSalaryOrder = [x for x in outfielderListSalaryOrder if x not in outfieldersToDelete]

        lowestSalaryOutfielders.remove(minProjectedPoints)

        try:
            lowestSalaryOutfielders.append(outfielderListSalaryOrder[2 + count])
        except IndexError:
            break

        count += 1

    return outfielderListSalaryOrder

print('\nAFTER FIRST FILTER!')
print('Pitchers: ' + str(len(positionFilter(pitchers))))
print('Catchers: ' + str(len(positionFilter(catchers))))
print('FirstBase: ' + str(len(positionFilter(firstBase))))
print('SecondBase: ' + str(len(positionFilter(secondBase))))
print('ThirdBase: ' + str(len(positionFilter(thirdBase))))
print('ShortStop: ' + str(len(positionFilter(shortStop))))
print('Outfielders: ' + str(len(ofPositionFilter(outfielders))))

pitchers = filterMoreExpensiveLessPP(positionFilter(pitchers))
catchers = filterMoreExpensiveLessPP(positionFilter(catchers))
firstBase = filterMoreExpensiveLessPP(positionFilter(firstBase))
secondBase = filterMoreExpensiveLessPP(positionFilter(secondBase))
thirdBase = filterMoreExpensiveLessPP(positionFilter(thirdBase))
shortStop = filterMoreExpensiveLessPP(positionFilter(shortStop))
outfielders = ofFilterMoreExpensiveLessPP(ofPositionFilter(outfielders))

print('\nAFTER BOTH FILTERS...')
print('Pitchers: ' + str(len(pitchers)))
print('Catchers: ' + str(len(catchers)))
print('FirstBase: ' + str(len(firstBase)))
print('SecondBase: ' + str(len(secondBase)))
print('ThirdBase: ' + str(len(thirdBase)))
print('ShortStop: ' + str(len(shortStop)))
print('Outfielders: ' + str(len(outfielders)))

start = time.time()
outfielderGroups = list(itertools.combinations(outfielders, 3))
print("\nNumber of oufielder combinations: {:,d}".format(len(outfielderGroups)))

allLineups = list(itertools.product(pitchers, catchers, firstBase, secondBase, thirdBase, shortStop, outfielderGroups))
print("\nNumber of possibly optimal lineups: {:,d}".format(len(allLineups)))
print(allLineups[2])
underCap = {}
count = 1
for lineup in allLineups:
    salary = 0
    for item in lineup:
        if type(item) == tuple:
            for of in item:
                salary += of[4]
        else:
            salary += playerDict[item][3]
    if salary <= 35000:
        underCap[count] = lineup
        count += 1

print("\nNumber of possibly optimal lineups under the cap: {:,d}\n".format(len(underCap)))

underCapPP = {}
for key in underCap:
    projectedPoints = 0
    for item in underCap[key]:
        if type(item) == tuple:
            for of in item:
                projectedPoints += of[3]
        else:
            projectedPoints += playerDict[item][2]
    underCapPP[projectedPoints] = underCap[key]

pp = max(underCapPP)
optimalLineup = underCapPP[pp]

capUsed = 0
for item in optimalLineup:
    if type(item) == tuple:
        for of in item:
            capUsed += of[4]
            print(of[1] + ": " + of[2] + ' PP: ' + str(round(of[3], 2)) + ' Cost: {:,d}'.format(of[4]))
    else:
        capUsed += playerDict[item][3]
        print(playerDict[item][0] + ": " + playerDict[item][1] + ' PP: ' + str(round(playerDict[item][2], 2)) + ' Cost: {:,d}'.format(playerDict[item][3]))

print("\nCap Used: ${:,d}".format(capUsed))
print("Projected Points: " + str(round(pp, 2)))

end = time.time()
print("\nRuntime from outfielderGroups calculation til end of program: " + str(end-start) + " seconds.")<|endoftext|>


<commit_before>from django.test import TestCase
import basic_check_util

class BasicCheckTest(TestCase):
    """
    While Ease-based Basic Check has been removed, we do want to validate that some simple scenarios
    will be returned back to the user:
    1) If the initial text has not changed
    2) If the response contains nothing but whitespace
    3) Validate that the user is not banned.
    """

    _INITIAL_DISPLAY = "How much wood could a woodchuck chuck if a woodchuck could chuck wood"
    _GOOD_STUDENT_ID = 42
    _BANNED_STUDENT_ID = 43
    _SKIP_BASIC_CHECKS = False  # No longer used. Should be removed on master.

    def test_initial_text_has_not_changed(self):
        success, results = basic_check_util.simple_quality_check(self._INITIAL_DISPLAY, self._INITIAL_DISPLAY,
                                                                 self._GOOD_STUDENT_ID, self._SKIP_BASIC_CHECKS)
        self.assertTrue(success)
        self.assertEqual(results['score'], 0, "Score should be zero since response equals initial display.")

    def test_whitespace_response(self):
        success, results = basic_check_util.simple_quality_check("        ", self._INITIAL_DISPLAY,
                                                                 self._GOOD_STUDENT_ID, self._SKIP_BASIC_CHECKS)
        self.assertTrue(success)
        self.assertEqual(results['score'], 0, "Score should be zero since response is all whitespace.")

    def test_good_essay(self):
        success, results = basic_check_util.simple_quality_check("This is a perfectly acceptable response.",
                                                                 self._INITIAL_DISPLAY, self._GOOD_STUDENT_ID,
                                                                 self._SKIP_BASIC_CHECKS)
        self.assertTrue(success)
        self.assertEqual(results['score'], 1, "Score should be 1 since response is fine.")

    def test_banned_student(self):
        success, results = basic_check_util.simple_quality_check("This is a perfectly acceptable response.",
                                                                 self._INITIAL_DISPLAY, self._BANNED_STUDENT_ID,
                                                                 self._SKIP_BASIC_CHECKS)
        self.assertTrue(success)
        self.assertEqual(results['score'], 0, "Score should be zero since student is banned.")<commit_msg>Remove bad unit test<commit_after>from django.test import TestCase
import basic_check_util

class BasicCheckTest(TestCase):
    """
    While Ease-based Basic Check has been removed, we do want to validate that some simple scenarios
    will be returned back to the user:
    1) If the initial text has not changed
    2) If the response contains nothing but whitespace
    3) Validate that the user is not banned.
    """

    _INITIAL_DISPLAY = "How much wood could a woodchuck chuck if a woodchuck could chuck wood"
    _GOOD_STUDENT_ID = 42
    _SKIP_BASIC_CHECKS = False  # No longer used. Should be removed on master.

    def test_initial_text_has_not_changed(self):
        success, results = basic_check_util.simple_quality_check(self._INITIAL_DISPLAY, self._INITIAL_DISPLAY,
                                                                 self._GOOD_STUDENT_ID, self._SKIP_BASIC_CHECKS)
        self.assertTrue(success)
        self.assertEqual(results['score'], 0, "Score should be zero since response equals initial display.")

    def test_whitespace_response(self):
        success, results = basic_check_util.simple_quality_check("        ", self._INITIAL_DISPLAY,
                                                                 self._GOOD_STUDENT_ID, self._SKIP_BASIC_CHECKS)
        self.assertTrue(success)
        self.assertEqual(results['score'], 0, "Score should be zero since response is all whitespace.")

    def test_good_essay(self):
        success, results = basic_check_util.simple_quality_check("This is a perfectly acceptable response.",
                                                                 self._INITIAL_DISPLAY, self._GOOD_STUDENT_ID,
                                                                 self._SKIP_BASIC_CHECKS)
        self.assertTrue(success)
        self.assertEqual(results['score'], 1, "Score should be 1 since response is fine.")<|endoftext|>


<commit_before>from collections import defaultdict, OrderedDict
from torch import nn
import numpy as np
import torch
from tabulate import tabulate
from basic_utils.env_wrapper import Env_wrapper
import scipy.signal
import time

def discount(x, gamma):
    return scipy.signal.lfilter([1.0], [1.0, -gamma], x[::-1])[::-1]

def update_default_config(tuples, usercfg):
    for (name, _, defval, _) in tuples:
        if name not in usercfg:
            usercfg[name] = defval
    return usercfg

def merge_before_after(info_before, info_after):
    info = OrderedDict()
    for k in info_before:
        info[k + '_before'] = info_before[k]
        info[k + '_after'] = info_after[k]
    return info

def compute_advantage(vf, paths, gamma, lam):
    for path in paths:
        rewards = path['reward'] * (1 - gamma) if gamma < 0.999 else path['reward']
        path['return'] = discount(rewards, gamma)
        values = vf.predict(path["observation"]).reshape((-1,))

        tds = rewards - values + np.append(values[1:] * gamma, 0)
        advantages = discount(tds, gamma * lam)
        path['advantage'] = advantages
    alladv = np.concatenate([path["advantage"] for path in paths])
    std = alladv.std()
    mean = alladv.mean()
    for path in paths:
        path["advantage"] = (path["advantage"] - mean) / std

def compute_target(qf, path, gamma, double=False):
    next_observations = path['next_observation']
    not_dones = path['not_done']
    rewards = path['reward'] * (1 - gamma) if gamma < 0.999 else path['reward']
    if not double:
        y_targ = qf.predict(next_observations, target=True).max(axis=1)
    else:
        ty = qf.predict(next_observations).argmax(axis=1)
        y_targ = qf.predict(next_observations, target=True)[np.arange(next_observations.shape[0]), ty]
    path['y_targ'] = y_targ * not_dones * gamma + rewards

class Callback:
    def __init__(self):
        self.counter = 0
        self.u_stats = dict()
        self.path_info = defaultdict(list)
        self.extra_info = dict()
        self.scores = []
        self.tstart = time.time()

    def print_table(self):
        self.counter += 1
        stats = OrderedDict()
        add_episode_stats(stats, self.path_info)
        for d in self.extra_info:
            stats[d] = self.extra_info[d]
        for di in self.u_stats:
            for k in self.u_stats[di]:
                self.u_stats[di][k] = np.mean(self.u_stats[di][k])
        for u in self.u_stats:
            add_prefixed_stats(stats, u, self.u_stats[u])
        stats["TimeElapsed"] = time.time() - self.tstart

        print("************ Iteration %i ************" % self.counter)
        print(tabulate(filter(lambda k: np.asarray(k[1]).size == 1, stats.items())))

        self.scores += self.path_info['episoderewards']
        self.u_stats = dict()
        self.path_info = defaultdict(list)
        self.extra_info = dict()

        return self.counter

    def num_batches(self):
        return len(self.path_info['episoderewards'])

    def add_update_info(self, u):
        if u is not None:
            for d in u:
                if d[0] not in self.u_stats:
                    self.u_stats[d[0]] = defaultdict(list)
                for k in d[1]:
                    self.u_stats[d[0]][k].append(d[1][k])

    def add_path_info(self, path_info, extra_info):
        self.path_info['episoderewards'] += [np.sum(p) for p in path_info]
        self.path_info['pathlengths'] += [len(p) for p in path_info]
        for d in extra_info:
            self.extra_info[d] = extra_info[d]

def add_episode_stats(stats, path_info):
    episoderewards = np.array(path_info['episoderewards'])
    pathlengths = np.array(path_info['pathlengths'])
    len_paths = len(episoderewards)

    stats["NumEpBatch"] = len_paths
    stats["EpRewMean"] = episoderewards.mean()
    stats["EpRewSEM"] = episoderewards.std() / np.sqrt(len_paths)
    stats["EpRewMax"] = episoderewards.max()
    stats["EpRewMin"] = episoderewards.min()
    stats["EpLenMean"] = pathlengths.mean()
    stats["EpLenMax"] = pathlengths.max()
    stats["EpLenMin"] = pathlengths.min()
    stats["RewPerStep"] = episoderewards.sum() / pathlengths.sum()

    return stats

def add_prefixed_stats(stats, prefix, d):
    if d is not None:
        for k in d:
            stats[prefix + "_" + k] = d[k]

use_cuda = torch.cuda.is_available()

def Variable(tensor, *args, **kwargs):
    if use_cuda:
        return torch.autograd.Variable(tensor, *args, **kwargs).cuda()
    else:
        return torch.autograd.Variable(tensor, *args, **kwargs)

def np_to_var(nparray):
    assert isinstance(nparray, np.ndarray)
    return torch.autograd.Variable(torch.from_numpy(nparray).float())

def pre_process_path(paths, keys):
    new_path = defaultdict(list)
    for k in keys:
        new_path[k] = np.concatenate([path[k] for path in paths])
        new_path[k] = np_to_var(np.array(new_path[k]))
        if len(new_path[k].size()) == 1:
            new_path[k] = new_path[k].view(-1, 1)
    return new_path

def get_flat_params_from(model):
    params = []
    for param in model.parameters():
        params.append(param.data.view(-1))
    flat_params = torch.cat(params)
    return flat_params

def set_flat_params_to(model, flat_params):
    prev_ind = 0
    for param in model.parameters():
        flat_size = int(np.prod(list(param.size())))
        param.data.copy_(flat_params[prev_ind:prev_ind + flat_size].view(param.size()))
        prev_ind += flat_size

def set_flat_grads_to(model, flat_grads):
    prev_ind = 0
    for param in model.parameters():
        flat_size = int(np.prod(list(param.size())))
        param.grad = Variable(flat_grads[prev_ind:prev_ind + flat_size].view(param.size()))
        prev_ind += flat_size

def get_env_info(cfg):
    env = Env_wrapper(cfg)
    cfg["observation_space"] = env.observation_space
    cfg["action_space"] = env.action_space
    env.close()
    return cfg

def turn_into_cuda(var):
    return var.cuda() if use_cuda else var

def log_gamma(xx):
    gamma_coeff = [
        76.18009172947146,
        -86.50532032941677,
        24.01409824083091,
        -1.231739572450155,
        0.1208650973866179e-2,
        -0.5395239384953e-5,
    ]
    magic1 = 1.000000000190015
    magic2 = 2.5066282746310005
    x = xx - 1.0
    t = x + 5.5
    t = t - (x + 0.5) * torch.log(t)
    ser = Variable(torch.ones(x.size())) * magic1
    for c in gamma_coeff:
        x = x + 1.0
        ser = ser + torch.pow(x / c, -1)
    return torch.log(ser * magic2) - t

def digamma(xx):
    gamma_coeff = [
        76.18009172947146,
        -86.50532032941677,
        24.01409824083091,
        -1.231739572450155,
        0.1208650973866179e-2,
        -0.5395239384953e-5,
    ]
    magic1 = 1.000000000190015
    x = xx - 1.0
    t = 5/(x+5.5) - torch.log(x+5.5)
    ser = Variable(torch.ones(x.size()), requires_grad=True) * magic1
    ser_p = Variable(torch.zeros(x.size()), requires_grad=True)
    for c in gamma_coeff:
        x = x + 1.0
        ser = ser + torch.pow(x / c, -1)
        ser_p = ser_p - c/(x*x)
    return ser_p/ser - t

def merge_dict(path, single_trans):
    for k in single_trans:
        path[k] += single_trans[k]
    return 1 - single_trans['not_done'][0]

def merge_train_data(u_stats):
    merged_dicts = dict()
    re = []
    for u in u_stats:
        for d in u:
            if d[0] not in merged_dicts:
                merged_dicts[d[0]] = defaultdict(list)
            for k in d[1]:
                merged_dicts[d[0]][k].append(d[1][k])
    for di in merged_dicts:
        for k in merged_dicts[di]:
            merged_dicts[di][k] = np.mean(merged_dicts[di][k])
        re.append((di, merged_dicts[di]))
    return re

def sign(k_id):
    return -1. if k_id % 2 == 0 else 1.
<commit_msg>add get_state_dict<commit_after>from collections import defaultdict, OrderedDict
from torch import nn
import numpy as np
import torch
from tabulate import tabulate
from basic_utils.env_wrapper import Env_wrapper
import scipy.signal
import time

def discount(x, gamma):
    return scipy.signal.lfilter([1.0], [1.0, -gamma], x[::-1])[::-1]

def update_default_config(tuples, usercfg):
    for (name, _, defval, _) in tuples:
        if name not in usercfg:
            usercfg[name] = defval
    return usercfg

def merge_before_after(info_before, info_after):
    info = OrderedDict()
    for k in info_before:
        info[k + '_before'] = info_before[k]
        info[k + '_after'] = info_after[k]
    return info

def compute_advantage(vf, paths, gamma, lam):
    for path in paths:
        rewards = path['reward'] * (1 - gamma) if gamma < 0.999 else path['reward']
        path['return'] = discount(rewards, gamma)
        values = vf.predict(path["observation"]).reshape((-1,))

        tds = rewards - values + np.append(values[1:] * gamma, 0)
        advantages = discount(tds, gamma * lam)
        path['advantage'] = advantages
    alladv = np.concatenate([path["advantage"] for path in paths])
    std = alladv.std()
    mean = alladv.mean()
    for path in paths:
        path["advantage"] = (path["advantage"] - mean) / std

def compute_target(qf, path, gamma, double=False):
    next_observations = path['next_observation']
    not_dones = path['not_done']
    rewards = path['reward'] * (1 - gamma) if gamma < 0.999 else path['reward']
    if not double:
        y_targ = qf.predict(next_observations, target=True).max(axis=1)
    else:
        ty = qf.predict(next_observations).argmax(axis=1)
        y_targ = qf.predict(next_observations, target=True)[np.arange(next_observations.shape[0]), ty]
    path['y_targ'] = y_targ * not_dones * gamma + rewards

class Callback:
    def __init__(self):
        self.counter = 0
        self.u_stats = dict()
        self.path_info = defaultdict(list)
        self.extra_info = dict()
        self.scores = []
        self.tstart = time.time()

    def print_table(self):
        self.counter += 1
        stats = OrderedDict()
        add_episode_stats(stats, self.path_info)
        for d in self.extra_info:
            stats[d] = self.extra_info[d]
        for di in self.u_stats:
            for k in self.u_stats[di]:
                self.u_stats[di][k] = np.mean(self.u_stats[di][k])
        for u in self.u_stats:
            add_prefixed_stats(stats, u, self.u_stats[u])
        stats["TimeElapsed"] = time.time() - self.tstart

        print("************ Iteration %i ************" % self.counter)
        print(tabulate(filter(lambda k: np.asarray(k[1]).size == 1, stats.items())))

        self.scores += self.path_info['episoderewards']
        self.u_stats = dict()
        self.path_info = defaultdict(list)
        self.extra_info = dict()

        return self.counter

    def num_batches(self):
        return len(self.path_info['episoderewards'])

    def add_update_info(self, u):
        if u is not None:
            for d in u:
                if d[0] not in self.u_stats:
                    self.u_stats[d[0]] = defaultdict(list)
                for k in d[1]:
                    self.u_stats[d[0]][k].append(d[1][k])

    def add_path_info(self, path_info, extra_info):
        self.path_info['episoderewards'] += [np.sum(p) for p in path_info]
        self.path_info['pathlengths'] += [len(p) for p in path_info]
        for d in extra_info:
            self.extra_info[d] = extra_info[d]

def add_episode_stats(stats, path_info):
    episoderewards = np.array(path_info['episoderewards'])
    pathlengths = np.array(path_info['pathlengths'])
    len_paths = len(episoderewards)

    stats["NumEpBatch"] = len_paths
    stats["EpRewMean"] = episoderewards.mean()
    stats["EpRewSEM"] = episoderewards.std() / np.sqrt(len_paths)
    stats["EpRewMax"] = episoderewards.max()
    stats["EpRewMin"] = episoderewards.min()
    stats["EpLenMean"] = pathlengths.mean()
    stats["EpLenMax"] = pathlengths.max()
    stats["EpLenMin"] = pathlengths.min()
    stats["RewPerStep"] = episoderewards.sum() / pathlengths.sum()

    return stats

def add_prefixed_stats(stats, prefix, d):
    if d is not None:
        for k in d:
            stats[prefix + "_" + k] = d[k]

use_cuda = torch.cuda.is_available()

def Variable(tensor, *args, **kwargs):
    if use_cuda:
        return torch.autograd.Variable(tensor, *args, **kwargs).cuda()
    else:
        return torch.autograd.Variable(tensor, *args, **kwargs)

def np_to_var(nparray):
    assert isinstance(nparray, np.ndarray)
    return torch.autograd.Variable(torch.from_numpy(nparray).float())

def pre_process_path(paths, keys):
    new_path = defaultdict(list)
    for k in keys:
        new_path[k] = np.concatenate([path[k] for path in paths])
        new_path[k] = np_to_var(np.array(new_path[k]))
        if len(new_path[k].size()) == 1:
            new_path[k] = new_path[k].view(-1, 1)
    return new_path

def get_flat_params_from(model):
    params = []
    for param in model.parameters():
        params.append(param.data.view(-1))
    flat_params = torch.cat(params)
    return flat_params

def set_flat_params_to(model, flat_params):
    prev_ind = 0
    for param in model.parameters():
        flat_size = int(np.prod(list(param.size())))
        param.data.copy_(flat_params[prev_ind:prev_ind + flat_size].view(param.size()))
        prev_ind += flat_size

def set_flat_grads_to(model, flat_grads):
    prev_ind = 0
    for param in model.parameters():
        flat_size = int(np.prod(list(param.size())))
        param.grad = Variable(flat_grads[prev_ind:prev_ind + flat_size].view(param.size()))
        prev_ind += flat_size

def get_env_info(cfg):
    env = Env_wrapper(cfg)
    cfg["observation_space"] = env.observation_space
    cfg["action_space"] = env.action_space
    env.close()
    return cfg

def turn_into_cuda(var):
    return var.cuda() if use_cuda else var

def get_state_dict(file):
    try:
        pretrain_state_dict = torch.load(file)
    except AssertionError:
        pretrain_state_dict = torch.load(file, map_location=lambda storage, location: storage)
    return pretrain_state_dict

def log_gamma(xx):
    gamma_coeff = [
        76.18009172947146,
        -86.50532032941677,
        24.01409824083091,
        -1.231739572450155,
        0.1208650973866179e-2,
        -0.5395239384953e-5,
    ]
    magic1 = 1.000000000190015
    magic2 = 2.5066282746310005
    x = xx - 1.0
    t = x + 5.5
    t = t - (x + 0.5) * torch.log(t)
    ser = Variable(torch.ones(x.size())) * magic1
    for c in gamma_coeff:
        x = x + 1.0
        ser = ser + torch.pow(x / c, -1)
    return torch.log(ser * magic2) - t

def digamma(xx):
    gamma_coeff = [
        76.18009172947146,
        -86.50532032941677,
        24.01409824083091,
        -1.231739572450155,
        0.1208650973866179e-2,
        -0.5395239384953e-5,
    ]
    magic1 = 1.000000000190015
    x = xx - 1.0
    t = 5/(x+5.5) - torch.log(x+5.5)
    ser = Variable(torch.ones(x.size()), requires_grad=True) * magic1
    ser_p = Variable(torch.zeros(x.size()), requires_grad=True)
    for c in gamma_coeff:
        x = x + 1.0
        ser = ser + torch.pow(x / c, -1)
        ser_p = ser_p - c/(x*x)
    return ser_p/ser - t

def merge_dict(path, single_trans):
    for k in single_trans:
        path[k] += single_trans[k]
    return 1 - single_trans['not_done'][0]

def merge_train_data(u_stats):
    merged_dicts = dict()
    re = []
    for u in u_stats:
        for d in u:
            if d[0] not in merged_dicts:
                merged_dicts[d[0]] = defaultdict(list)
            for k in d[1]:
                merged_dicts[d[0]][k].append(d[1][k])
    for di in merged_dicts:
        for k in merged_dicts[di]:
            merged_dicts[di][k] = np.mean(merged_dicts[di][k])
        re.append((di, merged_dicts[di]))
    return re

def sign(k_id):
    return -1. if k_id % 2 == 0 else 1.
<|endoftext|>


<commit_before>#!/usr/bin/python
#
# Copyright (c) 2012, 2013, NORDUnet A/S
# All rights reserved.
#
#   Redistribution and use in source and binary forms, with or
#   without modification, are permitted provided that the following
#   conditions are met:
#
#     1. Redistributions of source code must retain the above copyright
#        notice, this list of conditions and the following disclaimer.
#     2. Redistributions in binary form must reproduce the above
#        copyright notice, this list of conditions and the following
#        disclaimer in the documentation and/or other materials provided
#        with the distribution.
#     3. Neither the name of the NORDUnet nor the names of its
#        contributors may be used to endorse or promote products derived
#        from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# Author : Fredrik Thulin <fredrik@thulin.net>
#

import os
import stat
import pyhsm

class VCCSYHSMHasher():

    def __init__(self, device, lock, debug):
        self.yhsm = pyhsm.base.YHSM(device, debug)
        self.lock = lock

    def safe_hmac_sha1(self, key_handle, data):
        """
        Perform HMAC-SHA-1 operation using YubiHSM.

        Acquires a lock first if a lock instance was given at creation time.
        """
        self.lock_acquire()
        try:
            return self.hmac_sha1(key_handle, data)
        finally:
            self.lock_release()

    def hmac_sha1(self, key_handle, data):
        return self.yhsm.hmac_sha1(key_handle, data).get_hash()

    def load_temp_key(self, nonce, key_handle, aead):
        return self.yhsm.load_temp_key(nonce, key_handle, aead)

    def lock_acquire(self):
        return self.lock.acquire()

    def lock_release(self):
        return self.lock.release()

class NoOpLock():
    """
    A No-op lock class, to avoid a lot of "if self.lock:" in code using locks.
    """
    def acquire(self):
        pass

    def release(self):
        pass

def hasher_from_string(name, lock = None, debug = False):
    """
    Create a hasher instance from a name. Name can currently only be a
    name of a YubiHSM device, such as '/dev/ttyACM0'.

    An optional lock is passed in as an argument, to keep this module
    unaware of if threading is being used, and how. If a lock instance
    is given, it will be lock.acquire()'d and lock.release()'d when
    hashers hash.

    The lock must be reentrant to support OATH.
    """
    if not lock:
        lock = NoOpLock()
    try:
        mode = os.stat(name).st_mode
        if stat.S_ISCHR(mode):
            return VCCSYHSMHasher(name, lock, debug)
        raise ValueError("Not a character device : {!r}".format(name))
    except OSError:
        raise ValueError("Unknown hasher {!r}".format(name))
<commit_msg>safe_random: new function to get random bytes using HSM.<commit_after>#!/usr/bin/python
#
# Copyright (c) 2012, 2013, NORDUnet A/S
# All rights reserved.
#
#   Redistribution and use in source and binary forms, with or
#   without modification, are permitted provided that the following
#   conditions are met:
#
#     1. Redistributions of source code must retain the above copyright
#        notice, this list of conditions and the following disclaimer.
#     2. Redistributions in binary form must reproduce the above
#        copyright notice, this list of conditions and the following
#        disclaimer in the documentation and/or other materials provided
#        with the distribution.
#     3. Neither the name of the NORDUnet nor the names of its
#        contributors may be used to endorse or promote products derived
#        from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# Author : Fredrik Thulin <fredrik@thulin.net>
#

import os
import stat
import pyhsm

class VCCSYHSMHasher():

    def __init__(self, device, lock, debug):
        self.yhsm = pyhsm.base.YHSM(device, debug)
        self.lock = lock

    def safe_hmac_sha1(self, key_handle, data):
        """
        Perform HMAC-SHA-1 operation using YubiHSM.

        Acquires a lock first if a lock instance was given at creation time.
        """
        self.lock_acquire()
        try:
            return self.hmac_sha1(key_handle, data)
        finally:
            self.lock_release()

    def hmac_sha1(self, key_handle, data):
        return self.yhsm.hmac_sha1(key_handle, data).get_hash()

    def load_temp_key(self, nonce, key_handle, aead):
        return self.yhsm.load_temp_key(nonce, key_handle, aead)

    def lock_acquire(self):
        return self.lock.acquire()

    def lock_release(self):
        return self.lock.release()

    def safe_random(self, byte_count):
        """
        Generate random bytes using both YubiHSM random function and host OS.

        Acquires a lock first if a lock instance was given at creation time.
        """
        from_os = os.urandom(byte_count)
        self.lock_acquire()
        try:
            from_hsm = self.yhsm.random(byte_count)
            xored = ''.join([chr(ord(a) ^ ord(b)) for (a,b) in zip(from_hsm, from_os)])
            return xored
        finally:
            self.lock_release()

class NoOpLock():
    """
    A No-op lock class, to avoid a lot of "if self.lock:" in code using locks.
    """
    def acquire(self):
        pass

    def release(self):
        pass

def hasher_from_string(name, lock = None, debug = False):
    """
    Create a hasher instance from a name. Name can currently only be a
    name of a YubiHSM device, such as '/dev/ttyACM0'.

    An optional lock is passed in as an argument, to keep this module
    unaware of if threading is being used, and how. If a lock instance
    is given, it will be lock.acquire()'d and lock.release()'d when
    hashers hash.

    The lock must be reentrant to support OATH.
    """
    if not lock:
        lock = NoOpLock()
    try:
        mode = os.stat(name).st_mode
        if stat.S_ISCHR(mode):
            return VCCSYHSMHasher(name, lock, debug)
        raise ValueError("Not a character device : {!r}".format(name))
    except OSError:
        raise ValueError("Unknown hasher {!r}".format(name))
<|endoftext|>