sportsball 0.10.11__tar.gz → 0.10.13__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 (284) hide show
  1. {sportsball-0.10.11/sportsball.egg-info → sportsball-0.10.13}/PKG-INFO +2 -2
  2. {sportsball-0.10.11 → sportsball-0.10.13}/requirements.txt +1 -1
  3. {sportsball-0.10.11 → sportsball-0.10.13}/setup.py +1 -1
  4. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/__init__.py +1 -1
  5. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/afl/afl/afl_afl_league_model.py +20 -10
  6. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/afl/afltables/afl_afltables_league_model.py +24 -18
  7. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/aussportsbetting/aussportsbetting_league_model.py +21 -15
  8. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/combined/combined_league_model.py +16 -7
  9. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/espn/espn_league_model.py +40 -30
  10. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/google/google_address_model.py +19 -0
  11. sportsball-0.10.13/sportsball/data/hkjc/hkjc/hkjc_hkjc_league_model.py +111 -0
  12. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/league_model.py +2 -0
  13. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nba/nba/nba_nba_league_model.py +28 -22
  14. sportsball-0.10.13/sportsball/data/nba/nbacom/nba_nbacom_league_model.py +46 -0
  15. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/oddsportal/oddsportal_league_model.py +10 -4
  16. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/sportsdb/sportsdb_league_model.py +57 -49
  17. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/sportsreference/sportsreference_league_model.py +37 -31
  18. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/sportsreference/sportsreference_player_model.py +7 -5
  19. {sportsball-0.10.11 → sportsball-0.10.13/sportsball.egg-info}/PKG-INFO +2 -2
  20. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball.egg-info/requires.txt +1 -1
  21. sportsball-0.10.11/sportsball/data/hkjc/hkjc/hkjc_hkjc_league_model.py +0 -104
  22. sportsball-0.10.11/sportsball/data/nba/nbacom/nba_nbacom_league_model.py +0 -40
  23. {sportsball-0.10.11 → sportsball-0.10.13}/LICENSE +0 -0
  24. {sportsball-0.10.11 → sportsball-0.10.13}/MANIFEST.in +0 -0
  25. {sportsball-0.10.11 → sportsball-0.10.13}/README.md +0 -0
  26. {sportsball-0.10.11 → sportsball-0.10.13}/setup.cfg +0 -0
  27. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/__main__.py +0 -0
  28. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/args.py +0 -0
  29. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/cache.py +0 -0
  30. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/__init__.py +0 -0
  31. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/address_model.py +0 -0
  32. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/afl/__init__.py +0 -0
  33. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/afl/afl/__init__.py +0 -0
  34. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/afl/afl/afl_afl_bookie_model.py +0 -0
  35. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/afl/afl/afl_afl_game_model.py +0 -0
  36. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/afl/afl/afl_afl_odds_model.py +0 -0
  37. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/afl/afl/afl_afl_player_model.py +0 -0
  38. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/afl/afl/afl_afl_team_model.py +0 -0
  39. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/afl/afl/afl_afl_venue_model.py +0 -0
  40. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/afl/afltables/__init__.py +0 -0
  41. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/afl/afltables/afl_afltables_coach_model.py +0 -0
  42. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/afl/afltables/afl_afltables_game_model.py +0 -0
  43. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/afl/afltables/afl_afltables_player_model.py +0 -0
  44. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/afl/afltables/afl_afltables_team_model.py +0 -0
  45. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/afl/afltables/afl_afltables_venue_model.py +0 -0
  46. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/afl/aussportsbetting/__init__.py +0 -0
  47. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/afl/aussportsbetting/afl_aussportsbetting_league_model.py +0 -0
  48. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/afl/combined/__init__.py +0 -0
  49. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/afl/combined/afl_combined_league_model.py +0 -0
  50. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/afl/espn/__init__.py +0 -0
  51. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/afl/espn/afl_espn_league_model.py +0 -0
  52. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/afl/oddsportal/__init__.py +0 -0
  53. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/afl/oddsportal/afl_oddsportal_league_model.py +0 -0
  54. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/afl/position.py +0 -0
  55. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/aussportsbetting/__init__.py +0 -0
  56. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/aussportsbetting/aussportsbetting_bookie_model.py +0 -0
  57. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/aussportsbetting/aussportsbetting_game_model.py +0 -0
  58. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/aussportsbetting/aussportsbetting_odds_model.py +0 -0
  59. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/aussportsbetting/aussportsbetting_team_model.py +0 -0
  60. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/aussportsbetting/aussportsbetting_venue_model.py +0 -0
  61. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/bet.py +0 -0
  62. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/bookie_model.py +0 -0
  63. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/coach_model.py +0 -0
  64. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/combined/__init__.py +0 -0
  65. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/combined/combined_address_model.py +0 -0
  66. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/combined/combined_coach_model.py +0 -0
  67. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/combined/combined_game_model.py +0 -0
  68. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/combined/combined_player_model.py +0 -0
  69. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/combined/combined_team_model.py +0 -0
  70. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/combined/combined_venue_model.py +0 -0
  71. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/combined/combined_weather_model.py +0 -0
  72. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/combined/ffill.py +0 -0
  73. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/combined/most_interesting.py +0 -0
  74. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/combined/null_check.py +0 -0
  75. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/delimiter.py +0 -0
  76. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/dividend_model.py +0 -0
  77. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/espn/__init__.py +0 -0
  78. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/espn/espn_bookie_model.py +0 -0
  79. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/espn/espn_coach_model.py +0 -0
  80. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/espn/espn_game_model.py +0 -0
  81. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/espn/espn_odds_model.py +0 -0
  82. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/espn/espn_player_model.py +0 -0
  83. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/espn/espn_team_model.py +0 -0
  84. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/espn/espn_venue_model.py +0 -0
  85. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/field_type.py +0 -0
  86. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/game_model.py +0 -0
  87. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/google/__init__.py +0 -0
  88. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/google/google_news_model.py +0 -0
  89. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/hkjc/__init__.py +0 -0
  90. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/hkjc/hkjc/__init__.py +0 -0
  91. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/hkjc/hkjc/hkjc_hkjc_bookie_model.py +0 -0
  92. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/hkjc/hkjc/hkjc_hkjc_coach_model.py +0 -0
  93. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/hkjc/hkjc/hkjc_hkjc_dividend_model.py +0 -0
  94. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/hkjc/hkjc/hkjc_hkjc_game_model.py +0 -0
  95. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/hkjc/hkjc/hkjc_hkjc_odds_model.py +0 -0
  96. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/hkjc/hkjc/hkjc_hkjc_owner_model.py +0 -0
  97. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/hkjc/hkjc/hkjc_hkjc_player_model.py +0 -0
  98. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/hkjc/hkjc/hkjc_hkjc_team_model.py +0 -0
  99. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/hkjc/hkjc/hkjc_hkjc_venue_model.py +0 -0
  100. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/hkjc/position.py +0 -0
  101. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/league.py +0 -0
  102. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/model.py +0 -0
  103. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nba/__init__.py +0 -0
  104. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nba/combined/__init__.py +0 -0
  105. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nba/combined/nba_combined_league_model.py +0 -0
  106. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nba/espn/__init__.py +0 -0
  107. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nba/espn/nba_espn_league_model.py +0 -0
  108. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nba/nba/__init__.py +0 -0
  109. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nba/nba/nba_nba_game_model.py +0 -0
  110. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nba/nba/nba_nba_team_model.py +0 -0
  111. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nba/nbacom/__init__.py +0 -0
  112. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nba/nbacom/nba_nbacom_game_model.py +0 -0
  113. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nba/nbacom/nba_nbacom_player_model.py +0 -0
  114. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nba/nbacom/nba_nbacom_team_model.py +0 -0
  115. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nba/nbacom/nba_nbacom_venue_model.py +0 -0
  116. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nba/oddsportal/__init__.py +0 -0
  117. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nba/oddsportal/nba_oddsportal_league_model.py +0 -0
  118. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nba/position.py +0 -0
  119. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nba/sportsdb/__init__.py +0 -0
  120. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nba/sportsdb/nba_sportsdb_league_model.py +0 -0
  121. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nba/sportsreference/__init__.py +0 -0
  122. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nba/sportsreference/nba_sportsreference_league_model.py +0 -0
  123. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/ncaab/__init__.py +0 -0
  124. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/ncaab/combined/__init__.py +0 -0
  125. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/ncaab/combined/ncaab_combined_league_model.py +0 -0
  126. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/ncaab/espn/__init__.py +0 -0
  127. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/ncaab/espn/ncaab_espn_league_model.py +0 -0
  128. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/ncaab/oddsportal/__init__.py +0 -0
  129. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/ncaab/oddsportal/ncaab_oddsportal_league_model.py +0 -0
  130. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/ncaab/sportsdb/__init__.py +0 -0
  131. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/ncaab/sportsdb/ncaab_sportsdb_league_model.py +0 -0
  132. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/ncaab/sportsreference/__init__.py +0 -0
  133. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/ncaab/sportsreference/ncaab_sportsreference_league_model.py +0 -0
  134. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/ncaaf/__init__.py +0 -0
  135. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/ncaaf/combined/__init__.py +0 -0
  136. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/ncaaf/combined/ncaaf_combined_league_model.py +0 -0
  137. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/ncaaf/espn/__init__.py +0 -0
  138. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/ncaaf/espn/ncaaf_espn_league_model.py +0 -0
  139. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/ncaaf/oddsportal/__init__.py +0 -0
  140. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/ncaaf/oddsportal/ncaaf_oddsportal_league_model.py +0 -0
  141. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/ncaaf/sportsdb/__init__.py +0 -0
  142. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/ncaaf/sportsdb/ncaaf_sportsdb_league_model.py +0 -0
  143. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/ncaaf/sportsreference/__init__.py +0 -0
  144. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/ncaaf/sportsreference/ncaaf_sportsreference_league_model.py +0 -0
  145. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/news_model.py +0 -0
  146. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nfl/__init__.py +0 -0
  147. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nfl/aussportsbetting/__init__.py +0 -0
  148. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nfl/aussportsbetting/nfl_aussportsbetting_league_model.py +0 -0
  149. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nfl/combined/__init__.py +0 -0
  150. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nfl/combined/nfl_combined_league_model.py +0 -0
  151. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nfl/espn/__init__.py +0 -0
  152. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nfl/espn/nfl_espn_league_model.py +0 -0
  153. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nfl/oddsportal/__init__.py +0 -0
  154. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nfl/oddsportal/nfl_oddsportal_league_model.py +0 -0
  155. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nfl/position.py +0 -0
  156. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nfl/sportsdb/__init__.py +0 -0
  157. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nfl/sportsdb/nfl_sportsdb_league_model.py +0 -0
  158. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nfl/sportsreference/__init__.py +0 -0
  159. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nfl/sportsreference/nfl_sportsreference_league_model.py +0 -0
  160. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nhl/__init__.py +0 -0
  161. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nhl/combined/__init__.py +0 -0
  162. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nhl/combined/nhl_combined_league_model.py +0 -0
  163. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nhl/espn/__init__.py +0 -0
  164. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nhl/espn/nhl_espn_league_model.py +0 -0
  165. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nhl/oddsportal/__init__.py +0 -0
  166. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nhl/oddsportal/nhl_oddsportal_league_model.py +0 -0
  167. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nhl/position.py +0 -0
  168. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nhl/sportsdb/__init__.py +0 -0
  169. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nhl/sportsdb/nhl_sportsdb_league_model.py +0 -0
  170. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nhl/sportsreference/__init__.py +0 -0
  171. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/nhl/sportsreference/nhl_sportsreference_league_model.py +0 -0
  172. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/odds_model.py +0 -0
  173. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/oddsportal/__init__.py +0 -0
  174. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/oddsportal/decrypt.py +0 -0
  175. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/oddsportal/oddsportal_bookie_model.py +0 -0
  176. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/oddsportal/oddsportal_game_model.py +0 -0
  177. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/oddsportal/oddsportal_odds_model.py +0 -0
  178. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/oddsportal/oddsportal_team_model.py +0 -0
  179. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/oddsportal/oddsportal_venue_model.py +0 -0
  180. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/owner_model.py +0 -0
  181. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/player_model.py +0 -0
  182. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/season_type.py +0 -0
  183. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/sex.py +0 -0
  184. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/social_model.py +0 -0
  185. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/species.py +0 -0
  186. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/sportsdb/__init__.py +0 -0
  187. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/sportsdb/sportsdb_game_model.py +0 -0
  188. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/sportsdb/sportsdb_team_model.py +0 -0
  189. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/sportsdb/sportsdb_venue_model.py +0 -0
  190. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/sportsreference/__init__.py +0 -0
  191. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/sportsreference/sportsreference_coach_model.py +0 -0
  192. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/sportsreference/sportsreference_game_model.py +0 -0
  193. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/sportsreference/sportsreference_team_model.py +0 -0
  194. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/sportsreference/sportsreference_venue_model.py +0 -0
  195. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/team_model.py +0 -0
  196. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/venue_model.py +0 -0
  197. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/weather/__init__.py +0 -0
  198. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/weather/gribstream/__init__.py +0 -0
  199. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/weather/gribstream/gribstream_weather_model.py +0 -0
  200. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/weather/multi_weather_model.py +0 -0
  201. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/weather/openmeteo/__init__.py +0 -0
  202. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/weather/openmeteo/openmeteo_weather_model.py +0 -0
  203. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/weather_model.py +0 -0
  204. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/wikipedia/__init__.py +0 -0
  205. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/wikipedia/wikipedia_venue_model.py +0 -0
  206. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/x/__init__.py +0 -0
  207. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/data/x/x_social_model.py +0 -0
  208. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/logger.py +0 -0
  209. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/loglevel.py +0 -0
  210. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/playwright.py +0 -0
  211. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/sportsball.py +0 -0
  212. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/vendor/__init__.py +0 -0
  213. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball/vendor/pygooglenews/__init__.py +0 -0
  214. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball.egg-info/SOURCES.txt +0 -0
  215. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball.egg-info/dependency_links.txt +0 -0
  216. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball.egg-info/entry_points.txt +0 -0
  217. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball.egg-info/not-zip-safe +0 -0
  218. {sportsball-0.10.11 → sportsball-0.10.13}/sportsball.egg-info/top_level.txt +0 -0
  219. {sportsball-0.10.11 → sportsball-0.10.13}/tests/__init__.py +0 -0
  220. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/__init__.py +0 -0
  221. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/afl/__init__.py +0 -0
  222. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/afl/afl/__init__.py +0 -0
  223. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/afl/afl/afl_afl_game_model_test.py +0 -0
  224. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/afl/afl/afl_afl_league_model_test.py +0 -0
  225. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/afl/afltables/__init__.py +0 -0
  226. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/afl/afltables/afl_afltables_coach_model_test.py +0 -0
  227. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/afl/afltables/afl_afltables_game_model_test.py +0 -0
  228. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/afl/afltables/afl_afltables_league_model_test.py +0 -0
  229. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/afl/afltables/afl_afltables_player_model_test.py +0 -0
  230. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/aussportsbetting/__init__.py +0 -0
  231. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/aussportsbetting/aussportsbetting_game_model_test.py +0 -0
  232. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/combined/__init__.py +0 -0
  233. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/combined/combined_game_model_test.py +0 -0
  234. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/combined/combined_player_model_test.py +0 -0
  235. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/combined/combined_team_model_test.py +0 -0
  236. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/combined/combined_venue_model_test.py +0 -0
  237. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/espn/__init__.py +0 -0
  238. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/espn/espn_game_model_test.py +0 -0
  239. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/espn/espn_player_model_test.py +0 -0
  240. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/game_model_test.py +0 -0
  241. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/google/__init__.py +0 -0
  242. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/google/google_address_model_test.py +0 -0
  243. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/google/google_news_model_test.py +0 -0
  244. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/hkjc/__init__.py +0 -0
  245. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/hkjc/hkjc/__init__.py +0 -0
  246. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/hkjc/hkjc/hkjc_hkjc_game_model_test.py +0 -0
  247. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/hkjc/hkjc/hkjc_hkjc_player_model_test.py +0 -0
  248. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/nba/__init__.py +0 -0
  249. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/nba/nba/__init__.py +0 -0
  250. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/nba/nba/nba_nba_game_model_test.py +0 -0
  251. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/nba/nba/nba_nba_league_model_test.py +0 -0
  252. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/nba/nba/nba_nba_team_model_test.py +0 -0
  253. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/nba/sportsdb/__init__.py +0 -0
  254. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/nba/sportsdb/nba_sportsdb_league_model_test.py +0 -0
  255. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/nba/sportsreference/__init__.py +0 -0
  256. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/nba/sportsreference/nba_sportsreference_league_model_test.py +0 -0
  257. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/ncaab/__init__.py +0 -0
  258. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/ncaab/sportsreference/__init__.py +0 -0
  259. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/ncaab/sportsreference/ncaab_sportsreference_league_model_test.py +0 -0
  260. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/nfl/__init__.py +0 -0
  261. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/nfl/sportsdb/__init__.py +0 -0
  262. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/nfl/sportsdb/nfl_sportsdb_league_model_test.py +0 -0
  263. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/oddsportal/__init__.py +0 -0
  264. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/oddsportal/decrypt_test.py +0 -0
  265. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/oddsportal/oddsportal_game_model_test.py +0 -0
  266. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/oddsportal/oddsportal_league_model_test.py +0 -0
  267. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/player_model_test.py +0 -0
  268. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/social_model_test.py +0 -0
  269. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/sportsdb/__init__.py +0 -0
  270. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/sportsdb/sportsdb_game_model_test.py +0 -0
  271. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/sportsdb/sportsdb_league_model_test.py +0 -0
  272. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/sportsdb/sportsdb_team_model_test.py +0 -0
  273. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/sportsdb/sportsdb_venue_model_test.py +0 -0
  274. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/sportsreference/__init__.py +0 -0
  275. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/sportsreference/sportsreference_coach_model_test.py +0 -0
  276. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/sportsreference/sportsreference_game_model_test.py +0 -0
  277. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/sportsreference/sportsreference_league_model_test.py +0 -0
  278. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/sportsreference/sportsreference_player_model_test.py +0 -0
  279. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/sportsreference/sportsreference_team_model_test.py +0 -0
  280. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/sportsreference/sportsreference_venue_model_test.py +0 -0
  281. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/team_model_test.py +0 -0
  282. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/x/__init__.py +0 -0
  283. {sportsball-0.10.11 → sportsball-0.10.13}/tests/data/x/x_social_model_test.py +0 -0
  284. {sportsball-0.10.11 → sportsball-0.10.13}/tests/sportsball_test.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: sportsball
