Giter Club home page Giter Club logo

leeger's Introduction

leeger logo

Instant stats for any fantasy football league.

Last Commit
End-to-end Tests Unit Tests Formatting Check

Table of Contents

Overview

This library allows you to take data from an existing fantasy football league and get instant stats from that league into either a Python script or an Excel spreadsheet.

This library supports multiple fantasy sites AND manual league data input.

Python stats will be stored in these objects:

Excel sheets will include:

  • A tab for each year with team stats
  • A tab for each year with matchup info
  • A tab for all-time with team stats
  • A tab for all-time with matchup info
  • A tab for all-time with owner stats


The main idea behind this library is:

  1. Load stats into a League object
  2. Pass this League object into various library methods to extract stats


For guides on how to use this library, see the information under Supported League Loaders and in the example folder.

Quickstart Guide

1. Download Python

  • Download the latest supported version of Python here.
  • Currently, Python version 3.10+ is supported

2. Create a basic Python file to use this library

  • Create a file that ends in the extension ".py"
    • Example: my_script.py

3. Download this library

  • Navigate in your terminal to the directory where you created your Python script in Step 2
  • Run the command pip install leeger
    • If you do not have pip installed, you will need to install it

4. Download your league data using a league loader

  • Find the site/s you use for fantasy football here
  • Follow the Setup Documentation
  • Once you have everything you need for your selected site/s, use the code examples found here for your specific site/s to download your league data
    • You can put the code inside the Python script you created in Step 2
  • If you have leagues that are continued in multiple sites, you can pull from multiple sites and add the League objects together to combine the different sites
    • An example of this can be found here

5. Run your script

  • Navigate in your terminal to the directory where you created your Python script in Step 2
  • Run the command py my_script.py
    • Replace my_script.py with whatever you named your script in Step 2

6. Load your league stats into Excel

  • Slightly alter your script from Step 2 to include a function call to load your league stats into Excel
  • Follow this example
  • Make sure that you are passing the League object that you pulled from the league loader/s into the function call to put your stats into Excel

FAQ

Question: I'm getting this error when I run my script:

TypeError: dataclass() got an unexpected keyword argument 'kw_only'

Answer: This error occurs when the Python version you are using is not 3.10 or greater.
Make sure you are using Python version 3.10 or a newer version.


Q: How do I use this library to pull stats from my online fantasy league?

A:

  1. Find your fantasy site here and ensure you have everything you need for the site you are using
  2. Follow the example code snippets for your fantasy site to load the League object

Q: How can I get stats into Excel once I have my League object?

A: Follow this example code.


Q: Can I combine years from different fantasy sites that are loaded as separate League objects into a single League object?

A: Yes, the League object supports addition (+) to combine multiple league objects.
An example of this can be found here.


Q: Can I disable validation on my League object?

A: Yes. While it is not recommended that you disable this, as validation ensures the stats are calculated properly, disabling validation can be done by passing validate=False into any method that takes a League object OR any loadLeague() method from a League Loader.

Installation

Use the package manager pip to install.

pip install leeger

Supported League Loaders

Sites that you can automatically load your league data from.

Name Website Supported Setup Documentation
ESPN https://www.espn.com/fantasy/football/ โœ”๏ธ ESPN ๐Ÿ“„
Fleaflicker https://www.fleaflicker.com/ โœ”๏ธ Fleaflicker ๐Ÿ“„
MyFantasyLeague http://home.myfantasyleague.com/ โœ”๏ธ MyFantasyLeague ๐Ÿ“„
NFL https://fantasy.nfl.com/ โŒ โŒ
Sleeper https://sleeper.com/fantasy-football/ โœ”๏ธ Sleeper ๐Ÿ“„
Yahoo https://football.fantasysports.yahoo.com/ โœ”๏ธ Yahoo ๐Ÿ“„

If a fantasy site you use is not listed here and you would like it to be, please open an issue.

Stats Explained

Stats used in this library are documented here.

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Please make sure to update tests as appropriate.

Development

Run these commands from the root folder

  • Format Code: ./main fmt
  • Run Unit Tests: ./main test
  • Generate Coverage Report: ./main cov

Running Tests

Run the following command from the root folder:

  pytest

License

MIT

Credit

leeger's People

