sportsball 0.3.19__tar.gz → 0.3.22__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.19/sportsball.egg-info → sportsball-0.3.22}/PKG-INFO +5 -1
- {sportsball-0.3.19 → sportsball-0.3.22}/README.md +2 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/requirements.txt +2 -1
- {sportsball-0.3.19 → sportsball-0.3.22}/setup.py +9 -6
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/__init__.py +1 -1
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/combined/combined_league_model.py +2 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/google/google_address_model.py +38 -9
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/google/google_news_model.py +1 -1
- sportsball-0.3.22/sportsball/data/ncaaf/__init__.py +5 -0
- sportsball-0.3.22/sportsball/data/ncaaf/combined/ncaaf_combined_league_model.py +34 -0
- sportsball-0.3.22/sportsball/data/ncaaf/oddsportal/ncaaf_oddsportal_league_model.py +15 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/oddsportal/oddsportal_game_model.py +16 -9
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/oddsportal/oddsportal_league_model.py +32 -7
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/oddsportal/oddsportal_team_model.py +8 -5
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/sportsreference/sportsreference_game_model.py +130 -29
- sportsball-0.3.22/sportsball/vendor/pygooglenews/__init__.py +203 -0
- {sportsball-0.3.19 → sportsball-0.3.22/sportsball.egg-info}/PKG-INFO +5 -1
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball.egg-info/SOURCES.txt +8 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball.egg-info/requires.txt +2 -0
- sportsball-0.3.22/tests/data/oddsportal/__init__.py +0 -0
- sportsball-0.3.22/tests/data/oddsportal/oddsportal_game_model_test.py +35 -0
- sportsball-0.3.22/tests/data/sportsdb/__init__.py +0 -0
- sportsball-0.3.22/tests/data/sportsreference/__init__.py +0 -0
- sportsball-0.3.22/tests/data/sportsreference/sportsreference_game_model_test.py +97 -0
- sportsball-0.3.22/tests/data/x/__init__.py +0 -0
- sportsball-0.3.19/sportsball/data/ncaaf/__init__.py +0 -5
- sportsball-0.3.19/tests/data/sportsreference/sportsreference_game_model_test.py +0 -30
- {sportsball-0.3.19 → sportsball-0.3.22}/LICENSE +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/MANIFEST.in +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/setup.cfg +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/__main__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/args.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/cache.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/address_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/afltables/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/afltables/afl_afltables_game_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/afltables/afl_afltables_league_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/afltables/afl_afltables_player_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/afltables/afl_afltables_team_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/afltables/afl_afltables_venue_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/aussportsbetting/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/aussportsbetting/afl_aussportsbetting_league_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/combined/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/combined/afl_combined_league_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/espn/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/espn/afl_espn_league_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/oddsportal/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/oddsportal/afl_oddsportal_league_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/aussportsbetting/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/aussportsbetting/aussportsbetting_bookie_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/aussportsbetting/aussportsbetting_game_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/aussportsbetting/aussportsbetting_league_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/aussportsbetting/aussportsbetting_odds_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/aussportsbetting/aussportsbetting_team_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/aussportsbetting/aussportsbetting_venue_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/bookie_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/combined/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/combined/combined_address_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/combined/combined_game_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/combined/combined_player_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/combined/combined_team_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/combined/combined_venue_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/combined/combined_weather_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/espn/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/espn/espn_bookie_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/espn/espn_game_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/espn/espn_league_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/espn/espn_odds_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/espn/espn_player_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/espn/espn_team_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/espn/espn_venue_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/field_type.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/game_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/google/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/league.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/league_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/combined/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/combined/nba_combined_league_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/espn/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/espn/nba_espn_league_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/nba/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/nba/nba_nba_game_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/nba/nba_nba_league_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/nba/nba_nba_player_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/nba/nba_nba_team_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/oddsportal/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/oddsportal/nba_oddsportal_league_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/sportsdb/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/sportsdb/nba_sportsdb_league_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/sportsreference/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/sportsreference/nba_sportsreference_league_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/ncaab/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/ncaab/combined/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/ncaab/combined/ncaab_combined_league_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/ncaab/espn/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/ncaab/espn/ncaab_espn_league_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/ncaab/oddsportal/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/ncaab/oddsportal/ncaab_oddsportal_league_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/ncaab/sportsreference/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/ncaab/sportsreference/ncaab_sportsreference_league_model.py +0 -0
- {sportsball-0.3.19/sportsball/data/ncaaf/espn → sportsball-0.3.22/sportsball/data/ncaaf/combined}/__init__.py +0 -0
- {sportsball-0.3.19/sportsball/data/nfl/aussportsbetting → sportsball-0.3.22/sportsball/data/ncaaf/espn}/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/ncaaf/espn/ncaaf_espn_league_model.py +0 -0
- {sportsball-0.3.19/sportsball/data/nfl/combined → sportsball-0.3.22/sportsball/data/ncaaf/oddsportal}/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/news_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nfl/__init__.py +0 -0
- {sportsball-0.3.19/sportsball/data/nfl/oddsportal → sportsball-0.3.22/sportsball/data/nfl/aussportsbetting}/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nfl/aussportsbetting/nfl_aussportsbetting_league_model.py +0 -0
- {sportsball-0.3.19/sportsball/data/nfl/sportsdb → sportsball-0.3.22/sportsball/data/nfl/combined}/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nfl/combined/nfl_combined_league_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nfl/espn/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nfl/espn/nfl_espn_league_model.py +0 -0
- {sportsball-0.3.19/sportsball/data → sportsball-0.3.22/sportsball/data/nfl}/oddsportal/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nfl/oddsportal/nfl_oddsportal_league_model.py +0 -0
- {sportsball-0.3.19/sportsball/data → sportsball-0.3.22/sportsball/data/nfl}/sportsdb/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nfl/sportsdb/nfl_sportsdb_league_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/odds_model.py +0 -0
- {sportsball-0.3.19/sportsball/data/sportsreference → sportsball-0.3.22/sportsball/data/oddsportal}/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/oddsportal/oddsportal_bookie_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/oddsportal/oddsportal_odds_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/oddsportal/oddsportal_venue_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/player_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/season_type.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/social_model.py +0 -0
- {sportsball-0.3.19/sportsball/data/weather → sportsball-0.3.22/sportsball/data/sportsdb}/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/sportsdb/sportsdb_game_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/sportsdb/sportsdb_league_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/sportsdb/sportsdb_team_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/sportsdb/sportsdb_venue_model.py +0 -0
- {sportsball-0.3.19/sportsball/data/weather/gribstream → sportsball-0.3.22/sportsball/data/sportsreference}/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/sportsreference/sportsreference_league_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/sportsreference/sportsreference_player_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/sportsreference/sportsreference_team_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/sportsreference/sportsreference_venue_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/team_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/venue_model.py +0 -0
- {sportsball-0.3.19/sportsball/data/weather/openmeteo → sportsball-0.3.22/sportsball/data/weather}/__init__.py +0 -0
- {sportsball-0.3.19/sportsball/data/wikipedia → sportsball-0.3.22/sportsball/data/weather/gribstream}/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/weather/gribstream/gribstream_weather_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/weather/multi_weather_model.py +0 -0
- {sportsball-0.3.19/sportsball/data/x → sportsball-0.3.22/sportsball/data/weather/openmeteo}/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/weather/openmeteo/openmeteo_weather_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/weather_model.py +0 -0
- {sportsball-0.3.19/tests → sportsball-0.3.22/sportsball/data/wikipedia}/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/wikipedia/wikipedia_venue_model.py +0 -0
- {sportsball-0.3.19/tests/data → sportsball-0.3.22/sportsball/data/x}/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/x/x_social_model.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/logger.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/loglevel.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/proxy_session.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/session.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/sportsball.py +0 -0
- {sportsball-0.3.19/tests/data/afl → sportsball-0.3.22/sportsball/vendor}/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball.egg-info/dependency_links.txt +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball.egg-info/entry_points.txt +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball.egg-info/not-zip-safe +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/sportsball.egg-info/top_level.txt +0 -0
- {sportsball-0.3.19/tests/data/afl/afltables → sportsball-0.3.22/tests}/__init__.py +0 -0
- {sportsball-0.3.19/tests/data/aussportsbetting → sportsball-0.3.22/tests/data}/__init__.py +0 -0
- {sportsball-0.3.19/tests/data/combined → sportsball-0.3.22/tests/data/afl}/__init__.py +0 -0
- {sportsball-0.3.19/tests/data/espn → sportsball-0.3.22/tests/data/afl/afltables}/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/afl/afltables/afl_afltables_player_model_test.py +0 -0
- {sportsball-0.3.19/tests/data/google → sportsball-0.3.22/tests/data/aussportsbetting}/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/aussportsbetting/aussportsbetting_game_model_test.py +0 -0
- {sportsball-0.3.19/tests/data/nba → sportsball-0.3.22/tests/data/combined}/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/combined/combined_game_model_test.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/combined/combined_player_model_test.py +0 -0
- {sportsball-0.3.19/tests/data/nba/nba → sportsball-0.3.22/tests/data/espn}/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/espn/espn_game_model_test.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/espn/espn_player_model_test.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/game_model_test.py +0 -0
- {sportsball-0.3.19/tests/data/nba/sportsdb → sportsball-0.3.22/tests/data/google}/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/google/google_address_model_test.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/google/google_news_model_test.py +0 -0
- {sportsball-0.3.19/tests/data/nba/sportsreference → sportsball-0.3.22/tests/data/nba}/__init__.py +0 -0
- {sportsball-0.3.19/tests/data/ncaab → sportsball-0.3.22/tests/data/nba/nba}/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/nba/nba/nba_nba_game_model_test.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/nba/nba/nba_nba_league_model_test.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/nba/nba/nba_nba_player_model_test.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/nba/nba/nba_nba_team_model_test.py +0 -0
- {sportsball-0.3.19/tests/data/ncaab/sportsreference → sportsball-0.3.22/tests/data/nba/sportsdb}/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/nba/sportsdb/nba_sportsdb_league_model_test.py +0 -0
- {sportsball-0.3.19/tests/data/nfl → sportsball-0.3.22/tests/data/nba/sportsreference}/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/nba/sportsreference/nba_sportsreference_league_model_test.py +0 -0
- {sportsball-0.3.19/tests/data/nfl/sportsdb → sportsball-0.3.22/tests/data/ncaab}/__init__.py +0 -0
- {sportsball-0.3.19/tests/data/sportsdb → sportsball-0.3.22/tests/data/ncaab/sportsreference}/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/ncaab/sportsreference/ncaab_sportsreference_league_model_test.py +0 -0
- {sportsball-0.3.19/tests/data/sportsreference → sportsball-0.3.22/tests/data/nfl}/__init__.py +0 -0
- {sportsball-0.3.19/tests/data/x → sportsball-0.3.22/tests/data/nfl/sportsdb}/__init__.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/nfl/sportsdb/nfl_sportsdb_league_model_test.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/player_model_test.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/social_model_test.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/sportsdb/sportsdb_game_model_test.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/sportsdb/sportsdb_league_model_test.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/sportsdb/sportsdb_team_model_test.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/sportsdb/sportsdb_venue_model_test.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/sportsreference/sportsreference_league_model_test.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/sportsreference/sportsreference_player_model_test.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/sportsreference/sportsreference_team_model_test.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/sportsreference/sportsreference_venue_model_test.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/team_model_test.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/x/x_social_model_test.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/tests/proxy_session_test.py +0 -0
- {sportsball-0.3.19 → sportsball-0.3.22}/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.22
|
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
|
@@ -41,6 +41,8 @@ Requires-Dist: tenacity>=9.0.0
|
|
41
41
|
Requires-Dist: random_user_agent>=1.0.1
|
42
42
|
Requires-Dist: wayback>=0.4.5
|
43
43
|
Requires-Dist: cryptography>=44.0.0
|
44
|
+
Requires-Dist: feedparser>=6.0.11
|
45
|
+
Requires-Dist: dateparser>=1.2.0
|
44
46
|
Dynamic: author
|
45
47
|
Dynamic: author-email
|
46
48
|
Dynamic: classifier
|
@@ -97,6 +99,8 @@ Python 3.11.6:
|
|
97
99
|
- [random_user_agent](https://github.com/Luqman-Ud-Din/random_user_agent)
|
98
100
|
- [wayback](https://github.com/edgi-govdata-archiving/wayback)
|
99
101
|
- [cryptography](https://cryptography.io/en/latest/)
|
102
|
+
- [feedparser](https://github.com/kurtmckee/feedparser)
|
103
|
+
- [dateparser](https://dateparser.readthedocs.io/en/latest/)
|
100
104
|
|
101
105
|
## Raison D'être :thought_balloon:
|
102
106
|
|
@@ -43,6 +43,8 @@ Python 3.11.6:
|
|
43
43
|
- [random_user_agent](https://github.com/Luqman-Ud-Din/random_user_agent)
|
44
44
|
- [wayback](https://github.com/edgi-govdata-archiving/wayback)
|
45
45
|
- [cryptography](https://cryptography.io/en/latest/)
|
46
|
+
- [feedparser](https://github.com/kurtmckee/feedparser)
|
47
|
+
- [dateparser](https://dateparser.readthedocs.io/en/latest/)
|
46
48
|
|
47
49
|
## Raison D'être :thought_balloon:
|
48
50
|
|
@@ -18,7 +18,6 @@ nba_api>=1.7.0
|
|
18
18
|
timezonefinder>=6.5.7
|
19
19
|
pydantic>=2.10.4
|
20
20
|
flatten_json>=0.1.14
|
21
|
-
-e git+https://github.com/8W9aG/pygooglenews@d40ad6f01cb661bbb1c4b4022896f93c83c88364#egg=pygooglenews
|
22
21
|
extruct>=0.18.0
|
23
22
|
wikipedia-api>=0.8.1
|
24
23
|
tweepy>=4.15.0
|
@@ -29,3 +28,5 @@ tenacity>=9.0.0
|
|
29
28
|
random_user_agent>=1.0.1
|
30
29
|
wayback>=0.4.5
|
31
30
|
cryptography>=44.0.0
|
31
|
+
feedparser>=6.0.11
|
32
|
+
dateparser>=1.2.0
|
@@ -13,17 +13,20 @@ def install_requires() -> typing.List[str]:
|
|
13
13
|
with open(
|
14
14
|
Path(__file__).absolute().parent.joinpath('requirements.txt'), "r"
|
15
15
|
) as requirments_txt_handle:
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
16
|
+
for require in requirments_txt_handle:
|
17
|
+
if not require.startswith(".") and not require.startswith("-e"):
|
18
|
+
requires.append(require)
|
19
|
+
else:
|
20
|
+
require_file = require.split()[-1]
|
21
|
+
require_file = require_file.replace("git+", "")
|
22
|
+
package_name = require_file.split("#egg=")[-1]
|
23
|
+
requires.append(package_name + " @ " + require_file)
|
21
24
|
return requires
|
22
25
|
|
23
26
|
|
24
27
|
setup(
|
25
28
|
name='sportsball',
|
26
|
-
version='0.3.
|
29
|
+
version='0.3.22',
|
27
30
|
description='A library for pulling in and normalising sports stats.',
|
28
31
|
long_description=long_description,
|
29
32
|
long_description_content_type='text/markdown',
|
@@ -3,6 +3,7 @@
|
|
3
3
|
# pylint: disable=raise-missing-from
|
4
4
|
import logging
|
5
5
|
import multiprocessing
|
6
|
+
import traceback
|
6
7
|
from multiprocessing import Pool
|
7
8
|
from typing import Any, Iterator
|
8
9
|
|
@@ -21,6 +22,7 @@ def _produce_league_games(league_model: LeagueModel) -> list[dict[str, Any]]:
|
|
21
22
|
return [x.model_dump() for x in league_model.games]
|
22
23
|
except Exception as exc:
|
23
24
|
logging.error("Exception: %s", str(exc))
|
25
|
+
logging.error(traceback.format_exc())
|
24
26
|
raise ValueError(str(exc))
|
25
27
|
|
26
28
|
|
@@ -1108,6 +1108,15 @@ TEXAS_AM_COMMERCE_FIELD_HOUSE = SportsballGeocodeTuple(
|
|
1108
1108
|
housenumber="2600",
|
1109
1109
|
country="USA",
|
1110
1110
|
)
|
1111
|
+
WISDOM_GYM = SportsballGeocodeTuple(
|
1112
|
+
city="Stephenville",
|
1113
|
+
state="TX",
|
1114
|
+
postal="",
|
1115
|
+
lat=32.215438,
|
1116
|
+
lng=-98.220617,
|
1117
|
+
housenumber="",
|
1118
|
+
country="USA",
|
1119
|
+
)
|
1111
1120
|
_CACHED_GEOCODES: dict[str, Any] = {
|
1112
1121
|
"S.C.G. - Australia": SCG,
|
1113
1122
|
"Victoria Park - Australia": SportsballGeocodeTuple(
|
@@ -3528,15 +3537,7 @@ _CACHED_GEOCODES: dict[str, Any] = {
|
|
3528
3537
|
housenumber="8600",
|
3529
3538
|
country="USA",
|
3530
3539
|
),
|
3531
|
-
"Wisdom Gym, Stephenville, Texas":
|
3532
|
-
city="Stephenville",
|
3533
|
-
state="TX",
|
3534
|
-
postal="",
|
3535
|
-
lat=32.215438,
|
3536
|
-
lng=-98.220617,
|
3537
|
-
housenumber="",
|
3538
|
-
country="USA",
|
3539
|
-
),
|
3540
|
+
"Wisdom Gym, Stephenville, Texas": WISDOM_GYM,
|
3540
3541
|
"Skyhawk Arena, Martin, Tennessee": SportsballGeocodeTuple(
|
3541
3542
|
city="Martin",
|
3542
3543
|
state="TN",
|
@@ -7066,6 +7067,34 @@ _CACHED_GEOCODES: dict[str, Any] = {
|
|
7066
7067
|
housenumber="",
|
7067
7068
|
country="USA",
|
7068
7069
|
),
|
7070
|
+
"Dallas, Texas": SportsballGeocodeTuple(
|
7071
|
+
city="Dallas",
|
7072
|
+
state="TX",
|
7073
|
+
postal="",
|
7074
|
+
lat=32.779167,
|
7075
|
+
lng=-96.808889,
|
7076
|
+
housenumber="",
|
7077
|
+
country="USA",
|
7078
|
+
),
|
7079
|
+
"The Gabba, Brisbane, Australia": GABBA,
|
7080
|
+
"Sydney Cricket Ground, Sydney, Australia": SCG,
|
7081
|
+
"People First Stadium, Gold Coast, Australia": PEOPLE_FIRST_STADIUM,
|
7082
|
+
"Engie Stadium, Sydney, Australia": ENGIE_STADIUM,
|
7083
|
+
"Melbourne Cricket Ground, Melbourne, Australia": MCG,
|
7084
|
+
"GMHBA Stadium, Geelong, Australia": GMHBA_STADIUM,
|
7085
|
+
"Marvel Stadium, Melbourne, Australia": MARVEL_STADIUM,
|
7086
|
+
"Adelaide Oval, Adelaide, Australia": ADELAIDE_OVAL,
|
7087
|
+
"Optus Stadium, Perth, Australia": OPTUS_STADIUM,
|
7088
|
+
"Wisdom Gymnasium, Stephenville, Texas": WISDOM_GYM,
|
7089
|
+
"Charlotte, North Carolina": SportsballGeocodeTuple(
|
7090
|
+
city="Charlotte",
|
7091
|
+
state="NC",
|
7092
|
+
postal="",
|
7093
|
+
lat=35.227222,
|
7094
|
+
lng=-80.843056,
|
7095
|
+
housenumber="",
|
7096
|
+
country="USA",
|
7097
|
+
),
|
7069
7098
|
}
|
7070
7099
|
|
7071
7100
|
|
@@ -7,9 +7,9 @@ import pytest_is_running
|
|
7
7
|
import requests_cache
|
8
8
|
from bs4 import BeautifulSoup
|
9
9
|
from dateutil import parser
|
10
|
-
from pygooglenews import GoogleNews # type: ignore
|
11
10
|
|
12
11
|
from ...cache import MEMORY
|
12
|
+
from ...vendor.pygooglenews import GoogleNews # type: ignore
|
13
13
|
from ..league import League, long_name
|
14
14
|
from ..news_model import NewsModel
|
15
15
|
|
@@ -0,0 +1,34 @@
|
|
1
|
+
"""NCAAF combined league model."""
|
2
|
+
|
3
|
+
import requests_cache
|
4
|
+
|
5
|
+
from ...combined.combined_league_model import CombinedLeagueModel
|
6
|
+
from ...league import League
|
7
|
+
from ..espn.ncaaf_espn_league_model import NCAAFESPNLeagueModel
|
8
|
+
from ..oddsportal.ncaaf_oddsportal_league_model import \
|
9
|
+
NCAAFOddsPortalLeagueModel
|
10
|
+
|
11
|
+
NCAAF_TEAM_IDENTITY_MAP: dict[str, str] = {}
|
12
|
+
NCAAF_VENUE_IDENTITY_MAP: dict[str, str] = {}
|
13
|
+
|
14
|
+
|
15
|
+
class NCAAFCombinedLeagueModel(CombinedLeagueModel):
|
16
|
+
"""NCAAF combined implementation of the league model."""
|
17
|
+
|
18
|
+
def __init__(self, session: requests_cache.CachedSession) -> None:
|
19
|
+
super().__init__(
|
20
|
+
session,
|
21
|
+
League.NCAAF,
|
22
|
+
[
|
23
|
+
NCAAFESPNLeagueModel(session),
|
24
|
+
NCAAFOddsPortalLeagueModel(session),
|
25
|
+
],
|
26
|
+
)
|
27
|
+
|
28
|
+
@classmethod
|
29
|
+
def team_identity_map(cls) -> dict[str, str]:
|
30
|
+
return NCAAF_TEAM_IDENTITY_MAP
|
31
|
+
|
32
|
+
@classmethod
|
33
|
+
def venue_identity_map(cls) -> dict[str, str]:
|
34
|
+
return NCAAF_VENUE_IDENTITY_MAP
|
@@ -0,0 +1,15 @@
|
|
1
|
+
"""NCAAF OddsPortal league model."""
|
2
|
+
|
3
|
+
# pylint: disable=line-too-long
|
4
|
+
|
5
|
+
import requests_cache
|
6
|
+
|
7
|
+
from ...league import League
|
8
|
+
from ...oddsportal.oddsportal_league_model import OddsPortalLeagueModel
|
9
|
+
|
10
|
+
|
11
|
+
class NCAAFOddsPortalLeagueModel(OddsPortalLeagueModel):
|
12
|
+
"""NCAAF OddsPortal implementation of the league model."""
|
13
|
+
|
14
|
+
def __init__(self, session: requests_cache.CachedSession) -> None:
|
15
|
+
super().__init__(League.NCAAF, session)
|
@@ -24,17 +24,17 @@ def _create_oddsportal_game_model(
|
|
24
24
|
response = session.get(url)
|
25
25
|
response.raise_for_status()
|
26
26
|
|
27
|
-
soup = BeautifulSoup(
|
28
|
-
event_tag = soup.find("
|
27
|
+
soup = BeautifulSoup(response.text, "html.parser")
|
28
|
+
event_tag = soup.find("div", id="react-event-header")
|
29
29
|
if not isinstance(event_tag, Tag):
|
30
|
-
raise ValueError("event_tag is not a tag.")
|
31
|
-
event = json.loads(str(event_tag["
|
30
|
+
raise ValueError(f"event_tag is not a tag for URL: {url}.")
|
31
|
+
event = json.loads(str(event_tag["data"]))
|
32
32
|
|
33
33
|
event_body = event["eventBody"]
|
34
34
|
event_data = event["eventData"]
|
35
35
|
dt = datetime.datetime.fromtimestamp(event_body["startDate"])
|
36
36
|
end_dt = None
|
37
|
-
if
|
37
|
+
if event_body.get("endDate", False) is not False:
|
38
38
|
end_dt = datetime.datetime.fromtimestamp(event_body["endDate"])
|
39
39
|
version_id = str(event_data["versionId"])
|
40
40
|
sport_id = str(event_data["sportId"])
|
@@ -54,11 +54,12 @@ def _create_oddsportal_game_model(
|
|
54
54
|
src_response = session.get(src_url)
|
55
55
|
src_response.raise_for_status()
|
56
56
|
variables = src_response.text
|
57
|
-
|
57
|
+
sentinel = 'break}return e.next=9,g(r.data,"'
|
58
|
+
variables = variables[variables.find(sentinel) + len(sentinel) :]
|
58
59
|
variables = variables[
|
59
60
|
: variables.find('");case 9:return s=e.sent,l=JSON.parse(s),e.abrupt')
|
60
61
|
]
|
61
|
-
|
62
|
+
password_str, salt_str = variables.split('","')
|
62
63
|
salt = str.encode(salt_str)
|
63
64
|
password = str.encode(password_str)
|
64
65
|
break
|
@@ -68,6 +69,12 @@ def _create_oddsportal_game_model(
|
|
68
69
|
raise ValueError("password is null.")
|
69
70
|
|
70
71
|
bookie_names = event_body["providersNames"]
|
72
|
+
home_points = None
|
73
|
+
if event_body["homeResult"] != "":
|
74
|
+
home_points = float(event_body["homeResult"])
|
75
|
+
away_points = None
|
76
|
+
if event_body["awayResult"] != "":
|
77
|
+
away_points = float(event_body["awayResult"])
|
71
78
|
|
72
79
|
return GameModel(
|
73
80
|
dt=dt,
|
@@ -86,7 +93,7 @@ def _create_oddsportal_game_model(
|
|
86
93
|
dt,
|
87
94
|
event_data["home"],
|
88
95
|
league,
|
89
|
-
|
96
|
+
home_points,
|
90
97
|
version_id,
|
91
98
|
sport_id,
|
92
99
|
unique_id,
|
@@ -103,7 +110,7 @@ def _create_oddsportal_game_model(
|
|
103
110
|
dt,
|
104
111
|
event_data["away"],
|
105
112
|
league,
|
106
|
-
|
113
|
+
away_points,
|
107
114
|
version_id,
|
108
115
|
sport_id,
|
109
116
|
unique_id,
|
{sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/oddsportal/oddsportal_league_model.py
RENAMED
@@ -13,6 +13,16 @@ from ..league import League
|
|
13
13
|
from ..league_model import LeagueModel
|
14
14
|
from .oddsportal_game_model import create_oddsportal_game_model
|
15
15
|
|
16
|
+
# Sports
|
17
|
+
AMERICAN_FOOTBALL = "american-football"
|
18
|
+
BASKETBALL = "basketball"
|
19
|
+
|
20
|
+
# Countries
|
21
|
+
USA = "usa"
|
22
|
+
|
23
|
+
# Leagues
|
24
|
+
NCAA = "ncaa"
|
25
|
+
|
16
26
|
|
17
27
|
class OddsPortalLeagueModel(LeagueModel):
|
18
28
|
"""Odds Portal implementation of the league model."""
|
@@ -23,11 +33,13 @@ class OddsPortalLeagueModel(LeagueModel):
|
|
23
33
|
case League.AFL:
|
24
34
|
return "/".join(["aussie-rules", "australia", "afl", ""])
|
25
35
|
case League.NBA:
|
26
|
-
return "/".join([
|
36
|
+
return "/".join([BASKETBALL, USA, "nba", ""])
|
27
37
|
case League.NCAAB:
|
28
|
-
return "/".join([
|
38
|
+
return "/".join([BASKETBALL, USA, NCAA, ""])
|
39
|
+
case League.NCAAF:
|
40
|
+
return "/".join([AMERICAN_FOOTBALL, USA, NCAA, ""])
|
29
41
|
case League.NFL:
|
30
|
-
return "/".join([
|
42
|
+
return "/".join([AMERICAN_FOOTBALL, USA, "nfl", ""])
|
31
43
|
case _:
|
32
44
|
raise ValueError(f"Unsupported league: {self.league}")
|
33
45
|
|
@@ -41,7 +53,10 @@ class OddsPortalLeagueModel(LeagueModel):
|
|
41
53
|
if jsonld["@type"] != "SportsEvent":
|
42
54
|
continue
|
43
55
|
game_model = create_oddsportal_game_model(
|
44
|
-
self.session,
|
56
|
+
self.session,
|
57
|
+
urllib.parse.urljoin(base_url, jsonld["url"]),
|
58
|
+
self.league,
|
59
|
+
True,
|
45
60
|
)
|
46
61
|
pbar.update(1)
|
47
62
|
pbar.set_description(f"OddsPortal {game_model.dt}")
|
@@ -56,7 +71,11 @@ class OddsPortalLeagueModel(LeagueModel):
|
|
56
71
|
continue
|
57
72
|
seen_urls.add(url)
|
58
73
|
|
59
|
-
|
74
|
+
if url.endswith("results/"):
|
75
|
+
with self.session.cache_disabled():
|
76
|
+
response = self.session.get(url)
|
77
|
+
else:
|
78
|
+
response = self.session.get(url)
|
60
79
|
response.raise_for_status()
|
61
80
|
|
62
81
|
soup = BeautifulSoup(response.text, "html.parser")
|
@@ -73,9 +92,15 @@ class OddsPortalLeagueModel(LeagueModel):
|
|
73
92
|
if not isinstance(tournament_component, Tag):
|
74
93
|
raise ValueError("tournament_component is not a tag.")
|
75
94
|
matches = json.loads(str(tournament_component[":sport-data"]))
|
76
|
-
|
95
|
+
component = matches.get("tournamentGamesComponent", matches.get("d"))
|
96
|
+
if component.get("total") == 0:
|
97
|
+
break
|
98
|
+
for match in component.get("rows", []):
|
77
99
|
game_model = create_oddsportal_game_model(
|
78
|
-
self.session,
|
100
|
+
self.session,
|
101
|
+
urllib.parse.urljoin(url, match["url"]),
|
102
|
+
self.league,
|
103
|
+
False,
|
79
104
|
)
|
80
105
|
pbar.update(1)
|
81
106
|
pbar.set_description(f"OddsPortal {game_model.dt}")
|
@@ -25,7 +25,7 @@ def _create_oddsportal_team_model(
|
|
25
25
|
dt: datetime.datetime,
|
26
26
|
team_name: str,
|
27
27
|
league: League,
|
28
|
-
points: float,
|
28
|
+
points: float | None,
|
29
29
|
version_id: str,
|
30
30
|
sport_id: str,
|
31
31
|
unique_id: str,
|
@@ -38,7 +38,10 @@ def _create_oddsportal_team_model(
|
|
38
38
|
team_idx: int,
|
39
39
|
) -> TeamModel:
|
40
40
|
response = session.get(
|
41
|
-
f"https://www.oddsportal.com/
|
41
|
+
f"https://www.oddsportal.com/match-event/{version_id}-{sport_id}-{unique_id}-{default_bet_id}-{default_scope_id}-{xhash}.dat",
|
42
|
+
headers={
|
43
|
+
"X-Requested-With": "XMLHttpRequest",
|
44
|
+
},
|
42
45
|
)
|
43
46
|
response.raise_for_status()
|
44
47
|
decoded_data = base64.b64decode(response.content).decode()
|
@@ -70,7 +73,7 @@ def _create_oddsportal_team_model(
|
|
70
73
|
history = odds_data["history"][outcome_id]
|
71
74
|
odds_models = []
|
72
75
|
for bookie_id, bookie_name in bookie_names.items():
|
73
|
-
for odds, _, timestamp in history[
|
76
|
+
for odds, _, timestamp in history.get(bookie_id, []):
|
74
77
|
odds_models.append(
|
75
78
|
create_oddsportal_odds_model(
|
76
79
|
odds,
|
@@ -100,7 +103,7 @@ def _cached_create_oddsportal_team_model(
|
|
100
103
|
dt: datetime.datetime,
|
101
104
|
team_name: str,
|
102
105
|
league: League,
|
103
|
-
points: float,
|
106
|
+
points: float | None,
|
104
107
|
version_id: str,
|
105
108
|
sport_id: str,
|
106
109
|
unique_id: str,
|
@@ -136,7 +139,7 @@ def create_oddsportal_team_model(
|
|
136
139
|
dt: datetime.datetime,
|
137
140
|
team_name: str,
|
138
141
|
league: League,
|
139
|
-
points: float,
|
142
|
+
points: float | None,
|
140
143
|
version_id: str,
|
141
144
|
sport_id: str,
|
142
145
|
unique_id: str,
|
@@ -1,6 +1,6 @@
|
|
1
1
|
"""Sports Reference game model."""
|
2
2
|
|
3
|
-
# pylint: disable=too-many-locals,too-many-statements,unused-argument,protected-access
|
3
|
+
# pylint: disable=too-many-locals,too-many-statements,unused-argument,protected-access,too-many-arguments
|
4
4
|
import datetime
|
5
5
|
import io
|
6
6
|
import logging
|
@@ -22,19 +22,76 @@ from .sportsreference_team_model import create_sportsreference_team_model
|
|
22
22
|
from .sportsreference_venue_model import create_sportsreference_venue_model
|
23
23
|
|
24
24
|
|
25
|
-
def
|
25
|
+
def _find_old_dt(
|
26
|
+
dfs: list[pd.DataFrame],
|
26
27
|
session: requests_cache.CachedSession,
|
28
|
+
soup: BeautifulSoup,
|
27
29
|
url: str,
|
28
30
|
league: League,
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
31
|
+
player_urls: set[str],
|
32
|
+
fg: dict[str, int],
|
33
|
+
fga: dict[str, int],
|
34
|
+
offensive_rebounds: dict[str, int],
|
35
|
+
assists: dict[str, int],
|
36
|
+
turnovers: dict[str, int],
|
37
|
+
) -> tuple[datetime.datetime, list[TeamModel], str]:
|
38
|
+
teams: list[TeamModel] = []
|
39
|
+
dt = None
|
40
|
+
venue_name = None
|
41
|
+
for df in dfs:
|
42
|
+
test_row = df.iat[0, 0]
|
43
|
+
if "Prev Game" in test_row and len(df) == 2:
|
44
|
+
date_venue_split = df.iat[1, 0].split()
|
45
|
+
dt = parse(" ".join(date_venue_split[:5]))
|
46
|
+
venue_name = " ".join(date_venue_split[5:])
|
47
|
+
for col_idx in range(len(df.columns.values)):
|
48
|
+
team_row = df.iat[0, col_idx]
|
49
|
+
team_name_points = team_row.split("⇐")[0].strip()
|
50
|
+
points = int(team_name_points.split()[-1].strip())
|
51
|
+
team_name = " ".join(team_name_points.split()[:-1]).strip()
|
52
|
+
team_a = soup.find("a", text=team_name, href=True)
|
53
|
+
if not isinstance(team_a, Tag):
|
54
|
+
raise ValueError("team_a is not a tag.")
|
55
|
+
team_url = urllib.parse.urljoin(url, str(team_a.get("href")))
|
56
|
+
teams.append(
|
57
|
+
create_sportsreference_team_model(
|
58
|
+
session,
|
59
|
+
team_url,
|
60
|
+
dt,
|
61
|
+
league,
|
62
|
+
player_urls,
|
63
|
+
points,
|
64
|
+
fg,
|
65
|
+
fga,
|
66
|
+
offensive_rebounds,
|
67
|
+
assists,
|
68
|
+
turnovers,
|
69
|
+
)
|
70
|
+
)
|
71
|
+
break
|
72
|
+
|
73
|
+
if dt is None:
|
74
|
+
raise ValueError("dt is null.")
|
75
|
+
if venue_name is None:
|
76
|
+
raise ValueError("venue_name is null.")
|
77
|
+
|
78
|
+
return (dt, teams, venue_name)
|
79
|
+
|
37
80
|
|
81
|
+
def _find_new_dt(
|
82
|
+
soup: BeautifulSoup,
|
83
|
+
scorebox_meta_div: Tag,
|
84
|
+
url: str,
|
85
|
+
session: requests_cache.CachedSession,
|
86
|
+
league: League,
|
87
|
+
player_urls: set[str],
|
88
|
+
scores: list[float],
|
89
|
+
fg: dict[str, int],
|
90
|
+
fga: dict[str, int],
|
91
|
+
offensive_rebounds: dict[str, int],
|
92
|
+
assists: dict[str, int],
|
93
|
+
turnovers: dict[str, int],
|
94
|
+
) -> tuple[datetime.datetime, list[TeamModel], str]:
|
38
95
|
in_divs = scorebox_meta_div.find_all("div")
|
39
96
|
current_in_div_idx = 0
|
40
97
|
in_div = in_divs[current_in_div_idx]
|
@@ -54,6 +111,39 @@ def _create_sportsreference_game_model(
|
|
54
111
|
if not isinstance(scorebox_div, Tag):
|
55
112
|
raise ValueError("scorebox_div is not a Tag.")
|
56
113
|
|
114
|
+
teams: list[TeamModel] = []
|
115
|
+
for a in scorebox_div.find_all("a"):
|
116
|
+
team_url = urllib.parse.urljoin(url, a.get("href"))
|
117
|
+
if "/schools/" in team_url:
|
118
|
+
teams.append(
|
119
|
+
create_sportsreference_team_model(
|
120
|
+
session,
|
121
|
+
team_url,
|
122
|
+
dt,
|
123
|
+
league,
|
124
|
+
player_urls,
|
125
|
+
scores[len(teams)],
|
126
|
+
fg,
|
127
|
+
fga,
|
128
|
+
offensive_rebounds,
|
129
|
+
assists,
|
130
|
+
turnovers,
|
131
|
+
)
|
132
|
+
)
|
133
|
+
|
134
|
+
return (dt, teams, venue_name)
|
135
|
+
|
136
|
+
|
137
|
+
def _create_sportsreference_game_model(
|
138
|
+
session: requests_cache.CachedSession,
|
139
|
+
url: str,
|
140
|
+
league: League,
|
141
|
+
) -> GameModel:
|
142
|
+
# pylint: disable=too-many-branches
|
143
|
+
response = session.get(url)
|
144
|
+
response.raise_for_status()
|
145
|
+
soup = BeautifulSoup(response.text, "html.parser")
|
146
|
+
|
57
147
|
player_urls = set()
|
58
148
|
for a in soup.find_all("a"):
|
59
149
|
player_url = urllib.parse.urljoin(url, a.get("href"))
|
@@ -99,25 +189,36 @@ def _create_sportsreference_game_model(
|
|
99
189
|
for idx, player in enumerate(players):
|
100
190
|
turnovers[player] = tovs[idx]
|
101
191
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
192
|
+
scorebox_meta_div = soup.find("div", class_="scorebox_meta")
|
193
|
+
if not isinstance(scorebox_meta_div, Tag):
|
194
|
+
dt, teams, venue_name = _find_old_dt(
|
195
|
+
dfs,
|
196
|
+
session,
|
197
|
+
soup,
|
198
|
+
url,
|
199
|
+
league,
|
200
|
+
player_urls,
|
201
|
+
fg,
|
202
|
+
fga,
|
203
|
+
offensive_rebounds,
|
204
|
+
assists,
|
205
|
+
turnovers,
|
206
|
+
)
|
207
|
+
else:
|
208
|
+
dt, teams, venue_name = _find_new_dt(
|
209
|
+
soup,
|
210
|
+
scorebox_meta_div,
|
211
|
+
url,
|
212
|
+
session,
|
213
|
+
league,
|
214
|
+
player_urls,
|
215
|
+
scores,
|
216
|
+
fg,
|
217
|
+
fga,
|
218
|
+
offensive_rebounds,
|
219
|
+
assists,
|
220
|
+
turnovers,
|
221
|
+
)
|
121
222
|
|
122
223
|
season_type = SeasonType.REGULAR
|
123
224
|
for h2 in soup.find_all("h2"):
|