Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion espn_api/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.46.0'
__version__ = "0.46.0"
171 changes: 113 additions & 58 deletions espn_api/base_league.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,20 @@
from .utils.logger import Logger
from .requests.espn_requests import EspnFantasyRequests


class BaseLeague(ABC):
'''Creates a League instance for Public/Private ESPN league'''
def __init__(self, league_id: int, year: int, sport: str, espn_s2=None, swid=None, debug=False):
self.logger = Logger(name=f'{sport} league', debug=debug)
"""Creates a League instance for Public/Private ESPN league"""

def __init__(
self,
league_id: int,
year: int,
sport: str,
espn_s2=None,
swid=None,
debug=False,
):
self.logger = Logger(name=f"{sport} league", debug=debug)
self.league_id = league_id
self.year = year
self.teams = []
Expand All @@ -19,69 +29,103 @@ def __init__(self, league_id: int, year: int, sport: str, espn_s2=None, swid=Non

cookies = None
if espn_s2 and swid:
cookies = {
'espn_s2': espn_s2,
'SWID': swid
}
self.espn_request = EspnFantasyRequests(sport=sport, year=year, league_id=league_id, cookies=cookies, logger=self.logger)
cookies = {"espn_s2": espn_s2, "SWID": swid}
self.espn_request = EspnFantasyRequests(
sport=sport,
year=year,
league_id=league_id,
cookies=cookies,
logger=self.logger,
)

def __repr__(self):
return 'League(%s, %s)' % (self.league_id, self.year, )
return "League(%s, %s)" % (
self.league_id,
self.year,
)

def _fetch_league(self, SettingsClass = BaseSettings):
def _fetch_league(self, SettingsClass=BaseSettings):
data = self.espn_request.get_league()
self.currentMatchupPeriod = data['status']['currentMatchupPeriod']
self.scoringPeriodId = data['scoringPeriodId']
self.firstScoringPeriod = data['status']['firstScoringPeriod']
self.finalScoringPeriod = data['status']['finalScoringPeriod']
self.currentMatchupPeriod = data["status"]["currentMatchupPeriod"]
self.scoringPeriodId = data["scoringPeriodId"]
self.firstScoringPeriod = data["status"]["firstScoringPeriod"]
self.finalScoringPeriod = data["status"]["finalScoringPeriod"]
self.previousSeasons = [
year for year in data["status"]["previousSeasons"] if year < self.year
]
if self.year < 2018:
self.current_week = data['scoringPeriodId']
self.current_week = data["scoringPeriodId"]
else:
self.current_week = self.scoringPeriodId if self.scoringPeriodId <= data['status']['finalScoringPeriod'] else data['status']['finalScoringPeriod']
self.settings = SettingsClass(data['settings'])
self.members = data.get('members', [])
self.current_week = (
self.scoringPeriodId
if self.scoringPeriodId <= data["status"]["finalScoringPeriod"]
else data["status"]["finalScoringPeriod"]
)
self.settings = SettingsClass(data["settings"])
self.members = data.get("members", [])
return data

def _fetch_draft(self):
'''Creates list of Pick objects from the leagues draft'''
"""Creates list of Pick objects from the leagues draft"""
data = self.espn_request.get_league_draft()
# League has not drafted yet
if not data.get('draftDetail', {}).get('drafted'):
if not data.get("draftDetail", {}).get("drafted"):
return

picks = data.get('draftDetail', {}).get('picks', [])
picks = data.get("draftDetail", {}).get("picks", [])
for pick in picks:
team = self.get_team_data(pick.get('teamId'))
playerId = pick.get('playerId')
playerName = ''
team = self.get_team_data(pick.get("teamId"))
playerId = pick.get("playerId")
playerName = ""
if playerId in self.player_map:
playerName = self.player_map[playerId]
round_num = pick.get('roundId')
round_pick = pick.get('roundPickNumber')
bid_amount = pick.get('bidAmount')
keeper_status = pick.get('keeper')
nominatingTeam = self.get_team_data(pick.get('nominatingTeamId'))
self.draft.append(BasePick(team, playerId, playerName, round_num, round_pick, bid_amount, keeper_status, nominatingTeam))

def _fetch_teams(self, data, TeamClass, pro_schedule = None):
'''Fetch teams in league'''
round_num = pick.get("roundId")
round_pick = pick.get("roundPickNumber")
bid_amount = pick.get("bidAmount")
keeper_status = pick.get("keeper")
nominatingTeam = self.get_team_data(pick.get("nominatingTeamId"))
self.draft.append(
BasePick(
team,
playerId,
playerName,
round_num,
round_pick,
bid_amount,
keeper_status,
nominatingTeam,
)
)

def _fetch_teams(self, data, TeamClass, pro_schedule=None):
"""Fetch teams in league"""
self.teams = []
teams = data['teams']
schedule = data['schedule']
seasonId = data['seasonId']
members = data.get('members', [])
teams = data["teams"]
schedule = data["schedule"]
seasonId = data["seasonId"]
members = data.get("members", [])

team_roster = {}
for team in data['teams']:
team_roster[team['id']] = team.get('roster', {})
for team in data["teams"]:
team_roster[team["id"]] = team.get("roster", {})

for team in teams:
roster = team_roster[team['id']]
owners = [member for member in members if member.get('id') in team.get('owners', [])]
self.teams.append(TeamClass(team, roster=roster, schedule=schedule, year=seasonId, owners=owners, pro_schedule=pro_schedule))
roster = team_roster[team["id"]]
owners = [
member
for member in members
if member.get("id") in team.get("owners", [])
]
self.teams.append(
TeamClass(
team,
roster=roster,
schedule=schedule,
year=seasonId,
owners=owners,
pro_schedule=pro_schedule,
)
)

# sort by team ID
self.teams = sorted(self.teams, key=lambda x: x.team_id, reverse=False)
Expand All @@ -91,53 +135,64 @@ def _fetch_players(self):
# Map all player id's to player name
for player in data:
# two way map to find playerId's by name
self.player_map[player['id']] = player['fullName']
self.player_map[player["id"]] = player["fullName"]
# if two players have the same fullname use first one for now TODO update for multiple player names
if player['fullName'] not in self.player_map:
self.player_map[player['fullName']] = player['id']
if player["fullName"] not in self.player_map:
self.player_map[player["fullName"]] = player["id"]

def _get_pro_schedule(self, scoringPeriodId: int = None):
data = self.espn_request.get_pro_schedule()

pro_teams = data['settings']['proTeams']
pro_teams = data["settings"]["proTeams"]
pro_team_schedule = {}

for team in pro_teams:
pro_game = team.get('proGamesByScoringPeriod', {})
if team['id'] != 0 and (str(scoringPeriodId) in pro_game.keys() and pro_game[str(scoringPeriodId)]):
pro_game = team.get("proGamesByScoringPeriod", {})
if team["id"] != 0 and (
str(scoringPeriodId) in pro_game.keys()
and pro_game[str(scoringPeriodId)]
):
game_data = pro_game[str(scoringPeriodId)][0]
pro_team_schedule[team['id']] = (game_data['homeProTeamId'], game_data['date']) if team['id'] == game_data['awayProTeamId'] else (game_data['awayProTeamId'], game_data['date'])
pro_team_schedule[team["id"]] = (
(game_data["homeProTeamId"], game_data["date"])
if team["id"] == game_data["awayProTeamId"]
else (game_data["awayProTeamId"], game_data["date"])
)
return pro_team_schedule

def _get_all_pro_schedule(self):
data = self.espn_request.get_pro_schedule()

pro_teams = data.get('settings', {}).get('proTeams', {})
pro_teams = data.get("settings", {}).get("proTeams", {})
pro_team_schedule = {}

for team in pro_teams:
pro_game = team.get('proGamesByScoringPeriod', {})
pro_team_schedule[team['id']] = pro_game
pro_game = team.get("proGamesByScoringPeriod", {})
pro_team_schedule[team["id"]] = pro_game
return pro_team_schedule

def _get_offers(self, week: int = None):
'''Returns a list of free agent auction bids'''
"""Returns a list of free agent auction bids"""
if week is None:
bids = []
for week in range(0, self.finalScoringPeriod+1):
for week in range(0, self.finalScoringPeriod + 1):
data = self.espn_request.get_league_offers(week=week)
transactions = data.get('transactions', [])
transactions = data.get("transactions", [])
if transactions: # Only append non-empty transaction lists
for t in transactions:
bids.append(t)
else:
data = self.espn_request.get_league_offers(week=week)
bids = data.get('transactions', [])
bids = data.get("transactions", [])

return bids

def standings(self) -> List:
standings = sorted(self.teams, key=lambda x: x.final_standing if x.final_standing != 0 else x.standing, reverse=False)
standings = sorted(
self.teams,
key=lambda x: x.final_standing if x.final_standing != 0 else x.standing,
reverse=False,
)
return standings

def get_team_data(self, team_id: int) -> List:
Expand Down
91 changes: 51 additions & 40 deletions espn_api/base_offer.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,62 +3,73 @@

class Offer(object):
def __init__(self, data, player_map, get_team_data):
status = data['status']
self.id = data['id']
status = data["status"]
self.id = data["id"]
self.dateTime = None
if status == 'CANCELED':
self.result = 'Canceled'
if status == "CANCELED":
self.result = "Canceled"
else:
if status == 'EXECUTED':
self.result = 'Processed'
elif status == 'FAILED_INVALIDPLAYERSOURCE':
self.result = 'Outbid'
elif status == 'FAILED_AUCTIONBUDGETEXCEEDED':
self.result = 'Budget Exceeded'
elif status == 'FAILED_POSITIONLIMIT':
self.result = 'Position Limit Exceeded'
elif status == 'FAILED_ROSTERLOCK':
self.result = 'Failed Due to Roster Lock'
elif status == 'FAILED_PLAYERALREADYDROPPED' or status == 'FAILED_ROSTERLIMIT' or status == 'PENDING':
self.result = 'Player already dropped'
if status == "EXECUTED":
self.result = "Processed"
elif status == "FAILED_INVALIDPLAYERSOURCE":
self.result = "Outbid"
elif status == "FAILED_AUCTIONBUDGETEXCEEDED":
self.result = "Budget Exceeded"
elif status == "FAILED_POSITIONLIMIT":
self.result = "Position Limit Exceeded"
elif status == "FAILED_ROSTERLOCK":
self.result = "Failed Due to Roster Lock"
elif (
status == "FAILED_PLAYERALREADYDROPPED"
or status == "FAILED_ROSTERLIMIT"
or status == "PENDING"
):
self.result = "Player already dropped"
else:
self.result = status
# fixes bug with unprocessed waivers stuck on "PENDING" status
if 'processDate' in data:
self.dateTime = datetime.fromtimestamp(int(data['processDate'] / 1000)) # convert from milliseconds to seconds
self.amount = data['bidAmount']
self.teamId = data['teamId']
if "processDate" in data:
self.dateTime = datetime.fromtimestamp(
int(data["processDate"] / 1000)
) # convert from milliseconds to seconds
self.amount = data["bidAmount"]
self.teamId = data["teamId"]
self.droppedPlayer = None
for item in data['items']:
if item['type'] == 'ADD':
self.player = item['playerId']
elif item['type'] == 'DROP' and self.result == 'Processed':
self.droppedPlayer = item['playerId']
for item in data["items"]:
if item["type"] == "ADD":
self.player = item["playerId"]
elif item["type"] == "DROP" and self.result == "Processed":
self.droppedPlayer = item["playerId"]

def __lt__(self, other):
# sort by status, then bid amount
result_ranking = {'Processed': 7,
'Outbid': 6,
'Player already dropped': 5,
'Budget Exceeded': 4,
'Position Limit Exceeded': 3,
'Failed Due to Roster Lock': 2,
'CANCELLED': 1,
'PENDING': 0}
result_ranking = {
"Processed": 7,
"Outbid": 6,
"Player already dropped": 5,
"Budget Exceeded": 4,
"Position Limit Exceeded": 3,
"Failed Due to Roster Lock": 2,
"CANCELLED": 1,
"PENDING": 0,
}
if result_ranking[self.result] != result_ranking[other.result]:
return result_ranking[self.result] < result_ranking[other.result]
else:
# sort by bid amount
return self.amount < other.amount

def __repr__(self):
if self.result == 'Canceled':
return 'Canceled bid'
if self.result == "Canceled":
return "Canceled bid"
else:
ret_string = 'Offer(Date:{0}, Player:{1}, Team:{2}, Result:{3}, Bid:{4}'.format(self.dateTime, self.player, self.teamId,
self.result, self.amount)
ret_string = (
"Offer(Date:{0}, Player:{1}, Team:{2}, Result:{3}, Bid:{4}".format(
self.dateTime, self.player, self.teamId, self.result, self.amount
)
)
if self.droppedPlayer:
ret_string += ', Dropped:{0})'.format(self.droppedPlayer)
ret_string += ", Dropped:{0})".format(self.droppedPlayer)
else:
ret_string += ')'
return ret_string
ret_string += ")"
return ret_string
Loading