sportsball 0.3.15__tar.gz → 0.3.16__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sportsball-0.3.15/sportsball.egg-info → sportsball-0.3.16}/PKG-INFO +3 -1
- {sportsball-0.3.15 → sportsball-0.3.16}/README.md +2 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/setup.py +1 -1
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/__init__.py +1 -1
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/afl/afltables/afl_afltables_player_model.py +1 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/combined/combined_league_model.py +21 -4
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/combined/combined_player_model.py +5 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/espn/espn_player_model.py +1 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/google/google_address_model.py +67 -54
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/nba/nba/nba_nba_player_model.py +1 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/nba/nba/nba_nba_team_model.py +1 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/player_model.py +6 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/sportsdb/sportsdb_league_model.py +13 -12
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/sportsreference/sportsreference_game_model.py +20 -5
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/sportsreference/sportsreference_player_model.py +11 -4
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/sportsreference/sportsreference_team_model.py +35 -5
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/team_model.py +20 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/weather/openmeteo/openmeteo_weather_model.py +15 -9
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/proxy_session.py +46 -24
- {sportsball-0.3.15 → sportsball-0.3.16/sportsball.egg-info}/PKG-INFO +3 -1
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/combined/combined_player_model_test.py +1 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/nba/nba/nba_nba_game_model_test.py +4 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/nba/nba/nba_nba_team_model_test.py +2 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/player_model_test.py +1 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/sportsreference/sportsreference_player_model_test.py +1 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/sportsreference/sportsreference_team_model_test.py +3 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/LICENSE +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/MANIFEST.in +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/requirements.txt +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/setup.cfg +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/__main__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/args.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/cache.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/address_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/afl/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/afl/afltables/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/afl/afltables/afl_afltables_game_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/afl/afltables/afl_afltables_league_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/afl/afltables/afl_afltables_team_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/afl/afltables/afl_afltables_venue_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/afl/aussportsbetting/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/afl/aussportsbetting/afl_aussportsbetting_league_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/afl/combined/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/afl/combined/afl_combined_league_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/afl/espn/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/afl/espn/afl_espn_league_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/aussportsbetting/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/aussportsbetting/aussportsbetting_bookie_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/aussportsbetting/aussportsbetting_game_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/aussportsbetting/aussportsbetting_league_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/aussportsbetting/aussportsbetting_odds_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/aussportsbetting/aussportsbetting_team_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/aussportsbetting/aussportsbetting_venue_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/bookie_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/combined/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/combined/combined_address_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/combined/combined_game_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/combined/combined_team_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/combined/combined_venue_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/combined/combined_weather_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/espn/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/espn/espn_bookie_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/espn/espn_game_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/espn/espn_league_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/espn/espn_odds_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/espn/espn_team_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/espn/espn_venue_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/field_type.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/game_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/google/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/google/google_news_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/league.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/league_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/nba/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/nba/combined/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/nba/combined/nba_combined_league_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/nba/espn/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/nba/espn/nba_espn_league_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/nba/nba/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/nba/nba/nba_nba_game_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/nba/nba/nba_nba_league_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/nba/sportsdb/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/nba/sportsdb/nba_sportsdb_league_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/nba/sportsreference/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/nba/sportsreference/nba_sportsreference_league_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/ncaab/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/ncaab/combined/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/ncaab/combined/ncaab_combined_league_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/ncaab/espn/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/ncaab/espn/ncaab_espn_league_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/ncaab/sportsreference/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/ncaab/sportsreference/ncaab_sportsreference_league_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/ncaaf/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/ncaaf/espn/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/ncaaf/espn/ncaaf_espn_league_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/news_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/nfl/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/nfl/aussportsbetting/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/nfl/aussportsbetting/nfl_aussportsbetting_league_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/nfl/combined/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/nfl/combined/nfl_combined_league_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/nfl/espn/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/nfl/espn/nfl_espn_league_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/nfl/sportsdb/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/nfl/sportsdb/nfl_sportsdb_league_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/odds_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/season_type.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/social_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/sportsdb/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/sportsdb/sportsdb_game_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/sportsdb/sportsdb_team_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/sportsdb/sportsdb_venue_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/sportsreference/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/sportsreference/sportsreference_league_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/sportsreference/sportsreference_venue_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/venue_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/weather/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/weather/gribstream/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/weather/gribstream/gribstream_weather_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/weather/multi_weather_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/weather/openmeteo/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/weather_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/wikipedia/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/wikipedia/wikipedia_venue_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/x/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/x/x_social_model.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/logger.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/loglevel.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/session.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball/sportsball.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball.egg-info/SOURCES.txt +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball.egg-info/dependency_links.txt +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball.egg-info/entry_points.txt +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball.egg-info/not-zip-safe +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball.egg-info/requires.txt +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/sportsball.egg-info/top_level.txt +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/afl/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/afl/afltables/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/afl/afltables/afl_afltables_player_model_test.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/aussportsbetting/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/aussportsbetting/aussportsbetting_game_model_test.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/combined/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/combined/combined_game_model_test.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/espn/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/espn/espn_game_model_test.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/espn/espn_player_model_test.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/game_model_test.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/google/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/google/google_address_model_test.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/google/google_news_model_test.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/nba/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/nba/nba/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/nba/nba/nba_nba_league_model_test.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/nba/nba/nba_nba_player_model_test.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/nba/sportsdb/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/nba/sportsdb/nba_sportsdb_league_model_test.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/nba/sportsreference/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/nba/sportsreference/nba_sportsreference_league_model_test.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/ncaab/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/ncaab/sportsreference/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/ncaab/sportsreference/ncaab_sportsreference_league_model_test.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/nfl/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/nfl/sportsdb/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/nfl/sportsdb/nfl_sportsdb_league_model_test.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/social_model_test.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/sportsdb/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/sportsdb/sportsdb_game_model_test.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/sportsdb/sportsdb_league_model_test.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/sportsdb/sportsdb_team_model_test.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/sportsdb/sportsdb_venue_model_test.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/sportsreference/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/sportsreference/sportsreference_game_model_test.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/sportsreference/sportsreference_league_model_test.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/sportsreference/sportsreference_venue_model_test.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/team_model_test.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/x/__init__.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/data/x/x_social_model_test.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/proxy_session_test.py +0 -0
- {sportsball-0.3.15 → sportsball-0.3.16}/tests/sportsball_test.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: sportsball
|
3
|
-
Version: 0.3.
|
3
|
+
Version: 0.3.16
|
4
4
|
Summary: A library for pulling in and normalising sports stats.
|
5
5
|
Home-page: https://github.com/8W9aG/sportsball
|
6
6
|
Author: Will Sackfield
|
@@ -164,6 +164,7 @@ A representation of a team within a game.
|
|
164
164
|
* **field_goals**: The sum of the field goals made by the team in the game.
|
165
165
|
* **field_goals_attempted**: The sum of the field goals attempted by the team in the game.
|
166
166
|
* **offensive_rebounds**: The number of rebounds during offense by the team in the game.
|
167
|
+
* **assists**: The number of times the player on the team made a pass that resulted in a field goal in the game.
|
167
168
|
|
168
169
|
#### Player
|
169
170
|
|
@@ -177,6 +178,7 @@ A representation of a player within a team within a game.
|
|
177
178
|
* **field_goals**: The number of field goals the player made in the game.
|
178
179
|
* **field_goals_attempted**: The number of field goal attempts the player made in the game.
|
179
180
|
* **offensive_rebounds**: The number of rebounds during offense by the player made in the game.
|
181
|
+
* **assists**: The number of times the player made a pass that resulted in a field goal in the game.
|
180
182
|
|
181
183
|
#### Odds
|
182
184
|
|
@@ -111,6 +111,7 @@ A representation of a team within a game.
|
|
111
111
|
* **field_goals**: The sum of the field goals made by the team in the game.
|
112
112
|
* **field_goals_attempted**: The sum of the field goals attempted by the team in the game.
|
113
113
|
* **offensive_rebounds**: The number of rebounds during offense by the team in the game.
|
114
|
+
* **assists**: The number of times the player on the team made a pass that resulted in a field goal in the game.
|
114
115
|
|
115
116
|
#### Player
|
116
117
|
|
@@ -124,6 +125,7 @@ A representation of a player within a team within a game.
|
|
124
125
|
* **field_goals**: The number of field goals the player made in the game.
|
125
126
|
* **field_goals_attempted**: The number of field goal attempts the player made in the game.
|
126
127
|
* **offensive_rebounds**: The number of rebounds during offense by the player made in the game.
|
128
|
+
* **assists**: The number of times the player made a pass that resulted in a field goal in the game.
|
127
129
|
|
128
130
|
#### Odds
|
129
131
|
|
@@ -23,7 +23,7 @@ def install_requires() -> typing.List[str]:
|
|
23
23
|
|
24
24
|
setup(
|
25
25
|
name='sportsball',
|
26
|
-
version='0.3.
|
26
|
+
version='0.3.16',
|
27
27
|
description='A library for pulling in and normalising sports stats.',
|
28
28
|
long_description=long_description,
|
29
29
|
long_description_content_type='text/markdown',
|
@@ -3,7 +3,7 @@
|
|
3
3
|
import logging
|
4
4
|
import multiprocessing
|
5
5
|
from multiprocessing import Pool
|
6
|
-
from typing import Iterator
|
6
|
+
from typing import Any, Iterator
|
7
7
|
|
8
8
|
import requests_cache
|
9
9
|
|
@@ -14,9 +14,13 @@ from ..league_model import LeagueModel
|
|
14
14
|
from .combined_game_model import create_combined_game_model
|
15
15
|
|
16
16
|
|
17
|
-
def _produce_league_games(league_model: LeagueModel) -> list[
|
17
|
+
def _produce_league_games(league_model: LeagueModel) -> list[dict[str, Any]]:
|
18
18
|
setup_logger()
|
19
|
-
|
19
|
+
try:
|
20
|
+
return [x.model_dump() for x in league_model.games]
|
21
|
+
except Exception as exc:
|
22
|
+
logging.error("Exception: %s", str(exc))
|
23
|
+
raise ValueError(str(exc))
|
20
24
|
|
21
25
|
|
22
26
|
class CombinedLeagueModel(LeagueModel):
|
@@ -52,7 +56,20 @@ class CombinedLeagueModel(LeagueModel):
|
|
52
56
|
for league_model in self._league_models:
|
53
57
|
league_model.clear_session()
|
54
58
|
with Pool(min(multiprocessing.cpu_count(), len(self._league_models))) as p:
|
55
|
-
|
59
|
+
# We want to terminate immediately if any of our runners runs into trouble.
|
60
|
+
def _error_callback(exc: BaseException) -> None:
|
61
|
+
p.terminate()
|
62
|
+
raise ValueError(str(exc))
|
63
|
+
|
64
|
+
results = [
|
65
|
+
p.apply_async(
|
66
|
+
_produce_league_games, args=(x,), error_callback=_error_callback
|
67
|
+
)
|
68
|
+
for x in self._league_models
|
69
|
+
]
|
70
|
+
game_lists = [
|
71
|
+
[GameModel.model_validate(y) for y in x.get()] for x in results
|
72
|
+
]
|
56
73
|
|
57
74
|
for game_list in game_lists:
|
58
75
|
for game_model in game_list:
|
@@ -15,6 +15,7 @@ def create_combined_player_model(
|
|
15
15
|
field_goals = None
|
16
16
|
field_goals_attempted = None
|
17
17
|
offensive_rebounds = None
|
18
|
+
assists = None
|
18
19
|
for player_model in player_models:
|
19
20
|
player_model_jersey = player_model.jersey
|
20
21
|
if player_model_jersey is not None:
|
@@ -37,6 +38,9 @@ def create_combined_player_model(
|
|
37
38
|
player_model_offensive_rebounds = player_model.offensive_rebounds
|
38
39
|
if player_model_offensive_rebounds is not None:
|
39
40
|
offensive_rebounds = player_model_offensive_rebounds
|
41
|
+
player_model_assists = player_model.assists
|
42
|
+
if player_model_assists is not None:
|
43
|
+
assists = player_model_assists
|
40
44
|
return PlayerModel(
|
41
45
|
identifier=identifier,
|
42
46
|
jersey=jersey,
|
@@ -46,4 +50,5 @@ def create_combined_player_model(
|
|
46
50
|
field_goals=field_goals,
|
47
51
|
field_goals_attempted=field_goals_attempted,
|
48
52
|
offensive_rebounds=offensive_rebounds,
|
53
|
+
assists=assists,
|
49
54
|
)
|
@@ -973,6 +973,60 @@ GOLDEN_1_CENTER = SportsballGeocodeTuple(
|
|
973
973
|
housenumber="500",
|
974
974
|
country="USA",
|
975
975
|
)
|
976
|
+
DELTA_CENTER = SportsballGeocodeTuple(
|
977
|
+
city="Salt Lake City",
|
978
|
+
state="UT",
|
979
|
+
postal="",
|
980
|
+
lat=40.768333,
|
981
|
+
lng=-111.901111,
|
982
|
+
housenumber="301",
|
983
|
+
country="USA",
|
984
|
+
)
|
985
|
+
ATT_CENTER = SportsballGeocodeTuple(
|
986
|
+
city="San Antonio",
|
987
|
+
state="TX",
|
988
|
+
postal="",
|
989
|
+
lat=29.426944,
|
990
|
+
lng=-98.4375,
|
991
|
+
housenumber="1",
|
992
|
+
country="USA",
|
993
|
+
)
|
994
|
+
FTX_ARENA = SportsballGeocodeTuple(
|
995
|
+
city="Miami",
|
996
|
+
state="FL",
|
997
|
+
postal="",
|
998
|
+
lat=25.781389,
|
999
|
+
lng=-80.188056,
|
1000
|
+
housenumber="601",
|
1001
|
+
country="USA",
|
1002
|
+
)
|
1003
|
+
VIVINT_ARENA = SportsballGeocodeTuple(
|
1004
|
+
city="Salt Lake City",
|
1005
|
+
state="UT",
|
1006
|
+
postal="",
|
1007
|
+
lat=40.768333,
|
1008
|
+
lng=-111.901111,
|
1009
|
+
housenumber="301",
|
1010
|
+
country="USA",
|
1011
|
+
)
|
1012
|
+
CHESAPEAKE_ENERGY_ARENA = SportsballGeocodeTuple(
|
1013
|
+
city="Oklahoma City",
|
1014
|
+
state="OK",
|
1015
|
+
postal="",
|
1016
|
+
lat=35.463333,
|
1017
|
+
lng=-97.515,
|
1018
|
+
housenumber="100",
|
1019
|
+
country="USA",
|
1020
|
+
)
|
1021
|
+
ESPN_WIDE_WORLD_OF_SPORTS_COMPLEX = SportsballGeocodeTuple(
|
1022
|
+
city="Lake Buena Vista",
|
1023
|
+
state="FL",
|
1024
|
+
postal="32830",
|
1025
|
+
lat=28.337083,
|
1026
|
+
lng=-81.556,
|
1027
|
+
housenumber="1375",
|
1028
|
+
country="USA",
|
1029
|
+
)
|
976
1030
|
_CACHED_GEOCODES: dict[str, Any] = {
|
977
1031
|
"S.C.G. - Australia": SCG,
|
978
1032
|
"Victoria Park - Australia": SportsballGeocodeTuple(
|
@@ -6288,15 +6342,7 @@ _CACHED_GEOCODES: dict[str, Any] = {
|
|
6288
6342
|
housenumber="200",
|
6289
6343
|
country="USA",
|
6290
6344
|
),
|
6291
|
-
"Vivint Arena, Salt Lake City, Utah":
|
6292
|
-
city="Salt Lake City",
|
6293
|
-
state="UT",
|
6294
|
-
postal="",
|
6295
|
-
lat=40.768333,
|
6296
|
-
lng=-111.901111,
|
6297
|
-
housenumber="301",
|
6298
|
-
country="USA",
|
6299
|
-
),
|
6345
|
+
"Vivint Arena, Salt Lake City, Utah": VIVINT_ARENA,
|
6300
6346
|
"Rock Hill Sports & Event Center, Rock Hill, South Carolina": SportsballGeocodeTuple(
|
6301
6347
|
city="Rock Hill",
|
6302
6348
|
state="SC",
|
@@ -6487,24 +6533,8 @@ _CACHED_GEOCODES: dict[str, Any] = {
|
|
6487
6533
|
"Pepsi Center - Denver, Colorado, U.S. - United States": PEPSI_CENTRE,
|
6488
6534
|
"Staples Center": STAPLES_CENTRE,
|
6489
6535
|
"American Airlines Arena": AMERICAN_AIRLINES_ARENA,
|
6490
|
-
"Chesapeake Energy Arena - Oklahoma City, Oklahoma - United States":
|
6491
|
-
|
6492
|
-
state="OK",
|
6493
|
-
postal="",
|
6494
|
-
lat=35.463333,
|
6495
|
-
lng=-97.515,
|
6496
|
-
housenumber="100",
|
6497
|
-
country="USA",
|
6498
|
-
),
|
6499
|
-
"AT&T Center - San Antonio, Texas - United States": SportsballGeocodeTuple(
|
6500
|
-
city="San Antonio",
|
6501
|
-
state="TX",
|
6502
|
-
postal="",
|
6503
|
-
lat=29.426944,
|
6504
|
-
lng=-98.4375,
|
6505
|
-
housenumber="1",
|
6506
|
-
country="USA",
|
6507
|
-
),
|
6536
|
+
"Chesapeake Energy Arena - Oklahoma City, Oklahoma - United States": CHESAPEAKE_ENERGY_ARENA,
|
6537
|
+
"AT&T Center - San Antonio, Texas - United States": ATT_CENTER,
|
6508
6538
|
"Oakland Arena - Oakland, California - United States": SportsballGeocodeTuple(
|
6509
6539
|
city="Oakland",
|
6510
6540
|
state="CA",
|
@@ -6514,15 +6544,7 @@ _CACHED_GEOCODES: dict[str, Any] = {
|
|
6514
6544
|
housenumber="7000",
|
6515
6545
|
country="USA",
|
6516
6546
|
),
|
6517
|
-
"ESPN Wide World of Sports Complex":
|
6518
|
-
city="Lake Buena Vista",
|
6519
|
-
state="FL",
|
6520
|
-
postal="32830",
|
6521
|
-
lat=28.337083,
|
6522
|
-
lng=-81.556,
|
6523
|
-
housenumber="1375",
|
6524
|
-
country="USA",
|
6525
|
-
),
|
6547
|
+
"ESPN Wide World of Sports Complex": ESPN_WIDE_WORLD_OF_SPORTS_COMPLEX,
|
6526
6548
|
"International Amphitheatre": SportsballGeocodeTuple(
|
6527
6549
|
city="Chicago",
|
6528
6550
|
state="IL",
|
@@ -6798,15 +6820,7 @@ _CACHED_GEOCODES: dict[str, Any] = {
|
|
6798
6820
|
),
|
6799
6821
|
"Target Center - Minneapolis, Minnesota - United States": TARGET_CENTER,
|
6800
6822
|
"Thomas & Mack Center - Paradise, NV - United States": THOMAS_AND_MACK_CENTER,
|
6801
|
-
"Delta Center - Salt Lake City, Utah - United States":
|
6802
|
-
city="Salt Lake City",
|
6803
|
-
state="UT",
|
6804
|
-
postal="",
|
6805
|
-
lat=40.768333,
|
6806
|
-
lng=-111.901111,
|
6807
|
-
housenumber="301",
|
6808
|
-
country="USA",
|
6809
|
-
),
|
6823
|
+
"Delta Center - Salt Lake City, Utah - United States": DELTA_CENTER,
|
6810
6824
|
"Yokohama Arena": SportsballGeocodeTuple(
|
6811
6825
|
city="Kanagawa",
|
6812
6826
|
state="",
|
@@ -6829,15 +6843,7 @@ _CACHED_GEOCODES: dict[str, Any] = {
|
|
6829
6843
|
"Amway Arena": ORLANDO_ARENA,
|
6830
6844
|
"TD Garden - Boston, Massachusetts - United States": TD_GARDEN,
|
6831
6845
|
"American Airlines Center - Dallas, Texas, USA - United States": AMERICAN_AIRLINES_ARENA,
|
6832
|
-
"FTX Arena":
|
6833
|
-
city="Miami",
|
6834
|
-
state="FL",
|
6835
|
-
postal="",
|
6836
|
-
lat=25.781389,
|
6837
|
-
lng=-80.188056,
|
6838
|
-
housenumber="601",
|
6839
|
-
country="USA",
|
6840
|
-
),
|
6846
|
+
"FTX Arena": FTX_ARENA,
|
6841
6847
|
"Rose Garden": SportsballGeocodeTuple(
|
6842
6848
|
city="Portland",
|
6843
6849
|
state="OR",
|
@@ -6981,6 +6987,13 @@ _CACHED_GEOCODES: dict[str, Any] = {
|
|
6981
6987
|
housenumber="3930",
|
6982
6988
|
country="USA",
|
6983
6989
|
),
|
6990
|
+
"Delta Center, Salt Lake City, Utah": DELTA_CENTER,
|
6991
|
+
"AT&T Center, San Antonio, Texas": ATT_CENTER,
|
6992
|
+
"FTX Arena, Miami, Florida": FTX_ARENA,
|
6993
|
+
"Vivint Smart Home Arena, Salt Lake City, Utah": VIVINT_ARENA,
|
6994
|
+
"Chesapeake Energy Arena, Oklahoma City, Oklahoma": CHESAPEAKE_ENERGY_ARENA,
|
6995
|
+
"The Arena, Bay Lake, Florida": ESPN_WIDE_WORLD_OF_SPORTS_COMPLEX,
|
6996
|
+
"HP Field House, Bay Lake, Florida": ESPN_WIDE_WORLD_OF_SPORTS_COMPLEX,
|
6984
6997
|
}
|
6985
6998
|
|
6986
6999
|
|
@@ -13,6 +13,7 @@ PLAYER_FUMBLES_LOST_COLUMN: Literal["fumbles_lost"] = "fumbles_lost"
|
|
13
13
|
FIELD_GOALS_COLUMN: Literal["field_goals"] = "field_goals"
|
14
14
|
FIELD_GOALS_ATTEMPTED_COLUMN: Literal["field_goals_attempted"] = "field_goals_attempted"
|
15
15
|
OFFENSIVE_REBOUNDS_COLUMN: Literal["offensive_rebounds"] = "offensive_rebounds"
|
16
|
+
ASSISTS_COLUMN: Literal["assists"] = "assists"
|
16
17
|
|
17
18
|
|
18
19
|
class PlayerModel(BaseModel):
|
@@ -54,3 +55,8 @@ class PlayerModel(BaseModel):
|
|
54
55
|
json_schema_extra={TYPE_KEY: FieldType.LOOKAHEAD},
|
55
56
|
alias=OFFENSIVE_REBOUNDS_COLUMN,
|
56
57
|
)
|
58
|
+
assists: int | None = Field(
|
59
|
+
...,
|
60
|
+
json_schema_extra={TYPE_KEY: FieldType.LOOKAHEAD},
|
61
|
+
alias=ASSISTS_COLUMN,
|
62
|
+
)
|
@@ -103,18 +103,19 @@ class SportsDBLeagueModel(LeagueModel):
|
|
103
103
|
except ValueError:
|
104
104
|
pass
|
105
105
|
case SeasonType.REGULAR:
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
106
|
+
if self.league != League.NBA:
|
107
|
+
try:
|
108
|
+
for count, round_str in enumerate(range(1, 125)):
|
109
|
+
yield from self._produce_games(
|
110
|
+
str(round_str),
|
111
|
+
count,
|
112
|
+
self._league_id,
|
113
|
+
season_year,
|
114
|
+
season_type,
|
115
|
+
pbar,
|
116
|
+
)
|
117
|
+
except ValueError:
|
118
|
+
pass
|
118
119
|
case SeasonType.POSTSEASON:
|
119
120
|
for count, round_str in enumerate(
|
120
121
|
[125, 150, 160, 170, 180, 200]
|
@@ -1,12 +1,12 @@
|
|
1
1
|
"""Sports Reference game model."""
|
2
2
|
|
3
|
-
# pylint: disable=too-many-locals,too-many-statements,unused-argument
|
3
|
+
# pylint: disable=too-many-locals,too-many-statements,unused-argument,protected-access
|
4
4
|
import datetime
|
5
5
|
import io
|
6
6
|
import logging
|
7
|
-
import time
|
8
7
|
import urllib.parse
|
9
8
|
|
9
|
+
import dateutil
|
10
10
|
import pandas as pd
|
11
11
|
import pytest_is_running
|
12
12
|
import requests_cache
|
@@ -36,10 +36,19 @@ def _create_sportsreference_game_model(
|
|
36
36
|
raise ValueError("scorebox_meta_div is not a Tag.")
|
37
37
|
|
38
38
|
in_divs = scorebox_meta_div.find_all("div")
|
39
|
-
|
39
|
+
current_in_div_idx = 0
|
40
|
+
in_div = in_divs[current_in_div_idx]
|
40
41
|
in_div_text = in_div.get_text().strip()
|
41
|
-
|
42
|
-
|
42
|
+
current_in_div_idx += 1
|
43
|
+
if "Tournament" in in_div_text:
|
44
|
+
in_div_text = in_divs[1].get_text().strip()
|
45
|
+
current_in_div_idx += 1
|
46
|
+
try:
|
47
|
+
dt = parse(in_div_text)
|
48
|
+
except dateutil.parser._parser.ParserError as exc: # type: ignore
|
49
|
+
logging.error("Failed to parse date for URL: %s", url)
|
50
|
+
raise exc
|
51
|
+
venue_div = in_divs[current_in_div_idx]
|
43
52
|
venue_name = venue_div.get_text().strip()
|
44
53
|
scorebox_div = soup.find("div", class_="scorebox")
|
45
54
|
if not isinstance(scorebox_div, Tag):
|
@@ -62,6 +71,7 @@ def _create_sportsreference_game_model(
|
|
62
71
|
fg = {}
|
63
72
|
fga = {}
|
64
73
|
offensive_rebounds = {}
|
74
|
+
assists = {}
|
65
75
|
for df in dfs:
|
66
76
|
if df.index.nlevels > 1:
|
67
77
|
df.columns = df.columns.get_level_values(1)
|
@@ -79,6 +89,10 @@ def _create_sportsreference_game_model(
|
|
79
89
|
orebs = df["OREB"].tolist()
|
80
90
|
for idx, player in enumerate(players):
|
81
91
|
offensive_rebounds[player] = orebs[idx]
|
92
|
+
if "AST" in df.columns.values:
|
93
|
+
asts = df["AST"].tolist()
|
94
|
+
for idx, player in enumerate(players):
|
95
|
+
assists[player] = asts[idx]
|
82
96
|
|
83
97
|
teams: list[TeamModel] = []
|
84
98
|
for a in scorebox_div.find_all("a"):
|
@@ -95,6 +109,7 @@ def _create_sportsreference_game_model(
|
|
95
109
|
fg,
|
96
110
|
fga,
|
97
111
|
offensive_rebounds,
|
112
|
+
assists,
|
98
113
|
)
|
99
114
|
)
|
100
115
|
|
@@ -3,6 +3,7 @@
|
|
3
3
|
# pylint: disable=too-many-arguments,unused-argument
|
4
4
|
import datetime
|
5
5
|
import http
|
6
|
+
import logging
|
6
7
|
from urllib.parse import unquote
|
7
8
|
|
8
9
|
import pytest_is_running
|
@@ -26,18 +27,21 @@ def _create_sportsreference_player_model(
|
|
26
27
|
fg: dict[str, int],
|
27
28
|
fga: dict[str, int],
|
28
29
|
offensive_rebounds: dict[str, int],
|
30
|
+
assists: dict[str, int],
|
29
31
|
) -> PlayerModel | None:
|
30
32
|
"""Create a player model from NCAAB sports reference."""
|
31
33
|
player_url = _fix_url(player_url)
|
32
34
|
response = session.get(player_url, timeout=DEFAULT_TIMEOUT)
|
33
35
|
# Some players can't be accessed on sports reference
|
34
36
|
if response.status_code == http.HTTPStatus.FORBIDDEN:
|
37
|
+
logging.warning("Cannot access player at URL %s", player_url)
|
35
38
|
return None
|
36
39
|
response.raise_for_status()
|
37
40
|
soup = BeautifulSoup(response.text, "html.parser")
|
38
41
|
h1 = soup.find("h1")
|
39
42
|
if h1 is None:
|
40
|
-
|
43
|
+
logging.warning("h1 is null for %s", player_url)
|
44
|
+
return None
|
41
45
|
name = h1.get_text().strip()
|
42
46
|
return PlayerModel(
|
43
47
|
identifier=name,
|
@@ -48,6 +52,7 @@ def _create_sportsreference_player_model(
|
|
48
52
|
field_goals=fg.get(name),
|
49
53
|
field_goals_attempted=fga.get(name),
|
50
54
|
offensive_rebounds=offensive_rebounds.get(name),
|
55
|
+
assists=assists.get(name),
|
51
56
|
)
|
52
57
|
|
53
58
|
|
@@ -58,9 +63,10 @@ def _cached_create_sportsreference_player_model(
|
|
58
63
|
fg: dict[str, int],
|
59
64
|
fga: dict[str, int],
|
60
65
|
offensive_rebounds: dict[str, int],
|
66
|
+
assists: dict[str, int],
|
61
67
|
) -> PlayerModel | None:
|
62
68
|
return _create_sportsreference_player_model(
|
63
|
-
session, player_url, fg, fga, offensive_rebounds
|
69
|
+
session, player_url, fg, fga, offensive_rebounds, assists
|
64
70
|
)
|
65
71
|
|
66
72
|
|
@@ -71,13 +77,14 @@ def create_sportsreference_player_model(
|
|
71
77
|
fg: dict[str, int],
|
72
78
|
fga: dict[str, int],
|
73
79
|
offensive_rebounds: dict[str, int],
|
80
|
+
assists: dict[str, int],
|
74
81
|
) -> PlayerModel | None:
|
75
82
|
"""Create a player model from sports reference."""
|
76
83
|
if not pytest_is_running.is_running():
|
77
84
|
return _cached_create_sportsreference_player_model(
|
78
|
-
session, player_url, fg, fga, offensive_rebounds
|
85
|
+
session, player_url, fg, fga, offensive_rebounds, assists
|
79
86
|
)
|
80
87
|
with session.cache_disabled():
|
81
88
|
return _create_sportsreference_player_model(
|
82
|
-
session, player_url, fg, fga, offensive_rebounds
|
89
|
+
session, player_url, fg, fga, offensive_rebounds, assists
|
83
90
|
)
|
@@ -29,6 +29,7 @@ def _create_sportsreference_team_model(
|
|
29
29
|
fg: dict[str, int],
|
30
30
|
fga: dict[str, int],
|
31
31
|
offensive_rebounds: dict[str, int],
|
32
|
+
assists: dict[str, int],
|
32
33
|
) -> TeamModel:
|
33
34
|
response = session.get(url)
|
34
35
|
response.raise_for_status()
|
@@ -40,7 +41,7 @@ def _create_sportsreference_team_model(
|
|
40
41
|
except (json.decoder.JSONDecodeError, IndexError) as exc:
|
41
42
|
h1 = soup.find("h1")
|
42
43
|
if not isinstance(h1, Tag):
|
43
|
-
raise ValueError("h1 is null.") from exc
|
44
|
+
raise ValueError(f"h1 is null for {url}.") from exc
|
44
45
|
span = h1.find_all("span")
|
45
46
|
name = span[1].get_text().strip()
|
46
47
|
|
@@ -57,7 +58,7 @@ def _create_sportsreference_team_model(
|
|
57
58
|
y
|
58
59
|
for y in [ # pyright: ignore
|
59
60
|
create_sportsreference_player_model(
|
60
|
-
session, x, dt, fg, fga, offensive_rebounds
|
61
|
+
session, x, dt, fg, fga, offensive_rebounds, assists
|
61
62
|
)
|
62
63
|
for x in valid_player_urls
|
63
64
|
]
|
@@ -83,9 +84,19 @@ def _cached_create_sportsreference_team_model(
|
|
83
84
|
fg: dict[str, int],
|
84
85
|
fga: dict[str, int],
|
85
86
|
offensive_rebounds: dict[str, int],
|
87
|
+
assists: dict[str, int],
|
86
88
|
) -> TeamModel:
|
87
89
|
return _create_sportsreference_team_model(
|
88
|
-
session,
|
90
|
+
session,
|
91
|
+
url,
|
92
|
+
dt,
|
93
|
+
league,
|
94
|
+
player_urls,
|
95
|
+
points,
|
96
|
+
fg,
|
97
|
+
fga,
|
98
|
+
offensive_rebounds,
|
99
|
+
assists,
|
89
100
|
)
|
90
101
|
|
91
102
|
|
@@ -99,13 +110,32 @@ def create_sportsreference_team_model(
|
|
99
110
|
fg: dict[str, int],
|
100
111
|
fga: dict[str, int],
|
101
112
|
offensive_rebounds: dict[str, int],
|
113
|
+
assists: dict[str, int],
|
102
114
|
) -> TeamModel:
|
103
115
|
"""Create a team model from Sports Reference."""
|
104
116
|
if not pytest_is_running.is_running():
|
105
117
|
return _cached_create_sportsreference_team_model(
|
106
|
-
session,
|
118
|
+
session,
|
119
|
+
url,
|
120
|
+
dt,
|
121
|
+
league,
|
122
|
+
player_urls,
|
123
|
+
points,
|
124
|
+
fg,
|
125
|
+
fga,
|
126
|
+
offensive_rebounds,
|
127
|
+
assists,
|
107
128
|
)
|
108
129
|
with session.cache_disabled():
|
109
130
|
return _create_sportsreference_team_model(
|
110
|
-
session,
|
131
|
+
session,
|
132
|
+
url,
|
133
|
+
dt,
|
134
|
+
league,
|
135
|
+
player_urls,
|
136
|
+
points,
|
137
|
+
fg,
|
138
|
+
fga,
|
139
|
+
offensive_rebounds,
|
140
|
+
assists,
|
111
141
|
)
|
@@ -17,6 +17,7 @@ NAME_COLUMN: Literal["name"] = "name"
|
|
17
17
|
FIELD_GOALS_COLUMN: Literal["field_goals"] = "field_goals"
|
18
18
|
FIELD_GOALS_ATTEMPTED_COLUMN: Literal["field_goals_attempted"] = "field_goals_attempted"
|
19
19
|
OFFENSIVE_REBOUNDS_COLUMN: Literal["offensive_rebounds"] = "offensive_rebounds"
|
20
|
+
ASSISTS_COLUMN: Literal["assists"] = "assists"
|
20
21
|
|
21
22
|
|
22
23
|
def _calculate_kicks(data: dict[str, Any]) -> int | None:
|
@@ -75,6 +76,20 @@ def _calculate_offensive_rebounds(data: dict[str, Any]) -> int | None:
|
|
75
76
|
return offensive_rebounds
|
76
77
|
|
77
78
|
|
79
|
+
def _calculate_assists(data: dict[str, Any]) -> int | None:
|
80
|
+
assists = 0
|
81
|
+
found_assists = False
|
82
|
+
for player in data[PLAYER_COLUMN_PREFIX]:
|
83
|
+
player_assists = player.assists
|
84
|
+
if player_assists is None:
|
85
|
+
continue
|
86
|
+
found_assists = True
|
87
|
+
assists += player_assists
|
88
|
+
if not found_assists:
|
89
|
+
return None
|
90
|
+
return assists
|
91
|
+
|
92
|
+
|
78
93
|
class TeamModel(BaseModel):
|
79
94
|
"""The serialisable team class."""
|
80
95
|
|
@@ -116,3 +131,8 @@ class TeamModel(BaseModel):
|
|
116
131
|
json_schema_extra={TYPE_KEY: FieldType.LOOKAHEAD},
|
117
132
|
alias=OFFENSIVE_REBOUNDS_COLUMN,
|
118
133
|
)
|
134
|
+
assists: int | None = Field(
|
135
|
+
default_factory=_calculate_assists,
|
136
|
+
json_schema_extra={TYPE_KEY: FieldType.LOOKAHEAD},
|
137
|
+
alias=ASSISTS_COLUMN,
|
138
|
+
)
|
{sportsball-0.3.15 → sportsball-0.3.16}/sportsball/data/weather/openmeteo/openmeteo_weather_model.py
RENAMED
@@ -26,17 +26,23 @@ def _parse_openmeteo(
|
|
26
26
|
return None
|
27
27
|
if hourly is None:
|
28
28
|
raise ValueError("hourly is null.")
|
29
|
+
dt_index = pd.date_range(
|
30
|
+
start=pd.to_datetime(hourly.Time(), unit="s"),
|
31
|
+
end=pd.to_datetime(hourly.TimeEnd(), unit="s"),
|
32
|
+
freq=pd.Timedelta(seconds=hourly.Interval()),
|
33
|
+
inclusive="left",
|
34
|
+
tz=tz,
|
35
|
+
)
|
36
|
+
row_count = min(
|
37
|
+
len(hourly.Variables(0).ValuesAsNumpy()), # type: ignore
|
38
|
+
len(hourly.Variables(1).ValuesAsNumpy()), # type: ignore
|
39
|
+
len(dt_index),
|
40
|
+
)
|
29
41
|
hourly_df = pd.DataFrame(
|
30
|
-
index=
|
31
|
-
start=pd.to_datetime(hourly.Time(), unit="s"),
|
32
|
-
end=pd.to_datetime(hourly.TimeEnd(), unit="s"),
|
33
|
-
freq=pd.Timedelta(seconds=hourly.Interval()),
|
34
|
-
inclusive="left",
|
35
|
-
tz=tz,
|
36
|
-
)[: len(hourly.Variables(0).ValuesAsNumpy())], # type: ignore
|
42
|
+
index=dt_index[:row_count], # type: ignore
|
37
43
|
data={
|
38
|
-
"temperature_2m": hourly.Variables(0).ValuesAsNumpy(), # type: ignore
|
39
|
-
"relative_humidity_2m": hourly.Variables(1).ValuesAsNumpy(), # type: ignore
|
44
|
+
"temperature_2m": hourly.Variables(0).ValuesAsNumpy()[:row_count], # type: ignore
|
45
|
+
"relative_humidity_2m": hourly.Variables(1).ValuesAsNumpy()[:row_count], # type: ignore
|
40
46
|
},
|
41
47
|
)
|
42
48
|
dt = dt.replace(tzinfo=None)
|