diff --git a/draftfast/__init__.py b/draftfast/__init__.py index eb965cc..7dee6bd 100644 --- a/draftfast/__init__.py +++ b/draftfast/__init__.py @@ -6,7 +6,7 @@ exposure, pickem, showdown, - constants + constants, ) assert optimize diff --git a/draftfast/constants/__init__.py b/draftfast/constants/__init__.py index 33fbd69..ce37712 100644 --- a/draftfast/constants/__init__.py +++ b/draftfast/constants/__init__.py @@ -1,8 +1,10 @@ from draftfast.constants.roster_size import ROSTER_SIZE_BY_SITE_BY_SPORT -from draftfast.constants.positions import (POSITIONS_BY_SITE_BY_LEAGUE, - NBA_GENERAL_POSITIONS, - MLB_GENERAL_POSITIONS, - WNBA_GENERAL_POSITIONS) +from draftfast.constants.positions import ( + POSITIONS_BY_SITE_BY_LEAGUE, + NBA_GENERAL_POSITIONS, + MLB_GENERAL_POSITIONS, + WNBA_GENERAL_POSITIONS, +) from draftfast.constants.salary_cap import SALARY_CAP_BY_SITE_BY_LEAGUE assert ROSTER_SIZE_BY_SITE_BY_SPORT diff --git a/draftfast/constants/positions.py b/draftfast/constants/positions.py index b5d167b..31d182a 100644 --- a/draftfast/constants/positions.py +++ b/draftfast/constants/positions.py @@ -2,141 +2,136 @@ POSITIONS_BY_SITE_BY_LEAGUE = { - 'DRAFT_KINGS': { - 'NBA': [ - ['PG', 1, 3], - ['SG', 1, 3], - ['SF', 1, 3], - ['PF', 1, 3], - ['C', 1, 2] - ], - 'NBA_SHOWDOWN': [ - ['CPT', 1, 1], - ['FLEX', 5, 5], - ], - 'WNBA': [ - ['PG', 1, 3], - ['SG', 1, 3], - ['SF', 1, 4], - ['PF', 1, 4], - ], - 'NFL': get_nfl_positions(), - 'NFL_SHOWDOWN': get_nfl_showdown_positions(dk=True), - 'MLB': [ - ['SP', 0, 2], - ['RP', 0, 2], - ['C', 1, 1], - ['1B', 1, 1], - ['2B', 1, 1], - ['3B', 1, 1], - ['SS', 1, 1], - ['OF', 3, 3], - ], - 'SOCCER': [ - ['F', 2, 3], - ['M', 2, 3], - ['D', 2, 3], - ['GK', 1, 2], - ], - 'EL': [ - ['G', 2, 3], - ['F', 3, 4], - ], - 'NHL': [ - ['C', 2, 3], - ['W', 3, 4], - ['D', 2, 3], - ['G', 1, 1], - ], - 'NHL_SHOWDOWN': [ - ['FLEX', 6, 6], - ], - 'MLB_SHOWDOWN': [ - ['CPT', 1, 1], - ['FLEX', 5, 5], - ], - 'XFL': [ - ['QB', 1, 1], - ['RB', 1, 3], - ['WR', 2, 4], - ['DST', 1, 1] - ], - 'TEN': [ - ['P', 6, 6], - ], - 'PGA': [ - ['G', 6, 6], - ], - 'PGA_CAPTAIN': [ - ['CPT', 1, 1], - ['G', 5, 5], - ], - 'CSGO_SHOWDOWN': [ - ['CPT', 1, 1], - ['FLEX', 5, 5], - ], - 'F1_SHOWDOWN': [ - ['CPT', 1, 1], - ['D', 4, 4], - ['CNSTR', 1, 1], - ], - 'NASCAR': [ - ['D', 6, 6], - ] + "DRAFT_KINGS": { + "NBA": [ + ["PG", 1, 3], + ["SG", 1, 3], + ["SF", 1, 3], + ["PF", 1, 3], + ["C", 1, 2], + ], + "NBA_SHOWDOWN": [ + ["CPT", 1, 1], + ["FLEX", 5, 5], + ], + "WNBA": [ + ["PG", 1, 3], + ["SG", 1, 3], + ["SF", 1, 4], + ["PF", 1, 4], + ], + "NFL": get_nfl_positions(), + "NFL_SHOWDOWN": get_nfl_showdown_positions(dk=True), + "MLB": [ + ["SP", 0, 2], + ["RP", 0, 2], + ["C", 1, 1], + ["1B", 1, 1], + ["2B", 1, 1], + ["3B", 1, 1], + ["SS", 1, 1], + ["OF", 3, 3], + ], + "SOCCER": [ + ["F", 2, 3], + ["M", 2, 3], + ["D", 2, 3], + ["GK", 1, 2], + ], + "EL": [ + ["G", 2, 3], + ["F", 3, 4], + ], + "NHL": [ + ["C", 2, 3], + ["W", 3, 4], + ["D", 2, 3], + ["G", 1, 1], + ], + "NHL_SHOWDOWN": [ + ["FLEX", 6, 6], + ], + "MLB_SHOWDOWN": [ + ["CPT", 1, 1], + ["FLEX", 5, 5], + ], + "XFL": [["QB", 1, 1], ["RB", 1, 3], ["WR", 2, 4], ["DST", 1, 1]], + "TEN": [ + ["P", 6, 6], + ], + "PGA": [ + ["G", 6, 6], + ], + "PGA_CAPTAIN": [ + ["CPT", 1, 1], + ["G", 5, 5], + ], + "CSGO_SHOWDOWN": [ + ["CPT", 1, 1], + ["FLEX", 5, 5], + ], + "F1_SHOWDOWN": [ + ["CPT", 1, 1], + ["D", 4, 4], + ["CNSTR", 1, 1], + ], + "NASCAR": [ + ["D", 6, 6], + ], + }, + "FAN_DUEL": { + "NBA": [ + ["PG", 2, 2], + ["SG", 2, 2], + ["SF", 2, 2], + ["PF", 2, 2], + ["C", 1, 1], + ], + "MLB": [ + ["P", 1, 1], + ["1B", 1, 2], # TODO - allow C or 1B + ["2B", 1, 2], + ["3B", 1, 2], + ["SS", 1, 2], + ["OF", 3, 4], + ], + "MLB_MVP": [ + ["MVP", 1, 1], + ["STAR", 1, 1], + ["UTIL", 3, 3], + ], + "NBA_MVP": [ + ["MVP", 1, 1], + ["STAR", 1, 1], + ["PRO", 1, 1], + ["UTIL", 2, 2], + ], + "WNBA": [ + ["G", 3, 3], + ["F", 4, 4], + ], + "NFL": get_nfl_positions(d_abbrev="D"), + "NFL_MVP": get_nfl_showdown_positions(fd=True), + "NASCAR": [ + ["D", 5, 5], + ], + "PGA": [ + ["G", 6, 6], + ], }, - 'FAN_DUEL': { - 'NBA': [ - ['PG', 2, 2], - ['SG', 2, 2], - ['SF', 2, 2], - ['PF', 2, 2], - ['C', 1, 1], - ], - 'MLB': [ - ['P', 1, 1], - ['1B', 1, 2], # TODO - allow C or 1B - ['2B', 1, 2], - ['3B', 1, 2], - ['SS', 1, 2], - ['OF', 3, 4], - ], - 'MLB_MVP': [ - ['MVP', 1, 1], - ['STAR', 1, 1], - ['UTIL', 3, 3], - ], - 'NBA_MVP': [ - ['MVP', 1, 1], - ['STAR', 1, 1], - ['PRO', 1, 1], - ['UTIL', 2, 2], - ], - 'WNBA': [ - ['G', 3, 3], - ['F', 4, 4], - ], - 'NFL': get_nfl_positions(d_abbrev='D'), - 'NFL_MVP': get_nfl_showdown_positions(fd=True), - 'NASCAR': [ - ['D', 5, 5], - ], - 'PGA': [ - ['G', 6, 6], - ], - } } NBA_GENERAL_POSITIONS = [ - ['G', 3, 4], - ['F', 3, 4], - ['C', 1, 2], + ["G", 3, 4], + ["F", 3, 4], + ["C", 1, 2], ] MLB_GENERAL_POSITIONS = [ - ['P', 2, 2], + ["P", 2, 2], ] WNBA_GENERAL_POSITIONS = [ - ['G', 2, 3], - ['F', 3, 4], + ["G", 2, 3], + ["F", 3, 4], ] diff --git a/draftfast/constants/roster_size.py b/draftfast/constants/roster_size.py index 66a93b4..ba9defe 100644 --- a/draftfast/constants/roster_size.py +++ b/draftfast/constants/roster_size.py @@ -1,33 +1,33 @@ ROSTER_SIZE_BY_SITE_BY_SPORT = { - 'DRAFT_KINGS': { - 'NFL': 9, - 'NFL_SHOWDOWN': 6, - 'MLB_SHOWDOWN': 6, - 'NBA': 8, - 'NBA_SHOWDOWN': 6, - 'WNBA': 6, - 'MLB': 10, - 'SOCCER': 8, - 'EL': 6, - 'NHL': 9, - 'NHL_SHOWDOWN': 6, - 'XFL': 7, - 'TEN': 6, - 'PGA': 6, - 'PGA_CAPTAIN': 6, - 'CSGO_SHOWDOWN': 6, - 'NASCAR': 6, - 'F1_SHOWDOWN': 6, + "DRAFT_KINGS": { + "NFL": 9, + "NFL_SHOWDOWN": 6, + "MLB_SHOWDOWN": 6, + "NBA": 8, + "NBA_SHOWDOWN": 6, + "WNBA": 6, + "MLB": 10, + "SOCCER": 8, + "EL": 6, + "NHL": 9, + "NHL_SHOWDOWN": 6, + "XFL": 7, + "TEN": 6, + "PGA": 6, + "PGA_CAPTAIN": 6, + "CSGO_SHOWDOWN": 6, + "NASCAR": 6, + "F1_SHOWDOWN": 6, + }, + "FAN_DUEL": { + "NFL": 9, + "NFL_MVP": 5, + "MLB_MVP": 5, + "NBA_MVP": 5, + "NBA": 9, + "MLB": 9, + "WNBA": 7, + "NASCAR": 5, + "PGA": 6, }, - 'FAN_DUEL': { - 'NFL': 9, - 'NFL_MVP': 5, - 'MLB_MVP': 5, - 'NBA_MVP': 5, - 'NBA': 9, - 'MLB': 9, - 'WNBA': 7, - 'NASCAR': 5, - 'PGA': 6, - } } diff --git a/draftfast/constants/salary_cap.py b/draftfast/constants/salary_cap.py index 9b3784e..6024e21 100644 --- a/draftfast/constants/salary_cap.py +++ b/draftfast/constants/salary_cap.py @@ -1,33 +1,33 @@ SALARY_CAP_BY_SITE_BY_LEAGUE = { - 'DRAFT_KINGS': { - 'NFL': 50_000, - 'NFL_SHOWDOWN': 50_000, - 'NBA': 50_000, - 'NBA_SHOWDOWN': 50_000, - 'WNBA': 50_000, - 'MLB': 50_000, - 'SOCCER': 50_000, - 'EL': 50_000, - 'NHL': 50_000, - 'NHL_SHOWDOWN': 50_000, - 'MLB_SHOWDOWN': 50_000, - 'XFL': 50_000, - 'TEN': 50_000, - 'PGA': 50_000, - 'PGA_CAPTAIN': 50_000, - 'CSGO_SHOWDOWN': 50_000, - 'NASCAR': 50_000, - 'F1_SHOWDOWN': 50_000, + "DRAFT_KINGS": { + "NFL": 50_000, + "NFL_SHOWDOWN": 50_000, + "NBA": 50_000, + "NBA_SHOWDOWN": 50_000, + "WNBA": 50_000, + "MLB": 50_000, + "SOCCER": 50_000, + "EL": 50_000, + "NHL": 50_000, + "NHL_SHOWDOWN": 50_000, + "MLB_SHOWDOWN": 50_000, + "XFL": 50_000, + "TEN": 50_000, + "PGA": 50_000, + "PGA_CAPTAIN": 50_000, + "CSGO_SHOWDOWN": 50_000, + "NASCAR": 50_000, + "F1_SHOWDOWN": 50_000, + }, + "FAN_DUEL": { + "NFL": 60_000, + "NFL_MVP": 60_000, + "MLB_MVP": 35_000, + "NBA_MVP": 60_000, + "NBA": 60_000, + "MLB": 35_000, + "WNBA": 40_000, + "NASCAR": 50_000, + "PGA": 60_000, }, - 'FAN_DUEL': { - 'NFL': 60_000, - 'NFL_MVP': 60_000, - 'MLB_MVP': 35_000, - 'NBA_MVP': 60_000, - 'NBA': 60_000, - 'MLB': 35_000, - 'WNBA': 40_000, - 'NASCAR': 50_000, - 'PGA': 60_000, - } } diff --git a/draftfast/csv_parse/mlb_upload.py b/draftfast/csv_parse/mlb_upload.py index 734fe70..7f3e9dc 100644 --- a/draftfast/csv_parse/mlb_upload.py +++ b/draftfast/csv_parse/mlb_upload.py @@ -5,59 +5,58 @@ from draftfast import dke_exceptions as dke -upload_file = '{}/data/current-upload.csv'.format(os.getcwd()) +upload_file = "{}/data/current-upload.csv".format(os.getcwd()) def create_upload_file(): - subprocess.call(['touch', upload_file]) - with open(upload_file, 'w') as f: + subprocess.call(["touch", upload_file]) + with open(upload_file, "w") as f: writer = csv.writer(f) writer.writerow( [ - 'P', - 'P', - 'C', - '1B', - '2B', - '3B', - 'SS', - 'OF', - 'OF', - 'OF', - ]) + "P", + "P", + "C", + "1B", + "2B", + "3B", + "SS", + "OF", + "OF", + "OF", + ] + ) def map_pids(pid_file): player_map = {} - with open(pid_file, 'r') as f: + with open(pid_file, "r") as f: n = 0 fields = None for line in f.readlines(): n += 1 - if 'TeamAbbrev' in line: # line with field names was found - fields = line.split(',') + if "TeamAbbrev" in line: # line with field names was found + fields = line.split(",") break if not fields: raise dke.InvalidCSVUploadFileException( - "Check that you're using the DK CSV upload template, " + - "which can be found at " + - "https://www.draftkings.com/lineup/upload.") + "Check that you're using the DK CSV upload template, " + + "which can be found at " + + "https://www.draftkings.com/lineup/upload." + ) f.close() - f = islice(open(pid_file, 'r'), n, None) + f = islice(open(pid_file, "r"), n, None) reader = csv.DictReader(f, fieldnames=fields) for line in reader: - player_map[line['Name'] + ' ' + line['Position']] = line['ID'] + player_map[line["Name"] + " " + line["Position"]] = line["ID"] return player_map def update_upload_csv(player_map, roster): sorted_players = roster.sorted_players() - with open(upload_file, 'a') as f: + with open(upload_file, "a") as f: writer = csv.writer(f) - writer.writerow([ - p.get_player_id(player_map) - for p in sorted_players - ]) + writer.writerow([p.get_player_id(player_map) for p in sorted_players]) diff --git a/draftfast/csv_parse/salary_download.py b/draftfast/csv_parse/salary_download.py index 15adb58..38989dc 100644 --- a/draftfast/csv_parse/salary_download.py +++ b/draftfast/csv_parse/salary_download.py @@ -5,30 +5,31 @@ from draftfast.showdown.orm import ShowdownPlayer, MVPPlayer from draftfast.rules import ( RuleSet, - DRAFT_KINGS, FAN_DUEL, + DRAFT_KINGS, + FAN_DUEL, FD_NFL_MVP_RULE_SET, FD_MLB_MVP_RULE_SET, - FD_NBA_MVP_RULE_SET + FD_NBA_MVP_RULE_SET, ) GAME_KEY_MAP = { DRAFT_KINGS: { - 'name': 'Name', - 'salary': 'Salary', - 'team': 'teamAbbrev', - 'team_alt': 'TeamAbbrev', - 'game': 'GameInfo', - 'game_alt': 'Game Info', - 'avg': 'AvgPointsPerGame', + "name": "Name", + "salary": "Salary", + "team": "teamAbbrev", + "team_alt": "TeamAbbrev", + "game": "GameInfo", + "game_alt": "Game Info", + "avg": "AvgPointsPerGame", }, FAN_DUEL: { - 'name': 'Nickname', - 'team': 'Team', - 'team_alt': None, - 'game': 'Game', - 'game_alt': None, - 'avg': 'FPPG', - } + "name": "Nickname", + "team": "Team", + "team_alt": None, + "game": "Game", + "game_alt": None, + "avg": "FPPG", + }, } @@ -38,10 +39,10 @@ def generate_players_from_csvs( salary_file_location: str, game: str, - projection_file_location='', + projection_file_location="", verbose=False, - encoding='utf-8', - errors='replace', + encoding="utf-8", + errors="replace", ruleset=None, ) -> list: players = [] @@ -53,25 +54,26 @@ def generate_players_from_csvs( errors, ) - with open(salary_file_location, 'r', - encoding=encoding, errors=errors) as csv_file: + with open( + salary_file_location, "r", encoding=encoding, errors=errors + ) as csv_file: csv_data = csv.DictReader(csv_file) - pos_key = 'Position' - is_nhl = ruleset and ruleset.league == 'NHL' - is_showdown = ruleset and ruleset.game_type == 'showdown' + pos_key = "Position" + is_nhl = ruleset and ruleset.league == "NHL" + is_showdown = ruleset and ruleset.game_type == "showdown" if is_nhl or is_showdown: - pos_key = 'Roster Position' + pos_key = "Roster Position" for row in csv_data: - if ruleset and ruleset.game_type == 'pickem': + if ruleset and ruleset.game_type == "pickem": player = TieredPlayer( cost=0, # salary not applicable in pickem - name=row['Name'], - pos=row['Position'], - team=row['TeamAbbrev'], - matchup=row['Game Info'], - average_score=float(row['AvgPointsPerGame']), - tier=row['Roster Position'], + name=row["Name"], + pos=row["Position"], + team=row["TeamAbbrev"], + matchup=row["Game Info"], + average_score=float(row["AvgPointsPerGame"]), + tier=row["Roster Position"], ) _set_projections( projections, @@ -81,14 +83,14 @@ def generate_players_from_csvs( players.append(player) elif ruleset == FD_NFL_MVP_RULE_SET: parsed = _parse_fd_mvp_nfl_row( - pos=row['Position'], + pos=row["Position"], row=row, ) players += parsed continue elif ruleset in [FD_MLB_MVP_RULE_SET, FD_NBA_MVP_RULE_SET]: parsed = _parse_mvp_mlb_row( - pos=row['Position'], + pos=row["Position"], row=row, ruleset=ruleset, ) @@ -97,7 +99,7 @@ def generate_players_from_csvs( elif is_showdown: pos = row[pos_key] player = generate_player( - pos=row['Position'], + pos=row["Position"], row=row, game=game, ) @@ -106,12 +108,12 @@ def generate_players_from_csvs( player, verbose, ) - captain = pos == 'CPT' + captain = pos == "CPT" showdown_pos = None # F1 requires unique non-captain position - if ruleset.league == 'F1_SHOWDOWN': + if ruleset.league == "F1_SHOWDOWN": showdown_pos = pos if not captain else None players.append( @@ -122,8 +124,8 @@ def generate_players_from_csvs( ) ) else: - for pos in row[pos_key].split('/'): - if is_nhl and pos == 'UTIL': + for pos in row[pos_key].split("/"): + if is_nhl and pos == "UTIL": continue player = generate_player( pos=pos, @@ -142,26 +144,26 @@ def generate_players_from_csvs( def generate_player(pos, row, game): - ''' + """ Parses CSV row for DraftKings or FanDuel and returns a player. Note that DraftKings has different CSV formats for different sports. - ''' - avg_key = GAME_KEY_MAP[game]['avg'] - name_key = GAME_KEY_MAP[game]['name'] - team_key = GAME_KEY_MAP[game]['team'] - team_alt_key = GAME_KEY_MAP[game]['team_alt'] - game_key = GAME_KEY_MAP[game]['game'] - game_alt_key = GAME_KEY_MAP[game]['game_alt'] + """ + avg_key = GAME_KEY_MAP[game]["avg"] + name_key = GAME_KEY_MAP[game]["name"] + team_key = GAME_KEY_MAP[game]["team"] + team_alt_key = GAME_KEY_MAP[game]["team_alt"] + game_key = GAME_KEY_MAP[game]["game"] + game_alt_key = GAME_KEY_MAP[game]["game_alt"] avg = float(row.get(avg_key, 0) or 0) player = Player( pos, row[name_key].strip().rstrip(), - row['Salary'], - possible_positions=row['Position'], - multi_position='/' in row['Position'], + row["Salary"], + possible_positions=row["Position"], + multi_position="/" in row["Position"], team=row.get(team_key) or row.get(team_alt_key), matchup=row.get(game_key) or row.get(game_alt_key), average_score=avg, @@ -213,15 +215,12 @@ def _parse_mvp_mlb_row( row=row, game=FAN_DUEL, ) - util = MVPPlayer.from_player(player, game_position='UTIL') + util = MVPPlayer.from_player(player, game_position="UTIL") mvp = MVPPlayer.from_player( player, - game_position='MVP', - ) - star = MVPPlayer.from_player( - player, - game_position='STAR' + game_position="MVP", ) + star = MVPPlayer.from_player(player, game_position="STAR") # Unlike DK, FD does not break out players by multiplier position mvp.average_score *= MVPPlayer.MVP_MULTIPLIER @@ -229,26 +228,24 @@ def _parse_mvp_mlb_row( # NBA contains PRO if ruleset == FD_NBA_MVP_RULE_SET: - pro = MVPPlayer.from_player( - player, - game_position='PRO' - ) + pro = MVPPlayer.from_player(player, game_position="PRO") pro.average_score *= MVPPlayer.PRO_MULTIPLIER return [mvp, star, pro, util] return [mvp, star, util] -def _generate_projection_dict(projection_file_location: str, - encoding: str, - errors: str) -> dict: +def _generate_projection_dict( + projection_file_location: str, encoding: str, errors: str +) -> dict: projections = {} - with open(projection_file_location, 'r', - encoding=encoding, errors=errors) as csv_file: + with open( + projection_file_location, "r", encoding=encoding, errors=errors + ) as csv_file: csv_data = csv.DictReader(csv_file) for row in csv_data: - name = row.get('playername').strip().rstrip() - projections[name] = float(row.get('points')) + name = row.get("playername").strip().rstrip() + projections[name] = float(row.get("points")) return projections @@ -259,12 +256,12 @@ def _set_projections(projections, player, verbose): # try to find projection for e.g. 'Andrew Luck IND' if proj is None and player.team is not None: - alt_name = '{} {}'.format(player.name, player.team.upper()) + alt_name = "{} {}".format(player.name, player.team.upper()) proj = projections.get(alt_name) if proj is None: if verbose: - print('No projection for {}'.format(player.name)) + print("No projection for {}".format(player.name)) player.proj = 0 else: player.proj = proj diff --git a/draftfast/csv_parse/upload.py b/draftfast/csv_parse/upload.py index c98bd55..60693e6 100644 --- a/draftfast/csv_parse/upload.py +++ b/draftfast/csv_parse/upload.py @@ -1,108 +1,100 @@ import os from draftfast.rules import DRAFT_KINGS, FAN_DUEL -upload_file = '{}/data/current-upload.csv'.format(os.getcwd()) +upload_file = "{}/data/current-upload.csv".format(os.getcwd()) -def write_to_csv(writer, player_map, roster, game=DRAFT_KINGS, - league='NBA'): +def write_to_csv(writer, player_map, roster, game=DRAFT_KINGS, league="NBA"): players = roster.sorted_players() ordered_possible = [] - if game == DRAFT_KINGS and league == 'EL': + if game == DRAFT_KINGS and league == "EL": ordered_possible = [ - _on_position(players, ['G']), - _on_position(players, ['G']), - _on_position(players, ['F']), - _on_position(players, ['F']), - _on_position(players, ['F']), - players + _on_position(players, ["G"]), + _on_position(players, ["G"]), + _on_position(players, ["F"]), + _on_position(players, ["F"]), + _on_position(players, ["F"]), + players, ] - elif game == DRAFT_KINGS and league == 'NFL': + elif game == DRAFT_KINGS and league == "NFL": ordered_possible = [ - _on_position(players, ['QB']), - _on_position(players, ['RB']), - _on_position(players, ['RB']), - _on_position(players, ['WR']), - _on_position(players, ['WR']), - _on_position(players, ['WR']), - _on_position(players, ['TE']), - + _on_position(players, ["QB"]), + _on_position(players, ["RB"]), + _on_position(players, ["RB"]), + _on_position(players, ["WR"]), + _on_position(players, ["WR"]), + _on_position(players, ["WR"]), + _on_position(players, ["TE"]), # NFL Flex - _on_position(players, ['TE', 'WR', 'RB']), - _on_position(players, ['DST']), + _on_position(players, ["TE", "WR", "RB"]), + _on_position(players, ["DST"]), ] - elif game == DRAFT_KINGS and league == 'XFL': + elif game == DRAFT_KINGS and league == "XFL": ordered_possible = [ - _on_position(players, ['QB']), - _on_position(players, ['RB']), - _on_position(players, ['WR']), - _on_position(players, ['WR']), - _on_position(players, ['WR', 'RB']), - _on_position(players, ['WR', 'RB']), - _on_position(players, ['DST']), + _on_position(players, ["QB"]), + _on_position(players, ["RB"]), + _on_position(players, ["WR"]), + _on_position(players, ["WR"]), + _on_position(players, ["WR", "RB"]), + _on_position(players, ["WR", "RB"]), + _on_position(players, ["DST"]), ] - elif game == DRAFT_KINGS and league == 'SOCCER': + elif game == DRAFT_KINGS and league == "SOCCER": ordered_possible = [ - _on_position(players, ['F']), - _on_position(players, ['F']), - _on_position(players, ['M']), - _on_position(players, ['M']), - _on_position(players, ['D']), - _on_position(players, ['D']), - _on_position(players, ['GK']), - players + _on_position(players, ["F"]), + _on_position(players, ["F"]), + _on_position(players, ["M"]), + _on_position(players, ["M"]), + _on_position(players, ["D"]), + _on_position(players, ["D"]), + _on_position(players, ["GK"]), + players, ] - elif game == DRAFT_KINGS and league == 'NHL': + elif game == DRAFT_KINGS and league == "NHL": ordered_possible = [ - _on_position(players, ['C']), - _on_position(players, ['C']), - _on_position(players, ['W']), - _on_position(players, ['W']), - _on_position(players, ['W']), - _on_position(players, ['D']), - _on_position(players, ['D']), - _on_position(players, ['G']), - players + _on_position(players, ["C"]), + _on_position(players, ["C"]), + _on_position(players, ["W"]), + _on_position(players, ["W"]), + _on_position(players, ["W"]), + _on_position(players, ["D"]), + _on_position(players, ["D"]), + _on_position(players, ["G"]), + players, ] elif game == DRAFT_KINGS: ordered_possible = [ - _on_position(players, ['PG']), - _on_position(players, ['SG']), - _on_position(players, ['SF']), - _on_position(players, ['PF']), - _on_position(players, ['C']), - _on_position(players, ['SG', 'PG']), - _on_position(players, ['SF', 'PF']), - players + _on_position(players, ["PG"]), + _on_position(players, ["SG"]), + _on_position(players, ["SF"]), + _on_position(players, ["PF"]), + _on_position(players, ["C"]), + _on_position(players, ["SG", "PG"]), + _on_position(players, ["SF", "PF"]), + players, ] elif game == FAN_DUEL: ordered_possible = [ - _on_position(players, ['PG']), - _on_position(players, ['PG']), - _on_position(players, ['SG']), - _on_position(players, ['SG']), - _on_position(players, ['SF']), - _on_position(players, ['SF']), - _on_position(players, ['PF']), - _on_position(players, ['PF']), - _on_position(players, ['C']), + _on_position(players, ["PG"]), + _on_position(players, ["PG"]), + _on_position(players, ["SG"]), + _on_position(players, ["SG"]), + _on_position(players, ["SF"]), + _on_position(players, ["SF"]), + _on_position(players, ["PF"]), + _on_position(players, ["PF"]), + _on_position(players, ["C"]), ] ordered_lineup = [] counter = 0 for ps in ordered_possible: counter += 1 - not_used_ps = [ - p for p in ps - if p not in ordered_lineup - ] + not_used_ps = [p for p in ps if p not in ordered_lineup] ordered_lineup.append(not_used_ps[0]) - writer.writerow([ - p.get_player_id(player_map) - for p in ordered_lineup - ]) + writer.writerow([p.get_player_id(player_map) for p in ordered_lineup]) def _on_position(players, possible): diff --git a/draftfast/csv_parse/uploaders.py b/draftfast/csv_parse/uploaders.py index f538b22..e3262a0 100644 --- a/draftfast/csv_parse/uploaders.py +++ b/draftfast/csv_parse/uploaders.py @@ -9,49 +9,51 @@ NAME_MAP = { DRAFT_KINGS: { - 'start': 'TeamAbbrev', - 'name': 'Name', - 'position': 'Position', - 'id': 'ID', + "start": "TeamAbbrev", + "name": "Name", + "position": "Position", + "id": "ID", }, FAN_DUEL: { - 'start': '"Nickname"', - 'name': '"Nickname"', - 'position': '"Position"', - 'id': '"Player ID + Player Name"', + "start": '"Nickname"', + "name": '"Nickname"', + "position": '"Position"', + "id": '"Player ID + Player Name"', }, } def map_pids(pid_file, encoding, errors, game=DRAFT_KINGS): - start = NAME_MAP.get(game).get('start') - name = NAME_MAP.get(game).get('name') - position = NAME_MAP.get(game).get('position') - p_id = NAME_MAP.get(game).get('id') + start = NAME_MAP.get(game).get("start") + name = NAME_MAP.get(game).get("name") + position = NAME_MAP.get(game).get("position") + p_id = NAME_MAP.get(game).get("id") player_map = {} - with open(pid_file, 'r') as f: + with open(pid_file, "r") as f: n = 0 fields = None for line in f.readlines(): n += 1 if start in line: # line with field names was found - fields = line.split(',') + fields = line.split(",") break if not fields: raise dke.InvalidCSVUploadFileException( - "Check that you're using the DK CSV upload template, " + - "which can be found at " + - "https://www.draftkings.com/lineup/upload.") + "Check that you're using the DK CSV upload template, " + + "which can be found at " + + "https://www.draftkings.com/lineup/upload." + ) f.close() - f = islice(open(pid_file, 'r', - encoding=encoding, errors=errors), n, None) + f = islice( + open(pid_file, "r", encoding=encoding, errors=errors), n, None + ) reader = csv.DictReader(f, fieldnames=fields) for line in reader: # DraftKings adds spaces to DST for NFL - if 'DST' in line[position]: + if "DST" in line[position]: line[name] = line[name].strip() line[position] = line[position].strip() @@ -61,21 +63,25 @@ def map_pids(pid_file, encoding, errors, game=DRAFT_KINGS): class CSVUploader(object): - - def __init__(self, pid_file, upload_file='./upload.csv', - encoding='utf-8', errors='replace'): + def __init__( + self, + pid_file, + upload_file="./upload.csv", + encoding="utf-8", + errors="replace", + ): self.upload_file = upload_file self.encoding = encoding self.errors = errors self.pid_map = self._map_pids(pid_file) def _map_pids(self, pid_file): - raise NotImplementedError('You must implement _map_pids') + raise NotImplementedError("You must implement _map_pids") class DraftKingsUploader(CSVUploader): def write_rosters(self, rosters): - with open(self.upload_file, 'w') as f: + with open(self.upload_file, "w") as f: writer = csv.writer(f) writer.writerow(self.HEADERS) for roster in rosters: @@ -96,62 +102,84 @@ def _map_pids(self, pid_file): class DraftKingsNBAUploader(DraftKingsUploader): - LEAGUE = 'NBA' - HEADERS = [ - 'PG', 'SG', 'SF', - 'PF', 'C', 'G', 'F', 'UTIL' - ] + LEAGUE = "NBA" + HEADERS = ["PG", "SG", "SF", "PF", "C", "G", "F", "UTIL"] class DraftKingsELUploader(DraftKingsUploader): - LEAGUE = 'EL' + LEAGUE = "EL" HEADERS = [ - 'G', 'G', 'F', 'F', 'F', 'UTIL', + "G", + "G", + "F", + "F", + "F", + "UTIL", ] class DraftKingsSoccerUploader(DraftKingsUploader): - LEAGUE = 'SOCCER' + LEAGUE = "SOCCER" HEADERS = [ - 'F', 'F', 'M', 'M', 'D', 'D', 'GK', 'UTIL', + "F", + "F", + "M", + "M", + "D", + "D", + "GK", + "UTIL", ] class DraftKingsNHLUploader(DraftKingsUploader): - LEAGUE = 'NHL' + LEAGUE = "NHL" HEADERS = [ - 'C', 'C', 'W', 'W', 'W', 'D', - 'D', 'G', 'UTIL', + "C", + "C", + "W", + "W", + "W", + "D", + "D", + "G", + "UTIL", ] class DraftKingsNFLUploader(DraftKingsUploader): - LEAGUE = 'NFL' - HEADERS = [ - 'QB', 'RB', 'RB', - 'WR', 'WR', 'WR', - 'TE', 'FLEX', 'DST' - ] + LEAGUE = "NFL" + HEADERS = ["QB", "RB", "RB", "WR", "WR", "WR", "TE", "FLEX", "DST"] class DraftKingsXFLUploader(DraftKingsUploader): - LEAGUE = 'XFL' + LEAGUE = "XFL" HEADERS = [ - 'QB', 'RB', - 'WR', 'WR', - 'FLEX', 'FLEX', - 'DST', + "QB", + "RB", + "WR", + "WR", + "FLEX", + "FLEX", + "DST", ] class FanDuelNBAUploader(CSVUploader): HEADERS = [ - 'PG', 'PG', 'SG', 'SG', 'SF', - 'SF', 'PF', 'PF', 'C', + "PG", + "PG", + "SG", + "SG", + "SF", + "SF", + "PF", + "PF", + "C", ] def write_rosters(self, rosters): - with open(self.upload_file, 'w') as f: + with open(self.upload_file, "w") as f: writer = csv.writer(f) writer.writerow(self.HEADERS) for roster in rosters: @@ -177,7 +205,7 @@ class FanDuelNFLUploader(CSVUploader): class DraftKingsNBAPickemUploader(CSVUploader): def write_rosters(self, rosters): - with open(self.upload_file, 'w') as f: + with open(self.upload_file, "w") as f: writer = csv.DictWriter(f, fieldnames=pickem_orm.TIERS) writer.writeheader() for roster in rosters: @@ -192,16 +220,16 @@ def _map_pids(self, pid_file): class DraftKingsCaptainShowdownUploader(DraftKingsUploader): - HEADERS = [ - 'CPT', 'UTIL', 'UTIL', 'UTIL', 'UTIL', 'UTIL' - ] + HEADERS = ["CPT", "UTIL", "UTIL", "UTIL", "UTIL", "UTIL"] def write_rosters(self, rosters): - with open(self.upload_file, 'w') as f: + with open(self.upload_file, "w") as f: writer = csv.writer(f) writer.writerow(self.HEADERS) for roster in rosters: - writer.writerow([ - p.get_player_id(self.pid_map) - for p in roster.sorted_players() - ]) + writer.writerow( + [ + p.get_player_id(self.pid_map) + for p in roster.sorted_players() + ] + ) diff --git a/draftfast/exposure.py b/draftfast/exposure.py index 5168aa4..7b9dd9b 100644 --- a/draftfast/exposure.py +++ b/draftfast/exposure.py @@ -15,52 +15,59 @@ def parse_exposure_file(file_location): { : { min: , max: } } """ exposures = [] - with open(file_location, 'r') as filename: + with open(file_location, "r") as filename: reader = csv.DictReader(filename) for row in reader: - if 'name' not in row or \ - 'min' not in row or \ - 'max' not in row: - raise Exception(''' + if "name" not in row or "min" not in row or "max" not in row: + raise Exception( + """ You must provide a min, max and name for each row - got {}. - '''.format(row) + """.format( + row + ) ) - exposures.append({ - 'name': row['name'], - 'min': float(row['min']), - 'max': float(row['max']), - }) + exposures.append( + { + "name": row["name"], + "min": float(row["min"]), + "max": float(row["max"]), + } + ) return exposures -def get_exposure_args(existing_rosters, exposure_bounds, n, use_random, - random_seed) -> dict: +def get_exposure_args( + existing_rosters, exposure_bounds, n, use_random, random_seed +) -> dict: exposures = {} for r in existing_rosters: for p in r.players: exposures[p.name] = exposures.get(p.name, 0) + 1 if use_random: - return get_exposure_args_random(exposures, exposure_bounds, n, - random_seed) + return get_exposure_args_random( + exposures, exposure_bounds, n, random_seed + ) - return get_exposure_args_deterministic(exposures, existing_rosters, - exposure_bounds) + return get_exposure_args_deterministic( + exposures, existing_rosters, exposure_bounds + ) -def get_exposure_args_deterministic(exposures, existing_rosters, - exposure_bounds) -> dict: +def get_exposure_args_deterministic( + exposures, existing_rosters, exposure_bounds +) -> dict: banned = [] locked = [] for bound in exposure_bounds: - name = bound['name'] + name = bound["name"] total = float(len(existing_rosters) + 1) - min_lines = bound['min'] * total - max_lines = math.floor(bound['max'] * total) + min_lines = bound["min"] * total + max_lines = math.floor(bound["max"] * total) lineups = exposures.get(name, 0) if lineups < min_lines: @@ -70,28 +77,29 @@ def get_exposure_args_deterministic(exposures, existing_rosters, banned.append(name) return { - 'banned': banned, - 'locked': locked, + "banned": banned, + "locked": locked, } -def get_exposure_args_random(exposures, exposure_bounds, n, - random_seed) -> dict: +def get_exposure_args_random( + exposures, exposure_bounds, n, random_seed +) -> dict: locked = [] for bound in exposure_bounds: - name = bound['name'] + name = bound["name"] # TODO: maybe exclude players who have met max exposure? # randomly lock in players based on the desired exposure # TODO - downsize locked so solution is not impossible r = random.random() - if r <= bound['max']: + if r <= bound["max"]: locked.append(name) return { - 'banned': [], - 'locked': locked, + "banned": [], + "locked": locked, } @@ -108,13 +116,13 @@ def check_exposure(rosters, bounds): exposure_diffs = {} for bound in bounds: - name = bound['name'] + name = bound["name"] exposure = exposures.get(name, 0) - if exposure > len(rosters) * bound['max']: - exposure_diffs[name] = exposure - len(rosters) * bound['max'] - elif exposure < len(rosters) * bound['min']: - exposure_diffs[name] = exposure - len(rosters) * bound['min'] + if exposure > len(rosters) * bound["max"]: + exposure_diffs[name] = exposure - len(rosters) * bound["max"] + elif exposure < len(rosters) * bound["min"]: + exposure_diffs[name] = exposure - len(rosters) * bound["min"] return exposure_diffs @@ -127,53 +135,53 @@ def get_exposure_table(rosters, bounds): exposures[p.name] = exposures.get(p.name, 0) + 1 players[p.name] = p - exposures = OrderedDict(sorted(exposures.items(), - key=lambda t: t[1], - reverse=True)) + exposures = OrderedDict( + sorted(exposures.items(), key=lambda t: t[1], reverse=True) + ) table_data = [] headers = [ - 'Position', - 'Player', - 'Team', - 'Matchup', - 'Salary', - 'Projection', - '# Lineups', - 'Min', - 'Max' + "Position", + "Player", + "Team", + "Matchup", + "Salary", + "Projection", + "# Lineups", + "Min", + "Max", ] table_data.append(headers) for name, num in exposures.items(): - s_min = '' - s_max = '' + s_min = "" + s_max = "" # TODO format min/max as a single string if bounds: for bound in bounds: - if bound['name'] == name: - s_min = len(rosters) * bound['min'] - s_max = len(rosters) * bound['max'] + if bound["name"] == name: + s_min = len(rosters) * bound["min"] + s_max = len(rosters) * bound["max"] if num > s_max: - s_max = '\x1b[0;31;40m{:0.2f}\x1b[0m'.format(s_max) + s_max = "\x1b[0;31;40m{:0.2f}\x1b[0m".format(s_max) elif num < s_min: - s_min = '\x1b[0;31;40m{:0.2f}\x1b[0m'.format(s_min) + s_min = "\x1b[0;31;40m{:0.2f}\x1b[0m".format(s_min) continue - table_data.append(players[name].to_exposure_table_row(num, - s_min, - s_max)) + table_data.append( + players[name].to_exposure_table_row(num, s_min, s_max) + ) table = AsciiTable(table_data) - table.justify_columns[4] = 'right' - table.justify_columns[5] = 'right' - table.justify_columns[6] = 'right' - table.justify_columns[7] = 'right' - table.justify_columns[8] = 'right' + table.justify_columns[4] = "right" + table.justify_columns[5] = "right" + table.justify_columns[6] = "right" + table.justify_columns[7] = "right" + table.justify_columns[8] = "right" - return 'Roster Exposure:\n' + table.table + return "Roster Exposure:\n" + table.table def get_exposure_matrix(rosters, exclude=[]): @@ -193,13 +201,13 @@ def get_exposure_matrix(rosters, exclude=[]): if p1 in r and p2 in r: player_matrix[i, j] += 1 - rows = [[''] + sorted_names] + rows = [[""] + sorted_names] for i, p in enumerate(sorted_names): rows.append([p] + list(player_matrix[i, :])) table = AsciiTable(rows) table.inner_row_border = True - table.justify_columns = {i + 1: 'center' for i in range(len(sorted_names))} + table.justify_columns = {i + 1: "center" for i in range(len(sorted_names))} return table.table diff --git a/draftfast/lineup_constraints.py b/draftfast/lineup_constraints.py index d1afb89..5703ced 100644 --- a/draftfast/lineup_constraints.py +++ b/draftfast/lineup_constraints.py @@ -8,12 +8,14 @@ def _iterableify(x): class LineupConstraints(object): - def __init__(self, - locked: list = [], - position_locked: list = [], - banned: list = [], - position_banned: list = [], - groups: list = []): + def __init__( + self, + locked: list = [], + position_locked: list = [], + banned: list = [], + position_banned: list = [], + groups: list = [], + ): self._constraints = [] self._banned = set() self._locked = set() @@ -43,32 +45,32 @@ def __iter__(self): def __len__(self): return ( - len(self._constraints) + - len(self._locked) + - len(self._banned) + - len(self._position_locked) + - len(self._position_banned) + len(self._constraints) + + len(self._locked) + + len(self._banned) + + len(self._position_locked) + + len(self._position_banned) ) def __repr__(self): - constraints = ', '.join([repr(c) for c in self._constraints]) - lcs = 'LineupConstraintSet: {}'.format(constraints) - b1 = ''.format(self._banned) - bp1 = ''.format(self._position_banned) - lp1 = ''.format(self._locked) - l1 = ''.format(self._position_locked) - return '<{}, {}, {}, {}, {}>'.format(lcs, b1, bp1, l1, lp1) + constraints = ", ".join([repr(c) for c in self._constraints]) + lcs = "LineupConstraintSet: {}".format(constraints) + b1 = "".format(self._banned) + bp1 = "".format(self._position_banned) + lp1 = "".format(self._locked) + l1 = "".format(self._position_locked) + return "<{}, {}, {}, {}, {}>".format(lcs, b1, bp1, l1, lp1) def __str__(self): lines = [str(c) for c in self._constraints] if len(self._banned): - lines.append('Banned: ' + ', '.join(p for p in self._banned)) + lines.append("Banned: " + ", ".join(p for p in self._banned)) if len(self._locked): - lines.append('Locked: ' + ', '.join(p for p in self._locked)) + lines.append("Locked: " + ", ".join(p for p in self._locked)) if len(lines): - return '\n'.join(lines) + return "\n".join(lines) else: - return 'None' + return "None" def __eq__(self, constraintset): if len(self._constraints) != len(constraintset._constraints): @@ -110,7 +112,7 @@ def _check_conflicts(self, constraint): for p in constraint.players: if p in self._locked or p in self._banned: raise ConstraintConflictException( - 'Ban/lock constraint for {} already exists'.format(p) + "Ban/lock constraint for {} already exists".format(p) ) def _add(self, constraint): @@ -119,7 +121,7 @@ def _add(self, constraint): if constraint not in self._constraints: self._constraints.append(constraint) else: - raise ConstraintConflictException('Duplicate constraint') + raise ConstraintConflictException("Duplicate constraint") def is_banned(self, player: str) -> bool: return player in self._banned @@ -143,12 +145,12 @@ def ban(self, players): _players = _iterableify(players) if len(_players) == 0: - raise ConstraintException('Empty ban group') + raise ConstraintException("Empty ban group") for p in _players: if p in self: raise ConstraintConflictException( - '{} exists in another constraint'.format(p) + "{} exists in another constraint".format(p) ) self._banned.update(_players) @@ -156,12 +158,12 @@ def lock(self, players): _players = _iterableify(players) if len(_players) == 0: - raise ConstraintException('Empty lock group') + raise ConstraintException("Empty lock group") for p in _players: if p in self: raise ConstraintConflictException( - '{} exists in another constraint'.format(p) + "{} exists in another constraint".format(p) ) self._locked.update(_players) @@ -169,12 +171,12 @@ def position_lock(self, solver_ids): _solver_ids = _iterableify(solver_ids) if len(_solver_ids) == 0: - raise ConstraintException('Empty position lock group') + raise ConstraintException("Empty position lock group") for p in _solver_ids: if p in self: raise ConstraintConflictException( - '{} exists in another constraint'.format(p) + "{} exists in another constraint".format(p) ) self._position_locked.update(_solver_ids) @@ -182,12 +184,12 @@ def position_ban(self, solver_ids): _solver_ids = _iterableify(solver_ids) if len(_solver_ids) == 0: - raise ConstraintException('Empty position lock group') + raise ConstraintException("Empty position lock group") for p in _solver_ids: if p in self: raise ConstraintConflictException( - '{} exists in another constraint'.format(p) + "{} exists in another constraint".format(p) ) self._position_banned.update(_solver_ids) @@ -243,10 +245,10 @@ class ConstraintException(Exception): class PlayerConstraint(AbstractConstraint): def __init__(self, players): if not len(players): - raise ConstraintException('No players in group') + raise ConstraintException("No players in group") if len(players) != len(set(players)): - raise ConstraintException('Duplicate players in group') + raise ConstraintException("Duplicate players in group") self.players = players @@ -256,7 +258,7 @@ def __eq__(self, rule): return set(self.players) == set(rule.players) def __hash__(self): - return hash(''.join(sorted(self.players))) + return hash("".join(sorted(self.players))) def __contains__(self, player): return player in self.players @@ -277,21 +279,25 @@ def __init__(self, players, bound): self.exact = bound self._exact_bounds_sanity_check() else: - raise ConstraintException('Bound must be length 2 or int') + raise ConstraintException("Bound must be length 2 or int") def __repr__(self): - return ''.format(self._bounds_str, - self.players) + return "".format( + self._bounds_str, self.players + ) def __str__(self): - return 'Using {} of: {}'.format( - self._bounds_str, - ', '.join(p for p in self.players) + return "Using {} of: {}".format( + self._bounds_str, ", ".join(p for p in self.players) ) def __eq__(self, constraint): - return super().__eq__(constraint) and self.exact == constraint.exact \ - and self.lb == constraint.lb and self.ub == constraint.ub + return ( + super().__eq__(constraint) + and self.exact == constraint.exact + and self.lb == constraint.lb + and self.ub == constraint.ub + ) def __hash__(self): return hash((super().__hash__(), self.exact, self.lb, self.ub)) @@ -299,37 +305,38 @@ def __hash__(self): @property def _bounds_str(self): if self.exact: - return '{0.exact}'.format(self) + return "{0.exact}".format(self) - return '{0.lb} to {0.ub}'.format(self) + return "{0.lb} to {0.ub}".format(self) def _exact_bounds_sanity_check(self): if self.exact <= 0: raise ConstraintException( - 'Exact bound may not less than or equal to zero' + "Exact bound may not less than or equal to zero" ) if self.exact >= len(self.players): raise ConstraintException( - 'Exact bound may not be greater than or equal to number ' - 'of players in group' + "Exact bound may not be greater than or equal to number " + "of players in group" ) def _ub_lb_bounds_sanity_check(self): if self.lb < 1: raise ConstraintException( - 'Lower bound for {!r} cannot be less than 1'.format(self) + "Lower bound for {!r} cannot be less than 1".format(self) ) if self.ub == self.lb: raise ConstraintException( - 'Lower bound for {!r} cannot equal upper bound'.format(self) + "Lower bound for {!r} cannot equal upper bound".format(self) ) if self.ub < self.lb: raise ConstraintException( - 'Upper bound for {!r} cannot be less than lower bound.' - .format(self) + "Upper bound for {!r} cannot be less than lower bound.".format( + self + ) ) if self.ub > len(self.players) or self.lb > len(self.players): raise ConstraintException( - 'Bound for {!r} cannot be greater than number of players ' - 'group'.format(self) + "Bound for {!r} cannot be greater than number of players " + "group".format(self) ) diff --git a/draftfast/optimize.py b/draftfast/optimize.py index 6e593d2..40b52dc 100644 --- a/draftfast/optimize.py +++ b/draftfast/optimize.py @@ -4,21 +4,27 @@ from draftfast import player_pool as pool from draftfast.orm import RosterSelect, Roster from draftfast.optimizer import Optimizer -from draftfast.exposure import check_exposure, \ - get_exposure_table, get_exposure_matrix, get_exposure_args +from draftfast.exposure import ( + check_exposure, + get_exposure_table, + get_exposure_matrix, + get_exposure_args, +) from draftfast.rules import RuleSet from draftfast.settings import PlayerPoolSettings, OptimizerSettings from draftfast.lineup_constraints import LineupConstraints -def run(rule_set: RuleSet, - player_pool: list, - constraints: LineupConstraints = LineupConstraints(), - optimizer_settings: OptimizerSettings = OptimizerSettings(), - player_settings: PlayerPoolSettings = PlayerPoolSettings(), - exposure_dict: dict = dict(), - roster_gen: Roster = None, - verbose=False) -> Roster: +def run( + rule_set: RuleSet, + player_pool: list, + constraints: LineupConstraints = LineupConstraints(), + optimizer_settings: OptimizerSettings = OptimizerSettings(), + player_settings: PlayerPoolSettings = PlayerPoolSettings(), + exposure_dict: dict = dict(), + roster_gen: Roster = None, + verbose=False, +) -> Roster: players = player_pool if player_settings.exist() or constraints.exist(): players = pool.filter_pool( @@ -29,11 +35,11 @@ def run(rule_set: RuleSet, if not isinstance(rule_set, RuleSet): raise Exception("RuleSet not defined. Please refer to the docs") - if rule_set.game_type == 'showdown': + if rule_set.game_type == "showdown": if optimizer_settings.no_offense_against_defense: - print('WARNING:') - print('no_offense_against_defense setting ignored for showdown') - print('game types. Use no_defense_against_captain instead.') + print("WARNING:") + print("no_offense_against_defense setting ignored for showdown") + print("game types. Use no_defense_against_captain instead.") print() optimizer = Optimizer( @@ -57,14 +63,14 @@ def run(rule_set: RuleSet, roster.add_player(player) if verbose: - print('Optimal roster for: {}'.format(rule_set.league)) + print("Optimal roster for: {}".format(rule_set.league)) print(roster) return roster if verbose: print( - ''' + """ No solution found. Try adjusting your query by taking away constraints. @@ -81,11 +87,11 @@ def run(rule_set: RuleSet, {} PLAYER COUNT: {} - '''.format( + """.format( optimizer_settings, constraints, player_settings, - len(players or []) + len(players or []), ) ) return None @@ -102,7 +108,6 @@ def run_multi( exposure_bounds: List[dict] = list(), exposure_random_seed=None, ) -> [List[Roster], list]: - if not isinstance(rule_set, RuleSet): raise Exception("RuleSet not defined. Please refer to the docs") @@ -150,9 +155,9 @@ def run_multi( exposure_diffs = check_exposure(rosters, exposure_bounds) for n, d in exposure_diffs.items(): if d < 0: - print('{} is UNDER exposure by {} lineups'.format(n, d)) + print("{} is UNDER exposure by {} lineups".format(n, d)) else: - print('{} is OVER exposure by {} lineups'.format(n, d)) + print("{} is OVER exposure by {} lineups".format(n, d)) return rosters, exposure_diffs diff --git a/draftfast/optimizer.py b/draftfast/optimizer.py index 2d88ff9..b143ab2 100644 --- a/draftfast/optimizer.py +++ b/draftfast/optimizer.py @@ -1,8 +1,10 @@ from typing import List from ortools.linear_solver import pywraplp from draftfast.settings import OptimizerSettings -from draftfast.dke_exceptions import (InvalidBoundsException, - PlayerBanAndLockException) +from draftfast.dke_exceptions import ( + InvalidBoundsException, + PlayerBanAndLockException, +) from draftfast.orm import Player from draftfast.rules import RuleSet from draftfast.lineup_constraints import LineupConstraints @@ -15,11 +17,10 @@ def __init__( rule_set: RuleSet, settings: OptimizerSettings, lineup_constraints: LineupConstraints, - exposure_dict: dict + exposure_dict: dict, ): self.solver = pywraplp.Solver( - 'FD', - pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING + "FD", pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING ) self.players = players self.enumerated_players = list(enumerate(players)) @@ -32,11 +33,11 @@ def __init__( self.defensive_positions = rule_set.defensive_positions self.general_position_limits = rule_set.general_position_limits self.max_players_per_team = rule_set.max_players_per_team - self.showdown = rule_set.game_type == 'showdown' + self.showdown = rule_set.game_type == "showdown" self.settings = settings self.lineup_constraints = lineup_constraints - self.banned_for_exposure = exposure_dict.get('banned', []) - self.locked_for_exposure = exposure_dict.get('locked', []) + self.banned_for_exposure = exposure_dict.get("banned", []) + self.locked_for_exposure = exposure_dict.get("locked", []) self.custom_rules = settings.custom_rules self.min_teams = rule_set.min_teams or settings.min_teams self.position_per_team_rules = rule_set.position_per_team_rules @@ -48,9 +49,7 @@ def __init__( self.player_to_idx_map = dict() for idx, player in self.enumerated_players: - self.variables.append( - self.solver.IntVar(0, 1, player.solver_id) - ) + self.variables.append(self.solver.IntVar(0, 1, player.solver_id)) self._add_player_to_idx_maps(player, idx) @@ -80,14 +79,18 @@ def _add_player_to_idx_maps(self, p: Player, idx: int): self.name_to_idx_map[p.name].update([idx]) def _is_locked(self, p: Player) -> bool: - return self.lineup_constraints.is_locked(p.name) or \ - p.name in self.locked_for_exposure or \ - p.lock + return ( + self.lineup_constraints.is_locked(p.name) + or p.name in self.locked_for_exposure + or p.lock + ) def _is_banned(self, p: Player) -> bool: - return self.lineup_constraints.is_banned(p.name) or \ - p.name in self.banned_for_exposure or \ - p.ban + return ( + self.lineup_constraints.is_banned(p.name) + or p.name in self.banned_for_exposure + or p.ban + ) def _is_position_locked(self, p: Player) -> bool: return self.lineup_constraints.is_position_locked(p.solver_id) @@ -110,9 +113,13 @@ def solve(self) -> bool: self._set_custom_rules() self._set_position_team_constraints() - if self.offensive_positions and self.defensive_positions \ - and self.settings.no_offense_against_defense or \ - self.showdown and self.settings.no_defense_against_captain: + if ( + self.offensive_positions + and self.defensive_positions + and self.settings.no_offense_against_defense + or self.showdown + and self.settings.no_defense_against_captain + ): self._set_no_opp_defense() solution = self.solver.Solve() @@ -128,13 +135,12 @@ def _set_player_constraints(self): if lb > ub: raise InvalidBoundsException( - 'Invalid bounds for {}'.format( - p.name - ) + "Invalid bounds for {}".format(p.name) ) if (p.multi_position or self.showdown) and not ( - p.position_lock or p.position_ban): + p.position_lock or p.position_ban + ): if p.name not in multi_constraints.keys(): multi_constraints[p.name] = self.solver.Constraint(lb, ub) constraint = multi_constraints[p.name] @@ -175,10 +181,7 @@ def _set_salary_range(self): self.salary_max, ) for i, player in self.enumerated_players: - salary_cap.SetCoefficient( - self.variables[i], - player.cost - ) + salary_cap.SetCoefficient(self.variables[i], player.cost) def _set_roster_size(self): size_cap = self.solver.Constraint( @@ -207,16 +210,13 @@ def _set_stack(self): for i, player in self.enumerated_players: if stack_team == player.team: - stack_cap.SetCoefficient( - self.variables[i], - 1 - ) + stack_cap.SetCoefficient(self.variables[i], 1) self._set_stacking_type( stack_lock_pos, stack_lock_eligible_pos, stack_team, - stack.count + stack.count, ) def _set_stacking_type( @@ -231,20 +231,21 @@ def _set_stacking_type( enumerated_players = self.enumerated_players skillplayers_on_team = [ - self.variables[i] for i, p in enumerated_players + self.variables[i] + for i, p in enumerated_players if p.team == team and p.pos in stack_eligible_pos ] locked_on_team = [ - self.variables[i] for i, p in enumerated_players + self.variables[i] + for i, p in enumerated_players if p.team == team and p.pos == stack_lock_pos ] self.solver.Add( - self.solver.Sum(skillplayers_on_team) >= - self.solver.Sum(locked_on_team) + self.solver.Sum(skillplayers_on_team) + >= self.solver.Sum(locked_on_team) ) self.solver.Add( - (self.solver.Sum(skillplayers_on_team)) >= - count - 1 + (self.solver.Sum(skillplayers_on_team)) >= count - 1 ) def _set_combo(self): @@ -252,9 +253,9 @@ def _set_combo(self): combo = self.settings.force_combo combo_allow_te = self.settings.combo_allow_te - combo_skill_type = ['WR'] + combo_skill_type = ["WR"] if combo_allow_te: - combo_skill_type.append('TE') + combo_skill_type.append("TE") if combo: teams = set([p.team for p in self.players]) @@ -262,16 +263,18 @@ def _set_combo(self): for team in teams: skillplayers_on_team = [ - self.variables[i] for i, p in enumerated_players + self.variables[i] + for i, p in enumerated_players if p.team == team and p.pos in combo_skill_type ] qbs_on_team = [ - self.variables[i] for i, p in enumerated_players - if p.team == team and p.pos == 'QB' + self.variables[i] + for i, p in enumerated_players + if p.team == team and p.pos == "QB" ] self.solver.Add( - self.solver.Sum(skillplayers_on_team) >= - self.solver.Sum(qbs_on_team) + self.solver.Sum(skillplayers_on_team) + >= self.solver.Sum(qbs_on_team) ) def _set_no_opp_defense(self): @@ -282,16 +285,20 @@ def _set_no_opp_defense(self): for team in self.teams: offensive_against = [ - self.variables[i] for i, p in enumerated_players - if p.pos in offensive_pos and - p.is_opposing_team_in_match_up(team) + self.variables[i] + for i, p in enumerated_players + if p.pos in offensive_pos + and p.is_opposing_team_in_match_up(team) ] # TODO this is gross for showdown defensive = [ - self.variables[i] for i, p in enumerated_players - if p.team == team and p.pos in defensive_pos or - self.showdown and p.real_pos in defensive_pos + self.variables[i] + for i, p in enumerated_players + if p.team == team + and p.pos in defensive_pos + or self.showdown + and p.real_pos in defensive_pos ] for p in offensive_against: @@ -306,25 +313,26 @@ def _set_position_team_constraints(self): for rule in self.position_per_team_rules: position_group_func, max_pos = rule grouped_position_by_team = [ - self.variables[i] for i, p - in self.enumerated_players if p.team == team - and position_group_func(p.pos) + self.variables[i] + for i, p in self.enumerated_players + if p.team == team and position_group_func(p.pos) ] self.solver.Add( - max_pos >= - self.solver.Sum(grouped_position_by_team) + max_pos >= self.solver.Sum(grouped_position_by_team) ) def _set_custom_rules(self): if self.custom_rules: for rule in self.custom_rules: group_a = [ - self.variables[i] for i, p - in self.enumerated_players if rule.group_a(p) + self.variables[i] + for i, p in self.enumerated_players + if rule.group_a(p) ] group_b = [ - self.variables[i] for i, p - in self.enumerated_players if rule.group_b(p) + self.variables[i] + for i, p in self.enumerated_players + if rule.group_b(p) ] self.solver.Add( rule.comparison(self.solver.Sum, group_a, group_b) @@ -332,44 +340,32 @@ def _set_custom_rules(self): def _set_positions(self): for position, min_limit, max_limit in self.position_limits: - position_cap = self.solver.Constraint( - min_limit, - max_limit - ) + position_cap = self.solver.Constraint(min_limit, max_limit) for i, player in self.enumerated_players: if position == player.pos: position_cap.SetCoefficient(self.variables[i], 1) def _set_general_positions(self): - for general_position, min_limit, max_limit in \ - self.general_position_limits: + for ( + general_position, + min_limit, + max_limit, + ) in self.general_position_limits: position_cap = self.solver.Constraint(min_limit, max_limit) for i, player in self.enumerated_players: if general_position == player.mlb_general_position: - position_cap.SetCoefficient( - self.variables[i], - 1 - ) + position_cap.SetCoefficient(self.variables[i], 1) if general_position == player.nba_general_position: - position_cap.SetCoefficient( - self.variables[i], - 1 - ) + position_cap.SetCoefficient(self.variables[i], 1) def _set_no_duplicate_lineups(self): for roster in self.existing_rosters: max_repeats = self.roster_size - 1 if self.settings.uniques: - max_repeats = max( - self.roster_size - self.settings.uniques, - 1 - ) - repeated_players = self.solver.Constraint( - 0, - max_repeats - ) + max_repeats = max(self.roster_size - self.settings.uniques, 1) + repeated_players = self.solver.Constraint(0, max_repeats) for player in roster.sorted_players(): i = self.player_to_idx_map.get(player.solver_id) if i is not None: @@ -385,19 +381,17 @@ def _set_min_teams(self): team_var = self.solver.IntVar(0, 1, team) teams.append(team_var) players_on_team = [ - self.variables[i] for i, p - in self.enumerated_players if p.team == team + self.variables[i] + for i, p in self.enumerated_players + if p.team == team ] self.solver.Add( - team_var <= - self.solver.Sum(players_on_team) + team_var <= self.solver.Sum(players_on_team) ) self.solver.Add( - self.max_players_per_team >= - self.solver.Sum(players_on_team) + self.max_players_per_team + >= self.solver.Sum(players_on_team) ) if len(teams) > 0: - self.solver.Add( - self.solver.Sum(teams) >= self.settings.min_teams - ) + self.solver.Add(self.solver.Sum(teams) >= self.settings.min_teams) diff --git a/draftfast/orm.py b/draftfast/orm.py index ae98222..b6ce88e 100644 --- a/draftfast/orm.py +++ b/draftfast/orm.py @@ -6,13 +6,13 @@ import re try: - locale.setlocale(locale.LC_ALL, 'en_US') + locale.setlocale(locale.LC_ALL, "en_US") except Exception: pass def cs(n): - return locale._format('%d', n, grouping=True) + return locale._format("%d", n, grouping=True) @total_ordering @@ -55,7 +55,7 @@ def __init__( self.kv_store = kv_store def get_player_id(self, player_map): - return player_map[self.name + ' ' + self.possible_positions] + return player_map[self.name + " " + self.possible_positions] def to_table_row(self): return [ @@ -66,7 +66,7 @@ def to_table_row(self): cs(self.cost), self.proj, self.__format_v_avg(), - 'LOCK' if self.lock else '' + "LOCK" if self.lock else "", ] def to_exposure_table_row(self, n, s_min, s_max): @@ -79,12 +79,13 @@ def to_exposure_table_row(self, n, s_min, s_max): self.proj, n, s_min, - s_max + s_max, ] def is_opposing_team_in_match_up(self, team): - return (team.upper() != self.team.upper()) and \ - (team.upper() in self.matchup.upper()) + return (team.upper() != self.team.upper()) and ( + team.upper() in self.matchup.upper() + ) def __repr__(self): v_avg = self.__format_v_avg() @@ -96,18 +97,21 @@ def __repr__(self): cost=cs(self.cost), proj=self.proj, v_avg=v_avg, - lock='LOCK' if self.lock else '' + lock="LOCK" if self.lock else "", ) - return "[{pos: <2}] {name: <20} {team} {match} " \ - "(${cost}, {proj} ({v_avg})), {lock}".format( - **player_dict) + return ( + "[{pos: <2}] {name: <20} {team} {match} " + "(${cost}, {proj} ({v_avg})), {lock}".format(**player_dict) + ) def __eq__(self, player): - return self.pos == player.pos and \ - self.name == player.name and \ - self.cost == player.cost and \ - self.team == player.team + return ( + self.pos == player.pos + and self.name == player.name + and self.cost == player.cost + and self.team == player.team + ) def __hash__(self): return hash((self.pos, self.name, self.cost, self.team)) @@ -126,7 +130,7 @@ def solver_id(self): """ Used by optimizer to accommodate same player in different positions """ - return f'{self.name} {self.pos} {self.team}' + return f"{self.name} {self.pos} {self.team}" @property def roster_id(self): @@ -135,12 +139,12 @@ def roster_id(self): entering lineups,a lineup with the same players scores the same points irrespective of positions """ - return f'{self.name} {self.team}' + return f"{self.name} {self.team}" @property def formatted_position(self): if self.multi_position: - return f'{self.possible_positions} ({self.pos})' + return f"{self.possible_positions} ({self.pos})" return self.pos @property @@ -149,21 +153,21 @@ def v_avg(self): @property def is_home(self): - match_up_teams = self.matchup.split(' ')[0] - return self.team == match_up_teams.split('@')[-1] + match_up_teams = self.matchup.split(" ")[0] + return self.team == match_up_teams.split("@")[-1] @property def nba_general_position(self): - if self.pos == 'SG' or self.pos == 'PG' or self.pos == 'G': - return 'G' - elif self.pos == 'SF' or self.pos == 'PF' or self.pos == 'F': - return 'F' - return 'C' + if self.pos == "SG" or self.pos == "PG" or self.pos == "G": + return "G" + elif self.pos == "SF" or self.pos == "PF" or self.pos == "F": + return "F" + return "C" @property def mlb_general_position(self): - if self.pos in {'SP', 'RP'}: - return 'P' + if self.pos in {"SP", "RP"}: + return "P" return self.pos @property @@ -175,10 +179,10 @@ def short_name(self): return self.name # like "AJ McCarron" - if re.match(r'^[A-Z]{2}$', s[0]): + if re.match(r"^[A-Z]{2}$", s[0]): return s - return f'{s[0][0]}. {s[1]}' + return f"{s[0][0]}. {s[1]}" def __set_from_data_cache(self, player_data): if player_data is None: @@ -188,8 +192,8 @@ def __set_from_data_cache(self, player_data): def __format_v_avg(self): if self.v_avg > 0: - return '\x1b[0;32;40m{:0.2f}\x1b[0m'.format(self.v_avg) - return '\x1b[0;31;40m{:0.2f}\x1b[0m'.format(self.v_avg) + return "\x1b[0;32;40m{:0.2f}\x1b[0m".format(self.v_avg) + return "\x1b[0;31;40m{:0.2f}\x1b[0m".format(self.v_avg) class Roster: @@ -200,27 +204,27 @@ def __init__(self): def __repr__(self): table_data = [] headers = [ - 'Position', - 'Player', - 'Team', - 'Matchup', - 'Salary', - 'Projection', - 'vs. Avg.', - 'Locked' + "Position", + "Player", + "Team", + "Matchup", + "Salary", + "Projection", + "vs. Avg.", + "Locked", ] table_data.append(headers) for p in self.sorted_players(): table_data.append(p.to_table_row()) table = AsciiTable(table_data) - table.justify_columns[4] = 'right' - table.justify_columns[5] = 'right' - table.justify_columns[6] = 'right' + table.justify_columns[4] = "right" + table.justify_columns[5] = "right" + table.justify_columns[6] = "right" - aggregate_info = '\n\nProjected Score: {:0.2f} \t Cost: ${}'.format( - self.projected(), - cs(self.spent())) + aggregate_info = "\n\nProjected Score: {:0.2f} \t Cost: ${}".format( + self.projected(), cs(self.spent()) + ) return table.table + aggregate_info @@ -228,9 +232,9 @@ def __repr__(self): def identifier(self): if self.cached_id: return self.cached_id - self.cached_id = ' '.join(sorted([ - x.roster_id for x in self.sorted_players() - ])) + self.cached_id = " ".join( + sorted([x.roster_id for x in self.sorted_players()]) + ) return self.cached_id @@ -266,16 +270,13 @@ def projected(self): def position_order(self, player): # raises exception in case someone tries to instantiate base class - position_order = getattr(self, 'POSITION_ORDER') + position_order = getattr(self, "POSITION_ORDER") # default sort order is low->high, so use the negative of cost return position_order[player.pos], -player.cost def sorted_players(self): - return sorted( - self.players, - key=lambda p: self.position_order(p) - ) + return sorted(self.players, key=lambda p: self.position_order(p)) def different_player_count(self, other_roster): dpc = 0 @@ -323,10 +324,7 @@ def get_salary_frequency(self) -> List[Dict[int, int]]: salaries.append(r.spent()) counter = Counter(salaries) - return sorted( - counter.items(), - key=lambda items: items[0] - ) + return sorted(counter.items(), key=lambda items: items[0]) def get_similarity_score(self): """ @@ -344,12 +342,7 @@ def get_similarity_score(self): if r == r_comp: scores.append(1) else: - scores.append( - self.__get_roster_similarity( - r, - r_comp - ) - ) + scores.append(self.__get_roster_similarity(r, r_comp)) pairs.append(sorted([idx_comp, idx])) return sum(scores) / len(scores) @@ -358,16 +351,16 @@ def __get_roster_similarity(self, roster_a, roster_b): return roster_a.shared_player_count(roster_b) / len(roster_a.players) -''' +""" POSITION_ORDER is based on the order required by DraftKings' CSV download -''' +""" class ShowdownRoster(Roster): POSITION_ORDER = { - 'CPT': 0, - 'FLEX': 1, + "CPT": 0, + "FLEX": 1, } @property @@ -379,9 +372,9 @@ def identifier(self): """ if self.cached_id: return self.cached_id - self.cached_id = ' '.join(sorted([ - x.solver_id for x in self.sorted_players() - ])) + self.cached_id = " ".join( + sorted([x.solver_id for x in self.sorted_players()]) + ) return self.cached_id @@ -390,115 +383,109 @@ class MVPRoster(ShowdownRoster): POSITION_ORDER = { # TODO - adjust NFL FD to MVP format # and remove CPT, FLEX - 'CPT': 0, - 'MVP': 0, - 'FLEX': 1, - 'STAR': 1, - 'PRO': 2, - 'UTIL': 3, + "CPT": 0, + "MVP": 0, + "FLEX": 1, + "STAR": 1, + "PRO": 2, + "UTIL": 3, } class NFLRoster(Roster): POSITION_ORDER = { - 'QB': 0, - 'RB': 1, - 'WR': 2, - 'TE': 3, - 'DST': 4, - 'D': 5, + "QB": 0, + "RB": 1, + "WR": 2, + "TE": 3, + "DST": 4, + "D": 5, } class TenRoster(Roster): POSITION_ORDER = { - 'P': 1, + "P": 1, } class MLBRoster(Roster): POSITION_ORDER = { - 'P': 0, - 'RP': 0, - 'SP': 0, - 'C': 1, - '1B': 2, - '2B': 3, - '3B': 4, - 'SS': 5, - 'OF': 6, + "P": 0, + "RP": 0, + "SP": 0, + "C": 1, + "1B": 2, + "2B": 3, + "3B": 4, + "SS": 5, + "OF": 6, } class NBARoster(Roster): - POSITION_ORDER = { - 'PG': 0, - 'SG': 1, - 'SF': 2, - 'PF': 3, - 'C': 4 - } + POSITION_ORDER = {"PG": 0, "SG": 1, "SF": 2, "PF": 3, "C": 4} class WNBARoster(Roster): POSITION_ORDER = { - 'G': 0, - 'F': 1, - 'SG': 2, - 'SF': 3, - 'PF': 4, + "G": 0, + "F": 1, + "SG": 2, + "SF": 3, + "PF": 4, } class NASCARRoster(Roster): POSITION_ORDER = { - 'D': 0, + "D": 0, } class PGARoster(Roster): POSITION_ORDER = { - 'G': 0, + "G": 0, } class PGACaptainRoster(Roster): POSITION_ORDER = { - 'CPT': 0, - 'G': 1, + "CPT": 0, + "G": 1, } class SoccerRoster(Roster): POSITION_ORDER = { - 'F': 0, - 'M': 1, - 'D': 2, - 'GK': 3, + "F": 0, + "M": 1, + "D": 2, + "GK": 3, } class ELRoster(Roster): POSITION_ORDER = { - 'G': 0, - 'F': 1, + "G": 0, + "F": 1, } class NHLRoster(Roster): POSITION_ORDER = { - 'C': 0, - 'W': 1, - 'D': 2, - 'G': 3, + "C": 0, + "W": 1, + "D": 2, + "G": 3, } class F1ShowdownRoster(Roster): POSITION_ORDER = { - 'CPT': 0, - 'D': 1, - 'CNSTR': 2, + "CPT": 0, + "D": 1, + "CNSTR": 2, } @@ -506,28 +493,28 @@ class RosterSelect: @staticmethod def roster_gen(league): roster_dict = { - 'NBA': NBARoster(), - 'NBA_SHOWDOWN': ShowdownRoster(), - 'WNBA': WNBARoster(), - 'NFL': NFLRoster(), - 'NFL_SHOWDOWN': ShowdownRoster(), - 'MLB_MVP': MVPRoster(), - 'NBA_MVP': MVPRoster(), - 'NFL_MVP': MVPRoster(), - 'MLB': MLBRoster(), - 'PGA': PGARoster(), - 'PGA_CAPTAIN': PGACaptainRoster(), - 'NASCAR': NASCARRoster(), - 'SOCCER': SoccerRoster(), - 'EL': ELRoster(), - 'NHL': NHLRoster(), - 'NHL_SHOWDOWN': ShowdownRoster(), - 'MLB_SHOWDOWN': ShowdownRoster(), + "NBA": NBARoster(), + "NBA_SHOWDOWN": ShowdownRoster(), + "WNBA": WNBARoster(), + "NFL": NFLRoster(), + "NFL_SHOWDOWN": ShowdownRoster(), + "MLB_MVP": MVPRoster(), + "NBA_MVP": MVPRoster(), + "NFL_MVP": MVPRoster(), + "MLB": MLBRoster(), + "PGA": PGARoster(), + "PGA_CAPTAIN": PGACaptainRoster(), + "NASCAR": NASCARRoster(), + "SOCCER": SoccerRoster(), + "EL": ELRoster(), + "NHL": NHLRoster(), + "NHL_SHOWDOWN": ShowdownRoster(), + "MLB_SHOWDOWN": ShowdownRoster(), # XFL uses the same positions as NFL - 'XFL': NFLRoster(), - 'TEN': TenRoster(), - 'CSGO_SHOWDOWN': ShowdownRoster(), - 'F1_SHOWDOWN': F1ShowdownRoster(), + "XFL": NFLRoster(), + "TEN": TenRoster(), + "CSGO_SHOWDOWN": ShowdownRoster(), + "F1_SHOWDOWN": F1ShowdownRoster(), } return roster_dict[league] @@ -538,7 +525,7 @@ def __init__(self, team, opp): self.opponent = opp def __repr__(self): - return f'{self.team} @ {self.opponent}' + return f"{self.team} @ {self.opponent}" def team_in_game(self, team): return team == self.team or team == self.opponent diff --git a/draftfast/pickem/pickem_command_line.py b/draftfast/pickem/pickem_command_line.py index c448ad0..00d3cec 100644 --- a/draftfast/pickem/pickem_command_line.py +++ b/draftfast/pickem/pickem_command_line.py @@ -2,26 +2,32 @@ import os OPTIMIZE_COMMAND_LINE = [ - ['-use_averages', 'use averages as projections', False], - ['-v_avg', 'projections must be within points v avg', 100000], - ['-min_avg', 'player must exceed average points', 0], - ['-lp', 'lowest acceptable projection', 0], - ['-home', 'only select players playing at home', None], - ['-locked_teams', 'player must be on specified teams', None], - ['-banned_teams', 'player must not be on specified teams', None], - ['-source', 'data source to use', 'nfl_rotogrinders'], - ['-pids', 'player id file (create upload file)', None], - ['-keep_pids', 'Keep current upload file', None], - ['-salary_file', 'file location for salaries', - os.getcwd() + '/data/current-salaries.csv'], - ['-projection_file', 'file location for projections', - os.getcwd() + '/data/current-projections.csv'], - ['-randomize_projections', 'use random projection factor', None], + ["-use_averages", "use averages as projections", False], + ["-v_avg", "projections must be within points v avg", 100000], + ["-min_avg", "player must exceed average points", 0], + ["-lp", "lowest acceptable projection", 0], + ["-home", "only select players playing at home", None], + ["-locked_teams", "player must be on specified teams", None], + ["-banned_teams", "player must not be on specified teams", None], + ["-source", "data source to use", "nfl_rotogrinders"], + ["-pids", "player id file (create upload file)", None], + ["-keep_pids", "Keep current upload file", None], + [ + "-salary_file", + "file location for salaries", + os.getcwd() + "/data/current-salaries.csv", + ], + [ + "-projection_file", + "file location for projections", + os.getcwd() + "/data/current-projections.csv", + ], + ["-randomize_projections", "use random projection factor", None], ] MULTIPLE_ARGS_COMMAND = [ - '-teams', + "-teams", ] PARSER = argparse.ArgumentParser() @@ -29,13 +35,8 @@ def get_args(): for opt in OPTIMIZE_COMMAND_LINE: - nargs = '?' + nargs = "?" if opt[0] in MULTIPLE_ARGS_COMMAND: - nargs = '+' - PARSER.add_argument( - opt[0], - nargs=nargs, - help=opt[1], - default=opt[2] - ) + nargs = "+" + PARSER.add_argument(opt[0], nargs=nargs, help=opt[1], default=opt[2]) return PARSER.parse_args() diff --git a/draftfast/pickem/pickem_optimize.py b/draftfast/pickem/pickem_optimize.py index 8f303a0..c8feadb 100644 --- a/draftfast/pickem/pickem_optimize.py +++ b/draftfast/pickem/pickem_optimize.py @@ -8,16 +8,15 @@ def optimize( all_players: list, player_settings: PlayerPoolSettings = PlayerPoolSettings(), - constraints: LineupConstraints = LineupConstraints() + constraints: LineupConstraints = LineupConstraints(), ): lineup_players = [] - all_players = list(filter( - add_pickem_contraints(player_settings), - all_players - )) + all_players = list( + filter(add_pickem_contraints(player_settings), all_players) + ) if constraints.has_group_constraints(): - raise NotImplementedError('Groups are not supported for pickem') + raise NotImplementedError("Groups are not supported for pickem") for p in all_players: if constraints.is_banned(p.name): @@ -43,6 +42,4 @@ def optimize( def _get_player(name, all_players) -> TieredPlayer: - return next( - p for p in all_players if p.name == name - ) + return next(p for p in all_players if p.name == name) diff --git a/draftfast/pickem/pickem_orm.py b/draftfast/pickem/pickem_orm.py index 2c3ebaf..a45537a 100644 --- a/draftfast/pickem/pickem_orm.py +++ b/draftfast/pickem/pickem_orm.py @@ -1,12 +1,12 @@ from draftfast.orm import Player from terminaltables import AsciiTable -T1 = 'T1' -T2 = 'T2' -T3 = 'T3' -T4 = 'T4' -T5 = 'T5' -T6 = 'T6' +T1 = "T1" +T2 = "T2" +T3 = "T3" +T4 = "T4" +T5 = "T5" +T6 = "T6" TIERS = [ T1, @@ -19,13 +19,12 @@ class TieredLineup(object): - def __init__(self, players): - assert len(players) == 6, 'Must have six players' + assert len(players) == 6, "Must have six players" for idx, p in enumerate(players): if p.tier != TIERS[idx]: raise Exception( - 'Player {} is not in tier {} but in tier {}'.format( + "Player {} is not in tier {} but in tier {}".format( p.name, TIERS[idx], p.tier ) ) @@ -40,20 +39,22 @@ def __init__(self, players): ] = players def __repr__(self): - table_data = [[ - 'Name', - 'Tier', - 'Matchup', - 'Projected', - 'vs Avg', - 'Locked', - ]] + table_data = [ + [ + "Name", + "Tier", + "Matchup", + "Projected", + "vs Avg", + "Locked", + ] + ] for p in self.players: table_data.append(p.to_table_row()) return ( - AsciiTable(table_data).table + - '\n' + - 'Total: {}'.format(self.total) + AsciiTable(table_data).table + + "\n" + + "Total: {}".format(self.total) ) @property @@ -73,12 +74,9 @@ def total(self): class TieredPlayer(Player): - def __init__(self, tier, **kwargs): self.tier = tier - super(TieredPlayer, self).__init__( - **kwargs - ) + super(TieredPlayer, self).__init__(**kwargs) def to_table_row(self): return [ @@ -87,5 +85,5 @@ def to_table_row(self): self.matchup, self.proj, self.v_avg, - 'LOCK' if self.lock else '', + "LOCK" if self.lock else "", ] diff --git a/draftfast/pickem/pickem_upload.py b/draftfast/pickem/pickem_upload.py index 35cbcba..25c7194 100644 --- a/draftfast/pickem/pickem_upload.py +++ b/draftfast/pickem/pickem_upload.py @@ -5,20 +5,20 @@ def map_pids(pid_file): player_map = {} - with open(pid_file, 'r') as f: + with open(pid_file, "r") as f: n = 0 fields = None for line in f.readlines(): n += 1 - if 'TeamAbbrev' in line: # line with field names was found - fields = line.split(',') + if "TeamAbbrev" in line: # line with field names was found + fields = line.split(",") break f.close() - f = islice(open(pid_file, 'r'), n, None) + f = islice(open(pid_file, "r"), n, None) reader = csv.DictReader(f, fieldnames=fields) for line in reader: - player_map[line['Name']] = line['ID'] + player_map[line["Name"]] = line["ID"] return player_map diff --git a/draftfast/player_pool.py b/draftfast/player_pool.py index 16f30e4..0e8da44 100644 --- a/draftfast/player_pool.py +++ b/draftfast/player_pool.py @@ -4,31 +4,35 @@ from draftfast.settings import PlayerPoolSettings -def filter_pool(pool: list, - player_settings: PlayerPoolSettings) -> List[Player]: +def filter_pool( + pool: list, player_settings: PlayerPoolSettings +) -> List[Player]: if player_settings.randomize: for player in pool: factor = 1 + runiform( - -player_settings.randomize, - player_settings.randomize + -player_settings.randomize, player_settings.randomize ) player.proj = player.proj * factor - return list(filter( - add_filters(player_settings), - pool, - )) + return list( + filter( + add_filters(player_settings), + pool, + ) + ) def add_filters(settings: PlayerPoolSettings): def filter_fn(player: Player): - kwargs = {'player': player, 'settings': settings} - return _is_above_min_cost(**kwargs) and \ - _is_below_max_cost(**kwargs) and \ - _is_above_min_proj(**kwargs) and \ - _is_below_max_proj(**kwargs) and \ - _is_above_min_avg(**kwargs) and \ - _is_below_max_avg(**kwargs) + kwargs = {"player": player, "settings": settings} + return ( + _is_above_min_cost(**kwargs) + and _is_below_max_cost(**kwargs) + and _is_above_min_proj(**kwargs) + and _is_below_max_proj(**kwargs) + and _is_above_min_avg(**kwargs) + and _is_below_max_avg(**kwargs) + ) return filter_fn @@ -36,9 +40,10 @@ def filter_fn(player: Player): def add_pickem_contraints(settings: PlayerPoolSettings): def filter_fn(player: Player): # TODO - add team banning - kwargs = {'player': player, 'settings': settings} + kwargs = {"player": player, "settings": settings} return ( - _is_above_min_proj(**kwargs) and + _is_above_min_proj(**kwargs) + and # (not _is_banned_team(**kwargs)) and # _is_locked_team(**kwargs) and # _is_within_avg(**kwargs) and @@ -50,7 +55,7 @@ def filter_fn(player: Player): def lock_override(fn): def override_fn(**kwargs): - if kwargs['player'].lock: + if kwargs["player"].lock: return True return fn(**kwargs) diff --git a/draftfast/rules.py b/draftfast/rules.py index 4f337ed..027bacd 100644 --- a/draftfast/rules.py +++ b/draftfast/rules.py @@ -1,24 +1,33 @@ -from draftfast.constants.positions import (MLB_GENERAL_POSITIONS, - NBA_GENERAL_POSITIONS, - POSITIONS_BY_SITE_BY_LEAGUE) +from draftfast.constants.positions import ( + MLB_GENERAL_POSITIONS, + NBA_GENERAL_POSITIONS, + POSITIONS_BY_SITE_BY_LEAGUE, +) from draftfast.constants.roster_size import ROSTER_SIZE_BY_SITE_BY_SPORT from draftfast.constants.salary_cap import SALARY_CAP_BY_SITE_BY_LEAGUE -DRAFT_KINGS = 'DRAFT_KINGS' -FAN_DUEL = 'FAN_DUEL' +DRAFT_KINGS = "DRAFT_KINGS" +FAN_DUEL = "FAN_DUEL" class RuleSet(object): - def __init__(self, site, league, - roster_size, position_limits, - salary_max, salary_min=0, - general_position_limits=None, - offensive_positions=None, defensive_positions=None, - max_players_per_team=None, - min_teams=None, - position_per_team_rules=None, - game_type='classic'): + def __init__( + self, + site, + league, + roster_size, + position_limits, + salary_max, + salary_min=0, + general_position_limits=None, + offensive_positions=None, + defensive_positions=None, + max_players_per_team=None, + min_teams=None, + position_per_team_rules=None, + game_type="classic", + ): self.site = site self.league = league self.roster_size = roster_size @@ -36,286 +45,286 @@ def __init__(self, site, league, DK_NBA_RULE_SET = RuleSet( site=DRAFT_KINGS, - league='NBA', - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]['NBA'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['NBA'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['NBA'], + league="NBA", + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]["NBA"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["NBA"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["NBA"], general_position_limits=NBA_GENERAL_POSITIONS, ) DK_NBA_SHOWDOWN_RULE_SET = RuleSet( site=DRAFT_KINGS, - league='NBA_SHOWDOWN', - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]['NBA_SHOWDOWN'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['NBA_SHOWDOWN'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['NBA_SHOWDOWN'], - game_type='showdown', + league="NBA_SHOWDOWN", + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]["NBA_SHOWDOWN"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["NBA_SHOWDOWN"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["NBA_SHOWDOWN"], + game_type="showdown", general_position_limits=[], ) FD_NBA_RULE_SET = RuleSet( site=FAN_DUEL, - league='NBA', - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[FAN_DUEL]['NBA'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[FAN_DUEL]['NBA'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[FAN_DUEL]['NBA'], + league="NBA", + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[FAN_DUEL]["NBA"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[FAN_DUEL]["NBA"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[FAN_DUEL]["NBA"], general_position_limits=NBA_GENERAL_POSITIONS, ) DK_WNBA_RULE_SET = RuleSet( site=DRAFT_KINGS, - league='WNBA', - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]['WNBA'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['WNBA'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['WNBA'], + league="WNBA", + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]["WNBA"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["WNBA"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["WNBA"], general_position_limits=NBA_GENERAL_POSITIONS, ) FD_WNBA_RULE_SET = RuleSet( site=FAN_DUEL, - league='WNBA', - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[FAN_DUEL]['WNBA'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[FAN_DUEL]['WNBA'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[FAN_DUEL]['WNBA'], + league="WNBA", + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[FAN_DUEL]["WNBA"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[FAN_DUEL]["WNBA"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[FAN_DUEL]["WNBA"], general_position_limits=NBA_GENERAL_POSITIONS, ) DK_NFL_RULE_SET = RuleSet( site=DRAFT_KINGS, - league='NFL', - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]['NFL'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['NFL'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['NFL'], - offensive_positions=['QB', 'RB', 'WR', 'TE'], - defensive_positions=['DST'], + league="NFL", + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]["NFL"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["NFL"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["NFL"], + offensive_positions=["QB", "RB", "WR", "TE"], + defensive_positions=["DST"], general_position_limits=[], ) FD_NFL_RULE_SET = RuleSet( site=FAN_DUEL, - league='NFL', - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[FAN_DUEL]['NFL'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[FAN_DUEL]['NFL'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[FAN_DUEL]['NFL'], - offensive_positions=['QB', 'RB', 'WR', 'TE'], - defensive_positions=['D'], + league="NFL", + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[FAN_DUEL]["NFL"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[FAN_DUEL]["NFL"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[FAN_DUEL]["NFL"], + offensive_positions=["QB", "RB", "WR", "TE"], + defensive_positions=["D"], general_position_limits=[], ) DK_NFL_SHOWDOWN_RULE_SET = RuleSet( site=DRAFT_KINGS, - league='NFL_SHOWDOWN', - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]['NFL_SHOWDOWN'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['NFL_SHOWDOWN'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['NFL_SHOWDOWN'], - offensive_positions=['CPT'], - defensive_positions=['DST'], + league="NFL_SHOWDOWN", + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]["NFL_SHOWDOWN"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["NFL_SHOWDOWN"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["NFL_SHOWDOWN"], + offensive_positions=["CPT"], + defensive_positions=["DST"], general_position_limits=[], - game_type='showdown', + game_type="showdown", ) FD_NFL_MVP_RULE_SET = RuleSet( site=FAN_DUEL, - league='NFL_MVP', - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[FAN_DUEL]['NFL_MVP'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[FAN_DUEL]['NFL_MVP'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[FAN_DUEL]['NFL_MVP'], - offensive_positions=['CPT'], - defensive_positions=['D'], + league="NFL_MVP", + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[FAN_DUEL]["NFL_MVP"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[FAN_DUEL]["NFL_MVP"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[FAN_DUEL]["NFL_MVP"], + offensive_positions=["CPT"], + defensive_positions=["D"], general_position_limits=[], - game_type='showdown', + game_type="showdown", ) FD_MLB_MVP_RULE_SET = RuleSet( site=FAN_DUEL, - league='MLB_MVP', - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[FAN_DUEL]['MLB_MVP'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[FAN_DUEL]['MLB_MVP'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[FAN_DUEL]['MLB_MVP'], + league="MLB_MVP", + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[FAN_DUEL]["MLB_MVP"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[FAN_DUEL]["MLB_MVP"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[FAN_DUEL]["MLB_MVP"], general_position_limits=[], - game_type='showdown', + game_type="showdown", ) FD_NBA_MVP_RULE_SET = RuleSet( site=FAN_DUEL, - league='NBA_MVP', - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[FAN_DUEL]['NBA_MVP'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[FAN_DUEL]['NBA_MVP'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[FAN_DUEL]['NBA_MVP'], + league="NBA_MVP", + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[FAN_DUEL]["NBA_MVP"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[FAN_DUEL]["NBA_MVP"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[FAN_DUEL]["NBA_MVP"], general_position_limits=[], - game_type='showdown', + game_type="showdown", ) FD_PGA_RULE_SET = RuleSet( site=FAN_DUEL, - league='PGA', - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[FAN_DUEL]['PGA'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[FAN_DUEL]['PGA'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[FAN_DUEL]['PGA'], + league="PGA", + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[FAN_DUEL]["PGA"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[FAN_DUEL]["PGA"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[FAN_DUEL]["PGA"], general_position_limits=[], ) DK_PGA_RULE_SET = RuleSet( site=DRAFT_KINGS, - league='PGA', - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]['PGA'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['PGA'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['PGA'], + league="PGA", + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]["PGA"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["PGA"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["PGA"], general_position_limits=[], ) DK_PGA_SHOWDOWN_CAPTAIN_RULE_SET = RuleSet( site=DRAFT_KINGS, - league='PGA_CAPTAIN', - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]['PGA_CAPTAIN'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['PGA_CAPTAIN'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['PGA_CAPTAIN'], + league="PGA_CAPTAIN", + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]["PGA_CAPTAIN"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["PGA_CAPTAIN"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["PGA_CAPTAIN"], general_position_limits=[], - game_type='showdown', + game_type="showdown", ) FD_NASCAR_RULE_SET = RuleSet( site=FAN_DUEL, min_teams=1, - league='NASCAR', - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[FAN_DUEL]['NASCAR'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[FAN_DUEL]['NASCAR'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[FAN_DUEL]['NASCAR'], + league="NASCAR", + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[FAN_DUEL]["NASCAR"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[FAN_DUEL]["NASCAR"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[FAN_DUEL]["NASCAR"], general_position_limits=[], ) DK_NASCAR_RULE_SET = RuleSet( site=DRAFT_KINGS, min_teams=1, - league='NASCAR', - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]['NASCAR'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['NASCAR'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['NASCAR'], + league="NASCAR", + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]["NASCAR"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["NASCAR"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["NASCAR"], general_position_limits=[], ) DK_MLB_RULE_SET = RuleSet( site=DRAFT_KINGS, - league='MLB', + league="MLB", # Can start two pitchers and 5 hitters max_players_per_team=7, - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]['MLB'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['MLB'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['MLB'], + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]["MLB"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["MLB"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["MLB"], general_position_limits=MLB_GENERAL_POSITIONS, min_teams=3, - position_per_team_rules=[[lambda pos: 'P' not in pos, 5]], + position_per_team_rules=[[lambda pos: "P" not in pos, 5]], ) FD_MLB_RULE_SET = RuleSet( site=FAN_DUEL, - league='MLB', - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[FAN_DUEL]['MLB'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[FAN_DUEL]['MLB'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[FAN_DUEL]['MLB'], + league="MLB", + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[FAN_DUEL]["MLB"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[FAN_DUEL]["MLB"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[FAN_DUEL]["MLB"], general_position_limits=[], ) DK_SOCCER_RULE_SET = RuleSet( site=DRAFT_KINGS, - league='SOCCER', - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]['SOCCER'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['SOCCER'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['SOCCER'], - offensive_positions=['M', 'F'], - defensive_positions=['GK', 'D'], + league="SOCCER", + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]["SOCCER"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["SOCCER"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["SOCCER"], + offensive_positions=["M", "F"], + defensive_positions=["GK", "D"], general_position_limits=[], ) DK_EURO_LEAGUE_RULE_SET = RuleSet( site=DRAFT_KINGS, - league='EL', - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]['EL'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['EL'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['EL'], + league="EL", + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]["EL"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["EL"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["EL"], general_position_limits=[], ) DK_NHL_RULE_SET = RuleSet( site=DRAFT_KINGS, - league='NHL', - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]['NHL'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['NHL'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['NHL'], - offensive_positions=['C', 'W'], - defensive_positions=['G', 'D'], + league="NHL", + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]["NHL"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["NHL"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["NHL"], + offensive_positions=["C", "W"], + defensive_positions=["G", "D"], general_position_limits=[], ) DK_NHL_SHOWDOWN_RULE_SET = RuleSet( site=DRAFT_KINGS, - league='NHL_SHOWDOWN', - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]['NHL_SHOWDOWN'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['NHL_SHOWDOWN'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['NHL_SHOWDOWN'], - offensive_positions=['C', 'W'], - defensive_positions=['G', 'D'], + league="NHL_SHOWDOWN", + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]["NHL_SHOWDOWN"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["NHL_SHOWDOWN"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["NHL_SHOWDOWN"], + offensive_positions=["C", "W"], + defensive_positions=["G", "D"], general_position_limits=[], - game_type='showdown', + game_type="showdown", ) DK_NBA_PICKEM_RULE_SET = RuleSet( site=DRAFT_KINGS, - league='NBA', + league="NBA", roster_size=6, salary_max=None, position_limits=None, - game_type='pickem', + game_type="pickem", ) DK_MLB_SHOWDOWN_RULE_SET = RuleSet( site=DRAFT_KINGS, - league='MLB_SHOWDOWN', - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]['MLB_SHOWDOWN'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['MLB_SHOWDOWN'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['MLB_SHOWDOWN'], + league="MLB_SHOWDOWN", + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]["MLB_SHOWDOWN"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["MLB_SHOWDOWN"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["MLB_SHOWDOWN"], general_position_limits=[], - game_type='showdown' + game_type="showdown", ) DK_XFL_CLASSIC_RULE_SET = RuleSet( site=DRAFT_KINGS, - league='XFL', - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]['XFL'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['XFL'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['XFL'], + league="XFL", + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]["XFL"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["XFL"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["XFL"], general_position_limits=[], ) DK_TEN_CLASSIC_RULE_SET = RuleSet( site=DRAFT_KINGS, - league='TEN', - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]['TEN'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['TEN'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['TEN'], + league="TEN", + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]["TEN"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["TEN"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["TEN"], general_position_limits=[], ) DK_CSGO_SHOWDOWN = RuleSet( site=DRAFT_KINGS, - league='CSGO_SHOWDOWN', - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]['CSGO_SHOWDOWN'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['CSGO_SHOWDOWN'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['CSGO_SHOWDOWN'], - game_type='showdown', + league="CSGO_SHOWDOWN", + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]["CSGO_SHOWDOWN"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["CSGO_SHOWDOWN"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["CSGO_SHOWDOWN"], + game_type="showdown", general_position_limits=[], max_players_per_team=3, ) DK_F1_SHOWDOWN = RuleSet( site=DRAFT_KINGS, - league='F1_SHOWDOWN', - roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]['F1_SHOWDOWN'], - salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['F1_SHOWDOWN'], - position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]['F1_SHOWDOWN'], - game_type='showdown', + league="F1_SHOWDOWN", + roster_size=ROSTER_SIZE_BY_SITE_BY_SPORT[DRAFT_KINGS]["F1_SHOWDOWN"], + salary_max=SALARY_CAP_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["F1_SHOWDOWN"], + position_limits=POSITIONS_BY_SITE_BY_LEAGUE[DRAFT_KINGS]["F1_SHOWDOWN"], + game_type="showdown", general_position_limits=[], max_players_per_team=2, ) diff --git a/draftfast/rules_utils.py b/draftfast/rules_utils.py index 4a5008f..1e9c58b 100644 --- a/draftfast/rules_utils.py +++ b/draftfast/rules_utils.py @@ -3,14 +3,14 @@ def get_nfl_positions( wr_min=3, te_min=1, te_upper=2, - d_abbrev='DST', + d_abbrev="DST", ): return [ - ['QB', 1, 1], - ['RB', rb_min, 3], - ['WR', wr_min, 4], - ['TE', te_min, te_upper], - [d_abbrev, 1, 1] + ["QB", 1, 1], + ["RB", rb_min, 3], + ["WR", wr_min, 4], + ["TE", te_min, te_upper], + [d_abbrev, 1, 1], ] @@ -22,7 +22,4 @@ def get_nfl_showdown_positions(dk: bool = False, fd: bool = False) -> list: else: raise NotImplementedError - return [ - ['CPT', 1, 1], - ['FLEX', ub, ub] - ] + return [["CPT", 1, 1], ["FLEX", ub, ub]] diff --git a/draftfast/settings.py b/draftfast/settings.py index a670196..bb51588 100644 --- a/draftfast/settings.py +++ b/draftfast/settings.py @@ -3,10 +3,16 @@ class PlayerPoolSettings(object): - - def __init__(self, min_proj=None, max_proj=None, - min_avg=None, max_avg=None, min_salary=None, - max_salary=None, randomize=None): + def __init__( + self, + min_proj=None, + max_proj=None, + min_avg=None, + max_avg=None, + min_salary=None, + max_salary=None, + randomize=None, + ): self.min_proj = min_proj self.max_proj = max_proj self.min_avg = min_avg @@ -16,36 +22,36 @@ def __init__(self, min_proj=None, max_proj=None, self.randomize = randomize def exist(self): - return str(self) != 'None' + return str(self) != "None" # TODO: format this like a proper repr(), i.e. def __repr__(self): if not str(self): - return '' + return "" else: return str(self) def __str__(self): lines = [] if self.min_proj: - lines.append('Min projection: {}'.format(self.min_proj)) + lines.append("Min projection: {}".format(self.min_proj)) if self.max_proj: - lines.append('Max projection: {}'.format(self.min_proj)) + lines.append("Max projection: {}".format(self.min_proj)) if self.min_avg: - lines.append('Min average: {}'.format(self.min_proj)) + lines.append("Min average: {}".format(self.min_proj)) if self.max_avg: - lines.append('Max average: {}'.format(self.min_proj)) + lines.append("Max average: {}".format(self.min_proj)) if self.min_salary: - lines.append('Min salary: {}'.format(self.min_proj)) + lines.append("Min salary: {}".format(self.min_proj)) if self.max_salary: - lines.append('Max salary: {}'.format(self.min_proj)) + lines.append("Max salary: {}".format(self.min_proj)) if self.randomize: - lines.append('Randomization factor: {}'.format(self.min_proj)) + lines.append("Randomization factor: {}".format(self.min_proj)) if len(lines): - return '\n'.join(lines) + return "\n".join(lines) else: - return 'None' + return "None" def default_comparison( @@ -81,13 +87,15 @@ def __init__(self, group_a, group_b, comparison=None): def __repr__(self): import inspect as i - return f"{i.getsource(self.group_a)}" \ - f"{i.getsource(self.group_b)}" \ - f"{i.getsource(self.comparison)}" + return ( + f"{i.getsource(self.group_a)}" + f"{i.getsource(self.group_b)}" + f"{i.getsource(self.comparison)}" + ) -class OptimizerSettings(object): +class OptimizerSettings(object): def __init__( self, stacks=None, @@ -115,39 +123,35 @@ def __init__( # TODO: format this like a proper repr(), i.e. def __repr__(self): if not str(self): - return '' + return "" else: return str(self) def __str__(self): lines = [] if self.stacks and len(self.stacks): - lines.append('Stacks: {}'.format( - [(x.team, x.count) for x in self.stacks] - ) - ) + lines.append( + "Stacks: {}".format([(x.team, x.count) for x in self.stacks]) + ) if self.min_teams: - lines.append('Min teams: {}'.format(self.min_teams)) + lines.append("Min teams: {}".format(self.min_teams)) if self.no_offense_against_defense: - lines.append('No offense against D: {}'.format( + lines.append( + "No offense against D: {}".format( self.no_offense_against_defense ) ) if self.custom_rules: - lines.append('Custom rules: {}'.format( - self.custom_rules - )) + lines.append("Custom rules: {}".format(self.custom_rules)) if len(lines): - return '\n'.join(lines) + return "\n".join(lines) else: - return 'None' + return "None" class UploadSettings(object): - - def __init__(self, pid_file, upload_file, - rule_set, rosters): + def __init__(self, pid_file, upload_file, rule_set, rosters): self.pid_file = pid_file self.upload_file = upload_file self.rule_set = rule_set @@ -160,7 +164,7 @@ def __init__( team: str, count: int, stack_lock_pos=None, - stack_eligible_pos=None + stack_eligible_pos=None, ): self.team = team self.count = count diff --git a/draftfast/showdown/orm.py b/draftfast/showdown/orm.py index f551668..6a7dcca 100644 --- a/draftfast/showdown/orm.py +++ b/draftfast/showdown/orm.py @@ -4,25 +4,21 @@ class ShowdownPlayer(Player): - # Captain and MVP multiplier # TODO - make public _CAPTAIN_MULTIPLIER = 1.5 def __init__( - self, - player: Player, - captain: bool = False, - pos: Optional[str] = None + self, player: Player, captain: bool = False, pos: Optional[str] = None ): for k, v in player.__dict__.items(): - if hasattr(self, k) or k.startswith('__'): + if hasattr(self, k) or k.startswith("__"): continue setattr(self, k, deepcopy(v)) if captain: self.real_pos = self.pos - self.pos = 'CPT' + self.pos = "CPT" self.captain = True else: if pos: @@ -30,17 +26,17 @@ def __init__( self.real_pos = pos else: self.real_pos = self.pos - self.pos = 'FLEX' + self.pos = "FLEX" self.captain = False @property def formatted_position(self): - return '{} ({})'.format(self.pos, self.real_pos) + return "{} ({})".format(self.pos, self.real_pos) @property def is_captain(self): - return self.pos == 'CPT' + return self.pos == "CPT" @property def roster_id(self): @@ -48,7 +44,7 @@ def roster_id(self): Used for roster equality. Unlike classic, position matters in showdown at CPT level. """ - return f'{self.name} {self.team} {self.is_captain}' + return f"{self.name} {self.team} {self.is_captain}" @property def v_avg(self): @@ -98,4 +94,4 @@ def roster_id(self): Used for roster equality. Unlike classic, multipliers exist at MVP and star levels """ - return f'{self.name} {self.team} {self.pos}' + return f"{self.name} {self.team} {self.pos}" diff --git a/draftfast/test/test_csgo_showdown.py b/draftfast/test/test_csgo_showdown.py index cce64ba..40861a6 100644 --- a/draftfast/test/test_csgo_showdown.py +++ b/draftfast/test/test_csgo_showdown.py @@ -5,35 +5,44 @@ from draftfast.settings import OptimizerSettings from draftfast.showdown.orm import ShowdownPlayer -assertions = unittest.TestCase('__init__') +assertions = unittest.TestCase("__init__") def _build_mock_player_pool(): player_pool = [ - Player(name='A1', cost=5500, proj=100, pos='QB', - team='X', matchup='X@Y'), - Player(name='A2', cost=5500, proj=41, pos='QB', - team='X', matchup='X@Y'), - Player(name='A11', cost=5500, proj=50, pos='WR', - team='X', matchup='X@Y'), - Player(name='A3', cost=5500, proj=42, pos='WR', - team='X', matchup='X@Y'), - Player(name='A4', cost=5500, proj=43, pos='WR', - team='X', matchup='X@Y'), - Player(name='A5', cost=5500, proj=44, pos='WR', - team='X', matchup='X@Y'), - Player(name='A6', cost=5500, proj=45, pos='RB', - team='X', matchup='X@Y'), - + Player( + name="A1", cost=5500, proj=100, pos="QB", team="X", matchup="X@Y" + ), + Player( + name="A2", cost=5500, proj=41, pos="QB", team="X", matchup="X@Y" + ), + Player( + name="A11", cost=5500, proj=50, pos="WR", team="X", matchup="X@Y" + ), + Player( + name="A3", cost=5500, proj=42, pos="WR", team="X", matchup="X@Y" + ), + Player( + name="A4", cost=5500, proj=43, pos="WR", team="X", matchup="X@Y" + ), + Player( + name="A5", cost=5500, proj=44, pos="WR", team="X", matchup="X@Y" + ), + Player( + name="A6", cost=5500, proj=45, pos="RB", team="X", matchup="X@Y" + ), # Test that max players per team works. Everyone # on Y is projected for 1 point, under normal # opto should never be picked. - Player(name='A7', cost=5500, proj=1, pos='RB', - team='Y', matchup='X@Y'), - Player(name='A8', cost=5500, proj=1, pos='RB', - team='Y', matchup='X@Y'), - Player(name='A9', cost=5500, proj=1, pos='TE', - team='Y', matchup='X@Y'), + Player( + name="A7", cost=5500, proj=1, pos="RB", team="Y", matchup="X@Y" + ), + Player( + name="A8", cost=5500, proj=1, pos="RB", team="Y", matchup="X@Y" + ), + Player( + name="A9", cost=5500, proj=1, pos="TE", team="Y", matchup="X@Y" + ), ] def capt_boost(p): @@ -65,13 +74,11 @@ def test_csgo_mock(): rule_set=rules.DK_CSGO_SHOWDOWN, player_pool=mock_dk_pool, optimizer_settings=OptimizerSettings( - showdown_teams=('X', 'Y'), + showdown_teams=("X", "Y"), ), - verbose=True + verbose=True, ) assertions.assertNotEqual(roster, None) players = roster.players - assertions.assertEqual(len([ - x for x in players if x.team == 'Y' - ]), 3) + assertions.assertEqual(len([x for x in players if x.team == "Y"]), 3) diff --git a/draftfast/test/test_csv_parse.py b/draftfast/test/test_csv_parse.py index ed9d892..cddaf7a 100644 --- a/draftfast/test/test_csv_parse.py +++ b/draftfast/test/test_csv_parse.py @@ -2,20 +2,22 @@ import unittest from draftfast.csv_parse import salary_download from draftfast.rules import ( - DRAFT_KINGS, FAN_DUEL, - FD_NFL_MVP_RULE_SET, FD_MLB_MVP_RULE_SET, - FD_NBA_MVP_RULE_SET + DRAFT_KINGS, + FAN_DUEL, + FD_NFL_MVP_RULE_SET, + FD_MLB_MVP_RULE_SET, + FD_NBA_MVP_RULE_SET, ) from draftfast.optimize import run -assertions = unittest.TestCase('__init__') +assertions = unittest.TestCase("__init__") CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) -salaries = f'{CURRENT_DIR}/data/nba-test-salaries.csv' -projections = f'{CURRENT_DIR}/data/nba-test-projections.csv' -fd_mvp_nfl_salaries = f'{CURRENT_DIR}/data/nfl-mvp-fd-test-salaries.csv' -fd_mvp_mlb_salaries = f'{CURRENT_DIR}/data/mlb-mvp-fd-test-salaries.csv' -fd_mvp_nba_salaries = f'{CURRENT_DIR}/data/nba-mvp-fd-test-salaries.csv' +salaries = f"{CURRENT_DIR}/data/nba-test-salaries.csv" +projections = f"{CURRENT_DIR}/data/nba-test-projections.csv" +fd_mvp_nfl_salaries = f"{CURRENT_DIR}/data/nfl-mvp-fd-test-salaries.csv" +fd_mvp_mlb_salaries = f"{CURRENT_DIR}/data/mlb-mvp-fd-test-salaries.csv" +fd_mvp_nba_salaries = f"{CURRENT_DIR}/data/nba-mvp-fd-test-salaries.csv" def test_dk_nba_parse(): @@ -54,24 +56,17 @@ def test_fd_showdown_nfl(): # Two same ID players should break out captain and flex # and have identical costs - renfrow = [ - p for p in players - if p.name == 'Hunter Renfrow' - ] + renfrow = [p for p in players if p.name == "Hunter Renfrow"] assertions.assertEqual(len(renfrow), 2) assertions.assertEqual(renfrow[0].cost, renfrow[1].cost) assertions.assertAlmostEqual( - renfrow[0].average_score, - renfrow[1].average_score * 1.5 + renfrow[0].average_score, renfrow[1].average_score * 1.5 ) - assertions.assertEqual(renfrow[0].pos, 'CPT') - assertions.assertEqual(renfrow[1].pos, 'FLEX') + assertions.assertEqual(renfrow[0].pos, "CPT") + assertions.assertEqual(renfrow[1].pos, "FLEX") # Optimization should work - optimized = run( - rule_set=FD_NFL_MVP_RULE_SET, - player_pool=players - ) + optimized = run(rule_set=FD_NFL_MVP_RULE_SET, player_pool=players) assertions.assertEqual(len(optimized.players), 5) @@ -84,32 +79,20 @@ def test_fd_showdown_mlb(): ) assertions.assertEqual(len(players), 147) - judges = [ - p for p in players - if p.name == 'Aaron Judge' - ] + judges = [p for p in players if p.name == "Aaron Judge"] assertions.assertEqual(len(judges), 3) mvp, star, util = judges assertions.assertEqual(mvp.cost, star.cost, util.cost) - assertions.assertEqual(mvp.pos, 'MVP') - assertions.assertEqual(star.pos, 'STAR') - assertions.assertEqual(util.pos, 'UTIL') + assertions.assertEqual(mvp.pos, "MVP") + assertions.assertEqual(star.pos, "STAR") + assertions.assertEqual(util.pos, "UTIL") - assertions.assertAlmostEqual( - star.average_score, - util.average_score * 1.5 - ) - assertions.assertAlmostEqual( - mvp.average_score, - util.average_score * 2 - ) + assertions.assertAlmostEqual(star.average_score, util.average_score * 1.5) + assertions.assertAlmostEqual(mvp.average_score, util.average_score * 2) # Optimization should work - optimized = run( - rule_set=FD_MLB_MVP_RULE_SET, - player_pool=players - ) + optimized = run(rule_set=FD_MLB_MVP_RULE_SET, player_pool=players) assertions.assertEqual(len(optimized.players), 5) @@ -129,37 +112,22 @@ def test_fd_showdown_nba(): assertions.assertEqual(len(players), 20) - chefs = [ - p for p in players - if p.name == 'Stephen Curry' - ] + chefs = [p for p in players if p.name == "Stephen Curry"] assertions.assertEqual(len(chefs), 4) mvp, star, pro, util = chefs assertions.assertEqual(mvp.cost, star.cost, util.cost) - assertions.assertEqual(mvp.pos, 'MVP') - assertions.assertEqual(star.pos, 'STAR') - assertions.assertEqual(pro.pos, 'PRO') - assertions.assertEqual(util.pos, 'UTIL') + assertions.assertEqual(mvp.pos, "MVP") + assertions.assertEqual(star.pos, "STAR") + assertions.assertEqual(pro.pos, "PRO") + assertions.assertEqual(util.pos, "UTIL") - assertions.assertAlmostEqual( - pro.average_score, - util.average_score * 1.2 - ) - assertions.assertAlmostEqual( - star.average_score, - util.average_score * 1.5 - ) - assertions.assertAlmostEqual( - mvp.average_score, - util.average_score * 2 - ) + assertions.assertAlmostEqual(pro.average_score, util.average_score * 1.2) + assertions.assertAlmostEqual(star.average_score, util.average_score * 1.5) + assertions.assertAlmostEqual(mvp.average_score, util.average_score * 2) # Optimization should work - optimized = run( - rule_set=FD_NBA_MVP_RULE_SET, - player_pool=players - ) + optimized = run(rule_set=FD_NBA_MVP_RULE_SET, player_pool=players) print(optimized) assertions.assertEqual(len(optimized.players), 5) assertions.assertAlmostEqual(optimized.projected(), 276.99) diff --git a/draftfast/test/test_csv_upload.py b/draftfast/test/test_csv_upload.py index f1b4c5c..2f5ae74 100644 --- a/draftfast/test/test_csv_upload.py +++ b/draftfast/test/test_csv_upload.py @@ -5,12 +5,11 @@ from draftfast import rules from draftfast import optimize from draftfast.csv_parse import uploaders, salary_download -from draftfast.pickem.pickem_optimize import ( - optimize as p_optimize -) +from draftfast.pickem.pickem_optimize import optimize as p_optimize import unittest -assertions = unittest.TestCase('__init__') + +assertions = unittest.TestCase("__init__") CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) @@ -20,48 +19,50 @@ def test_dk_nba_upload(): row = _get_first_written_row( game=rules.DRAFT_KINGS, - salary_file_location='{}/data/dk-nba-salaries.csv'.format(CURRENT_DIR), + salary_file_location="{}/data/dk-nba-salaries.csv".format(CURRENT_DIR), rule_set=rules.DK_NBA_RULE_SET, - pid_file='{}/data/dk-nba-pids.csv'.format(CURRENT_DIR), + pid_file="{}/data/dk-nba-pids.csv".format(CURRENT_DIR), Uploader=uploaders.DraftKingsNBAUploader, ) assertEqual( sorted(row), - sorted([ - '11743190', - '11743146', - '11743013', - '11743142', - '11743007', - '11743176', - '11743369', - '11743024', - ]) + sorted( + [ + "11743190", + "11743146", + "11743013", + "11743142", + "11743007", + "11743176", + "11743369", + "11743024", + ] + ), ) def test_dk_nfl_upload(): row = _get_first_written_row( game=rules.DRAFT_KINGS, - salary_file_location='{}/data/dk-nfl-upload-salaries.csv'.format( + salary_file_location="{}/data/dk-nfl-upload-salaries.csv".format( CURRENT_DIR ), rule_set=rules.DK_NFL_RULE_SET, - pid_file='{}/data/dk-nfl-upload.csv'.format(CURRENT_DIR), + pid_file="{}/data/dk-nfl-upload.csv".format(CURRENT_DIR), Uploader=uploaders.DraftKingsNFLUploader, ) assertEqual( row, [ - '13651346', - '13651384', - '13651396', - '13651574', - '13651608', - '13651652', - '13651838', - '13651402', - '13651964', + "13651346", + "13651384", + "13651396", + "13651574", + "13651608", + "13651652", + "13651838", + "13651402", + "13651964", ], ) @@ -69,22 +70,22 @@ def test_dk_nfl_upload(): def test_dk_el_upload(): row = _get_first_written_row( game=rules.DRAFT_KINGS, - salary_file_location='{}/data/dk-euro-league-salaries.csv'.format( + salary_file_location="{}/data/dk-euro-league-salaries.csv".format( CURRENT_DIR ), rule_set=rules.DK_EURO_LEAGUE_RULE_SET, - pid_file='{}/data/dk-euro-league-pids.csv'.format(CURRENT_DIR), + pid_file="{}/data/dk-euro-league-pids.csv".format(CURRENT_DIR), Uploader=uploaders.DraftKingsELUploader, ) assertEqual( row, [ - '11799918', - '11799942', - '11799922', - '11799956', - '11800052', - '11799950', + "11799918", + "11799942", + "11799922", + "11799956", + "11800052", + "11799950", ], ) @@ -92,24 +93,24 @@ def test_dk_el_upload(): def test_dk_soccer_upload(): row = _get_first_written_row( game=rules.DRAFT_KINGS, - salary_file_location='{}/data/dk-soccer-salaries.csv'.format( + salary_file_location="{}/data/dk-soccer-salaries.csv".format( CURRENT_DIR ), rule_set=rules.DK_SOCCER_RULE_SET, - pid_file='{}/data/dk-soccer-pids.csv'.format(CURRENT_DIR), + pid_file="{}/data/dk-soccer-pids.csv".format(CURRENT_DIR), Uploader=uploaders.DraftKingsSoccerUploader, ) assertEqual( row, [ - '11801828', - '11801837', - '11801757', - '11801761', - '11801685', - '11801733', - '11801676', - '11801778', + "11801828", + "11801837", + "11801757", + "11801761", + "11801685", + "11801733", + "11801676", + "11801778", ], ) @@ -117,53 +118,55 @@ def test_dk_soccer_upload(): def test_fd_nba_upload(): row = _get_first_written_row( game=rules.FAN_DUEL, - salary_file_location='{}/data/fd-nba-salaries.csv'.format(CURRENT_DIR), + salary_file_location="{}/data/fd-nba-salaries.csv".format(CURRENT_DIR), rule_set=rules.FD_NBA_RULE_SET, - pid_file='{}/data/fd-nba-pids.csv'.format(CURRENT_DIR), + pid_file="{}/data/fd-nba-pids.csv".format(CURRENT_DIR), Uploader=uploaders.FanDuelNBAUploader, ) assertEqual( row, [ - '30803-9535:Kyle Lowry', - '30803-9475:Derrick Rose', - '30803-9714:DeMar DeRozan', - '30803-40201:Dennis Schroder', - '30803-9646:Kevin Durant', - '30803-12341:Paul George', - '30803-9957:Serge Ibaka', - '30803-9874:Kevin Love', - '30803-12362:DeMarcus Cousins', - ] + "30803-9535:Kyle Lowry", + "30803-9475:Derrick Rose", + "30803-9714:DeMar DeRozan", + "30803-40201:Dennis Schroder", + "30803-9646:Kevin Durant", + "30803-12341:Paul George", + "30803-9957:Serge Ibaka", + "30803-9874:Kevin Love", + "30803-12362:DeMarcus Cousins", + ], ) def test_dk_nhl_uploader(): row = _get_first_written_row( game=rules.DRAFT_KINGS, - salary_file_location='{}/data/dk-nhl-salaries.csv'.format(CURRENT_DIR), + salary_file_location="{}/data/dk-nhl-salaries.csv".format(CURRENT_DIR), rule_set=rules.DK_NHL_RULE_SET, - pid_file='{}/data/dk-nhl-pids.csv'.format(CURRENT_DIR), + pid_file="{}/data/dk-nhl-pids.csv".format(CURRENT_DIR), Uploader=uploaders.DraftKingsNHLUploader, ) assertEqual( sorted(row), - sorted([ - '11845288', - '11845290', - '11845526', - '11845550', - '11845942', - '11845960', - '11846094', - '11846329', - '11845460', - ]), + sorted( + [ + "11845288", + "11845290", + "11845526", + "11845550", + "11845942", + "11845960", + "11846094", + "11846329", + "11845460", + ] + ), ) def test_pickem_nba_upload(): - salary_file_location = '{}/data/dk-nba-pickem-salaries.csv'.format( + salary_file_location = "{}/data/dk-nba-pickem-salaries.csv".format( CURRENT_DIR ) players = salary_download.generate_players_from_csvs( @@ -171,12 +174,14 @@ def test_pickem_nba_upload(): salary_file_location=salary_file_location, ruleset=rules.DK_NBA_PICKEM_RULE_SET, ) - rosters = [p_optimize( - all_players=players, - )] - - pid_file = '{}/data/dk-nba-pickem-pids.csv'.format(CURRENT_DIR) - upload_file = '{}/data/current-upload.csv'.format(CURRENT_DIR) + rosters = [ + p_optimize( + all_players=players, + ) + ] + + pid_file = "{}/data/dk-nba-pickem-pids.csv".format(CURRENT_DIR) + upload_file = "{}/data/current-upload.csv".format(CURRENT_DIR) uploader = uploaders.DraftKingsNBAPickemUploader( pid_file=pid_file, upload_file=upload_file, @@ -184,80 +189,80 @@ def test_pickem_nba_upload(): uploader.write_rosters(rosters) row = None - with open(upload_file, 'r') as csvfile: - reader = csv.reader(csvfile, delimiter=',') + with open(upload_file, "r") as csvfile: + reader = csv.reader(csvfile, delimiter=",") for idx, row in enumerate(reader): if idx == 0: continue assertEqual( row, [ - '11839390', - '11839397', - '11839400', - '11839405', - '11839420', - '11839422', - ] + "11839390", + "11839397", + "11839400", + "11839405", + "11839420", + "11839422", + ], ) def test_dk_nfl_showdown_upload(): row = _get_first_written_row_dk_showdown( - salary_file='dk-nfl-showdown-salaries.csv', - pid_file='dk-nfl-showdown-pids.csv', + salary_file="dk-nfl-showdown-salaries.csv", + pid_file="dk-nfl-showdown-pids.csv", ruleset=rules.DK_NFL_SHOWDOWN_RULE_SET, Uploader=uploaders.DraftKingsCaptainShowdownUploader, ) assertEqual( row, [ - '11896024', - '11895994', - '11895995', - '11895996', - '11895997', - '11896018', - ] + "11896024", + "11895994", + "11895995", + "11895996", + "11895997", + "11896018", + ], ) def test_dk_nba_showdown_upload(): row = _get_first_written_row_dk_showdown( - salary_file='dk-nba-showdown-salaries.csv', - pid_file='dk-nba-showdown-pids.csv', + salary_file="dk-nba-showdown-salaries.csv", + pid_file="dk-nba-showdown-pids.csv", ruleset=rules.DK_NBA_SHOWDOWN_RULE_SET, Uploader=uploaders.DraftKingsCaptainShowdownUploader, ) assertEqual( row, [ - '11915867', - '11915844', - '11915845', - '11915846', - '11915852', - '11915853', + "11915867", + "11915844", + "11915845", + "11915846", + "11915852", + "11915853", ], ) def test_dk_mlb_showdown_upload(): row = _get_first_written_row_dk_showdown( - salary_file='dk-mlb-showdown-salaries.csv', - pid_file='dk-mlb-showdown-pids.csv', + salary_file="dk-mlb-showdown-salaries.csv", + pid_file="dk-mlb-showdown-pids.csv", ruleset=rules.DK_MLB_SHOWDOWN_RULE_SET, Uploader=uploaders.DraftKingsCaptainShowdownUploader, ) assertEqual( row, [ - '12895602', - '12895494', - '12895495', - '12895496', - '12895510', - '12895600', + "12895602", + "12895494", + "12895495", + "12895496", + "12895510", + "12895600", ], ) @@ -268,32 +273,32 @@ def proj(players): p.proj = idx row = _get_first_written_row_dk_showdown( - salary_file='dk-xfl-salaries.csv', - pid_file='dk-xfl-pids.csv', + salary_file="dk-xfl-salaries.csv", + pid_file="dk-xfl-pids.csv", ruleset=rules.DK_XFL_CLASSIC_RULE_SET, Uploader=uploaders.DraftKingsXFLUploader, - players_side_effect=proj + players_side_effect=proj, ) assertEqual( row, [ - '14224920', - '14225002', - '14225226', - '14225228', - '14225230', - '14225232', - '14225241' - ] + "14224920", + "14225002", + "14225226", + "14225228", + "14225230", + "14225232", + "14225241", + ], ) def _get_first_written_row( - game: str, - salary_file_location: str, - rule_set: rules.RuleSet, - pid_file: str, - Uploader: Type[uploaders.CSVUploader], + game: str, + salary_file_location: str, + rule_set: rules.RuleSet, + pid_file: str, + Uploader: Type[uploaders.CSVUploader], ) -> list: players = salary_download.generate_players_from_csvs( game=game, @@ -305,7 +310,7 @@ def _get_first_written_row( player_pool=players, verbose=True, ) - upload_file = '{}/data/current-upload.csv'.format(CURRENT_DIR) + upload_file = "{}/data/current-upload.csv".format(CURRENT_DIR) uploader = Uploader( pid_file=pid_file, upload_file=upload_file, @@ -313,8 +318,8 @@ def _get_first_written_row( uploader.write_rosters([roster]) row = None - with open(upload_file, 'r') as csvfile: - reader = csv.reader(csvfile, delimiter=',') + with open(upload_file, "r") as csvfile: + reader = csv.reader(csvfile, delimiter=",") for idx, row in enumerate(reader): if idx == 0: continue @@ -331,9 +336,9 @@ def _get_first_written_row_dk_showdown( pid_file: str, ruleset: rules.RuleSet, Uploader: Type[uploaders.CSVUploader], - players_side_effect: types.FunctionType = _noop + players_side_effect: types.FunctionType = _noop, ) -> list: - salary_file_location = '{}/data/{}'.format( + salary_file_location = "{}/data/{}".format( CURRENT_DIR, salary_file, ) @@ -343,14 +348,16 @@ def _get_first_written_row_dk_showdown( ruleset=ruleset, ) players_side_effect(players) - rosters = [optimize.run( - player_pool=players, - rule_set=ruleset, - verbose=True, - )] - - pid_file_location = '{}/data/{}'.format(CURRENT_DIR, pid_file) - upload_file = '{}/data/current-upload.csv'.format(CURRENT_DIR) + rosters = [ + optimize.run( + player_pool=players, + rule_set=ruleset, + verbose=True, + ) + ] + + pid_file_location = "{}/data/{}".format(CURRENT_DIR, pid_file) + upload_file = "{}/data/current-upload.csv".format(CURRENT_DIR) uploader = Uploader( pid_file=pid_file_location, upload_file=upload_file, @@ -358,8 +365,8 @@ def _get_first_written_row_dk_showdown( uploader.write_rosters(rosters) row = None - with open(upload_file, 'r') as csvfile: - reader = csv.reader(csvfile, delimiter=',') + with open(upload_file, "r") as csvfile: + reader = csv.reader(csvfile, delimiter=",") for idx, row in enumerate(reader): if idx == 0: continue diff --git a/draftfast/test/test_custom.py b/draftfast/test/test_custom.py index e22b392..5d476c9 100644 --- a/draftfast/test/test_custom.py +++ b/draftfast/test/test_custom.py @@ -5,33 +5,34 @@ from draftfast.orm import Roster import unittest -assertions = unittest.TestCase('__init__') + +assertions = unittest.TestCase("__init__") CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) -salary_file = '{}/data/soccer-showdown.csv'.format(CURRENT_DIR) +salary_file = "{}/data/soccer-showdown.csv".format(CURRENT_DIR) class Showdown(Roster): POSITION_ORDER = { - 'M': 0, - 'F': 1, - 'D': 2, - 'GK': 3, + "M": 0, + "F": 1, + "D": 2, + "GK": 3, } showdown_limits = [ - ['M', 0, 6], - ['F', 0, 6], - ['D', 0, 6], - ['GK', 0, 6], + ["M", 0, 6], + ["F", 0, 6], + ["D", 0, 6], + ["GK", 0, 6], ] def test_el_dk(): soccer_rules = rules.RuleSet( site=rules.DRAFT_KINGS, - league='SOCCER_SHOWDOWN', + league="SOCCER_SHOWDOWN", roster_size=6, position_limits=showdown_limits, salary_max=50_000, diff --git a/draftfast/test/test_custom_rules.py b/draftfast/test/test_custom_rules.py index 25eb714..6b18a93 100644 --- a/draftfast/test/test_custom_rules.py +++ b/draftfast/test/test_custom_rules.py @@ -4,31 +4,32 @@ from draftfast.settings import OptimizerSettings, CustomRule import unittest -assertions = unittest.TestCase('__init__') + +assertions = unittest.TestCase("__init__") def construct_pool(): mock_nba_pool = [ - Player(name='A1', cost=5500, proj=100, pos='PG'), - Player(name='A2', cost=5500, proj=41, pos='PG'), - Player(name='A100', cost=5500, proj=501, pos='PG'), - Player(name='A101', cost=5500, proj=500, pos='PG'), - Player(name='A11', cost=5500, proj=50, pos='PG'), - Player(name='A3', cost=5500, proj=42, pos='SG'), - Player(name='A4', cost=5500, proj=0, pos='SG'), - Player(name='A5', cost=5500, proj=44, pos='SF'), - Player(name='A6', cost=5500, proj=45, pos='SF'), - Player(name='A7', cost=5500, proj=46, pos='PF'), - Player(name='A8', cost=5500, proj=47, pos='PF'), - Player(name='A9', cost=5500, proj=0, pos='C'), - Player(name='A10', cost=5500, proj=49, pos='C'), + Player(name="A1", cost=5500, proj=100, pos="PG"), + Player(name="A2", cost=5500, proj=41, pos="PG"), + Player(name="A100", cost=5500, proj=501, pos="PG"), + Player(name="A101", cost=5500, proj=500, pos="PG"), + Player(name="A11", cost=5500, proj=50, pos="PG"), + Player(name="A3", cost=5500, proj=42, pos="SG"), + Player(name="A4", cost=5500, proj=0, pos="SG"), + Player(name="A5", cost=5500, proj=44, pos="SF"), + Player(name="A6", cost=5500, proj=45, pos="SF"), + Player(name="A7", cost=5500, proj=46, pos="PF"), + Player(name="A8", cost=5500, proj=47, pos="PF"), + Player(name="A9", cost=5500, proj=0, pos="C"), + Player(name="A10", cost=5500, proj=49, pos="C"), ] team = 0 for p in mock_nba_pool: team += 1 - if p.name in ['A101', 'A100', 'A10']: - p.team = 'SomeTeam' + if p.name in ["A101", "A100", "A10"]: + p.team = "SomeTeam" else: p.team = str(team) @@ -44,17 +45,14 @@ def test_if_one_then_one(): verbose=True, ) names = {p.name for p in roster.players} - assertions.assertEqual( - True, - 'A1' in names and 'A4' not in names - ) + assertions.assertEqual(True, "A1" in names and "A4" not in names) settings = OptimizerSettings( custom_rules=[ # Always play A1 with A9 and A4 CustomRule( - group_a=lambda p: p.name == 'A1', - group_b=lambda p: p.name == 'A4', - comparison=lambda s_sum, a, b: s_sum(a) == s_sum(b) + group_a=lambda p: p.name == "A1", + group_b=lambda p: p.name == "A4", + comparison=lambda s_sum, a, b: s_sum(a) == s_sum(b), ) ] ) @@ -67,19 +65,16 @@ def test_if_one_then_one(): names = {p.name for p in roster.players} # Without this rule, A1 and A4 are not in the same lineup. - assertions.assertEqual( - True, - 'A1' in names and 'A4' in names - ) + assertions.assertEqual(True, "A1" in names and "A4" in names) # Confirm now that the rule prevents one without the other mock_nba_pool = construct_pool() for p in mock_nba_pool: - if p.name == 'A1': + if p.name == "A1": # A1 normally would always be in the lineup # due to highest projection among PGs p.proj = 502 - if p.name == 'A4': + if p.name == "A4": # A4 projection is so negative it should # never be in any lineup p.proj = -1_000_000 @@ -91,10 +86,7 @@ def test_if_one_then_one(): optimizer_settings=settings, ) names = {p.name for p in roster.players} - assertions.assertEqual( - True, - 'A1' not in names and 'A4' not in names - ) + assertions.assertEqual(True, "A1" not in names and "A4" not in names) def test_if_one_then_two(): @@ -108,15 +100,14 @@ def test_if_one_then_two(): ) names = {p.name for p in roster.players} assertions.assertEqual( - True, - 'A1' in names and 'A4' not in names and 'A9' not in names + True, "A1" in names and "A4" not in names and "A9" not in names ) settings = OptimizerSettings( custom_rules=[ # Always play A1 with A9 and A4 CustomRule( - group_a=lambda p: p.name == 'A1', - group_b=lambda p: p.name == 'A9' or p.name == 'A4' + group_a=lambda p: p.name == "A1", + group_b=lambda p: p.name == "A9" or p.name == "A4", ) ] ) @@ -133,8 +124,7 @@ def test_if_one_then_two(): # Without this rule, A4 and A9 would never appear in the optimized # lineup. Both have a 0 point projection. assertions.assertEqual( - True, - 'A1' in names and 'A9' in names and 'A4' in names + True, "A1" in names and "A9" in names and "A4" in names ) @@ -148,19 +138,16 @@ def test_never_two(): verbose=True, ) names = {p.name for p in roster.players} - assertions.assertEqual( - True, - 'A101' in names and 'A100' in names - ) + assertions.assertEqual(True, "A101" in names and "A100" in names) # Never play two players together settings = OptimizerSettings( custom_rules=[ - CustomRule( - group_a=lambda p: p, - group_b=lambda p: p.name == 'A100' or p.name == 'A101', - comparison=lambda sum, a, b: sum(b) <= 1 - ) + CustomRule( + group_a=lambda p: p, + group_b=lambda p: p.name == "A100" or p.name == "A101", + comparison=lambda sum, a, b: sum(b) <= 1, + ) ] ) @@ -174,10 +161,7 @@ def test_never_two(): # Without this rule, A4 and A9 would never appear in the optimized # lineup. Both have a 0 point projection. - assertions.assertEqual( - True, - 'A101' not in names and 'A100' in names - ) + assertions.assertEqual(True, "A101" not in names and "A100" in names) def test_team_rules(): @@ -187,8 +171,8 @@ def test_team_rules(): settings = OptimizerSettings( custom_rules=[ CustomRule( - group_a=lambda p: p.pos == 'C' and p.team == 'SomeTeam', - group_b=lambda p: p.pos == 'PG' and p.team == 'SomeTeam', + group_a=lambda p: p.pos == "C" and p.team == "SomeTeam", + group_b=lambda p: p.pos == "PG" and p.team == "SomeTeam", ) ] ) @@ -200,6 +184,5 @@ def test_team_rules(): ) names = {p.name for p in roster.players} assertions.assertEqual( - True, - 'A100' in names and 'A101' in names and 'A10' in names + True, "A100" in names and "A101" in names and "A10" in names ) diff --git a/draftfast/test/test_el.py b/draftfast/test/test_el.py index f6baeff..67f8753 100644 --- a/draftfast/test/test_el.py +++ b/draftfast/test/test_el.py @@ -4,10 +4,11 @@ from draftfast.csv_parse import salary_download import unittest -assertions = unittest.TestCase('__init__') + +assertions = unittest.TestCase("__init__") CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) -salary_file = '{}/data/dk-euro-league-salaries.csv'.format(CURRENT_DIR) +salary_file = "{}/data/dk-euro-league-salaries.csv".format(CURRENT_DIR) def test_el_dk(): diff --git a/draftfast/test/test_exposure.py b/draftfast/test/test_exposure.py index 4e8a27b..41cf7f7 100644 --- a/draftfast/test/test_exposure.py +++ b/draftfast/test/test_exposure.py @@ -4,12 +4,13 @@ from draftfast.csv_parse import salary_download import unittest -assertions = unittest.TestCase('__init__') + +assertions = unittest.TestCase("__init__") CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) -salary_file = '{}/data/dk-nfl-salaries.csv'.format(CURRENT_DIR) -fd_nfl_salary_file = '{}/data/fd-nfl-salaries.csv'.format(CURRENT_DIR) -projection_file = '{}/data/dk-nfl-projections.csv'.format(CURRENT_DIR) +salary_file = "{}/data/dk-nfl-salaries.csv".format(CURRENT_DIR) +fd_nfl_salary_file = "{}/data/fd-nfl-salaries.csv".format(CURRENT_DIR) +projection_file = "{}/data/dk-nfl-projections.csv".format(CURRENT_DIR) def test_deterministic_exposure_limits(): @@ -24,20 +25,20 @@ def test_deterministic_exposure_limits(): rule_set=rules.DK_NFL_RULE_SET, player_pool=players, exposure_bounds=[ - {'name': 'Andrew Luck', 'min': 0.5, 'max': 0.7}, - {'name': 'Alshon Jeffery', 'min': 1, 'max': 1}, + {"name": "Andrew Luck", "min": 0.5, "max": 0.7}, + {"name": "Alshon Jeffery", "min": 1, "max": 1}, ], ) assertions.assertEqual(len(rosters), iterations) assertions.assertEqual(len(exposure_diffs), 0) players = [p.name for p in rosters[0].players] - assertions.assertTrue('Andrew Luck' in players) - assertions.assertTrue('Alshon Jeffery' in players) + assertions.assertTrue("Andrew Luck" in players) + assertions.assertTrue("Alshon Jeffery" in players) players = [p.name for p in rosters[1].players] - assertions.assertTrue('Andrew Luck' not in players) - assertions.assertTrue('Alshon Jeffery' in players) + assertions.assertTrue("Andrew Luck" not in players) + assertions.assertTrue("Alshon Jeffery" in players) def test_random_exposure_limits(): diff --git a/draftfast/test/test_f1_showdown.py b/draftfast/test/test_f1_showdown.py index e73815c..9c28d32 100644 --- a/draftfast/test/test_f1_showdown.py +++ b/draftfast/test/test_f1_showdown.py @@ -5,11 +5,12 @@ from draftfast.showdown.orm import ShowdownPlayer import unittest -assertions = unittest.TestCase('__init__') + +assertions = unittest.TestCase("__init__") CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) -salary_file = '{}/data/f1-salaries-showdown.csv'.format(CURRENT_DIR) +salary_file = "{}/data/f1-salaries-showdown.csv".format(CURRENT_DIR) def test_f1_dk(): diff --git a/draftfast/test/test_golf.py b/draftfast/test/test_golf.py index 8b55fd7..13ee129 100644 --- a/draftfast/test/test_golf.py +++ b/draftfast/test/test_golf.py @@ -3,20 +3,21 @@ from draftfast.orm import Player import unittest -assertions = unittest.TestCase('__init__') -GOLFER, CPT = 'G', 'CPT' +assertions = unittest.TestCase("__init__") + +GOLFER, CPT = "G", "CPT" def test_golf_dk(): player_pool = [ - Player(name='G1', cost=5500, proj=55, pos=GOLFER), - Player(name='G2', cost=5600, proj=55, pos=GOLFER), - Player(name='G3', cost=5700, proj=55, pos=GOLFER), - Player(name='G4', cost=5800, proj=55, pos=GOLFER), - Player(name='G5', cost=5800, proj=55, pos=GOLFER), - Player(name='G6', cost=5900, proj=55, pos=GOLFER), - Player(name='G7', cost=10000, proj=155, pos=GOLFER), + Player(name="G1", cost=5500, proj=55, pos=GOLFER), + Player(name="G2", cost=5600, proj=55, pos=GOLFER), + Player(name="G3", cost=5700, proj=55, pos=GOLFER), + Player(name="G4", cost=5800, proj=55, pos=GOLFER), + Player(name="G5", cost=5800, proj=55, pos=GOLFER), + Player(name="G6", cost=5900, proj=55, pos=GOLFER), + Player(name="G7", cost=10000, proj=155, pos=GOLFER), ] roster = run( rule_set=rules.DK_PGA_RULE_SET, @@ -28,13 +29,13 @@ def test_golf_dk(): def test_golf_dk_captain(): player_pool = [ - Player(name='G1', cost=5500, proj=1, pos=CPT), - Player(name='G2', cost=5600, proj=55, pos=GOLFER), - Player(name='G3', cost=5700, proj=55, pos=GOLFER), - Player(name='G4', cost=5800, proj=55, pos=GOLFER), - Player(name='G5', cost=5800, proj=55, pos=GOLFER), - Player(name='G6', cost=5900, proj=55, pos=GOLFER), - Player(name='G7', cost=10000, proj=155, pos=GOLFER), + Player(name="G1", cost=5500, proj=1, pos=CPT), + Player(name="G2", cost=5600, proj=55, pos=GOLFER), + Player(name="G3", cost=5700, proj=55, pos=GOLFER), + Player(name="G4", cost=5800, proj=55, pos=GOLFER), + Player(name="G5", cost=5800, proj=55, pos=GOLFER), + Player(name="G6", cost=5900, proj=55, pos=GOLFER), + Player(name="G7", cost=10000, proj=155, pos=GOLFER), ] roster = run( rule_set=rules.DK_PGA_SHOWDOWN_CAPTAIN_RULE_SET, diff --git a/draftfast/test/test_lineup_constraints.py b/draftfast/test/test_lineup_constraints.py index c6a51fb..f98e47a 100644 --- a/draftfast/test/test_lineup_constraints.py +++ b/draftfast/test/test_lineup_constraints.py @@ -1,54 +1,60 @@ -from draftfast.lineup_constraints import (LineupConstraints, - ConstraintConflictException, - ConstraintException) +from draftfast.lineup_constraints import ( + LineupConstraints, + ConstraintConflictException, + ConstraintException, +) import unittest -assertions = unittest.TestCase('__init__') + +assertions = unittest.TestCase("__init__") def test_constraint_string_args(): lcs = LineupConstraints() - lcs.ban('Sam Bradford') - lcs.lock('Will Fuller') + lcs.ban("Sam Bradford") + lcs.lock("Will Fuller") assertions.assertEqual(len(lcs), 2) def test_constraint_contains(): lcs = LineupConstraints() - lcs.add_group_constraint(['A', 'B'], 1) - lcs.ban(['C']) - lcs.add_group_constraint(['E', 'F', 'G'], (1, 3)) - lcs.lock(['H']) + lcs.add_group_constraint(["A", "B"], 1) + lcs.ban(["C"]) + lcs.add_group_constraint(["E", "F", "G"], (1, 3)) + lcs.lock(["H"]) - for c in ['A', 'B', 'C', 'E', 'F', 'G', 'H']: + for c in ["A", "B", "C", "E", "F", "G", "H"]: assertions.assertEqual(c in lcs, True) def test_constraint_set_eq(): lcs1 = LineupConstraints() - lcs1.add_group_constraint(['Spencer Ware', 'Amari Cooper'], 1) - lcs1.ban(['Packers']) - lcs1.add_group_constraint(['Eli Manning', 'Russell Wilson', 'Doug Martin'], - (1, 3)) - lcs1.lock(['Will Fuller']) + lcs1.add_group_constraint(["Spencer Ware", "Amari Cooper"], 1) + lcs1.ban(["Packers"]) + lcs1.add_group_constraint( + ["Eli Manning", "Russell Wilson", "Doug Martin"], (1, 3) + ) + lcs1.lock(["Will Fuller"]) lcs2 = LineupConstraints() - lcs2.add_group_constraint(['Spencer Ware', 'Amari Cooper'], 1) - lcs2.ban(['Packers']) - lcs2.add_group_constraint(['Eli Manning', 'Russell Wilson', 'Doug Martin'], - (1, 3)) - lcs2.lock(['Will Fuller']) + lcs2.add_group_constraint(["Spencer Ware", "Amari Cooper"], 1) + lcs2.ban(["Packers"]) + lcs2.add_group_constraint( + ["Eli Manning", "Russell Wilson", "Doug Martin"], (1, 3) + ) + lcs2.lock(["Will Fuller"]) assertions.assertEqual(lcs1, lcs2) def test_build_constraint_set(): lcs = LineupConstraints() - lcs.add_group_constraint(['Spencer Ware', 'Amari Cooper'], 1) - lcs.ban(['Packers']) - lcs.add_group_constraint(['Eli Manning', 'Russell Wilson', 'Doug Martin'], - (1, 3)) - lcs.lock(['Will Fuller']) + lcs.add_group_constraint(["Spencer Ware", "Amari Cooper"], 1) + lcs.ban(["Packers"]) + lcs.add_group_constraint( + ["Eli Manning", "Russell Wilson", "Doug Martin"], (1, 3) + ) + lcs.lock(["Will Fuller"]) assertions.assertEqual(len(lcs), 4) @@ -56,99 +62,97 @@ def test_build_constraint_set(): def test_dup_group_rule(): with assertions.assertRaises(ConstraintConflictException): lcs = LineupConstraints() - lcs.add_group_constraint(['Spencer Ware', 'Amari Cooper'], 1) - lcs.add_group_constraint(['Spencer Ware', 'Amari Cooper'], 1) + lcs.add_group_constraint(["Spencer Ware", "Amari Cooper"], 1) + lcs.add_group_constraint(["Spencer Ware", "Amari Cooper"], 1) def test_dup_group_rule2(): with assertions.assertRaises(ConstraintConflictException): lcs = LineupConstraints() lcs.add_group_constraint( - ['Eli Manning', 'Russell Wilson', 'Doug Martin'], - (1, 2) + ["Eli Manning", "Russell Wilson", "Doug Martin"], (1, 2) ) lcs.add_group_constraint( - ['Eli Manning', 'Russell Wilson', 'Doug Martin'], - (1, 2) + ["Eli Manning", "Russell Wilson", "Doug Martin"], (1, 2) ) def test_bad_group_shadow_lock_bound(): with assertions.assertRaises(ConstraintException): lcs = LineupConstraints() - lcs.add_group_constraint(['Spencer Ware', 'Amari Cooper'], 2) + lcs.add_group_constraint(["Spencer Ware", "Amari Cooper"], 2) def test_bad_group_shadow_lock_hi_lo_bound(): with assertions.assertRaises(ConstraintException): lcs = LineupConstraints() - lcs.add_group_constraint(['Spencer Ware', 'Amari Cooper'], (2, 2)) + lcs.add_group_constraint(["Spencer Ware", "Amari Cooper"], (2, 2)) def test_bad_group_shadow_ban_bound(): with assertions.assertRaises(ConstraintException): lcs = LineupConstraints() - lcs.add_group_constraint(['Spencer Ware', 'Amari Cooper'], 0) + lcs.add_group_constraint(["Spencer Ware", "Amari Cooper"], 0) def test_bad_group_shadow_ban_hi_lo_bound(): with assertions.assertRaises(ConstraintException): lcs = LineupConstraints() - lcs.add_group_constraint(['Spencer Ware', 'Amari Cooper'], (0, 0)) + lcs.add_group_constraint(["Spencer Ware", "Amari Cooper"], (0, 0)) def test_bad_group_duplicate_bounds(): with assertions.assertRaises(ConstraintException): lcs = LineupConstraints() - lcs.add_group_constraint(['Spencer Ware', 'Amari Cooper'], (1, 1)) + lcs.add_group_constraint(["Spencer Ware", "Amari Cooper"], (1, 1)) def test_bad_group_negative_min(): with assertions.assertRaises(ConstraintException): lcs = LineupConstraints() - lcs.add_group_constraint(['Spencer Ware', 'Amari Cooper'], (-1, 1)) + lcs.add_group_constraint(["Spencer Ware", "Amari Cooper"], (-1, 1)) def test_bad_group_zero_min(): with assertions.assertRaises(ConstraintException): lcs = LineupConstraints() - lcs.add_group_constraint(['Spencer Ware', 'Amari Cooper'], (0, 1)) + lcs.add_group_constraint(["Spencer Ware", "Amari Cooper"], (0, 1)) def test_bad_group_max(): with assertions.assertRaises(ConstraintException): lcs = LineupConstraints() - lcs.add_group_constraint(['Spencer Ware', 'Amari Cooper'], 3) + lcs.add_group_constraint(["Spencer Ware", "Amari Cooper"], 3) def test_bad_group_max_set(): with assertions.assertRaises(ConstraintException): lcs = LineupConstraints() - lcs.add_group_constraint(['Spencer Ware', 'Amari Cooper'], (1, 3)) + lcs.add_group_constraint(["Spencer Ware", "Amari Cooper"], (1, 3)) def test_bad_group_dup_player(): with assertions.assertRaises(ConstraintException): lcs = LineupConstraints() - lcs.add_group_constraint(['Amari Cooper', 'Amari Cooper'], 1) + lcs.add_group_constraint(["Amari Cooper", "Amari Cooper"], 1) def test_bad_group_bounds_type(): with assertions.assertRaises(ConstraintException): lcs = LineupConstraints() - lcs.add_group_constraint(['Spencer Ware', 'Amari Cooper'], '1') + lcs.add_group_constraint(["Spencer Ware", "Amari Cooper"], "1") def test_bad_group_too_many_bounds(): with assertions.assertRaises(ConstraintException): lcs = LineupConstraints() - lcs.add_group_constraint(['Spencer Ware', 'Amari Cooper'], (1, 1, 2)) + lcs.add_group_constraint(["Spencer Ware", "Amari Cooper"], (1, 1, 2)) def test_single_player_group(): with assertions.assertRaises(ConstraintException): lcs = LineupConstraints() - lcs.add_group_constraint(['Spencer Ware'], 1) + lcs.add_group_constraint(["Spencer Ware"], 1) def test_empty_group(): @@ -172,40 +176,40 @@ def test_empty_ban(): def test_ban_lock_conflict(): with assertions.assertRaises(ConstraintConflictException): lcs = LineupConstraints() - lcs.lock(['Will Fuller']) - lcs.ban(['Will Fuller']) + lcs.lock(["Will Fuller"]) + lcs.ban(["Will Fuller"]) def test_lock_ban_conflict(): with assertions.assertRaises(ConstraintConflictException): lcs = LineupConstraints() - lcs.ban(['Will Fuller']) - lcs.lock(['Will Fuller']) + lcs.ban(["Will Fuller"]) + lcs.lock(["Will Fuller"]) def test_lock_group_conflict(): with assertions.assertRaises(ConstraintConflictException): lcs = LineupConstraints() - lcs.lock(['Eli Manning']) - lcs.add_group_constraint(['Eli Manning', 'Doug Martin'], (1, 2)) + lcs.lock(["Eli Manning"]) + lcs.add_group_constraint(["Eli Manning", "Doug Martin"], (1, 2)) def test_group_lock_conflict(): with assertions.assertRaises(ConstraintConflictException): lcs = LineupConstraints() - lcs.add_group_constraint(['Eli Manning', 'Doug Martin'], (1, 2)) - lcs.lock(['Eli Manning']) + lcs.add_group_constraint(["Eli Manning", "Doug Martin"], (1, 2)) + lcs.lock(["Eli Manning"]) def test_ban_group_conflict(): with assertions.assertRaises(ConstraintConflictException): lcs = LineupConstraints() - lcs.ban(['Eli Manning']) - lcs.add_group_constraint(['Eli Manning', 'Doug Martin'], (1, 2)) + lcs.ban(["Eli Manning"]) + lcs.add_group_constraint(["Eli Manning", "Doug Martin"], (1, 2)) def test_group_ban_conflict(): with assertions.assertRaises(ConstraintConflictException): lcs = LineupConstraints() - lcs.add_group_constraint(['Eli Manning', 'Doug Martin'], (1, 2)) - lcs.ban(['Eli Manning']) + lcs.add_group_constraint(["Eli Manning", "Doug Martin"], (1, 2)) + lcs.ban(["Eli Manning"]) diff --git a/draftfast/test/test_mlb.py b/draftfast/test/test_mlb.py index 582b98e..a880da8 100644 --- a/draftfast/test/test_mlb.py +++ b/draftfast/test/test_mlb.py @@ -7,9 +7,9 @@ from draftfast.settings import CustomRule, OptimizerSettings CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) -salary_file = '{}/data/dk-mlb-salaries.csv'.format(CURRENT_DIR) +salary_file = "{}/data/dk-mlb-salaries.csv".format(CURRENT_DIR) -assertions = unittest.TestCase('__init__') +assertions = unittest.TestCase("__init__") def test_mlb_dk(): @@ -26,24 +26,22 @@ def test_mlb_dk(): # Test general position limits assertions.assertNotEqual(roster, None) - assertions.assertTrue('RP' in [x.pos for x in roster.players]) + assertions.assertTrue("RP" in [x.pos for x in roster.players]) def test_five_batters_max(): player_pool = [ - Player(pos='P', name='A', cost=5000, team='C'), - Player(pos='P', name='B', cost=5000, team='B'), - - Player(pos='1B', name='C', cost=5000, team='C'), - Player(pos='OF', name='H', cost=5000, team='C'), - Player(pos='OF', name='I', cost=5000, team='C'), - Player(pos='C', name='F', cost=5000, team='C'), - Player(pos='2B', name='D', cost=5000, team='C'), - Player(pos='2B', name='E', cost=5000, team='C'), - Player(pos='3B', name='E', cost=5000, team='C'), - - Player(pos='SS', name='G', cost=5000, team='Q'), - Player(pos='OF', name='J', cost=5000, team='G'), + Player(pos="P", name="A", cost=5000, team="C"), + Player(pos="P", name="B", cost=5000, team="B"), + Player(pos="1B", name="C", cost=5000, team="C"), + Player(pos="OF", name="H", cost=5000, team="C"), + Player(pos="OF", name="I", cost=5000, team="C"), + Player(pos="C", name="F", cost=5000, team="C"), + Player(pos="2B", name="D", cost=5000, team="C"), + Player(pos="2B", name="E", cost=5000, team="C"), + Player(pos="3B", name="E", cost=5000, team="C"), + Player(pos="SS", name="G", cost=5000, team="Q"), + Player(pos="OF", name="J", cost=5000, team="G"), ] roster = run( @@ -53,17 +51,13 @@ def test_five_batters_max(): ) assert roster is None - player_pool.append(Player(pos='3B', name='EA', cost=5000, team='A')) + player_pool.append(Player(pos="3B", name="EA", cost=5000, team="A")) roster = run( rule_set=rules.DK_MLB_RULE_SET, player_pool=player_pool, verbose=True, ) - c_in_roster = [ - x for x in roster.players - if x.team == 'C' - and x.pos != 'P' - ] + c_in_roster = [x for x in roster.players if x.team == "C" and x.pos != "P"] assert len(c_in_roster) < 6 @@ -77,7 +71,7 @@ def test_custom_rules(): ruleset=rules.DK_MLB_RULE_SET, ) for p in player_pool: - if p.team == 'ATL' and p.pos == '1B': + if p.team == "ATL" and p.pos == "1B": p.proj = 1_000 def comp(sum, a, b): @@ -88,33 +82,25 @@ def comp(sum, a, b): custom_rules.append( CustomRule( # Given 1B in optimized lineup - group_a=lambda p: - p.pos == '1B' and p.team == 'ATL', - + group_a=lambda p: p.pos == "1B" and p.team == "ATL", # Ensure the stack is four players - group_b=lambda p: - '1B' not in p.pos and p.team == 'ATL', # batters only - + group_b=lambda p: "1B" not in p.pos + and p.team == "ATL", # batters only comparison=comp, ) ) custom_rules.append( CustomRule( # Given 1B in optimized lineup - group_a=lambda p: - p.pos == '1B' and p.team == 'BOS', - + group_a=lambda p: p.pos == "1B" and p.team == "BOS", # Ensure the stack is four players - group_b=lambda p: - '1B' not in p.pos and p.team == 'BOS', # batters only - + group_b=lambda p: "1B" not in p.pos + and p.team == "BOS", # batters only comparison=comp, ) ) - settings = OptimizerSettings( - custom_rules=custom_rules - ) + settings = OptimizerSettings(custom_rules=custom_rules) roster = run( rule_set=rules.DK_MLB_RULE_SET, @@ -122,7 +108,12 @@ def comp(sum, a, b): verbose=True, optimizer_settings=settings, ) - team_for_first = [p for p in roster.players if p.pos == '1B'][0].team - total = len([p for p in roster.players - if p.team == team_for_first and 'P' not in p.pos]) + team_for_first = [p for p in roster.players if p.pos == "1B"][0].team + total = len( + [ + p + for p in roster.players + if p.team == team_for_first and "P" not in p.pos + ] + ) assert total > 3, f"{total} below 4" diff --git a/draftfast/test/test_nba_general.py b/draftfast/test/test_nba_general.py index 240fb42..11ca926 100644 --- a/draftfast/test/test_nba_general.py +++ b/draftfast/test/test_nba_general.py @@ -5,39 +5,38 @@ from draftfast import rules from draftfast.csv_parse import salary_download as sd -assertions = unittest.TestCase('__init__') +assertions = unittest.TestCase("__init__") def test_general_guard(): - pg = Player(name='A', cost=1, proj=1, pos='PG') - assertions.assertEqual(pg.nba_general_position, 'G') - sg = Player(name='A', cost=1, proj=1, pos='SG') - assertions.assertEqual(sg.nba_general_position, 'G') + pg = Player(name="A", cost=1, proj=1, pos="PG") + assertions.assertEqual(pg.nba_general_position, "G") + sg = Player(name="A", cost=1, proj=1, pos="SG") + assertions.assertEqual(sg.nba_general_position, "G") def test_general_forward(): - pg = Player(name='A', cost=1, proj=1, pos='SF') - assertions.assertEqual(pg.nba_general_position, 'F') - sg = Player(name='A', cost=1, proj=1, pos='PF') - assertions.assertEqual(sg.nba_general_position, 'F') + pg = Player(name="A", cost=1, proj=1, pos="SF") + assertions.assertEqual(pg.nba_general_position, "F") + sg = Player(name="A", cost=1, proj=1, pos="PF") + assertions.assertEqual(sg.nba_general_position, "F") def test_general_center(): - pg = Player(name='A', cost=1, proj=1, pos='C') - assertions.assertEqual(pg.nba_general_position, 'C') + pg = Player(name="A", cost=1, proj=1, pos="C") + assertions.assertEqual(pg.nba_general_position, "C") def test_optimize_with_general(): def get_player_count_at_pos(roster, pos): - return len([ - p for p in roster.players - if p.nba_general_position == pos - ]) + return len( + [p for p in roster.players if p.nba_general_position == pos] + ) current_dir = os.path.dirname(os.path.abspath(__file__)) players = sd.generate_players_from_csvs( game=rules.DRAFT_KINGS, - salary_file_location='{}/data/dk-nba-salaries.csv'.format(current_dir) + salary_file_location="{}/data/dk-nba-salaries.csv".format(current_dir), ) rosters = [] @@ -65,12 +64,12 @@ def get_player_count_at_pos(roster, pos): assertions.assertEqual(rosters[i], rosters[0]) assertions.assertEqual(rosters[i].projected(), 279.53) - assertions.assertTrue(get_player_count_at_pos( - rosters[i], 'G') in [3, 4] + assertions.assertTrue( + get_player_count_at_pos(rosters[i], "G") in [3, 4] ) - assertions.assertTrue(get_player_count_at_pos( - rosters[i], 'F') in [3, 4] + assertions.assertTrue( + get_player_count_at_pos(rosters[i], "F") in [3, 4] ) - assertions.assertTrue(get_player_count_at_pos( - rosters[i], 'C') in [1, 2] + assertions.assertTrue( + get_player_count_at_pos(rosters[i], "C") in [1, 2] ) diff --git a/draftfast/test/test_nfl_showdown.py b/draftfast/test/test_nfl_showdown.py index 0526a67..7337494 100644 --- a/draftfast/test/test_nfl_showdown.py +++ b/draftfast/test/test_nfl_showdown.py @@ -7,59 +7,83 @@ from draftfast.showdown.orm import ShowdownPlayer from draftfast.lineup_constraints import LineupConstraints -assertions = unittest.TestCase('__init__') +assertions = unittest.TestCase("__init__") def _build_mock_player_pool(): player_pool = [ - Player(name='A1', cost=5500, proj=100, pos='QB', - team='X', matchup='X@Y'), - Player(name='A2', cost=5500, proj=41, pos='QB', - team='X', matchup='X@Y'), - Player(name='A11', cost=5500, proj=50, pos='WR', - team='X', matchup='X@Y'), - Player(name='A3', cost=5500, proj=42, pos='WR', - team='X', matchup='X@Y'), - Player(name='A4', cost=5500, proj=43, pos='WR', - team='X', matchup='X@Y'), - Player(name='A5', cost=5500, proj=44, pos='WR', - team='X', matchup='X@Y'), - Player(name='A6', cost=5500, proj=45, pos='RB', - team='X', matchup='X@Y'), - Player(name='A7', cost=5500, proj=46, pos='RB', - team='X', matchup='X@Y'), - Player(name='A8', cost=5500, proj=47, pos='RB', - team='X', matchup='X@Y'), - Player(name='A9', cost=5500, proj=48, pos='TE', - team='X', matchup='X@Y'), - Player(name='A10', cost=5500, proj=49, pos='TE', - team='X', matchup='X@Y'), - Player(name='A12', cost=5500, proj=51, pos='DST', - team='X', matchup='X@Y'), - Player(name='A14', cost=5500, proj=40, pos='QB', - team='Y', matchup='X@Y'), - Player(name='A21', cost=5500, proj=41, pos='QB', - team='Y', matchup='X@Y'), - Player(name='A11', cost=5500, proj=50, pos='WR', - team='Y', matchup='X@Y'), - Player(name='A31', cost=5500, proj=42, pos='WR', - team='Y', matchup='X@Y'), - Player(name='A41', cost=5500, proj=43, pos='WR', - team='Y', matchup='X@Y'), - Player(name='A51', cost=5500, proj=54, pos='WR', - team='Y', matchup='X@Y'), - Player(name='A61', cost=5500, proj=45, pos='RB', - team='Y', matchup='X@Y'), - Player(name='A71', cost=5500, proj=56, pos='RB', - team='Y', matchup='X@Y'), - Player(name='A81', cost=5500, proj=47, pos='RB', - team='Y', matchup='X@Y'), - Player(name='A91', cost=5500, proj=48, pos='TE', - team='Y', matchup='X@Y'), - Player(name='A110', cost=5500, proj=49, pos='TE', - team='Y', matchup='X@Y'), - Player(name='A112', cost=5500, proj=60, pos='DST', - team='Y', matchup='X@Y'), + Player( + name="A1", cost=5500, proj=100, pos="QB", team="X", matchup="X@Y" + ), + Player( + name="A2", cost=5500, proj=41, pos="QB", team="X", matchup="X@Y" + ), + Player( + name="A11", cost=5500, proj=50, pos="WR", team="X", matchup="X@Y" + ), + Player( + name="A3", cost=5500, proj=42, pos="WR", team="X", matchup="X@Y" + ), + Player( + name="A4", cost=5500, proj=43, pos="WR", team="X", matchup="X@Y" + ), + Player( + name="A5", cost=5500, proj=44, pos="WR", team="X", matchup="X@Y" + ), + Player( + name="A6", cost=5500, proj=45, pos="RB", team="X", matchup="X@Y" + ), + Player( + name="A7", cost=5500, proj=46, pos="RB", team="X", matchup="X@Y" + ), + Player( + name="A8", cost=5500, proj=47, pos="RB", team="X", matchup="X@Y" + ), + Player( + name="A9", cost=5500, proj=48, pos="TE", team="X", matchup="X@Y" + ), + Player( + name="A10", cost=5500, proj=49, pos="TE", team="X", matchup="X@Y" + ), + Player( + name="A12", cost=5500, proj=51, pos="DST", team="X", matchup="X@Y" + ), + Player( + name="A14", cost=5500, proj=40, pos="QB", team="Y", matchup="X@Y" + ), + Player( + name="A21", cost=5500, proj=41, pos="QB", team="Y", matchup="X@Y" + ), + Player( + name="A11", cost=5500, proj=50, pos="WR", team="Y", matchup="X@Y" + ), + Player( + name="A31", cost=5500, proj=42, pos="WR", team="Y", matchup="X@Y" + ), + Player( + name="A41", cost=5500, proj=43, pos="WR", team="Y", matchup="X@Y" + ), + Player( + name="A51", cost=5500, proj=54, pos="WR", team="Y", matchup="X@Y" + ), + Player( + name="A61", cost=5500, proj=45, pos="RB", team="Y", matchup="X@Y" + ), + Player( + name="A71", cost=5500, proj=56, pos="RB", team="Y", matchup="X@Y" + ), + Player( + name="A81", cost=5500, proj=47, pos="RB", team="Y", matchup="X@Y" + ), + Player( + name="A91", cost=5500, proj=48, pos="TE", team="Y", matchup="X@Y" + ), + Player( + name="A110", cost=5500, proj=49, pos="TE", team="Y", matchup="X@Y" + ), + Player( + name="A112", cost=5500, proj=60, pos="DST", team="Y", matchup="X@Y" + ), ] def capt_boost(p): @@ -90,9 +114,9 @@ def test_nfl_dk_showdown_mock(): rule_set=rules.DK_NFL_SHOWDOWN_RULE_SET, player_pool=mock_dk_pool, optimizer_settings=OptimizerSettings( - showdown_teams=('X', 'Y'), + showdown_teams=("X", "Y"), ), - verbose=True + verbose=True, ) assertions.assertNotEqual(roster, None) @@ -106,16 +130,16 @@ def test_nfl_showdown_no_def_against_capt(): rule_set=rules.DK_NFL_SHOWDOWN_RULE_SET, player_pool=mock_dk_pool, optimizer_settings=OptimizerSettings( - showdown_teams=('X', 'Y'), + showdown_teams=("X", "Y"), no_defense_against_captain=True, ), - verbose=True + verbose=True, ) assertions.assertNotEqual(roster, None) assertions.assertEqual(roster.projected(), 408.0) for p in roster.players: - assertions.assertNotEqual(p.name, 'A112') + assertions.assertNotEqual(p.name, "A112") def test_nfl_showdown_lock_general(): @@ -125,17 +149,17 @@ def test_nfl_showdown_lock_general(): rule_set=rules.DK_NFL_SHOWDOWN_RULE_SET, player_pool=mock_dk_pool, optimizer_settings=OptimizerSettings( - showdown_teams=('X', 'Y'), + showdown_teams=("X", "Y"), no_defense_against_captain=True, ), constraints=LineupConstraints( - locked=['A14'], + locked=["A14"], ), - verbose=True + verbose=True, ) assertions.assertNotEqual(roster, None) assertions.assertEqual(roster.projected(), 399.0) - assertions.assertTrue('A14' in [x.name for x in roster.players]) + assertions.assertTrue("A14" in [x.name for x in roster.players]) def test_nfl_showdown_lock_captain(): @@ -145,18 +169,18 @@ def test_nfl_showdown_lock_captain(): rule_set=rules.DK_NFL_SHOWDOWN_RULE_SET, player_pool=mock_dk_pool, optimizer_settings=OptimizerSettings( - showdown_teams=('X', 'Y'), + showdown_teams=("X", "Y"), no_defense_against_captain=True, ), constraints=LineupConstraints( - position_locked=['A2 CPT X'], + position_locked=["A2 CPT X"], ), - verbose=True + verbose=True, ) assertions.assertNotEqual(roster, None) assertions.assertEqual(roster.projected(), 370.5) - cpt = [x for x in roster.players if x.pos == 'CPT'][0] - assertions.assertEqual('A2', cpt.name) + cpt = [x for x in roster.players if x.pos == "CPT"][0] + assertions.assertEqual("A2", cpt.name) def test_nfl_showdown_lock_flex(): @@ -166,22 +190,18 @@ def test_nfl_showdown_lock_flex(): rule_set=rules.DK_NFL_SHOWDOWN_RULE_SET, player_pool=mock_dk_pool, optimizer_settings=OptimizerSettings( - showdown_teams=('X', 'Y'), + showdown_teams=("X", "Y"), no_defense_against_captain=True, ), constraints=LineupConstraints( - position_locked=['A1 FLEX X'], + position_locked=["A1 FLEX X"], ), - verbose=True + verbose=True, ) assertions.assertNotEqual(roster, None) assertions.assertEqual(roster.projected(), 386.0) - flex = [ - x for x in roster.players - if x.pos == 'FLEX' - and x.name == 'A1' - ][0] - assertions.assertEqual('A1', flex.name) + flex = [x for x in roster.players if x.pos == "FLEX" and x.name == "A1"][0] + assertions.assertEqual("A1", flex.name) def test_nfl_showdown_ban_general(): @@ -191,17 +211,17 @@ def test_nfl_showdown_ban_general(): rule_set=rules.DK_NFL_SHOWDOWN_RULE_SET, player_pool=mock_dk_pool, optimizer_settings=OptimizerSettings( - showdown_teams=('X', 'Y'), + showdown_teams=("X", "Y"), no_defense_against_captain=True, ), constraints=LineupConstraints( - banned=['A1'], + banned=["A1"], ), - verbose=True + verbose=True, ) assertions.assertNotEqual(roster, None) assertions.assertEqual(roster.projected(), 334.0) - assertions.assertTrue('A1' not in [x.name for x in roster.players]) + assertions.assertTrue("A1" not in [x.name for x in roster.players]) def test_nfl_showdown_ban_specific(): @@ -211,19 +231,15 @@ def test_nfl_showdown_ban_specific(): rule_set=rules.DK_NFL_SHOWDOWN_RULE_SET, player_pool=mock_dk_pool, optimizer_settings=OptimizerSettings( - showdown_teams=('X', 'Y'), + showdown_teams=("X", "Y"), no_defense_against_captain=True, ), constraints=LineupConstraints( - position_banned=['A1 CPT X'], + position_banned=["A1 CPT X"], ), - verbose=True + verbose=True, ) assertions.assertNotEqual(roster, None) assertions.assertEqual(roster.projected(), 386.0) - flex = [ - x for x in roster.players - if x.pos == 'FLEX' - and x.name == 'A1' - ][0] - assertions.assertEqual('A1', flex.name) + flex = [x for x in roster.players if x.pos == "FLEX" and x.name == "A1"][0] + assertions.assertEqual("A1", flex.name) diff --git a/draftfast/test/test_nhl.py b/draftfast/test/test_nhl.py index e124468..effc244 100644 --- a/draftfast/test/test_nhl.py +++ b/draftfast/test/test_nhl.py @@ -6,9 +6,9 @@ from draftfast.settings import OptimizerSettings, Stack CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) -salary_file = '{}/data/dk-nhl-salaries.csv'.format(CURRENT_DIR) +salary_file = "{}/data/dk-nhl-salaries.csv".format(CURRENT_DIR) -assertions = unittest.TestCase('__init__') +assertions = unittest.TestCase("__init__") def test_nhl_dk(): @@ -37,17 +37,17 @@ def test_triple_stack(): verbose=True, optimizer_settings=OptimizerSettings( stacks=[ - Stack(team='TOR', count=3), - Stack(team='COL', count=3), - Stack(team='VAN', count=2), + Stack(team="TOR", count=3), + Stack(team="COL", count=3), + Stack(team="VAN", count=2), ] - ) + ), ) players = roster.sorted_players() - phi_players = [x for x in players if x.team == 'TOR'] - fla_players = [x for x in players if x.team == 'COL'] - nsh_players = [x for x in players if x.team == 'VAN'] + phi_players = [x for x in players if x.team == "TOR"] + fla_players = [x for x in players if x.team == "COL"] + nsh_players = [x for x in players if x.team == "VAN"] assertions.assertEqual(len(phi_players), 3) assertions.assertEqual(len(fla_players), 3) assertions.assertEqual(len(nsh_players), 2) diff --git a/draftfast/test/test_optimize.py b/draftfast/test/test_optimize.py index 5fa8991..4a3551d 100644 --- a/draftfast/test/test_optimize.py +++ b/draftfast/test/test_optimize.py @@ -8,44 +8,44 @@ from draftfast.settings import OptimizerSettings, Stack from draftfast.lineup_constraints import LineupConstraints -assertions = unittest.TestCase('__init__') +assertions = unittest.TestCase("__init__") mock_nba_pool = [ - Player(name='A1', cost=5500, proj=40, pos='PG'), - Player(name='A2', cost=5500, proj=41, pos='PG'), - Player(name='A11', cost=5500, proj=50, pos='PG'), - Player(name='A3', cost=5500, proj=42, pos='SG'), - Player(name='A4', cost=5500, proj=43, pos='SG'), - Player(name='A5', cost=5500, proj=44, pos='SF'), - Player(name='A6', cost=5500, proj=45, pos='SF'), - Player(name='A7', cost=5500, proj=46, pos='PF'), - Player(name='A8', cost=5500, proj=47, pos='PF'), - Player(name='A9', cost=5500, proj=48, pos='C'), - Player(name='A10', cost=5500, proj=49, pos='C'), + Player(name="A1", cost=5500, proj=40, pos="PG"), + Player(name="A2", cost=5500, proj=41, pos="PG"), + Player(name="A11", cost=5500, proj=50, pos="PG"), + Player(name="A3", cost=5500, proj=42, pos="SG"), + Player(name="A4", cost=5500, proj=43, pos="SG"), + Player(name="A5", cost=5500, proj=44, pos="SF"), + Player(name="A6", cost=5500, proj=45, pos="SF"), + Player(name="A7", cost=5500, proj=46, pos="PF"), + Player(name="A8", cost=5500, proj=47, pos="PF"), + Player(name="A9", cost=5500, proj=48, pos="C"), + Player(name="A10", cost=5500, proj=49, pos="C"), ] mock_nfl_pool = [ - Player(name='A1', cost=5500, proj=40, pos='QB'), - Player(name='A2', cost=5500, proj=41, pos='QB'), - Player(name='A11', cost=5500, proj=50, pos='WR'), - Player(name='A3', cost=5500, proj=42, pos='WR'), - Player(name='A4', cost=5500, proj=43, pos='WR'), - Player(name='A5', cost=5500, proj=44, pos='WR'), - Player(name='A6', cost=5500, proj=45, pos='RB'), - Player(name='A7', cost=5500, proj=46, pos='RB'), - Player(name='A8', cost=5500, proj=47, pos='RB'), - Player(name='A9', cost=5500, proj=48, pos='TE'), - Player(name='A10', cost=5500, proj=49, pos='TE'), - Player(name='A12', cost=5500, proj=51, pos='DST'), - Player(name='A13', cost=5500, proj=52, pos='DST'), + Player(name="A1", cost=5500, proj=40, pos="QB"), + Player(name="A2", cost=5500, proj=41, pos="QB"), + Player(name="A11", cost=5500, proj=50, pos="WR"), + Player(name="A3", cost=5500, proj=42, pos="WR"), + Player(name="A4", cost=5500, proj=43, pos="WR"), + Player(name="A5", cost=5500, proj=44, pos="WR"), + Player(name="A6", cost=5500, proj=45, pos="RB"), + Player(name="A7", cost=5500, proj=46, pos="RB"), + Player(name="A8", cost=5500, proj=47, pos="RB"), + Player(name="A9", cost=5500, proj=48, pos="TE"), + Player(name="A10", cost=5500, proj=49, pos="TE"), + Player(name="A12", cost=5500, proj=51, pos="DST"), + Player(name="A13", cost=5500, proj=52, pos="DST"), ] CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) -salary_file = '{}/data/dk-nfl-salaries.csv'.format(CURRENT_DIR) -fd_nfl_salary_file = '{}/data/fd-nfl-salaries.csv'.format(CURRENT_DIR) -projection_file = '{}/data/dk-nfl-projections.csv'.format(CURRENT_DIR) +salary_file = "{}/data/dk-nfl-salaries.csv".format(CURRENT_DIR) +fd_nfl_salary_file = "{}/data/fd-nfl-salaries.csv".format(CURRENT_DIR) +projection_file = "{}/data/dk-nfl-projections.csv".format(CURRENT_DIR) def test_nba_dk(): @@ -68,9 +68,7 @@ def test_nba_dk_with_csv(): def test_nba_fd(): roster = run( - rule_set=rules.FD_NBA_RULE_SET, - player_pool=mock_nba_pool, - verbose=True + rule_set=rules.FD_NBA_RULE_SET, player_pool=mock_nba_pool, verbose=True ) assertions.assertNotEqual(roster, None) @@ -90,12 +88,9 @@ def test_nfl_dk(): salary_file_location=salary_file, projection_file_location=projection_file, game=rules.DRAFT_KINGS, - ) roster = run( - rule_set=rules.DK_NFL_RULE_SET, - player_pool=players, - verbose=True + rule_set=rules.DK_NFL_RULE_SET, player_pool=players, verbose=True ) assertions.assertNotEqual(roster, None) @@ -108,9 +103,7 @@ def test_nfl_fd(): game=rules.FAN_DUEL, ) roster = run( - rule_set=rules.FD_NFL_RULE_SET, - player_pool=players, - verbose=True + rule_set=rules.FD_NFL_RULE_SET, player_pool=players, verbose=True ) assertions.assertNotEqual(roster, None) @@ -127,14 +120,14 @@ def test_multi_position(): rule_set=rules.DK_NFL_RULE_SET, player_pool=players, constraints=LineupConstraints( - locked=['Eli Manning'], + locked=["Eli Manning"], ), - verbose=True + verbose=True, ) assertions.assertNotEqual(roster, None) - multi_pos = [p for p in roster.players if p.name == 'Eli Manning'] + multi_pos = [p for p in roster.players if p.name == "Eli Manning"] assertions.assertEqual(len(multi_pos), 1) - assertions.assertEqual(multi_pos[0].pos, 'TE') + assertions.assertEqual(multi_pos[0].pos, "TE") def test_multi_roster_nfl(): @@ -144,9 +137,7 @@ def test_multi_roster_nfl(): game=rules.DRAFT_KINGS, ) roster = run( - rule_set=rules.DK_NFL_RULE_SET, - player_pool=players, - verbose=True + rule_set=rules.DK_NFL_RULE_SET, player_pool=players, verbose=True ) second_roster = run( rule_set=rules.DK_NFL_RULE_SET, @@ -154,7 +145,7 @@ def test_multi_roster_nfl(): optimizer_settings=OptimizerSettings( existing_rosters=[roster], ), - verbose=True + verbose=True, ) assertions.assertNotEqual(roster, None) @@ -207,12 +198,10 @@ def test_uniques_nba(): crossover_a = list(set(players).intersection(second_players)) crossover_b = list(set(players).intersection(third_players)) assertions.assertEqual( - len(crossover_a), - rules.DK_NBA_RULE_SET.roster_size - 1 + len(crossover_a), rules.DK_NBA_RULE_SET.roster_size - 1 ) assertions.assertEqual( - len(crossover_b), - rules.DK_NBA_RULE_SET.roster_size - 2 + len(crossover_b), rules.DK_NBA_RULE_SET.roster_size - 2 ) @@ -228,12 +217,12 @@ def test_respect_lock(): player_pool=players, verbose=True, constraints=LineupConstraints( - locked=['Andrew Luck'], + locked=["Andrew Luck"], ), ) qb = roster.sorted_players()[0] - assertions.assertEqual(qb.pos, 'QB') - assertions.assertEqual(qb.name, 'Andrew Luck') + assertions.assertEqual(qb.pos, "QB") + assertions.assertEqual(qb.name, "Andrew Luck") def test_respect_ban(): @@ -248,11 +237,11 @@ def test_respect_ban(): player_pool=players, verbose=True, constraints=LineupConstraints( - banned=['Eli Manning'], + banned=["Eli Manning"], ), ) for player in roster.sorted_players(): - assertions.assertNotEqual(player.name, 'Eli Manning') + assertions.assertNotEqual(player.name, "Eli Manning") def test_respect_group1(): @@ -262,22 +251,20 @@ def test_respect_group1(): game=rules.DRAFT_KINGS, ) - grouped_players = ('DeAndre Hopkins', 'Amari Cooper', 'Sammy Watkins') + grouped_players = ("DeAndre Hopkins", "Amari Cooper", "Sammy Watkins") roster = run( rule_set=rules.DK_NFL_RULE_SET, player_pool=players, verbose=True, constraints=LineupConstraints( - groups=[ - [grouped_players, 2] - ], + groups=[[grouped_players, 2]], ), ) - group_count = len([ - x for x in roster.sorted_players() if x.name in grouped_players - ]) + group_count = len( + [x for x in roster.sorted_players() if x.name in grouped_players] + ) assertions.assertEqual(group_count, 2) @@ -289,11 +276,11 @@ def test_respect_group2(): ) grouped_players = ( - 'Ryan Fitzpatrick', - 'Lamar Miller', - 'DeAndre Hopkins', - 'Amari Cooper', - 'Sammy Watkins' + "Ryan Fitzpatrick", + "Lamar Miller", + "DeAndre Hopkins", + "Amari Cooper", + "Sammy Watkins", ) roster = run( @@ -301,15 +288,13 @@ def test_respect_group2(): player_pool=players, verbose=True, constraints=LineupConstraints( - groups=[ - [grouped_players, (2, 3)] - ], + groups=[[grouped_players, (2, 3)]], ), ) - group_count = len([ - x for x in roster.sorted_players() if x.name in grouped_players - ]) + group_count = len( + [x for x in roster.sorted_players() if x.name in grouped_players] + ) assertions.assertTrue(group_count >= 2 and group_count <= 3) @@ -321,11 +306,11 @@ def test_respect_group3(): ) grouped_players = ( - 'Ryan Fitzpatrick', - 'Lamar Miller', - 'DeAndre Hopkins', - 'Amari Cooper', - 'Sammy Watkins' + "Ryan Fitzpatrick", + "Lamar Miller", + "DeAndre Hopkins", + "Amari Cooper", + "Sammy Watkins", ) roster = run( @@ -333,15 +318,13 @@ def test_respect_group3(): player_pool=players, verbose=True, constraints=LineupConstraints( - groups=[ - [grouped_players, 1] - ], + groups=[[grouped_players, 1]], ), ) - group_count = len([ - x for x in roster.sorted_players() if x.name in grouped_players - ]) + group_count = len( + [x for x in roster.sorted_players() if x.name in grouped_players] + ) assertions.assertTrue(group_count == 1) @@ -355,21 +338,21 @@ def test_stack(): rule_set=rules.DK_NFL_RULE_SET, player_pool=players, optimizer_settings=OptimizerSettings( - stacks=[ - Stack(team='NE', count=5) - ] + stacks=[Stack(team="NE", count=5)] ), verbose=True, ) - ne_players_count = len([ - p for p in roster.sorted_players() - if p.team == 'NE' - ]) + ne_players_count = len( + [p for p in roster.sorted_players() if p.team == "NE"] + ) assertions.assertEqual(5, ne_players_count) - ne_def = len([ - p for p in roster.sorted_players() - if p.team == 'NE' and p.pos == 'DST' - ]) + ne_def = len( + [ + p + for p in roster.sorted_players() + if p.team == "NE" and p.pos == "DST" + ] + ) assertions.assertEqual(ne_def, 1) @@ -385,29 +368,34 @@ def test_custom_stack(): optimizer_settings=OptimizerSettings( stacks=[ Stack( - team='NE', + team="NE", count=5, - stack_lock_pos=['QB'], - stack_eligible_pos=['WR'], + stack_lock_pos=["QB"], + stack_eligible_pos=["WR"], ) ] ), verbose=True, ) - ne_players_count = len([ - p for p in roster.sorted_players() - if p.team == 'NE' - ]) + ne_players_count = len( + [p for p in roster.sorted_players() if p.team == "NE"] + ) assertions.assertEqual(5, ne_players_count) - ne_def = len([ - p for p in roster.sorted_players() - if p.team == 'NE' and p.pos == 'DST' - ]) + ne_def = len( + [ + p + for p in roster.sorted_players() + if p.team == "NE" and p.pos == "DST" + ] + ) assertions.assertEqual(ne_def, 0) - wides = len([ - p for p in roster.sorted_players() - if p.team == 'NE' and p.pos == 'WR' - ]) + wides = len( + [ + p + for p in roster.sorted_players() + if p.team == "NE" and p.pos == "WR" + ] + ) assertions.assertEqual(wides, 4) @@ -422,19 +410,14 @@ def test_force_combo(): rule_set=rules.DK_NFL_RULE_SET, player_pool=players, optimizer_settings=OptimizerSettings( - stacks=[ - Stack(team='NE', count=5) - ] + stacks=[Stack(team="NE", count=5)] ), constraints=LineupConstraints( - locked=['Sam Bradford'], + locked=["Sam Bradford"], ), ) qb = roster.sorted_players()[0] - team_count = len([ - x for x in roster.sorted_players() - if x.team == qb.team - ]) + team_count = len([x for x in roster.sorted_players() if x.team == qb.team]) assertions.assertEqual(team_count, 1) # QB/WR combo @@ -449,24 +432,28 @@ def test_force_combo(): optimizer_settings=OptimizerSettings( force_combo=True, ), - constraints=LineupConstraints( - banned=['Ryan Fitzpatrick'] - ), + constraints=LineupConstraints(banned=["Ryan Fitzpatrick"]), verbose=True, ) qb = roster.sorted_players()[0] - assertions.assertEqual(qb.pos, 'QB') + assertions.assertEqual(qb.pos, "QB") - wr_team_count = len([ - x for x in roster.sorted_players() - if x.team == qb.team and x.pos == 'WR' - ]) + wr_team_count = len( + [ + x + for x in roster.sorted_players() + if x.team == qb.team and x.pos == "WR" + ] + ) assertions.assertEqual(wr_team_count, 1) - te_team_count = len([ - x for x in roster.sorted_players() - if x.team == qb.team and x.pos == 'TE' - ]) + te_team_count = len( + [ + x + for x in roster.sorted_players() + if x.team == qb.team and x.pos == "TE" + ] + ) assertions.assertEqual(te_team_count, 0) @@ -485,17 +472,20 @@ def test_te_combo(): combo_allow_te=True, ), constraints=LineupConstraints( - banned=['Kellen Davis'], - locked=['Philip Rivers'], + banned=["Kellen Davis"], + locked=["Philip Rivers"], ), verbose=True, ) qb = roster.sorted_players()[0] - assertions.assertEqual(qb.pos, 'QB') - team_count = len([ - x for x in roster.sorted_players() - if x.team == qb.team and x.pos == 'TE' - ]) + assertions.assertEqual(qb.pos, "QB") + team_count = len( + [ + x + for x in roster.sorted_players() + if x.team == qb.team and x.pos == "TE" + ] + ) assertions.assertEqual(team_count, 1) # make sure WR/QB still works @@ -512,16 +502,19 @@ def test_te_combo(): combo_allow_te=True, ), constraints=LineupConstraints( - locked=['Andrew Luck'], + locked=["Andrew Luck"], ), verbose=True, ) qb = roster.sorted_players()[0] - assertions.assertEqual(qb.pos, 'QB') - team_count = len([ - x for x in roster.sorted_players() - if x.team == qb.team and x.pos == 'WR' - ]) + assertions.assertEqual(qb.pos, "QB") + team_count = len( + [ + x + for x in roster.sorted_players() + if x.team == qb.team and x.pos == "WR" + ] + ) assertions.assertEqual(team_count, 1) @@ -535,20 +528,18 @@ def test_impossible_constraints(): rule_set=rules.DK_NFL_RULE_SET, player_pool=players, optimizer_settings=OptimizerSettings( - stacks=[ - Stack(team='NE', count=100) - ], - no_offense_against_defense=True + stacks=[Stack(team="NE", count=100)], + no_offense_against_defense=True, ), constraints=LineupConstraints( - banned=['Sammy Watkins', 'Kellen Davis'], - locked=['Spencer Ware'], + banned=["Sammy Watkins", "Kellen Davis"], + locked=["Spencer Ware"], groups=[ - [('Philip Rivers', 'Sam Bradford', 'Andrew Luck'), 2], - [('Saints', 'Alshon Jeffery', 'Lamar Miller'), (1, 3)] - ] + [("Philip Rivers", "Sam Bradford", "Andrew Luck"), 2], + [("Saints", "Alshon Jeffery", "Lamar Miller"), (1, 3)], + ], ), - verbose=True + verbose=True, ) assertions.assertEqual(roster, None) @@ -556,31 +547,67 @@ def test_impossible_constraints(): def test_multi_position_group_constraint(): players = [ - Player(name='A', cost=5500, proj=400, pos='QB', - possible_positions='QB/WR', multi_position=True), - Player(name='A', cost=5500, proj=400, pos='WR', - possible_positions='QB/WR', multi_position=True), - Player(name='B', cost=5500, proj=41, pos='QB'), - Player(name='C', cost=5500, proj=500, pos='WR', - possible_positions='RB/WR', multi_position=True), - Player(name='C', cost=5500, proj=500, pos='RB', - possible_positions='RB/WR', multi_position=True), - Player(name='D', cost=5500, proj=42, pos='WR'), - Player(name='E', cost=5500, proj=43, pos='WR'), - Player(name='F', cost=5500, proj=44, pos='WR'), - Player(name='G', cost=5500, proj=45, pos='RB'), - Player(name='H', cost=5500, proj=46, pos='RB'), - Player(name='I', cost=5500, proj=47, pos='RB'), - Player(name='J', cost=5500, proj=480, pos='TE', - possible_positions='TE/WR', multi_position=True), - Player(name='J', cost=5500, proj=480, pos='WR', - possible_positions='TE/WR', multi_position=True), - Player(name='K', cost=5500, proj=49, pos='TE'), - Player(name='L', cost=5500, proj=51, pos='DST'), - Player(name='M', cost=5500, proj=52, pos='DST'), + Player( + name="A", + cost=5500, + proj=400, + pos="QB", + possible_positions="QB/WR", + multi_position=True, + ), + Player( + name="A", + cost=5500, + proj=400, + pos="WR", + possible_positions="QB/WR", + multi_position=True, + ), + Player(name="B", cost=5500, proj=41, pos="QB"), + Player( + name="C", + cost=5500, + proj=500, + pos="WR", + possible_positions="RB/WR", + multi_position=True, + ), + Player( + name="C", + cost=5500, + proj=500, + pos="RB", + possible_positions="RB/WR", + multi_position=True, + ), + Player(name="D", cost=5500, proj=42, pos="WR"), + Player(name="E", cost=5500, proj=43, pos="WR"), + Player(name="F", cost=5500, proj=44, pos="WR"), + Player(name="G", cost=5500, proj=45, pos="RB"), + Player(name="H", cost=5500, proj=46, pos="RB"), + Player(name="I", cost=5500, proj=47, pos="RB"), + Player( + name="J", + cost=5500, + proj=480, + pos="TE", + possible_positions="TE/WR", + multi_position=True, + ), + Player( + name="J", + cost=5500, + proj=480, + pos="WR", + possible_positions="TE/WR", + multi_position=True, + ), + Player(name="K", cost=5500, proj=49, pos="TE"), + Player(name="L", cost=5500, proj=51, pos="DST"), + Player(name="M", cost=5500, proj=52, pos="DST"), ] - grouped_players = ('A', 'C', 'J') + grouped_players = ("A", "C", "J") roster = run( rule_set=rules.DK_NFL_RULE_SET, @@ -590,12 +617,12 @@ def test_multi_position_group_constraint(): [grouped_players, 2], ] ), - verbose=True + verbose=True, ) - group_count = len([ - x for x in roster.sorted_players() if x.name in grouped_players - ]) + group_count = len( + [x for x in roster.sorted_players() if x.name in grouped_players] + ) assertions.assertEqual(group_count, 2) assertions.assertEqual(roster.projected(), 1304) @@ -607,7 +634,7 @@ def test_multi_position_group_constraint2(): game=rules.DRAFT_KINGS, ) - grouped_players = ('Eli Manning', 'Dez Bryant', 'Geno Smith') + grouped_players = ("Eli Manning", "Dez Bryant", "Geno Smith") roster = run( rule_set=rules.DK_NFL_RULE_SET, @@ -617,65 +644,83 @@ def test_multi_position_group_constraint2(): [grouped_players, 2], ] ), - verbose=True + verbose=True, ) - group_count = len([ - x for x in roster.sorted_players() if x.name in grouped_players - ]) + group_count = len( + [x for x in roster.sorted_players() if x.name in grouped_players] + ) assertions.assertEqual(group_count, 2) assertions.assertAlmostEqual(roster.projected(), 120.89999999999999) def test_no_opposing_def_dk_nfl_mock(): mock_pool = [ - Player(name='A1', cost=5500, proj=40, pos='QB', team='X', - matchup='X@Y'), - Player(name='A2', cost=5500, proj=41, pos='QB', team='Y', - matchup='X@Y'), - Player(name='A11', cost=5500, proj=50, pos='WR', team='X', - matchup='X@Y'), - Player(name='A3', cost=5500, proj=42, pos='WR', team='Y', - matchup='X@Y'), - Player(name='A4', cost=5500, proj=43, pos='WR', team='X', - matchup='X@Y'), - Player(name='A5', cost=5500, proj=44, pos='WR', team='Y', - matchup='X@Y'), - Player(name='A111', cost=5500, proj=50, pos='WR', team='X', - matchup='X@Y'), - Player(name='A31', cost=5500, proj=42, pos='WR', team='Y', - matchup='X@Y'), - Player(name='A41', cost=5500, proj=62, pos='WR', team='X', - matchup='X@Y'), - Player(name='A51', cost=5500, proj=63, pos='WR', team='Y', - matchup='X@Y'), - Player(name='A6', cost=5500, proj=45, pos='RB', team='X', - matchup='X@Y'), - Player(name='A7', cost=5500, proj=46, pos='RB', team='Y', - matchup='X@Y'), - Player(name='A8', cost=5500, proj=47, pos='RB', team='X', - matchup='X@Y'), - Player(name='A71', cost=5500, proj=46, pos='RB', team='Y', - matchup='X@Y'), - Player(name='A81', cost=5500, proj=47, pos='RB', team='X', - matchup='X@Y'), - Player(name='A711', cost=5500, proj=46, pos='RB', team='Y', - matchup='X@Y'), - Player(name='A9', cost=5500, proj=48, pos='TE', team='X', - matchup='X@Y'), - Player(name='A10', cost=5500, proj=49, pos='TE', team='Y', - matchup='X@Y'), - Player(name='A12', cost=5500, proj=51, pos='DST', team='X', - matchup='X@Y'), - Player(name='A13', cost=5500, proj=500, pos='DST', team='Y', - matchup='X@Y'), + Player( + name="A1", cost=5500, proj=40, pos="QB", team="X", matchup="X@Y" + ), + Player( + name="A2", cost=5500, proj=41, pos="QB", team="Y", matchup="X@Y" + ), + Player( + name="A11", cost=5500, proj=50, pos="WR", team="X", matchup="X@Y" + ), + Player( + name="A3", cost=5500, proj=42, pos="WR", team="Y", matchup="X@Y" + ), + Player( + name="A4", cost=5500, proj=43, pos="WR", team="X", matchup="X@Y" + ), + Player( + name="A5", cost=5500, proj=44, pos="WR", team="Y", matchup="X@Y" + ), + Player( + name="A111", cost=5500, proj=50, pos="WR", team="X", matchup="X@Y" + ), + Player( + name="A31", cost=5500, proj=42, pos="WR", team="Y", matchup="X@Y" + ), + Player( + name="A41", cost=5500, proj=62, pos="WR", team="X", matchup="X@Y" + ), + Player( + name="A51", cost=5500, proj=63, pos="WR", team="Y", matchup="X@Y" + ), + Player( + name="A6", cost=5500, proj=45, pos="RB", team="X", matchup="X@Y" + ), + Player( + name="A7", cost=5500, proj=46, pos="RB", team="Y", matchup="X@Y" + ), + Player( + name="A8", cost=5500, proj=47, pos="RB", team="X", matchup="X@Y" + ), + Player( + name="A71", cost=5500, proj=46, pos="RB", team="Y", matchup="X@Y" + ), + Player( + name="A81", cost=5500, proj=47, pos="RB", team="X", matchup="X@Y" + ), + Player( + name="A711", cost=5500, proj=46, pos="RB", team="Y", matchup="X@Y" + ), + Player( + name="A9", cost=5500, proj=48, pos="TE", team="X", matchup="X@Y" + ), + Player( + name="A10", cost=5500, proj=49, pos="TE", team="Y", matchup="X@Y" + ), + Player( + name="A12", cost=5500, proj=51, pos="DST", team="X", matchup="X@Y" + ), + Player( + name="A13", cost=5500, proj=500, pos="DST", team="Y", matchup="X@Y" + ), ] # mock pool is constructed such that optimal lineup has qb opposing dst roster = run( - rule_set=rules.DK_NFL_RULE_SET, - player_pool=mock_pool, - verbose=True + rule_set=rules.DK_NFL_RULE_SET, player_pool=mock_pool, verbose=True ) assertions.assertEqual(roster.projected(), 909) @@ -687,10 +732,8 @@ def test_no_opposing_def_dk_nfl_mock(): roster = run( rule_set=rules.DK_NFL_RULE_SET, player_pool=mock_pool, - optimizer_settings=OptimizerSettings( - no_offense_against_defense=True - ), - verbose=True + optimizer_settings=OptimizerSettings(no_offense_against_defense=True), + verbose=True, ) assertions.assertEqual(roster, None) @@ -703,29 +746,28 @@ def test_no_opposing_def_dk_nfl_mock(): min_teams=1, no_offense_against_defense=True, ), - verbose=True + verbose=True, ) assertions.assertEqual(roster.projected(), 877) assertions.assertEqual(len(set([p.team for p in roster.players])), 1) # add a player from a third team, min 2 teams - mock_pool.append(Player( - name='B2', cost=5500, proj=70, pos='QB', team='Q', matchup='Q@Z' - ) + mock_pool.append( + Player( + name="B2", cost=5500, proj=70, pos="QB", team="Q", matchup="Q@Z" + ) ) roster = run( rule_set=rules.DK_NFL_RULE_SET, player_pool=deepcopy(mock_pool), - optimizer_settings=OptimizerSettings( - no_offense_against_defense=True - ), - verbose=True + optimizer_settings=OptimizerSettings(no_offense_against_defense=True), + verbose=True, ) for p in roster.players: if p.pos in rules.DK_NFL_RULE_SET.offensive_positions: - assertions.assertNotEqual(p.team, 'X') + assertions.assertNotEqual(p.team, "X") def test_no_opposing_def_dk_nfl(): @@ -738,30 +780,22 @@ def test_no_opposing_def_dk_nfl(): roster = run( rule_set=rules.DK_NFL_RULE_SET, player_pool=players, - optimizer_settings=OptimizerSettings( - no_offense_against_defense=True - ), - constraints=LineupConstraints( - locked=['Bengals'] - ), - verbose=True + optimizer_settings=OptimizerSettings(no_offense_against_defense=True), + constraints=LineupConstraints(locked=["Bengals"]), + verbose=True, ) for p in roster.players: if p.pos in rules.DK_NFL_RULE_SET.offensive_positions: - assertions.assertNotEqual(p.team, 'CIN') + assertions.assertNotEqual(p.team, "CIN") # force impossible lineup roster = run( rule_set=rules.DK_NFL_RULE_SET, player_pool=players, - optimizer_settings=OptimizerSettings( - no_offense_against_defense=True - ), - constraints=LineupConstraints( - locked=['Bengals', 'Ryan Fitzpatrick'] - ), - verbose=True + optimizer_settings=OptimizerSettings(no_offense_against_defense=True), + constraints=LineupConstraints(locked=["Bengals", "Ryan Fitzpatrick"]), + verbose=True, ) assertions.assertEqual(roster, None) @@ -775,32 +809,26 @@ def test_no_opposing_def_fd_nfl(): roster = run( rule_set=rules.FD_NFL_RULE_SET, player_pool=players, - optimizer_settings=OptimizerSettings( - no_offense_against_defense=True - ), - constraints=LineupConstraints( - locked=['Jacksonville Jaguars'] - ), - verbose=True + optimizer_settings=OptimizerSettings(no_offense_against_defense=True), + constraints=LineupConstraints(locked=["Jacksonville Jaguars"]), + verbose=True, ) assertions.assertNotEqual(roster, None) for p in roster.players: if p.pos in rules.DK_NFL_RULE_SET.offensive_positions: - assertions.assertNotEqual(p.team, 'IND') + assertions.assertNotEqual(p.team, "IND") # force impossible lineup roster = run( rule_set=rules.FD_NFL_RULE_SET, player_pool=players, - optimizer_settings=OptimizerSettings( - no_offense_against_defense=True - ), + optimizer_settings=OptimizerSettings(no_offense_against_defense=True), constraints=LineupConstraints( - locked=['Eric Ebron', 'Jacksonville Jaguars'] + locked=["Eric Ebron", "Jacksonville Jaguars"] ), - verbose=True + verbose=True, ) assertions.assertEqual(roster, None) @@ -814,13 +842,9 @@ def test_no_mutate_side_effect(): run( rule_set=rules.FD_NFL_RULE_SET, player_pool=players, - optimizer_settings=OptimizerSettings( - no_offense_against_defense=True - ), - constraints=LineupConstraints( - locked=['Tom Brady'] - ), - verbose=True + optimizer_settings=OptimizerSettings(no_offense_against_defense=True), + constraints=LineupConstraints(locked=["Tom Brady"]), + verbose=True, ) - brady = next((p for p in players if p.name == 'Tom Brady')) + brady = next((p for p in players if p.name == "Tom Brady")) assertions.assertEqual(brady.lock, False) diff --git a/draftfast/test/test_pickem.py b/draftfast/test/test_pickem.py index cfd2c20..bd3f1d9 100644 --- a/draftfast/test/test_pickem.py +++ b/draftfast/test/test_pickem.py @@ -4,7 +4,7 @@ from draftfast.settings import PlayerPoolSettings from draftfast.lineup_constraints import LineupConstraints -assertions = unittest.TestCase('__init__') +assertions = unittest.TestCase("__init__") def _generate_player(name, proj, tier, **kwargs): @@ -13,41 +13,38 @@ def _generate_player(name, proj, tier, **kwargs): name=name, proj=proj, tier=tier, - pos=kwargs.get('pos'), - team=kwargs.get('team'), - matchup=kwargs.get('matchup'), - average_score=kwargs.get('average_score', 0), + pos=kwargs.get("pos"), + team=kwargs.get("team"), + matchup=kwargs.get("matchup"), + average_score=kwargs.get("average_score", 0), ) -_BOS = 'BOS' -_GS = 'GS' +_BOS = "BOS" +_GS = "GS" def _generate_test_player_data(): return [ - _generate_player('A', 50, pickem_orm.T1, team=_BOS), - _generate_player('B', 49, pickem_orm.T1, team=_GS), - _generate_player('C', 48, pickem_orm.T2, team=_BOS), - _generate_player('D', 47, pickem_orm.T2, team=_GS), - _generate_player('E', 46, pickem_orm.T3, team=_BOS), - _generate_player('F', 45, pickem_orm.T3, team=_GS), - _generate_player('G', 44, pickem_orm.T4, team=_BOS), - _generate_player('H', 43, pickem_orm.T4, team=_GS), - _generate_player('I', 42, pickem_orm.T5, team=_BOS), - _generate_player('J', 41, pickem_orm.T5, team=_GS), - _generate_player('K', 40, pickem_orm.T6, team=_BOS), - _generate_player('L', 39, pickem_orm.T6, team=_GS), + _generate_player("A", 50, pickem_orm.T1, team=_BOS), + _generate_player("B", 49, pickem_orm.T1, team=_GS), + _generate_player("C", 48, pickem_orm.T2, team=_BOS), + _generate_player("D", 47, pickem_orm.T2, team=_GS), + _generate_player("E", 46, pickem_orm.T3, team=_BOS), + _generate_player("F", 45, pickem_orm.T3, team=_GS), + _generate_player("G", 44, pickem_orm.T4, team=_BOS), + _generate_player("H", 43, pickem_orm.T4, team=_GS), + _generate_player("I", 42, pickem_orm.T5, team=_BOS), + _generate_player("J", 41, pickem_orm.T5, team=_GS), + _generate_player("K", 40, pickem_orm.T6, team=_BOS), + _generate_player("L", 39, pickem_orm.T6, team=_GS), ] def test_default_lineup(): players = _generate_test_player_data() optimized = optimize(players) - assertions.assertEqual( - optimized.total, - 50 + 48 + 46 + 44 + 42 + 40 - ) + assertions.assertEqual(optimized.total, 50 + 48 + 46 + 44 + 42 + 40) def test_banned_players(): @@ -56,25 +53,20 @@ def test_banned_players(): optimized = optimize( players, player_settings=PlayerPoolSettings(), - constraints=LineupConstraints(banned=['A', 'C']) - ) - assertions.assertEqual( - optimized.total, - 49 + 47 + 46 + 44 + 42 + 40 + constraints=LineupConstraints(banned=["A", "C"]), ) + assertions.assertEqual(optimized.total, 49 + 47 + 46 + 44 + 42 + 40) def test_locked_players(): players = _generate_test_player_data() optimized = optimize( - players, - constraints=LineupConstraints(locked=['B', 'D']) - ) - assertions.assertEqual( - optimized.total, - 49 + 47 + 46 + 44 + 42 + 40 + players, constraints=LineupConstraints(locked=["B", "D"]) ) + assertions.assertEqual(optimized.total, 49 + 47 + 46 + 44 + 42 + 40) + + # # # def test_banned_teams(): diff --git a/draftfast/test/test_player.py b/draftfast/test/test_player.py index f60031d..ed07fc9 100644 --- a/draftfast/test/test_player.py +++ b/draftfast/test/test_player.py @@ -1,9 +1,9 @@ import unittest from draftfast.orm import Player -assertions = unittest.TestCase('__init__') +assertions = unittest.TestCase("__init__") def test_player_value(): - pg = Player(name='A', cost=5500, proj=55, pos='PG') + pg = Player(name="A", cost=5500, proj=55, pos="PG") assertions.assertEqual(pg.value, 10) diff --git a/draftfast/test/test_player_pool.py b/draftfast/test/test_player_pool.py index 05f2e67..96039af 100644 --- a/draftfast/test/test_player_pool.py +++ b/draftfast/test/test_player_pool.py @@ -4,12 +4,12 @@ from draftfast.orm import Player from draftfast.settings import PlayerPoolSettings -assertions = unittest.TestCase('__init__') +assertions = unittest.TestCase("__init__") p_a, p_b, p_c = [ - Player(name='A1', cost=5500, proj=20, pos='PG'), - Player(name='A2', cost=7000, proj=30, pos='PG'), - Player(name='A3', cost=10000, proj=55, pos='PG'), + Player(name="A1", cost=5500, proj=20, pos="PG"), + Player(name="A2", cost=7000, proj=30, pos="PG"), + Player(name="A3", cost=10000, proj=55, pos="PG"), ] mock_player_pool = [p_a, p_b, p_c] @@ -41,10 +41,10 @@ def test_respects_max_cost(): def test_randomize(): random.seed(1) - pool = filter_pool(mock_player_pool, PlayerPoolSettings( - randomize=0.1, - )) - assertions.assertEqual( - pool[0].proj, - 18.537456976449604 + pool = filter_pool( + mock_player_pool, + PlayerPoolSettings( + randomize=0.1, + ), ) + assertions.assertEqual(pool[0].proj, 18.537456976449604) diff --git a/draftfast/test/test_roster.py b/draftfast/test/test_roster.py index ea4d62f..96d2423 100644 --- a/draftfast/test/test_roster.py +++ b/draftfast/test/test_roster.py @@ -1,15 +1,19 @@ from draftfast.orm import ( - NFLRoster, Player, ShowdownRoster, RosterGroup, MVPRoster + NFLRoster, + Player, + ShowdownRoster, + RosterGroup, + MVPRoster, ) import unittest -assertions = unittest.TestCase('__init__') +assertions = unittest.TestCase("__init__") def test_roster_equality(): - player_a = Player(pos='RB', name='A', cost=1, team='X') - player_b = Player(pos='QB', name='B', cost=1, team='X') - player_c = Player(pos='QB', name='C', cost=1, team='X') + player_a = Player(pos="RB", name="A", cost=1, team="X") + player_b = Player(pos="QB", name="B", cost=1, team="X") + player_c = Player(pos="QB", name="C", cost=1, team="X") roster_a = NFLRoster() roster_a.add_player(player_a) @@ -28,10 +32,10 @@ def test_roster_equality(): def test_roster_equality_with_position_shuffle(): - player_a = Player(pos='RB', name='A', cost=1, team='X') - player_a_new_pos = Player(pos='WR', name='A', cost=1, team='X') - player_b = Player(pos='QB', name='B', cost=1, team='X') - player_c = Player(pos='QB', name='C', cost=1, team='X') + player_a = Player(pos="RB", name="A", cost=1, team="X") + player_a_new_pos = Player(pos="WR", name="A", cost=1, team="X") + player_b = Player(pos="QB", name="B", cost=1, team="X") + player_c = Player(pos="QB", name="C", cost=1, team="X") roster_a = NFLRoster() roster_a.add_player(player_a) @@ -54,10 +58,10 @@ def test_showdown_roster_equality_and_position_shuffle(): In Showdown, point changes result from CPT assignment, so two lineups are not equal given the same player. """ - player_a = Player(pos='UTIL', name='A', cost=1, team='A') - player_a_new_pos = Player(pos='MVP', name='A', cost=1, team='A') - player_b = Player(pos='UTIL', name='B', cost=1, team='C') - player_c = Player(pos='UTIL', name='C', cost=1, team='D') + player_a = Player(pos="UTIL", name="A", cost=1, team="A") + player_a_new_pos = Player(pos="MVP", name="A", cost=1, team="A") + player_b = Player(pos="UTIL", name="B", cost=1, team="C") + player_c = Player(pos="UTIL", name="C", cost=1, team="D") roster_a = MVPRoster() roster_a.add_player(player_a) @@ -80,10 +84,10 @@ def test_mvp_roster_equality_and_position_shuffle(): In Showdown, point changes result from CPT assignment, so two lineups are not equal given the same player. """ - player_a = Player(pos='FLEX', name='A', cost=1, team='A') - player_a_new_pos = Player(pos='CPT', name='A', cost=1, team='A') - player_b = Player(pos='FLEX', name='B', cost=1, team='C') - player_c = Player(pos='FLEX', name='C', cost=1, team='D') + player_a = Player(pos="FLEX", name="A", cost=1, team="A") + player_a_new_pos = Player(pos="CPT", name="A", cost=1, team="A") + player_b = Player(pos="FLEX", name="B", cost=1, team="C") + player_c = Player(pos="FLEX", name="C", cost=1, team="D") roster_a = ShowdownRoster() roster_a.add_player(player_a) @@ -102,9 +106,9 @@ def test_mvp_roster_equality_and_position_shuffle(): def test_roster_set(): - player_a = Player(pos='RB', name='A', cost=1, team='X') - player_b = Player(pos='QB', name='B', cost=1, team='X') - player_c = Player(pos='QB', name='C', cost=1, team='X') + player_a = Player(pos="RB", name="A", cost=1, team="X") + player_b = Player(pos="QB", name="B", cost=1, team="X") + player_c = Player(pos="QB", name="C", cost=1, team="X") roster_a = NFLRoster() roster_a.add_player(player_a) @@ -121,9 +125,9 @@ def test_roster_set(): def test_roster_group(): - player_a = Player(pos='RB', name='A', cost=1, team='X') - player_b = Player(pos='QB', name='B', cost=1, team='X') - player_c = Player(pos='QB', name='C', cost=1, team='X') + player_a = Player(pos="RB", name="A", cost=1, team="X") + player_b = Player(pos="QB", name="B", cost=1, team="X") + player_c = Player(pos="QB", name="C", cost=1, team="X") roster_a = NFLRoster() roster_a.add_player(player_a) @@ -138,49 +142,39 @@ def test_roster_group(): roster_c.add_player(player_c) rg = RosterGroup(rosters=[roster_a, roster_b]) + assertions.assertEqual(rg.get_similarity_score(), 1) + assertions.assertEqual(rg.get_salary_frequency(), [(2, 2)]) assertions.assertEqual( - rg.get_similarity_score(), - 1 - ) - assertions.assertEqual( - rg.get_salary_frequency(), - [(2, 2)] - ) - assertions.assertEqual( - rg.get_player_frequency(), - [(player_a, 2), (player_b, 2)] + rg.get_player_frequency(), [(player_a, 2), (player_b, 2)] ) rg_2 = RosterGroup(rosters=[roster_a, roster_c]) - assertions.assertEqual( - rg_2.get_similarity_score(), - 0.5 - ) + assertions.assertEqual(rg_2.get_similarity_score(), 0.5) rg_3 = RosterGroup(rosters=[roster_a, roster_b, roster_c]) assertions.assertEqual( rg_3.get_similarity_score(), # (1 + 0.5 + 0.5)/3 - 2 / 3 + 2 / 3, ) roster_d = NFLRoster() roster_d.add_player(player_a) - roster_d.add_player(Player(pos='QB', name='D', cost=1, team='X')) + roster_d.add_player(Player(pos="QB", name="D", cost=1, team="X")) # All lineups share half of the same players rg_4 = RosterGroup(rosters=[roster_a, roster_c, roster_d]) assertions.assertEqual( rg_4.get_similarity_score(), # (0.5 + 0.5 + 0.5)/3 - 0.5 + 0.5, ) def test_shared_and_different_player_count(): - player_a = Player(pos='RB', name='A', cost=1, team='X') - player_b = Player(pos='QB', name='B', cost=1, team='X') - player_c = Player(pos='QB', name='C', cost=1, team='X') + player_a = Player(pos="RB", name="A", cost=1, team="X") + player_b = Player(pos="QB", name="B", cost=1, team="X") + player_c = Player(pos="QB", name="C", cost=1, team="X") roster_a = NFLRoster() roster_a.add_player(player_a) @@ -194,27 +188,9 @@ def test_shared_and_different_player_count(): roster_c.add_player(player_a) roster_c.add_player(player_c) - assertions.assertEqual( - roster_a.different_player_count(roster_b), - 0 - ) - assertions.assertEqual( - roster_a.shared_player_count(roster_b), - 2 - ) - assertions.assertEqual( - roster_a.different_player_count(roster_c), - 1 - ) - assertions.assertEqual( - roster_a.shared_player_count(roster_c), - 1 - ) - assertions.assertEqual( - roster_b.different_player_count(roster_c), - 1 - ) - assertions.assertEqual( - roster_b.shared_player_count(roster_c), - 1 - ) + assertions.assertEqual(roster_a.different_player_count(roster_b), 0) + assertions.assertEqual(roster_a.shared_player_count(roster_b), 2) + assertions.assertEqual(roster_a.different_player_count(roster_c), 1) + assertions.assertEqual(roster_a.shared_player_count(roster_c), 1) + assertions.assertEqual(roster_b.different_player_count(roster_c), 1) + assertions.assertEqual(roster_b.shared_player_count(roster_c), 1) diff --git a/draftfast/test/test_soccer.py b/draftfast/test/test_soccer.py index ad5918b..cac614a 100644 --- a/draftfast/test/test_soccer.py +++ b/draftfast/test/test_soccer.py @@ -7,9 +7,9 @@ from draftfast.lineup_constraints import LineupConstraints CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) -salary_file = '{}/data/dk-soccer-salaries.csv'.format(CURRENT_DIR) +salary_file = "{}/data/dk-soccer-salaries.csv".format(CURRENT_DIR) -assertions = unittest.TestCase('__init__') +assertions = unittest.TestCase("__init__") def test_soccer_dk(): @@ -34,7 +34,7 @@ def test_soccer_dk_no_opp_d(): rule_set=rules.DK_SOCCER_RULE_SET, player_pool=player_pool, constraints=LineupConstraints( - locked=['Maxi Gomez'], + locked=["Maxi Gomez"], ), optimizer_settings=OptimizerSettings( no_offense_against_defense=False, @@ -42,12 +42,10 @@ def test_soccer_dk_no_opp_d(): verbose=True, ) cel_off_players = [ - p for p in roster.players if p.team == 'CEL' - and p.pos in ['M', 'F'] + p for p in roster.players if p.team == "CEL" and p.pos in ["M", "F"] ] lgn_d_players = [ - p for p in roster.players if p.team == 'LGN' - and p.pos in ['D', 'GK'] + p for p in roster.players if p.team == "LGN" and p.pos in ["D", "GK"] ] assertions.assertEqual(len(cel_off_players), 2) assertions.assertEqual(len(lgn_d_players), 2) @@ -56,7 +54,7 @@ def test_soccer_dk_no_opp_d(): rule_set=rules.DK_SOCCER_RULE_SET, player_pool=player_pool, constraints=LineupConstraints( - locked=['Maxi Gomez'], + locked=["Maxi Gomez"], ), optimizer_settings=OptimizerSettings( no_offense_against_defense=True, @@ -64,12 +62,10 @@ def test_soccer_dk_no_opp_d(): verbose=True, ) cel_off_players = [ - p for p in roster.players if p.team == 'CEL' - and p.pos in ['M', 'F'] + p for p in roster.players if p.team == "CEL" and p.pos in ["M", "F"] ] lgn_d_players = [ - p for p in roster.players if p.team == 'LGN' - and p.pos in ['D', 'GK'] + p for p in roster.players if p.team == "LGN" and p.pos in ["D", "GK"] ] assertions.assertEqual(len(cel_off_players), 2) assertions.assertEqual(len(lgn_d_players), 0) diff --git a/draftfast/test/test_tennis.py b/draftfast/test/test_tennis.py index 524c9ac..b826f18 100644 --- a/draftfast/test/test_tennis.py +++ b/draftfast/test/test_tennis.py @@ -7,9 +7,9 @@ from draftfast.csv_parse import salary_download CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) -salary_file = '{}/data/dk-ten-salaries.csv'.format(CURRENT_DIR) +salary_file = "{}/data/dk-ten-salaries.csv".format(CURRENT_DIR) -assertions = unittest.TestCase('__init__') +assertions = unittest.TestCase("__init__") def test_tennis_lineup(): diff --git a/draftfast/test/test_xfl.py b/draftfast/test/test_xfl.py index 8a0f542..8b8423e 100644 --- a/draftfast/test/test_xfl.py +++ b/draftfast/test/test_xfl.py @@ -5,10 +5,10 @@ from draftfast.csv_parse import salary_download CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) -salary_file = '{}/data/dk-xfl-salaries.csv'.format(CURRENT_DIR) +salary_file = "{}/data/dk-xfl-salaries.csv".format(CURRENT_DIR) -assertions = unittest.TestCase('__init__') +assertions = unittest.TestCase("__init__") def test_xlf_lineup():