Contributors

dependabot[bot] avatar joeyagreco avatar ryandaydev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

leeger's Issues

[LEAGUE LOADER]: Yahoo league loader unable to find more than 1 league year

League Loader

Yahoo

Summary

The yahoo league ids change every year so it is only able to find the first year, and then leeger fails when the script detects not all years were found.

League Info

No response

Error Logs

Error Traceback (most recent call last): File "C:\D\windows\git\leeger\test\test_league_loader\test_YahooLeagueLoader.py", line 46, in test_league league: League = yahooLeagueLoader.loadLeague() File "C:\D\windows\git\leeger\leeger\league_loader\YahooLeagueLoader.py", line 69, in loadLeague raise DoesNotExistException(f"Found {len(yahooLeagues)} years, expected to find {len(self._years)}.") leeger.exception.DoesNotExistException.DoesNotExistException: Found 1 years, expected to find 2.

[LEAGUE LOADER]: Fails on TypeError

League Loader

Yahoo

Summary

This is probably user error and not the forum for support, but I wasn't sure how else to reach out for help. League Loader fails with TypeError: dataclass() got an unexpected keyword argument 'kw_only'

League Info

Yahoo league ID# 14981 - it may be private.

Error Logs

Traceback (most recent call last):
  File "/home/wcarter/scratch/fantasy-stats/stats.py", line 1, in <module>
    from leeger.league_loader import YahooLeagueLoader
  File "/home/linuxbrew/.linuxbrew/Cellar/[email protected]/3.9.12/lib/python3.9/site-packages/leeger/league_loader/__init__.py", line 1, in <module>
    from .ESPNLeagueLoader import ESPNLeagueLoader
  File "/home/linuxbrew/.linuxbrew/Cellar/[email protected]/3.9.12/lib/python3.9/site-packages/leeger/league_loader/ESPNLeagueLoader.py", line 6, in <module>
    from leeger.league_loader.LeagueLoader import LeagueLoader
  File "/home/linuxbrew/.linuxbrew/Cellar/[email protected]/3.9.12/lib/python3.9/site-packages/leeger/league_loader/LeagueLoader.py", line 5, in <module>
    from leeger.model.league.League import League
  File "/home/linuxbrew/.linuxbrew/Cellar/[email protected]/3.9.12/lib/python3.9/site-packages/leeger/model/league/__init__.py", line 1, in <module>
    from .League import League
  File "/home/linuxbrew/.linuxbrew/Cellar/[email protected]/3.9.12/lib/python3.9/site-packages/leeger/model/league/League.py", line 6, in <module>
    from leeger.model.league.Owner import Owner
  File "/home/linuxbrew/.linuxbrew/Cellar/[email protected]/3.9.12/lib/python3.9/site-packages/leeger/model/league/Owner.py", line 9, in <module>
    @dataclass(kw_only=False, eq=False)
TypeError: dataclass() got an unexpected keyword argument 'kw_only'

[FEATURE]: Add Support for Multi-Week Matchups

Notes

Currently, matchups for playoffs/championship are only evaluated as 1 week per matchup.

Some leagues have multiple weeks for a playoff/championship matchup.

Support should be added for stat calculations and for each league loader.

TODO


  • Add support for multi-week matchups in stat calculations
  • Add support for multi-week matchups in Sleeper League Loader
  • Add support for multi-week matchups in Yahoo League Loader
  • Add support for multi-week matchups in ESPN League Loader
  • Add support for multi-week matchups in MyFantasyLeague League Loader

[FEATURE]: Franchise history and individual user history for all time stats

Notes

Currently leeger appears to grab only franchise history for a league, so each team year after year is basically expected to be the same user or relatively the same team (if dynasty for example).

Also, would be nice if there was a flag or switch to break it down by user, so as a old owner is replaced, you could see the new owner history from the time they joined the league for all owners. So you would end up with more records than teams since you could have many new owners over the history of a league.

For example, yahoo has a specific user guid, so you could organize each user by guid for every year to group them together.

[LEAGUE LOADER]: Yahoo league loader fails when it incorrectly detects 2 championship matchups

League Loader

Yahoo

Summary

Yahoo league loader fails when it incorrectly detects 2 championship matchups. One of the matchups is a consolation.

