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.
Files changed (208) hide show
  1. {sportsball-0.3.19/sportsball.egg-info → sportsball-0.3.22}/PKG-INFO +5 -1
  2. {sportsball-0.3.19 → sportsball-0.3.22}/README.md +2 -0
  3. {sportsball-0.3.19 → sportsball-0.3.22}/requirements.txt +2 -1
  4. {sportsball-0.3.19 → sportsball-0.3.22}/setup.py +9 -6
  5. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/__init__.py +1 -1
  6. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/combined/combined_league_model.py +2 -0
  7. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/google/google_address_model.py +38 -9
  8. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/google/google_news_model.py +1 -1
  9. sportsball-0.3.22/sportsball/data/ncaaf/__init__.py +5 -0
  10. sportsball-0.3.22/sportsball/data/ncaaf/combined/ncaaf_combined_league_model.py +34 -0
  11. sportsball-0.3.22/sportsball/data/ncaaf/oddsportal/ncaaf_oddsportal_league_model.py +15 -0
  12. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/oddsportal/oddsportal_game_model.py +16 -9
  13. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/oddsportal/oddsportal_league_model.py +32 -7
  14. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/oddsportal/oddsportal_team_model.py +8 -5
  15. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/sportsreference/sportsreference_game_model.py +130 -29
  16. sportsball-0.3.22/sportsball/vendor/pygooglenews/__init__.py +203 -0
  17. {sportsball-0.3.19 → sportsball-0.3.22/sportsball.egg-info}/PKG-INFO +5 -1
  18. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball.egg-info/SOURCES.txt +8 -0
  19. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball.egg-info/requires.txt +2 -0
  20. sportsball-0.3.22/tests/data/oddsportal/__init__.py +0 -0
  21. sportsball-0.3.22/tests/data/oddsportal/oddsportal_game_model_test.py +35 -0
  22. sportsball-0.3.22/tests/data/sportsdb/__init__.py +0 -0
  23. sportsball-0.3.22/tests/data/sportsreference/__init__.py +0 -0
  24. sportsball-0.3.22/tests/data/sportsreference/sportsreference_game_model_test.py +97 -0
  25. sportsball-0.3.22/tests/data/x/__init__.py +0 -0
  26. sportsball-0.3.19/sportsball/data/ncaaf/__init__.py +0 -5
  27. sportsball-0.3.19/tests/data/sportsreference/sportsreference_game_model_test.py +0 -30
  28. {sportsball-0.3.19 → sportsball-0.3.22}/LICENSE +0 -0
  29. {sportsball-0.3.19 → sportsball-0.3.22}/MANIFEST.in +0 -0
  30. {sportsball-0.3.19 → sportsball-0.3.22}/setup.cfg +0 -0
  31. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/__main__.py +0 -0
  32. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/args.py +0 -0
  33. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/cache.py +0 -0
  34. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/__init__.py +0 -0
  35. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/address_model.py +0 -0
  36. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/__init__.py +0 -0
  37. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/afltables/__init__.py +0 -0
  38. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/afltables/afl_afltables_game_model.py +0 -0
  39. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/afltables/afl_afltables_league_model.py +0 -0
  40. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/afltables/afl_afltables_player_model.py +0 -0
  41. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/afltables/afl_afltables_team_model.py +0 -0
  42. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/afltables/afl_afltables_venue_model.py +0 -0
  43. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/aussportsbetting/__init__.py +0 -0
  44. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/aussportsbetting/afl_aussportsbetting_league_model.py +0 -0
  45. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/combined/__init__.py +0 -0
  46. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/combined/afl_combined_league_model.py +0 -0
  47. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/espn/__init__.py +0 -0
  48. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/espn/afl_espn_league_model.py +0 -0
  49. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/oddsportal/__init__.py +0 -0
  50. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/afl/oddsportal/afl_oddsportal_league_model.py +0 -0
  51. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/aussportsbetting/__init__.py +0 -0
  52. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/aussportsbetting/aussportsbetting_bookie_model.py +0 -0
  53. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/aussportsbetting/aussportsbetting_game_model.py +0 -0
  54. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/aussportsbetting/aussportsbetting_league_model.py +0 -0
  55. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/aussportsbetting/aussportsbetting_odds_model.py +0 -0
  56. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/aussportsbetting/aussportsbetting_team_model.py +0 -0
  57. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/aussportsbetting/aussportsbetting_venue_model.py +0 -0
  58. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/bookie_model.py +0 -0
  59. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/combined/__init__.py +0 -0
  60. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/combined/combined_address_model.py +0 -0
  61. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/combined/combined_game_model.py +0 -0
  62. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/combined/combined_player_model.py +0 -0
  63. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/combined/combined_team_model.py +0 -0
  64. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/combined/combined_venue_model.py +0 -0
  65. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/combined/combined_weather_model.py +0 -0
  66. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/espn/__init__.py +0 -0
  67. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/espn/espn_bookie_model.py +0 -0
  68. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/espn/espn_game_model.py +0 -0
  69. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/espn/espn_league_model.py +0 -0
  70. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/espn/espn_odds_model.py +0 -0
  71. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/espn/espn_player_model.py +0 -0
  72. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/espn/espn_team_model.py +0 -0
  73. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/espn/espn_venue_model.py +0 -0
  74. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/field_type.py +0 -0
  75. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/game_model.py +0 -0
  76. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/google/__init__.py +0 -0
  77. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/league.py +0 -0
  78. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/league_model.py +0 -0
  79. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/model.py +0 -0
  80. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/__init__.py +0 -0
  81. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/combined/__init__.py +0 -0
  82. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/combined/nba_combined_league_model.py +0 -0
  83. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/espn/__init__.py +0 -0
  84. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/espn/nba_espn_league_model.py +0 -0
  85. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/nba/__init__.py +0 -0
  86. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/nba/nba_nba_game_model.py +0 -0
  87. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/nba/nba_nba_league_model.py +0 -0
  88. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/nba/nba_nba_player_model.py +0 -0
  89. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/nba/nba_nba_team_model.py +0 -0
  90. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/oddsportal/__init__.py +0 -0
  91. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/oddsportal/nba_oddsportal_league_model.py +0 -0
  92. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/sportsdb/__init__.py +0 -0
  93. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/sportsdb/nba_sportsdb_league_model.py +0 -0
  94. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/sportsreference/__init__.py +0 -0
  95. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nba/sportsreference/nba_sportsreference_league_model.py +0 -0
  96. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/ncaab/__init__.py +0 -0
  97. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/ncaab/combined/__init__.py +0 -0
  98. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/ncaab/combined/ncaab_combined_league_model.py +0 -0
  99. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/ncaab/espn/__init__.py +0 -0
  100. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/ncaab/espn/ncaab_espn_league_model.py +0 -0
  101. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/ncaab/oddsportal/__init__.py +0 -0
  102. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/ncaab/oddsportal/ncaab_oddsportal_league_model.py +0 -0
  103. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/ncaab/sportsreference/__init__.py +0 -0
  104. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/ncaab/sportsreference/ncaab_sportsreference_league_model.py +0 -0
  105. {sportsball-0.3.19/sportsball/data/ncaaf/espn → sportsball-0.3.22/sportsball/data/ncaaf/combined}/__init__.py +0 -0
  106. {sportsball-0.3.19/sportsball/data/nfl/aussportsbetting → sportsball-0.3.22/sportsball/data/ncaaf/espn}/__init__.py +0 -0
  107. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/ncaaf/espn/ncaaf_espn_league_model.py +0 -0
  108. {sportsball-0.3.19/sportsball/data/nfl/combined → sportsball-0.3.22/sportsball/data/ncaaf/oddsportal}/__init__.py +0 -0
  109. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/news_model.py +0 -0
  110. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nfl/__init__.py +0 -0
  111. {sportsball-0.3.19/sportsball/data/nfl/oddsportal → sportsball-0.3.22/sportsball/data/nfl/aussportsbetting}/__init__.py +0 -0
  112. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nfl/aussportsbetting/nfl_aussportsbetting_league_model.py +0 -0
  113. {sportsball-0.3.19/sportsball/data/nfl/sportsdb → sportsball-0.3.22/sportsball/data/nfl/combined}/__init__.py +0 -0
  114. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nfl/combined/nfl_combined_league_model.py +0 -0
  115. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nfl/espn/__init__.py +0 -0
  116. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nfl/espn/nfl_espn_league_model.py +0 -0
  117. {sportsball-0.3.19/sportsball/data → sportsball-0.3.22/sportsball/data/nfl}/oddsportal/__init__.py +0 -0
  118. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nfl/oddsportal/nfl_oddsportal_league_model.py +0 -0
  119. {sportsball-0.3.19/sportsball/data → sportsball-0.3.22/sportsball/data/nfl}/sportsdb/__init__.py +0 -0
  120. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/nfl/sportsdb/nfl_sportsdb_league_model.py +0 -0
  121. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/odds_model.py +0 -0
  122. {sportsball-0.3.19/sportsball/data/sportsreference → sportsball-0.3.22/sportsball/data/oddsportal}/__init__.py +0 -0
  123. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/oddsportal/oddsportal_bookie_model.py +0 -0
  124. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/oddsportal/oddsportal_odds_model.py +0 -0
  125. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/oddsportal/oddsportal_venue_model.py +0 -0
  126. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/player_model.py +0 -0
  127. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/season_type.py +0 -0
  128. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/social_model.py +0 -0
  129. {sportsball-0.3.19/sportsball/data/weather → sportsball-0.3.22/sportsball/data/sportsdb}/__init__.py +0 -0
  130. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/sportsdb/sportsdb_game_model.py +0 -0
  131. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/sportsdb/sportsdb_league_model.py +0 -0
  132. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/sportsdb/sportsdb_team_model.py +0 -0
  133. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/sportsdb/sportsdb_venue_model.py +0 -0
  134. {sportsball-0.3.19/sportsball/data/weather/gribstream → sportsball-0.3.22/sportsball/data/sportsreference}/__init__.py +0 -0
  135. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/sportsreference/sportsreference_league_model.py +0 -0
  136. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/sportsreference/sportsreference_player_model.py +0 -0
  137. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/sportsreference/sportsreference_team_model.py +0 -0
  138. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/sportsreference/sportsreference_venue_model.py +0 -0
  139. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/team_model.py +0 -0
  140. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/venue_model.py +0 -0
  141. {sportsball-0.3.19/sportsball/data/weather/openmeteo → sportsball-0.3.22/sportsball/data/weather}/__init__.py +0 -0
  142. {sportsball-0.3.19/sportsball/data/wikipedia → sportsball-0.3.22/sportsball/data/weather/gribstream}/__init__.py +0 -0
  143. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/weather/gribstream/gribstream_weather_model.py +0 -0
  144. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/weather/multi_weather_model.py +0 -0
  145. {sportsball-0.3.19/sportsball/data/x → sportsball-0.3.22/sportsball/data/weather/openmeteo}/__init__.py +0 -0
  146. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/weather/openmeteo/openmeteo_weather_model.py +0 -0
  147. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/weather_model.py +0 -0
  148. {sportsball-0.3.19/tests → sportsball-0.3.22/sportsball/data/wikipedia}/__init__.py +0 -0
  149. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/wikipedia/wikipedia_venue_model.py +0 -0
  150. {sportsball-0.3.19/tests/data → sportsball-0.3.22/sportsball/data/x}/__init__.py +0 -0
  151. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/data/x/x_social_model.py +0 -0
  152. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/logger.py +0 -0
  153. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/loglevel.py +0 -0
  154. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/proxy_session.py +0 -0
  155. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/session.py +0 -0
  156. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball/sportsball.py +0 -0
  157. {sportsball-0.3.19/tests/data/afl → sportsball-0.3.22/sportsball/vendor}/__init__.py +0 -0
  158. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball.egg-info/dependency_links.txt +0 -0
  159. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball.egg-info/entry_points.txt +0 -0
  160. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball.egg-info/not-zip-safe +0 -0
  161. {sportsball-0.3.19 → sportsball-0.3.22}/sportsball.egg-info/top_level.txt +0 -0
  162. {sportsball-0.3.19/tests/data/afl/afltables → sportsball-0.3.22/tests}/__init__.py +0 -0
  163. {sportsball-0.3.19/tests/data/aussportsbetting → sportsball-0.3.22/tests/data}/__init__.py +0 -0
  164. {sportsball-0.3.19/tests/data/combined → sportsball-0.3.22/tests/data/afl}/__init__.py +0 -0
  165. {sportsball-0.3.19/tests/data/espn → sportsball-0.3.22/tests/data/afl/afltables}/__init__.py +0 -0
  166. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/afl/afltables/afl_afltables_player_model_test.py +0 -0
  167. {sportsball-0.3.19/tests/data/google → sportsball-0.3.22/tests/data/aussportsbetting}/__init__.py +0 -0
  168. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/aussportsbetting/aussportsbetting_game_model_test.py +0 -0
  169. {sportsball-0.3.19/tests/data/nba → sportsball-0.3.22/tests/data/combined}/__init__.py +0 -0
  170. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/combined/combined_game_model_test.py +0 -0
  171. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/combined/combined_player_model_test.py +0 -0
  172. {sportsball-0.3.19/tests/data/nba/nba → sportsball-0.3.22/tests/data/espn}/__init__.py +0 -0
  173. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/espn/espn_game_model_test.py +0 -0
  174. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/espn/espn_player_model_test.py +0 -0
  175. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/game_model_test.py +0 -0
  176. {sportsball-0.3.19/tests/data/nba/sportsdb → sportsball-0.3.22/tests/data/google}/__init__.py +0 -0
  177. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/google/google_address_model_test.py +0 -0
  178. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/google/google_news_model_test.py +0 -0
  179. {sportsball-0.3.19/tests/data/nba/sportsreference → sportsball-0.3.22/tests/data/nba}/__init__.py +0 -0
  180. {sportsball-0.3.19/tests/data/ncaab → sportsball-0.3.22/tests/data/nba/nba}/__init__.py +0 -0
  181. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/nba/nba/nba_nba_game_model_test.py +0 -0
  182. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/nba/nba/nba_nba_league_model_test.py +0 -0
  183. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/nba/nba/nba_nba_player_model_test.py +0 -0
  184. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/nba/nba/nba_nba_team_model_test.py +0 -0
  185. {sportsball-0.3.19/tests/data/ncaab/sportsreference → sportsball-0.3.22/tests/data/nba/sportsdb}/__init__.py +0 -0
  186. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/nba/sportsdb/nba_sportsdb_league_model_test.py +0 -0
  187. {sportsball-0.3.19/tests/data/nfl → sportsball-0.3.22/tests/data/nba/sportsreference}/__init__.py +0 -0
  188. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/nba/sportsreference/nba_sportsreference_league_model_test.py +0 -0
  189. {sportsball-0.3.19/tests/data/nfl/sportsdb → sportsball-0.3.22/tests/data/ncaab}/__init__.py +0 -0
  190. {sportsball-0.3.19/tests/data/sportsdb → sportsball-0.3.22/tests/data/ncaab/sportsreference}/__init__.py +0 -0
  191. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/ncaab/sportsreference/ncaab_sportsreference_league_model_test.py +0 -0
  192. {sportsball-0.3.19/tests/data/sportsreference → sportsball-0.3.22/tests/data/nfl}/__init__.py +0 -0
  193. {sportsball-0.3.19/tests/data/x → sportsball-0.3.22/tests/data/nfl/sportsdb}/__init__.py +0 -0
  194. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/nfl/sportsdb/nfl_sportsdb_league_model_test.py +0 -0
  195. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/player_model_test.py +0 -0
  196. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/social_model_test.py +0 -0
  197. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/sportsdb/sportsdb_game_model_test.py +0 -0
  198. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/sportsdb/sportsdb_league_model_test.py +0 -0
  199. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/sportsdb/sportsdb_team_model_test.py +0 -0
  200. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/sportsdb/sportsdb_venue_model_test.py +0 -0
  201. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/sportsreference/sportsreference_league_model_test.py +0 -0
  202. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/sportsreference/sportsreference_player_model_test.py +0 -0
  203. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/sportsreference/sportsreference_team_model_test.py +0 -0
  204. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/sportsreference/sportsreference_venue_model_test.py +0 -0
  205. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/team_model_test.py +0 -0
  206. {sportsball-0.3.19 → sportsball-0.3.22}/tests/data/x/x_social_model_test.py +0 -0
  207. {sportsball-0.3.19 → sportsball-0.3.22}/tests/proxy_session_test.py +0 -0
  208. {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.19
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
- requires = [
17
- x
18
- for x in requirments_txt_handle
19
- if not x.startswith(".") and not x.startswith("-e")
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.19',
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',
@@ -1,3 +1,3 @@
1
1
  """The main module for sportsball."""
2
2
 
3
- __VERSION__ = "0.3.19"
3
+ __VERSION__ = "0.3.22"
@@ -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": SportsballGeocodeTuple(
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,5 @@
1
+ """The ncaaf data sportsball module."""
2
+
3
+ # ruff: noqa: F401
4
+ from .combined.ncaaf_combined_league_model import \
5
+ NCAAFCombinedLeagueModel as NCAAFLeagueModel
@@ -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(url, "html.parser")
28
- event_tag = soup.find("Event")
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[":data"]))
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 event_data["endDate"] is not False:
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
- variables = variables[variables.find('break}return e.next=9,g(r.data,"') :]
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
- salt_str, password_str = variables.split('","')
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
- float(event_body["homeResult"]),
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
- float(event_body["awayResult"]),
113
+ away_points,
107
114
  version_id,