3
- Version: 0.10.11
3
+ Version: 0.10.13
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
@@ -47,7 +47,7 @@ Requires-Dist: playwright>=1.51.0
47
47
  Requires-Dist: cchardet>=2.2.0a2
48
48
  Requires-Dist: lxml>=5.3.0
49
49
  Requires-Dist: gender-guesser>=0.4.0
50
- Requires-Dist: scrapesession>=0.0.7
50
+ Requires-Dist: scrapesession>=0.0.11
51
51
  Requires-Dist: pyhigh>=0.0.6
52
52
  Dynamic: author
53
53
  Dynamic: author-email
@@ -34,5 +34,5 @@ playwright>=1.51.0
34
34
  cchardet>=2.2.0a2
35
35
  lxml>=5.3.0
36
36
  gender-guesser>=0.4.0
37
- scrapesession>=0.0.7
37
+ scrapesession>=0.0.11
38
38
  pyhigh>=0.0.6
@@ -26,7 +26,7 @@ def install_requires() -> typing.List[str]:
26
26
 
27
27
  setup(
28
28
  name='sportsball',
29
- version='0.10.11',
29
+ version='0.10.13',
30
30
  description='A library for pulling in and normalising sports stats.',
31
31
  long_description=long_description,
32
32
  long_description_content_type='text/markdown',
@@ -4,4 +4,4 @@
4
4
  import cchardet # type: ignore
5
5
  import lxml # noqa: ignore
6
6
 
7
- __VERSION__ = "0.10.11"
7
+ __VERSION__ = "0.10.13"
@@ -15,7 +15,7 @@ from scrapesession.scrapesession import ScrapeSession # type: ignore
15
15
  from ....playwright import ensure_install
16
16
  from ...game_model import VERSION, GameModel
17
17
  from ...league import League
18
- from ...league_model import LeagueModel
18
+ from ...league_model import SHUTDOWN_FLAG, LeagueModel
19
19
  from ..position import Position, position_from_str
20
20
  from .afl_afl_game_model import create_afl_afl_game_model, parse_players_v1
21
21
 
@@ -28,6 +28,8 @@ def _parse_v1(
28
28
  playwright: Playwright,
29
29
  ) -> Iterator[GameModel]:
30
30
  for div in soup.find_all("div", {"class": re.compile(".*js-match-list-item.*")}):
31
+ if SHUTDOWN_FLAG.is_set():
32
+ return
31
33
  team_names = []
32
34
  for span in div.find_all(
33
35
  "span", {"class": re.compile(".*team-lineups__team-name.*")}
@@ -77,6 +79,8 @@ def _parse_v2_soup(
77
79
  tuple[list[str], list[list[tuple[str, str, str, str, Position]]], str, str]
78
80
  ]:
79
81
  for div in soup.find_all("div", {"class": "team-lineups__item"}):
82
+ if SHUTDOWN_FLAG.is_set():
83
+ return
80
84
  team_names = []
81
85
  for span in div.find_all(
82
86
  "span", {"class": re.compile(".*team-lineups-header__name.*")}
@@ -218,12 +222,18 @@ class AFLAFLLeagueModel(LeagueModel):
218
222
 
219
223
  @property
220
224
  def games(self) -> Iterator[GameModel]:
221
- ladder = self._ladder
222
- ensure_install()
223
- with sync_playwright() as p:
224
- browser = p.chromium.launch()
225
- context = browser.new_context()
226
- page = context.new_page()
227
- url = "https://www.afl.com.au/matches/team-lineups"
228
- page.goto(url, wait_until="networkidle")
229
- yield from _parse_game_info(page.content(), self.session, ladder, url, p)
225
+ try:
226
+ ladder = self._ladder
227
+ ensure_install()
228
+ with sync_playwright() as p:
229
+ browser = p.chromium.launch()
230
+ context = browser.new_context()
231
+ page = context.new_page()
232
+ url = "https://www.afl.com.au/matches/team-lineups"
233
+ page.goto(url, wait_until="networkidle")
234
+ yield from _parse_game_info(
235
+ page.content(), self.session, ladder, url, p
236
+ )
237
+ except Exception as exc:
238
+ SHUTDOWN_FLAG.set()
239
+ raise exc
@@ -15,7 +15,7 @@ from scrapesession.scrapesession import ScrapeSession # type: ignore
15
15
 
16
16
  from ...game_model import GameModel
17
17
  from ...league import League
18
- from ...league_model import LeagueModel
18
+ from ...league_model import SHUTDOWN_FLAG, LeagueModel
19
19
  from ...season_type import SeasonType
20
20
  from .afl_afltables_game_model import create_afl_afltables_game_model
21
21
 
@@ -82,6 +82,8 @@ class AFLAFLTablesLeagueModel(LeagueModel):
82
82
  if "Venue:" in td_text:
83
83
  current_dt = _find_dt(td_text, season_url)
84
84
  for a in table.find_all("a", href=True):
85
+ if SHUTDOWN_FLAG.is_set():
86
+ return
85
87
  if a.get_text().strip().lower() == "match stats":
86
88
  url = urllib.parse.urljoin(season_url, a.get("href"))
87
89
  if url in urls_duplicates:
@@ -149,20 +151,24 @@ class AFLAFLTablesLeagueModel(LeagueModel):
149
151
 
150
152
  @property
151
153
  def games(self) -> Iterator[GameModel]:
152
- with self.session.cache_disabled():
153
- with self.session.wayback_disabled():
154
- response = self.session.get(_SEASON_URL)
155
- response.raise_for_status()
156
- soup = BeautifulSoup(response.text, "lxml")
157
- with tqdm.tqdm(position=self.position) as pbar:
158
- for table in soup.find_all("table"):
159
- for tr in table.find_all("tr"):
160
- for td in tr.find_all("td"):
161
- for a in td.find_all("a"):
162
- url = urllib.parse.urljoin(_SEASON_URL, a.get("href"))
163
- yield from self._produce_games(
164
- url, SeasonType.REGULAR, pbar
165
- )
166
- yield from self._produce_games(
167
- url, SeasonType.POSTSEASON, pbar
168
- )
154
+ try:
155
+ with self.session.cache_disabled():
156
+ with self.session.wayback_disabled():
157
+ response = self.session.get(_SEASON_URL)
158
+ response.raise_for_status()
159
+ soup = BeautifulSoup(response.text, "lxml")
160
+ with tqdm.tqdm(position=self.position) as pbar:
161
+ for table in soup.find_all("table"):
162
+ for tr in table.find_all("tr"):
163
+ for td in tr.find_all("td"):
164
+ for a in td.find_all("a"):
165
+ url = urllib.parse.urljoin(_SEASON_URL, a.get("href"))
166
+ yield from self._produce_games(
167
+ url, SeasonType.REGULAR, pbar
168
+ )
169
+ yield from self._produce_games(
170
+ url, SeasonType.POSTSEASON, pbar
171
+ )
172
+ except Exception as exc:
173
+ SHUTDOWN_FLAG.set()
174
+ raise exc
@@ -11,7 +11,7 @@ from scrapesession.scrapesession import ScrapeSession # type: ignore
11
11
 
12
12
  from ..game_model import GameModel
13
13
  from ..league import League
14
- from ..league_model import LeagueModel
14
+ from ..league_model import SHUTDOWN_FLAG, LeagueModel
15
15
  from .aussportsbetting_game_model import create_aussportsbetting_game_model
16
16
 
17
17
 
@@ -98,17 +98,23 @@ class AusSportsBettingLeagueModel(LeagueModel):
98
98
 
99
99
  @property
100
100
  def games(self) -> Iterator[GameModel]:
101
- with self.session.cache_disabled():
102
- response = self.session.get(self._spreadsheet_url)
103
- response.raise_for_status()
104
- workbook = load_workbook(filename=BytesIO(response.content))
105
- ws = workbook.active
106
- if ws is None:
107
- raise ValueError("ws is null.")
108
- with tqdm.tqdm(position=self.position) as pbar:
109
- for row in ws.iter_rows():
110
- game_model = self._row_to_game(row)
111
- if game_model is not None:
112
- pbar.update(1)
113
- pbar.set_description(f"AusSportsBetting - {game_model.dt}")
114
- yield game_model
101
+ try:
102
+ with self.session.cache_disabled():
103
+ response = self.session.get(self._spreadsheet_url)
104
+ response.raise_for_status()
105
+ workbook = load_workbook(filename=BytesIO(response.content))
106
+ ws = workbook.active
107
+ if ws is None:
108
+ raise ValueError("ws is null.")
109
+ with tqdm.tqdm(position=self.position) as pbar:
110
+ for row in ws.iter_rows():
111
+ if SHUTDOWN_FLAG.is_set():
112
+ return
113
+ game_model = self._row_to_game(row)
114
+ if game_model is not None:
115
+ pbar.update(1)
116
+ pbar.set_description(f"AusSportsBetting - {game_model.dt}")
117
+ yield game_model
118
+ except Exception as exc:
119
+ SHUTDOWN_FLAG.set()
120
+ raise exc
@@ -3,7 +3,7 @@
3
3
  # pylint: disable=raise-missing-from,too-many-locals
4
4
  import logging
5
5
  import multiprocessing
6
- from concurrent.futures import ThreadPoolExecutor
6
+ from concurrent.futures import ThreadPoolExecutor, as_completed
7
7
  from typing import Any, Iterator
8
8
 
9
9
  from scrapesession.scrapesession import ScrapeSession # type: ignore
@@ -65,12 +65,21 @@ class CombinedLeagueModel(LeagueModel):
65
65
  ) as p:
66
66
  # We want to terminate immediately if any of our runners runs into trouble.
67
67
 
68
- results = list(
69
- p.map(
70
- _produce_league_games,
71
- self._league_models,
72
- )
73
- )
68
+ futures = {
69
+ p.submit(_produce_league_games, model): model
70
+ for model in self._league_models
71
+ }
72
+
73
+ results = []
74
+ try:
75
+ for future in as_completed(futures):
76
+ result = future.result() # Raises if an exception occurred
77
+ results.append(result)
78
+ except Exception:
79
+ # Cancel all pending futures
80
+ for f in futures:
81
+ f.cancel()
82
+ raise # Optionally re-raise the exception
74
83
  game_lists = [[GameModel.model_validate(y) for y in x] for x in results]
75
84
 
76
85
  for game_list in game_lists:
@@ -8,7 +8,7 @@ from scrapesession.scrapesession import ScrapeSession # type: ignore
8
8
 
9
9
  from ..game_model import GameModel
10
10
  from ..league import League
11
- from ..league_model import LeagueModel
11
+ from ..league_model import SHUTDOWN_FLAG, LeagueModel
12
12
  from ..season_type import SeasonType
13
13
  from .espn_game_model import create_espn_game_model
14
14
 
@@ -136,6 +136,8 @@ class ESPNLeagueModel(LeagueModel):
136
136
  weeks_response.raise_for_status()
137
137
  weeks = weeks_response.json()
138
138
  for item in weeks["items"]:
139
+ if SHUTDOWN_FLAG.is_set():
140
+ return
139
141
  if cache_disabled:
140
142
  with self.session.cache_disabled():
141
143
  week_response = self.session.get(item["$ref"])
@@ -153,35 +155,43 @@ class ESPNLeagueModel(LeagueModel):
153
155
 
154
156
  @property
155
157
  def games(self) -> Iterator[GameModel]:
156
- with self.session.wayback_disabled():
157
- page = 1
158
- first = True
159
- with tqdm.tqdm(position=self.position) as pbar:
160
- while True:
161
- if page == 1:
162
- with self.session.cache_disabled():
158
+ try:
159
+ with self.session.wayback_disabled():
160
+ page = 1
161
+ first = True
162
+ with tqdm.tqdm(position=self.position) as pbar:
163
+ while True:
164
+ if page == 1:
165
+ with self.session.cache_disabled():
166
+ response = self.session.get(
167
+ self._start_url + f"&page={page}"
168
+ )
169
+ else:
163
170
  response = self.session.get(
164
171
  self._start_url + f"&page={page}"
165
172
  )
166
- else:
167
- response = self.session.get(self._start_url + f"&page={page}")
168
- response.raise_for_status()
169
- seasons = response.json()
170
- for item in seasons.get("items", []):
171
- season_response = self.session.get(item["$ref"])
172
- season_response.raise_for_status()
173
- season_json = season_response.json()
174
-
175
- for season_item in season_json["types"]["items"]:
176
- season_type_response = self.session.get(season_item["$ref"])
177
- season_type_response.raise_for_status()
178
- season_type_json = season_type_response.json()
179
-
180
- yield from self._produce_week_games(
181
- season_type_json, page, pbar, first
182
- )
183
- first = False
184
-
185
- if page >= seasons.get("pageCount", 0):
186
- break
187
- page += 1
173
+ response.raise_for_status()
174
+ seasons = response.json()
175
+ for item in seasons.get("items", []):
176
+ season_response = self.session.get(item["$ref"])
177
+ season_response.raise_for_status()
178
+ season_json = season_response.json()
179
+
180
+ for season_item in season_json["types"]["items"]:
181
+ season_type_response = self.session.get(
182
+ season_item["$ref"]
183
+ )
184
+ season_type_response.raise_for_status()
185
+ season_type_json = season_type_response.json()
186
+
187
+ yield from self._produce_week_games(
188
+ season_type_json, page, pbar, first
189
+ )
190
+ first = False
191
+
192
+ if page >= seasons.get("pageCount", 0):
193
+ break
194
+ page += 1
195
+ except Exception as exc:
196
+ SHUTDOWN_FLAG.set()
197
+ raise exc
@@ -18535,6 +18535,25 @@ _CACHED_GEOCODES: dict[str, Any] = {
18535
18535
  housenumber="",
18536
18536
  country="USA",
18537
18537
  ),
18538
+ "Villanova College": SportsballGeocodeTuple(
18539
+ city="Villanova",
18540
+ state="PA",
18541
+ postal="",
18542
+ lat=40.03771,
18543
+ lng=-75.33755,
18544
+ housenumber="",
18545
+ country="USA",
18546
+ ),
18547
+ "Canadian Tire Centre, Ottawa, ON, Canada": SportsballGeocodeTuple(
18548
+ city="Ottawa",
18549
+ state="ON",
18550
+ postal="",
18551
+ lat=45.296944,
18552
+ lng=-75.927222,
18553
+ housenumber="",
18554
+ country="Canada",
18555
+ ),
18556
+ "American Airlines Center": AMERICAN_AIRLINES_ARENA,
18538
18557
  }
18539
18558
 
18540
18559
 
@@ -0,0 +1,111 @@
1
+ """The HKJC league model."""
2
+
3
+ # pylint: disable=line-too-long,too-many-statements
4
+ import datetime
5
+ import http
6
+ import urllib.parse
7
+ from typing import Iterator
8
+ from urllib.parse import urlparse
9
+
10
+ import tqdm
11
+ from bs4 import BeautifulSoup
12
+ from scrapesession.scrapesession import ScrapeSession # type: ignore
13
+
14
+ from ...game_model import GameModel
15
+ from ...league import League
16
+ from ...league_model import SHUTDOWN_FLAG, LeagueModel
17
+ from .hkjc_hkjc_game_model import (RACE_COURSE_QUERY_KEY, RACE_DATE_QUERY_KEY,
18
+ RACE_NUMBER_QUERY_KEY,
19
+ create_hkjc_hkjc_game_model)
20
+ from .hkjc_hkjc_venue_model import HAPPY_VALLEY_VENUE_CODE, SHA_TIN_VENUE_CODE
21
+
22
+ _BAD_URLS = {
23
+ "https://common.hkjc.com/racing/information/English/Racing/LocalResults.aspx?RaceDate=2025/03/05&Racecourse=HV&RaceNo=9",
24
+ "https://common.hkjc.com/racing/information/English/Racing/LocalResults.aspx?RaceDate=1992/04/22&Racecourse=HV&RaceNo=4",
25
+ "https://common.hkjc.com/racing/information/English/Racing/LocalResults.aspx?RaceDate=1992/04/22&Racecourse=HV&RaceNo=5",
26
+ "https://common.hkjc.com/racing/information/English/Racing/LocalResults.aspx?RaceDate=1992/04/22&Racecourse=HV&RaceNo=6",
27
+ }
28
+
29
+
30
+ class HKJCHKJCLeagueModel(LeagueModel):
31
+ """HKJC HKJC implementation of the league model."""
32
+
33
+ def __init__(self, session: ScrapeSession, position: int | None = None) -> None:
34
+ super().__init__(League.HKJC, session, position=position)
35
+
36
+ @classmethod
37
+ def name(cls) -> str:
38
+ return "hkjc-league-model"
39
+
40
+ @property
41
+ def games(self) -> Iterator[GameModel]: # type: ignore
42
+ try:
43
+
44
+ def games_for_date(dt: datetime.date) -> Iterator[GameModel]:
45
+ dt_str = dt.strftime("%Y/%m/%d")
46
+ for course in [SHA_TIN_VENUE_CODE, HAPPY_VALLEY_VENUE_CODE]:
47
+ with self.session.wayback_disabled():
48
+ response = self.session.get(
49
+ f"https://racing.hkjc.com/racing/information/English/Racing/LocalResults.aspx?{RACE_DATE_QUERY_KEY}={dt_str}&{RACE_COURSE_QUERY_KEY}={course}&{RACE_NUMBER_QUERY_KEY}=1",
50
+ )
51
+ response.raise_for_status()
52
+ game_model = create_hkjc_hkjc_game_model(
53
+ self.session, response.text, response.url
54
+ )
55
+ if game_model is not None:
56
+ yield game_model
57
+ soup = BeautifulSoup(response.text, "lxml")
58
+ seen_urls = {response.url}
59
+ for a in soup.find_all("a", href=True):
60
+ if SHUTDOWN_FLAG.is_set():
61
+ return
62
+ url = urllib.parse.urljoin(response.url, a.get("href"))
63
+ if url in seen_urls:
64
+ continue
65
+ o = urlparse(url)
66
+ if not o.path.endswith("/LocalResults.aspx"):
67
+ continue
68
+ if url in _BAD_URLS:
69
+ continue
70
+ query = urllib.parse.parse_qs(o.query)
71
+ if RACE_NUMBER_QUERY_KEY not in query:
72
+ continue
73
+ if query[RACE_COURSE_QUERY_KEY][0] != course:
74
+ continue
75
+ with self.session.wayback_disabled():
76
+ response = self.session.get(url)
77
+ if response.status_code == http.HTTPStatus.NOT_FOUND:
78
+ continue
79
+ response.raise_for_status()
80
+ game_model = create_hkjc_hkjc_game_model(
81
+ self.session, response.text, response.url
82
+ )
83
+ if game_model is not None:
84
+ yield game_model
85
+ seen_urls.add(url)
86
+
87
+ today_date = datetime.datetime.today().date()
88
+ last_scraped_date: datetime.date | None = None
89
+ current_date = today_date
90
+
91
+ with tqdm.tqdm(position=self.position) as pbar:
92
+ while (
93
+ last_scraped_date is None
94
+ or (last_scraped_date - current_date).days < 360
95
+ ):
96
+ if current_date >= today_date:
97
+ with self.session.cache_disabled():
98
+ for game_model in games_for_date(current_date):
99
+ last_scraped_date = current_date
100
+ pbar.update(1)
101
+ yield game_model
102
+ else:
103
+ for game_model in games_for_date(current_date):
104
+ last_scraped_date = current_date
105
+ pbar.update(1)
106
+ yield game_model
107
+ pbar.set_description(f"HKJC {current_date}")
108
+ current_date -= datetime.timedelta(days=1)
109
+ except Exception as exc:
110
+ SHUTDOWN_FLAG.set()
111
+ raise exc
@@ -2,6 +2,7 @@
2
2
 
3
3
  # pylint: disable=line-too-long
4
4
  import datetime
5
+ import threading
5
6
  from typing import Iterator, get_args, get_origin
6
7
 
7
8
  import pandas as pd
@@ -19,6 +20,7 @@ from .model import Model
19
20
  from .venue_model import VENUE_ADDRESS_COLUMN
20
21
 
21
22
  LEAGUE_COLUMN = "league"
23
+ SHUTDOWN_FLAG = threading.Event()
22
24
 
23
25
 
24
26
  def _clear_column_list(df: pd.DataFrame) -> pd.DataFrame:
@@ -13,7 +13,7 @@ from scrapesession.scrapesession import ScrapeSession # type: ignore
13
13
 
14
14
  from ...game_model import GameModel
15
15
  from ...league import League
16
- from ...league_model import LeagueModel
16
+ from ...league_model import SHUTDOWN_FLAG, LeagueModel
17
17
  from .nba_nba_game_model import create_nba_nba_game_model
18
18
 
19
19
 
@@ -83,6 +83,8 @@ class NBANBALeagueModel(LeagueModel):
83
83
  pbar: tqdm.tqdm,
84
84
  ) -> Iterator[GameModel]:
85
85
  for _, row in all_games.iterrows():
86
+ if SHUTDOWN_FLAG.is_set():
87
+ return
86
88
  season_id = row["SEASON_ID"]
87
89
  dt = parse(row["GAME_DATE"])
88
90
  season_info = seasons.get(
@@ -112,30 +114,34 @@ class NBANBALeagueModel(LeagueModel):
112
114
 
113
115
  @property
114
116
  def games(self) -> Iterator[GameModel]:
115
- to_date = datetime.datetime.today().date()
116
- seasons: dict[str, NBANBALeagueModel._SeasonInfo] = {}
117
- first_call = False
118
- with tqdm.tqdm(position=self.position) as pbar:
119
- while True:
120
- next_date = to_date - relativedelta(years=1)
121
- if not first_call:
122
- with self.session.cache_disabled():
117
+ try:
118
+ to_date = datetime.datetime.today().date()
119
+ seasons: dict[str, NBANBALeagueModel._SeasonInfo] = {}
120
+ first_call = False
121
+ with tqdm.tqdm(position=self.position) as pbar:
122
+ while True:
123
+ next_date = to_date - relativedelta(years=1)
124
+ if not first_call:
125
+ with self.session.cache_disabled():
126
+ result = leaguegamefinder.LeagueGameFinder(
127
+ league_id_nullable=self._league_id,
128
+ date_from_nullable=next_date.strftime("%m/%d/%Y"),
129
+ date_to_nullable=to_date.strftime("%m/%d/%Y"),
130
+ )
131
+ first_call = True
132
+ else:
123
133
  result = leaguegamefinder.LeagueGameFinder(
124
134
  league_id_nullable=self._league_id,
125
135
  date_from_nullable=next_date.strftime("%m/%d/%Y"),
126
136
  date_to_nullable=to_date.strftime("%m/%d/%Y"),
127
137
  )
128
- first_call = True
129
- else:
130
- result = leaguegamefinder.LeagueGameFinder(
131
- league_id_nullable=self._league_id,
132
- date_from_nullable=next_date.strftime("%m/%d/%Y"),
133
- date_to_nullable=to_date.strftime("%m/%d/%Y"),
134
- )
135
138
 
136
- all_games = _combine_team_games(result.get_data_frames()[0])
137
- all_games = all_games.sort_values(by="GAME_DATE", ascending=True)
138
- if all_games.empty:
139
- break
140
- yield from self._produce_games(all_games, seasons, pbar)
141
- to_date = next_date
139
+ all_games = _combine_team_games(result.get_data_frames()[0])
140
+ all_games = all_games.sort_values(by="GAME_DATE", ascending=True)
141
+ if all_games.empty:
142
+ break
143
+ yield from self._produce_games(all_games, seasons, pbar)
144
+ to_date = next_date
145
+ except Exception as exc:
146
+ SHUTDOWN_FLAG.set()
147
+ raise exc
@@ -0,0 +1,46 @@
1
+ """NBA NBA.com league model."""
2
+
3
+ # pylint: disable=too-many-statements,protected-access,too-many-locals,bare-except,too-many-branches,duplicate-code
4
+ import datetime
5
+ import logging
6
+ from typing import Iterator
7
+
8
+ from scrapesession.scrapesession import ScrapeSession # type: ignore
9
+
10
+ from ...game_model import VERSION, GameModel
11
+ from ...league import League
12
+ from ...league_model import SHUTDOWN_FLAG, LeagueModel
13
+ from .nba_nbacom_game_model import create_nba_nbacom_game_model
14
+
15
+
16
+ class NBANBAComLeagueModel(LeagueModel):
17
+ """NBA NBA.com implementation of the league model."""
18
+
19
+ def __init__(self, session: ScrapeSession, position: int | None = None) -> None:
20
+ super().__init__(League.AFL, session, position=position)
21
+
22
+ @classmethod
23
+ def name(cls) -> str:
24
+ return "nba-nbacom-league-model"
25
+
26
+ @property
27
+ def games(self) -> Iterator[GameModel]:
28
+ try:
29
+ with self.session.cache_disabled():
30
+ date_slug = datetime.datetime.today().date().strftime("%Y%m%d")
31
+ response = self.session.get(
32
+ f"https://stats.nba.com/js/data/leaders/00_daily_lineups_{date_slug}.json"
33
+ )
34
+ if response.ok:
35
+ lineup = response.json()
36
+ for game in lineup["games"]:
37
+ if SHUTDOWN_FLAG.is_set():
38
+ return
39
+ yield create_nba_nbacom_game_model(
40
+ game=game, session=self.session, version=VERSION
41
+ )
42
+ else:
43
+ logging.warning("Failed to fetch NBA daily lineups.")
44
+ except Exception as exc:
45
+ SHUTDOWN_FLAG.set()
46
+ raise exc
@@ -15,7 +15,7 @@ from scrapesession.scrapesession import ScrapeSession # type: ignore
15
15
 
16
16
  from ..game_model import GameModel
17
17
  from ..league import League
18
- from ..league_model import LeagueModel
18
+ from ..league_model import SHUTDOWN_FLAG, LeagueModel
19
19
  from .decrypt import fetch_data
20
20
  from .oddsportal_game_model import create_oddsportal_game_model
21
21
 
@@ -63,6 +63,8 @@ def _process_results_pages(
63
63
  if d.get("total") == 0:
64
64
  return
65
65
  for row in d.get("rows", []):
66
+ if SHUTDOWN_FLAG.is_set():
67
+ return
66
68
  game_model = create_oddsportal_game_model(
67
69
  session, urllib.parse.urljoin(url, row["url"]), league, False
68
70
  )
@@ -165,6 +167,10 @@ class OddsPortalLeagueModel(LeagueModel):
165
167
 
166
168
  @property
167
169
  def games(self) -> Iterator[GameModel]:
168
- with tqdm.tqdm(position=self.position) as pbar:
169
- yield from self._find_next(pbar)
170
- yield from self._find_previous(pbar)
170
+ try:
171
+ with tqdm.tqdm(position=self.position) as pbar:
172
+ yield from self._find_next(pbar)
173
+ yield from self._find_previous(pbar)
174
+ except Exception as exc:
175
+ SHUTDOWN_FLAG.set()
176
+ raise exc