League Info

No response

Error Logs

Error Traceback (most recent call last): File "C:\D\windows\git\leeger\test\test_league_loader\test_YahooLeagueLoader.py", line 47, in test_league leagueToExcel(league, "C:/D/windows/git/leeger/dsbLeagueStats.xlsx") File "C:\D\windows\git\leeger\leeger\util\excel.py", line 24, in leagueToExcel yearToExcel(year, filePath, **kwargs) File "C:\D\windows\git\leeger\leeger\util\excel.py", line 154, in yearToExcel statsWithTitles = yearStatSheet(year, **kwargs).preferredOrderWithTitle() File "C:\D\windows\git\leeger\leeger\util\stat_sheet.py", line 92, in yearStatSheet wins = GameOutcomeYearCalculator.getWins(year, **kwargs) File "C:\D\windows\git\leeger\leeger\decorator\validators.py", line 65, in wrapFunction yearValidation.runAllChecks(year) File "C:\D\windows\git\leeger\leeger\validate\yearValidation.py", line 20, in runAllChecks checkAllWeeks(year) File "C:\D\windows\git\leeger\leeger\validate\yearValidation.py", line 40, in checkAllWeeks weekValidation.runAllChecks(week) File "C:\D\windows\git\leeger\leeger\validate\weekValidation.py", line 16, in runAllChecks checkWeekDoesNotHaveMoreThanOneChampionshipMatchup(week) File "C:\D\windows\git\leeger\leeger\validate\weekValidation.py", line 83, in checkWeekDoesNotHaveMoreThanOneChampionshipMatchup raise InvalidWeekFormatException( leeger.exception.InvalidWeekFormatException.InvalidWeekFormatException: Week 16 has 2 championship matchups. Maximum is 1.

[LEAGUE LOADER]: Could not find league for year 2022 with ID

League Loader

Yahoo

Summary

The League Loader does not look like it is pulling previous seasons from Yahoo properly. I am getting the error message: Could not find league for year 2022 with ID (414, 957486).

It looks like when Yahoo gives the League Loader the 'previousLeagueID', it gives a vector of 2 numbers (in my case [414, 957486]). The 957486 value is the correct value for the ID of my league in 2022. But, the script throws this error because instead of just trying to match 957486, it is looking to match the entire vector (414, 957486). If I manually change the 'currentLeagueId' from the vector to only 957486 right as it does the check on line 100 of YahooLeagueLoader.py, then it all seems to run fine. So, I'm not sure where the 414 is coming from, but it looks like when updating the 'previousLeagueId' on Line 103, it should only grab the second number in the vector, and convert it to a string. Something like:

previousLeagueId = str(league.past_league_id[2])

League Info

Yahoo
2023 League ID: 382757
2022 League ID: 957486

Error Logs

No response

[LEAGUE LOADER]: Running ESPN example gives TypeError: dataclass() got an unexpected keyword argument 'kw_only'

League Loader

ESPN

Summary

Win10, using Python 3.8.5
I attempted to run the ESPN example, found the relevant data for private league and ran and got
TypeError: dataclass() got an unexpected keyword argument 'kw_only'

I found a similar issue googling around which suggested running pip install attrs --upgrade to fix but that did not help. Any advice would be apricated. Thanks!

League Info

No response

Error Logs

Traceback (most recent call last):
File "C:\Python38\Lib\site-packages\leeger\league_loader\ESPNShadowStalkers.py", line 1, in
from leeger.league_loader import ESPNLeagueLoader
File "C:\Python38\lib\site-packages\leeger\league_loader_init_.py", line 1, in
from .ESPNLeagueLoader import ESPNLeagueLoader
File "C:\Python38\lib\site-packages\leeger\league_loader\ESPNLeagueLoader.py", line 6, in
from leeger.league_loader.LeagueLoader import LeagueLoader
File "C:\Python38\lib\site-packages\leeger\league_loader\LeagueLoader.py", line 5, in
from leeger.model.league.League import League
File "C:\Python38\lib\site-packages\leeger\model\league_init_.py", line 1, in
from .League import League
File "C:\Python38\lib\site-packages\leeger\model\league\League.py", line 6, in
from leeger.model.league.Owner import Owner
File "C:\Python38\lib\site-packages\leeger\model\league\Owner.py", line 9, in
@DataClass(kw_only=True, eq=False)

Sleeper League Loader (Key Error)

League Loader

Sleeper

Summary

When I try the basic "quick start" for loading in a sleeper league, I get a KeyError: 7. Will post the full log below. Wondering if it has to do with a team that the owner was removed and is now just an NPC team. Also, sorry if this is mentioned somewhere in the README or anything, I wasn't able to find it.

League Info

League ID: 1000931507806011392
Season: 2023

Error Logs

KeyError Traceback (most recent call last)
Cell In[8], line 2
1 sleeperLeagueLoader = SleeperLeagueLoader("1000931507806011392", [2023])
----> 2 League = sleeperLeagueLoader.loadLeague()

File ~\anaconda3\envs\py36\Lib\site-packages\leeger\league_loader\SleeperLeagueLoader.py:121, in SleeperLeagueLoader.loadLeague(self, validate)
119 def loadLeague(self, validate: bool = True) -> League:
120 sleeperLeagues = self.__getAllLeagues()
--> 121 league = self.__buildLeague(sleeperLeagues)
122 if validate:
123 # validate new league
124 leagueValidation.runAllChecks(league)

File ~\anaconda3\envs\py36\Lib\site-packages\leeger\league_loader\SleeperLeagueLoader.py:136, in SleeperLeagueLoader.__buildLeague(self, sleeperLeagues)
133 for sleeperLeague in sleeperLeagues:
134 # save league name for each year
135 self._leagueNameByYear[int(sleeperLeague.season)] = sleeperLeague.name
--> 136 years.append(self.__buildYear(sleeperLeague))
137 return League(name=self._getLeagueName(), owners=owners, years=self._getValidYears(years))

File ~\anaconda3\envs\py36\Lib\site-packages\leeger\league_loader\SleeperLeagueLoader.py:147, in SleeperLeagueLoader.__buildYear(self, sleeperLeague)
143 self._sleeperDivisionIdToDivisionMap[divisionNumber] = Division(
144 name=getattr(sleeperLeague.metadata, f"division
{divisionNumber}")
145 )
146 teams = self.__buildTeams(sleeperLeague)
--> 147 weeks = self.__buildWeeks(sleeperLeague)
148 # add YearSettings
149 yearSettings = YearSettings()

File ~\anaconda3\envs\py36\Lib\site-packages\leeger\league_loader\SleeperLeagueLoader.py:192, in SleeperLeagueLoader.__buildWeeks(self, sleeperLeague)
189 for sleeperMatchupPair in sleeperMatchupIdToSleeperMatchupMap.values():
190 # team A
191 teamASleeperMatchup = sleeperMatchupPair[0]
--> 192 teamA = self.__sleeperRosterIdToTeamMap[teamASleeperMatchup.roster_id]
194 # team B
195 teamBSleeperMatchup = sleeperMatchupPair[1]

KeyError: 7

[LEAGUE LOADER]: IndexError: list index out of range in __buildWeeks

League Loader

ESPN

Summary

Finally got it to run (thanks!). Ran on first league, no problems at all. Tried it out on 2nd ESPN league and got a IndexError: list index out of range error. Full stack trace is attached.

Let me know if you need any more info, this is really cool!

League Info

No response

Error Logs

Traceback (most recent call last):
File "C:\Users...\AppData\Local\Programs\Python\Python310\Lib\site-packages\leeger\league_loader\ESPN_High_School.py", line 10, in
league: League = espnLeagueLoader.loadLeague()
File "C:\Users...\AppData\Local\Programs\Python\Python310\lib\site-packages\leeger\league_loader\ESPNLeagueLoader.py", line 51, in loadLeague
return self.__buildLeague(espnLeagueYears)
File "C:\Users...\AppData\Local\Programs\Python\Python310\lib\site-packages\leeger\league_loader\ESPNLeagueLoader.py", line 59, in __buildLeague
years.append(self.__buildYear(espnLeague))
File "C:\Users...\AppData\Local\Programs\Python\Python310\lib\site-packages\leeger\league_loader\ESPNLeagueLoader.py", line 74, in __buildYear
weeks = self.__buildWeeks(espnLeague)
File "C:\Users...\AppData\Local\Programs\Python\Python310\lib\site-packages\leeger\league_loader\ESPNLeagueLoader.py", line 88, in __buildWeeks
if espnTeam.team_id in espnTeamIDsWithMatchups or espnTeam.outcomes[i] == self.__ESPN_BYE_OUTCOME:
IndexError: list index out of range

[LEAGUE LOADER]: AttributeError: 'Matchup' object has no attribute 'winner_team_key'

League Loader

Yahoo

Summary

Thanks so much for this program. I don't have much Python experience, so that might be my issue. But I am very interested in trying to get this to work. It looks like there is lots of good info. Anyways, I successfully logged into the Yahoo Fantasy API (I gave it permission). But now I am getting that error when trying to run this line:
league: League = yahooLeagueLoader.loadLeague()

I am trying to run this for a current league (2022). Maybe that is the issue? The full error I think is this:
teamAHasTiebreaker = yahooMatchup.winner_team_key == yahooTeamA.team_key and yahooMatchup.is_tied == 0
AttributeError: 'Matchup' object has no attribute 'winner_team_key'

Maybe only having data for Week 1 is not enough for this program to do everything it needs to do?

League Info

No response

Error Logs

teamAHasTiebreaker = yahooMatchup.winner_team_key == yahooTeamA.team_key and yahooMatchup.is_tied == 0
AttributeError: 'Matchup' object has no attribute 'winner_team_key'

[LEAGUE LOADER]: AttributeError: 'Matchup' object has no attribute 'winner_team_key'

League Loader

Yahoo

Summary

Yahoo league loader errors out when an actual tie has occurred on a Yahoo league season.

League Info

League ID: 137588
Year: 2018

Error Logs

Traceback (most recent call last):
  File "/Users/whcarter3/scratch/ETFLstats/stats.py", line 37, in <module>
    league: League = yahooLeagueLoader.loadLeague()
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/leeger/league_loader/YahooLeagueLoader.py", line 73, in loadLeague
    return self.__buildLeague(yahooLeagues)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/leeger/league_loader/YahooLeagueLoader.py", line 81, in __buildLeague
    years.append(self.__buildYear(yahooLeague))
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/leeger/league_loader/YahooLeagueLoader.py", line 87, in __buildYear
    weeks = self.__buildWeeks(yahooLeague)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/leeger/league_loader/YahooLeagueLoader.py", line 106, in __buildWeeks
    teamAHasTiebreaker = yahooMatchup.winner_team_key == yahooTeamA.team_key and yahooMatchup.is_tied == 0
AttributeError: 'Matchup' object has no attribute 'winner_team_key'

Excel Color Map Raising Error

League Loader

Yahoo

Summary

Believe yahoo bug?

Traceback (most recent call last):
File "/Users/brandonschleter/Sleeper/my_script.py", line 41, in
leagueToExcel(myLeague, "/myLeagueStats.xlsx")
File "/Users/brandonschleter/miniconda3/envs/Sleeper/lib/python3.10/site-packages/leeger/util/excel.py", line 68, in leagueToExcel
teamIdToColorMap[team.id] = ownerIdToColorMap[team.ownerId]
KeyError: '959818########'`

Here was CoPilot's suggestions for excel.py (unsure if needed)

`if team.ownerId not in ownerIdToColorMap:
ownerIdToColorMap[team.ownerId] = default_color # replace default_color with the default color value you want to use

teamIdToColorMap[team.id] = ownerIdToColorMap[team.ownerId]`

Thoughts?

League Info

I am doing this by combining a Yahoo loader (successful API links) and a Sleeper loader. macos. I do not believe it is even getting to the point of the Sleeper loader due to color key error with yahoo. Our league changes it's 'name' each year, keeps things fresh.

using file name as my_script.py to keep all things congruent.

Error Logs

No response

[LEAGUE LOADER]: Dealing with changed ownership

League Loader

ESPN

Summary

When trying to load multiple seasons of a given league an exception error is raised for _getOwnerByName in LeagueLoader if a different owner is identified for a given team slot. Is there a workaround to allow analysis of leagues with ownership changes? I dont want to merge changed owners, I would like to keep them separate for statistical purposes.

League Info

No response

Error Logs

No response

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.