108
115
  sport_id,
109
116
  unique_id,
@@ -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(["basketball", "usa", "nba", ""])
36
+ return "/".join([BASKETBALL, USA, "nba", ""])
27
37
  case League.NCAAB:
28
- return "/".join(["basketball", "usa", "ncaa", ""])
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(["american-football", "usa", "nfl", ""])
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, jsonld["url"], self.league, True
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
- response = self.session.get(url)
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
- for match in matches["tournamentGamesComponent"]["rows"]:
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, match["url"], self.league, False
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/feed/match-event/{version_id}-{sport_id}-{unique_id}-{default_bet_id}-{default_scope_id}-{xhash}.dat"
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[bookie_id]:
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 _create_sportsreference_game_model(
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
- ) -> GameModel:
30
- # pylint: disable=too-many-branches
31
- response = session.get(url)
32
- response.raise_for_status()
33
- soup = BeautifulSoup(response.text, "html.parser")
34
- scorebox_meta_div = soup.find("div", class_="scorebox_meta")
35
- if not isinstance(scorebox_meta_div, Tag):
36
- raise ValueError("scorebox_meta_div is not a Tag.")
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
- teams: list[TeamModel] = []
103
- for a in scorebox_div.find_all("a"):
104
- team_url = urllib.parse.urljoin(url, a.get("href"))
105
- if "/schools/" in team_url:
106
- teams.append(
107
- create_sportsreference_team_model(
108
- session,
109
- team_url,
110
- dt,
111
- league,
112
- player_urls,
113
- scores[len(teams)],
114
- fg,
115
- fga,
116
- offensive_rebounds,
117
- assists,
118
- turnovers,
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"):