sportsball 0.3.16__tar.gz → 0.3.18__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 (183) hide show
  1. {sportsball-0.3.16/sportsball.egg-info → sportsball-0.3.18}/PKG-INFO +2 -2
  2. {sportsball-0.3.16 → sportsball-0.3.18}/README.md +1 -1
  3. {sportsball-0.3.16 → sportsball-0.3.18}/setup.py +1 -1
  4. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/__init__.py +1 -1
  5. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/afl/afltables/afl_afltables_league_model.py +8 -1
  6. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/afl/afltables/afl_afltables_player_model.py +1 -0
  7. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/afl/afltables/afl_afltables_venue_model.py +22 -3
  8. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/aussportsbetting/aussportsbetting_league_model.py +2 -1
  9. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/combined/combined_league_model.py +1 -0
  10. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/combined/combined_player_model.py +5 -0
  11. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/espn/espn_player_model.py +2 -0
  12. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/google/google_address_model.py +57 -27
  13. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/nba/nba/nba_nba_player_model.py +1 -0
  14. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/nba/nba/nba_nba_team_model.py +1 -0
  15. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/player_model.py +6 -0
  16. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/sportsreference/sportsreference_game_model.py +6 -0
  17. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/sportsreference/sportsreference_player_model.py +7 -3
  18. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/sportsreference/sportsreference_team_model.py +8 -2
  19. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/team_model.py +21 -0
  20. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/weather/gribstream/gribstream_weather_model.py +29 -4
  21. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/weather/multi_weather_model.py +2 -2
  22. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/weather/openmeteo/openmeteo_weather_model.py +33 -4
  23. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/proxy_session.py +2 -42
  24. {sportsball-0.3.16 → sportsball-0.3.18/sportsball.egg-info}/PKG-INFO +2 -2
  25. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/combined/combined_player_model_test.py +1 -0
  26. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/nba/nba/nba_nba_game_model_test.py +4 -0
  27. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/nba/nba/nba_nba_team_model_test.py +2 -0
  28. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/player_model_test.py +1 -0
  29. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/sportsreference/sportsreference_player_model_test.py +1 -0
  30. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/sportsreference/sportsreference_team_model_test.py +3 -0
  31. {sportsball-0.3.16 → sportsball-0.3.18}/LICENSE +0 -0
  32. {sportsball-0.3.16 → sportsball-0.3.18}/MANIFEST.in +0 -0
  33. {sportsball-0.3.16 → sportsball-0.3.18}/requirements.txt +0 -0
  34. {sportsball-0.3.16 → sportsball-0.3.18}/setup.cfg +0 -0
  35. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/__main__.py +0 -0
  36. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/args.py +0 -0
  37. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/cache.py +0 -0
  38. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/__init__.py +0 -0
  39. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/address_model.py +0 -0
  40. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/afl/__init__.py +0 -0
  41. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/afl/afltables/__init__.py +0 -0
  42. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/afl/afltables/afl_afltables_game_model.py +0 -0
  43. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/afl/afltables/afl_afltables_team_model.py +0 -0
  44. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/afl/aussportsbetting/__init__.py +0 -0
  45. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/afl/aussportsbetting/afl_aussportsbetting_league_model.py +0 -0
  46. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/afl/combined/__init__.py +0 -0
  47. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/afl/combined/afl_combined_league_model.py +0 -0
  48. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/afl/espn/__init__.py +0 -0
  49. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/afl/espn/afl_espn_league_model.py +0 -0
  50. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/aussportsbetting/__init__.py +0 -0
  51. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/aussportsbetting/aussportsbetting_bookie_model.py +0 -0
  52. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/aussportsbetting/aussportsbetting_game_model.py +0 -0
  53. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/aussportsbetting/aussportsbetting_odds_model.py +0 -0
  54. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/aussportsbetting/aussportsbetting_team_model.py +0 -0
  55. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/aussportsbetting/aussportsbetting_venue_model.py +0 -0
  56. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/bookie_model.py +0 -0
  57. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/combined/__init__.py +0 -0
  58. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/combined/combined_address_model.py +0 -0
  59. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/combined/combined_game_model.py +0 -0
  60. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/combined/combined_team_model.py +0 -0
  61. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/combined/combined_venue_model.py +0 -0
  62. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/combined/combined_weather_model.py +0 -0
  63. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/espn/__init__.py +0 -0
  64. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/espn/espn_bookie_model.py +0 -0
  65. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/espn/espn_game_model.py +0 -0
  66. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/espn/espn_league_model.py +0 -0
  67. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/espn/espn_odds_model.py +0 -0
  68. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/espn/espn_team_model.py +0 -0
  69. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/espn/espn_venue_model.py +0 -0
  70. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/field_type.py +0 -0
  71. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/game_model.py +0 -0
  72. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/google/__init__.py +0 -0
  73. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/google/google_news_model.py +0 -0
  74. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/league.py +0 -0
  75. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/league_model.py +0 -0
  76. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/model.py +0 -0
  77. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/nba/__init__.py +0 -0
  78. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/nba/combined/__init__.py +0 -0
  79. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/nba/combined/nba_combined_league_model.py +0 -0
  80. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/nba/espn/__init__.py +0 -0
  81. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/nba/espn/nba_espn_league_model.py +0 -0
  82. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/nba/nba/__init__.py +0 -0
  83. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/nba/nba/nba_nba_game_model.py +0 -0
  84. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/nba/nba/nba_nba_league_model.py +0 -0
  85. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/nba/sportsdb/__init__.py +0 -0
  86. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/nba/sportsdb/nba_sportsdb_league_model.py +0 -0
  87. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/nba/sportsreference/__init__.py +0 -0
  88. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/nba/sportsreference/nba_sportsreference_league_model.py +0 -0
  89. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/ncaab/__init__.py +0 -0
  90. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/ncaab/combined/__init__.py +0 -0
  91. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/ncaab/combined/ncaab_combined_league_model.py +0 -0
  92. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/ncaab/espn/__init__.py +0 -0
  93. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/ncaab/espn/ncaab_espn_league_model.py +0 -0
  94. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/ncaab/sportsreference/__init__.py +0 -0
  95. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/ncaab/sportsreference/ncaab_sportsreference_league_model.py +0 -0
  96. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/ncaaf/__init__.py +0 -0
  97. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/ncaaf/espn/__init__.py +0 -0
  98. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/ncaaf/espn/ncaaf_espn_league_model.py +0 -0
  99. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/news_model.py +0 -0
  100. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/nfl/__init__.py +0 -0
  101. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/nfl/aussportsbetting/__init__.py +0 -0
  102. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/nfl/aussportsbetting/nfl_aussportsbetting_league_model.py +0 -0
  103. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/nfl/combined/__init__.py +0 -0
  104. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/nfl/combined/nfl_combined_league_model.py +0 -0
  105. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/nfl/espn/__init__.py +0 -0
  106. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/nfl/espn/nfl_espn_league_model.py +0 -0
  107. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/nfl/sportsdb/__init__.py +0 -0
  108. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/nfl/sportsdb/nfl_sportsdb_league_model.py +0 -0
  109. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/odds_model.py +0 -0
  110. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/season_type.py +0 -0
  111. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/social_model.py +0 -0
  112. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/sportsdb/__init__.py +0 -0
  113. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/sportsdb/sportsdb_game_model.py +0 -0
  114. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/sportsdb/sportsdb_league_model.py +0 -0
  115. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/sportsdb/sportsdb_team_model.py +0 -0
  116. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/sportsdb/sportsdb_venue_model.py +0 -0
  117. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/sportsreference/__init__.py +0 -0
  118. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/sportsreference/sportsreference_league_model.py +0 -0
  119. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/sportsreference/sportsreference_venue_model.py +0 -0
  120. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/venue_model.py +0 -0
  121. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/weather/__init__.py +0 -0
  122. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/weather/gribstream/__init__.py +0 -0
  123. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/weather/openmeteo/__init__.py +0 -0
  124. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/weather_model.py +0 -0
  125. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/wikipedia/__init__.py +0 -0
  126. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/wikipedia/wikipedia_venue_model.py +0 -0
  127. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/x/__init__.py +0 -0
  128. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/data/x/x_social_model.py +0 -0
  129. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/logger.py +0 -0
  130. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/loglevel.py +0 -0
  131. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/session.py +0 -0
  132. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball/sportsball.py +0 -0
  133. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball.egg-info/SOURCES.txt +0 -0
  134. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball.egg-info/dependency_links.txt +0 -0
  135. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball.egg-info/entry_points.txt +0 -0
  136. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball.egg-info/not-zip-safe +0 -0
  137. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball.egg-info/requires.txt +0 -0
  138. {sportsball-0.3.16 → sportsball-0.3.18}/sportsball.egg-info/top_level.txt +0 -0
  139. {sportsball-0.3.16 → sportsball-0.3.18}/tests/__init__.py +0 -0
  140. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/__init__.py +0 -0
  141. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/afl/__init__.py +0 -0
  142. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/afl/afltables/__init__.py +0 -0
  143. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/afl/afltables/afl_afltables_player_model_test.py +0 -0
  144. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/aussportsbetting/__init__.py +0 -0
  145. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/aussportsbetting/aussportsbetting_game_model_test.py +0 -0
  146. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/combined/__init__.py +0 -0
  147. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/combined/combined_game_model_test.py +0 -0
  148. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/espn/__init__.py +0 -0
  149. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/espn/espn_game_model_test.py +0 -0
  150. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/espn/espn_player_model_test.py +0 -0
  151. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/game_model_test.py +0 -0
  152. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/google/__init__.py +0 -0
  153. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/google/google_address_model_test.py +0 -0
  154. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/google/google_news_model_test.py +0 -0
  155. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/nba/__init__.py +0 -0
  156. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/nba/nba/__init__.py +0 -0
  157. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/nba/nba/nba_nba_league_model_test.py +0 -0
  158. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/nba/nba/nba_nba_player_model_test.py +0 -0
  159. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/nba/sportsdb/__init__.py +0 -0
  160. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/nba/sportsdb/nba_sportsdb_league_model_test.py +0 -0
  161. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/nba/sportsreference/__init__.py +0 -0
  162. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/nba/sportsreference/nba_sportsreference_league_model_test.py +0 -0
  163. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/ncaab/__init__.py +0 -0
  164. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/ncaab/sportsreference/__init__.py +0 -0
  165. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/ncaab/sportsreference/ncaab_sportsreference_league_model_test.py +0 -0
  166. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/nfl/__init__.py +0 -0
  167. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/nfl/sportsdb/__init__.py +0 -0
  168. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/nfl/sportsdb/nfl_sportsdb_league_model_test.py +0 -0
  169. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/social_model_test.py +0 -0
  170. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/sportsdb/__init__.py +0 -0
  171. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/sportsdb/sportsdb_game_model_test.py +0 -0
  172. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/sportsdb/sportsdb_league_model_test.py +0 -0
  173. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/sportsdb/sportsdb_team_model_test.py +0 -0
  174. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/sportsdb/sportsdb_venue_model_test.py +0 -0
  175. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/sportsreference/__init__.py +0 -0
  176. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/sportsreference/sportsreference_game_model_test.py +0 -0
  177. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/sportsreference/sportsreference_league_model_test.py +0 -0
  178. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/sportsreference/sportsreference_venue_model_test.py +0 -0
  179. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/team_model_test.py +0 -0
  180. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/x/__init__.py +0 -0
  181. {sportsball-0.3.16 → sportsball-0.3.18}/tests/data/x/x_social_model_test.py +0 -0
  182. {sportsball-0.3.16 → sportsball-0.3.18}/tests/proxy_session_test.py +0 -0
  183. {sportsball-0.3.16 → sportsball-0.3.18}/tests/sportsball_test.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: sportsball
3
- Version: 0.3.16
3
+ Version: 0.3.18
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
@@ -244,7 +244,7 @@ Social media posts one day out from the game.
244
244
  This library uses very aggressive caching due to the large data requirements. If the requests are about a recent game (generally in the last 7 days) the caching is bypassed. The caching is as follows:
245
245
 
246
246
  1. A joblib disk cache that caches calls to pydantic model creation functions. This changes on every version update to keep the models in sync. This is the fastest cache.
247
- 2. A requests cache backed by sqlite that caches requests for 1 year.
247
+ 2. A requests cache backed by sqlite that caches requests forever.
248
248
  3. An attempt to find the response is made to the wayback machine, and used if found.
249
249
 
250
250
  It's very recommended that the user uses proxies defined in the `PROXIES` environment variable. The more proxies the easier it is to collect data.
@@ -191,7 +191,7 @@ Social media posts one day out from the game.
191
191
  This library uses very aggressive caching due to the large data requirements. If the requests are about a recent game (generally in the last 7 days) the caching is bypassed. The caching is as follows:
192
192
 
193
193
  1. A joblib disk cache that caches calls to pydantic model creation functions. This changes on every version update to keep the models in sync. This is the fastest cache.
194
- 2. A requests cache backed by sqlite that caches requests for 1 year.
194
+ 2. A requests cache backed by sqlite that caches requests forever.
195
195
  3. An attempt to find the response is made to the wayback machine, and used if found.
196
196
 
197
197
  It's very recommended that the user uses proxies defined in the `PROXIES` environment variable. The more proxies the easier it is to collect data.
@@ -23,7 +23,7 @@ def install_requires() -> typing.List[str]:
23
23
 
24
24
  setup(
25
25
  name='sportsball',
26
- version='0.3.16',
26
+ version='0.3.18',
27
27
  description='A library for pulling in and normalising sports stats.',
28
28
  long_description=long_description,
29
29
  long_description_content_type='text/markdown',
@@ -1,3 +1,3 @@
1
1
  """The main module for sportsball."""
2
2
 
3
- __VERSION__ = "0.3.16"
3
+ __VERSION__ = "0.3.18"
@@ -1,5 +1,7 @@
1
1
  """AFL AFLTables league model."""
2
2
 
3
+ # pylint: disable=too-many-statements
4
+ import datetime
3
5
  import os
4
6
  import urllib.parse
5
7
  from typing import Iterator
@@ -34,7 +36,12 @@ class AFLAFLTablesLeagueModel(LeagueModel):
34
36
  filename, _ = os.path.splitext(last_component)
35
37
  year = int(filename)
36
38
 
37
- response = self.session.get(season_url)
39
+ if year < datetime.datetime.now().year - 1:
40
+ with self.session.cache_disabled():
41
+ response = self.session.get(season_url)
42
+ else:
43
+ response = self.session.get(season_url)
44
+
38
45
  soup = BeautifulSoup(response.text, "html.parser")
39
46
  in_finals = False
40
47
  game_number = 0
@@ -29,6 +29,7 @@ def _create_afl_afltables_player_model(
29
29
  field_goals_attempted=None,
30
30
  offensive_rebounds=None,
31
31
  assists=None,
32
+ turnovers=None,
32
33
  )
33
34
 
34
35
 
@@ -4,6 +4,7 @@ import datetime
4
4
  import os
5
5
  from urllib.parse import urlparse
6
6
 
7
+ import pytest_is_running
7
8
  import requests_cache
8
9
  from bs4 import BeautifulSoup
9
10
 
@@ -12,11 +13,9 @@ from ...google.google_address_model import create_google_address_model
12
13
  from ...venue_model import VenueModel
13
14
 
14
15
 
15
- @MEMORY.cache(ignore=["session"])
16
- def create_afl_afltables_venue_model(
16
+ def _create_afl_afltables_venue_model(
17
17
  url: str, session: requests_cache.CachedSession, dt: datetime.datetime
18
18
  ) -> VenueModel:
19
- """Create a venue model from AFL tables."""
20
19
  o = urlparse(url)
21
20
  last_component = o.path.split("/")[-1]
22
21
  identifier, _ = os.path.splitext(last_component)
@@ -35,3 +34,23 @@ def create_afl_afltables_venue_model(
35
34
  is_grass=None,
36
35
  is_indoor=None,
37
36
  )
37
+
38
+
39
+ @MEMORY.cache(ignore=["session"])
40
+ def _cached_create_afl_afltables_venue_model(
41
+ url: str, session: requests_cache.CachedSession, dt: datetime.datetime
42
+ ) -> VenueModel:
43
+ return _create_afl_afltables_venue_model(url, session, dt)
44
+
45
+
46
+ def create_afl_afltables_venue_model(
47
+ url: str, session: requests_cache.CachedSession, dt: datetime.datetime
48
+ ) -> VenueModel:
49
+ """Create a venue model from AFL tables."""
50
+ if (
51
+ not pytest_is_running.is_running()
52
+ and dt < datetime.datetime.now() - datetime.timedelta(days=7)
53
+ ):
54
+ return _cached_create_afl_afltables_venue_model(url, session, dt)
55
+ with session.cache_disabled():
56
+ return _create_afl_afltables_venue_model(url, session, dt)
@@ -88,7 +88,8 @@ class AusSportsBettingLeagueModel(LeagueModel):
88
88
 
89
89
  @property
90
90
  def games(self) -> Iterator[GameModel]:
91
- response = self.session.get(self._spreadsheet_url)
91
+ with self.session.cache_disabled():
92
+ response = self.session.get(self._spreadsheet_url)
92
93
  response.raise_for_status()
93
94
  workbook = load_workbook(filename=BytesIO(response.content))
94
95
  ws = workbook.active
@@ -1,5 +1,6 @@
1
1
  """Combined league model."""
2
2
 
3
+ # pylint: disable=raise-missing-from
3
4
  import logging
4
5
  import multiprocessing
5
6
  from multiprocessing import Pool
@@ -16,6 +16,7 @@ def create_combined_player_model(
16
16
  field_goals_attempted = None
17
17
  offensive_rebounds = None
18
18
  assists = None
19
+ turnovers = None
19
20
  for player_model in player_models:
20
21
  player_model_jersey = player_model.jersey
21
22
  if player_model_jersey is not None:
@@ -41,6 +42,9 @@ def create_combined_player_model(
41
42
  player_model_assists = player_model.assists
42
43
  if player_model_assists is not None:
43
44
  assists = player_model_assists
45
+ player_model_turnovers = player_model.turnovers
46
+ if player_model_turnovers is not None:
47
+ turnovers = player_model_turnovers
44
48
  return PlayerModel(
45
49
  identifier=identifier,
46
50
  jersey=jersey,
@@ -51,4 +55,5 @@ def create_combined_player_model(
51
55
  field_goals_attempted=field_goals_attempted,
52
56
  offensive_rebounds=offensive_rebounds,
53
57
  assists=assists,
58
+ turnovers=turnovers,
54
59
  )
@@ -1,5 +1,6 @@
1
1
  """ESPN player model."""
2
2
 
3
+ # pylint: disable=duplicate-code
3
4
  import datetime
4
5
  from typing import Any
5
6
 
@@ -38,6 +39,7 @@ def _create_espn_player_model(
38
39
  field_goals_attempted=None,
39
40
  offensive_rebounds=None,
40
41
  assists=None,
42
+ turnovers=None,
41
43
  )
42
44
 
43
45
 
@@ -1027,6 +1027,33 @@ ESPN_WIDE_WORLD_OF_SPORTS_COMPLEX = SportsballGeocodeTuple(
1027
1027
  housenumber="1375",
1028
1028
  country="USA",
1029
1029
  )
1030
+ QUICKEN_LOANS_ARENA = SportsballGeocodeTuple(
1031
+ city="Cleveland",
1032
+ state="OH",
1033
+ postal="",
1034
+ lat=41.496389,
1035
+ lng=-81.688056,
1036
+ housenumber="1",
1037
+ country="USA",
1038
+ )
1039
+ KASEYA_CENTER = SportsballGeocodeTuple(
1040
+ city="Miami",
1041
+ state="FL",
1042
+ postal="",
1043
+ lat=25.781389,
1044
+ lng=-80.188056,
1045
+ housenumber="601",
1046
+ country="USA",
1047
+ )
1048
+ DUNN_OLIVER_ACADOME = SportsballGeocodeTuple(
1049
+ city="Montgomery",
1050
+ state="AL",
1051
+ postal="",
1052
+ lat=32.36185,
1053
+ lng=-86.293158,
1054
+ housenumber="",
1055
+ country="USA",
1056
+ )
1030
1057
  _CACHED_GEOCODES: dict[str, Any] = {
1031
1058
  "S.C.G. - Australia": SCG,
1032
1059
  "Victoria Park - Australia": SportsballGeocodeTuple(
@@ -5853,15 +5880,7 @@ _CACHED_GEOCODES: dict[str, Any] = {
5853
5880
  housenumber="1000",
5854
5881
  country="USA",
5855
5882
  ),
5856
- "Dunn–Oliver Acadome, Montgomery, Alabama": SportsballGeocodeTuple(
5857
- city="Montgomery",
5858
- state="AL",
5859
- postal="",
5860
- lat=32.36185,
5861
- lng=-86.293158,
5862
- housenumber="",
5863
- country="USA",
5864
- ),
5883
+ "Dunn–Oliver Acadome, Montgomery, Alabama": DUNN_OLIVER_ACADOME,
5865
5884
  "Health & Physical Education Arena, Houston, Texas": SportsballGeocodeTuple(
5866
5885
  city="Houston",
5867
5886
  state="TX",
@@ -6521,15 +6540,7 @@ _CACHED_GEOCODES: dict[str, Any] = {
6521
6540
  country="USA",
6522
6541
  ),
6523
6542
  "America West Arena": AMERICA_WEST_ARENA,
6524
- "Quicken Loans Arena - Cleveland, Ohio - United States": SportsballGeocodeTuple(
6525
- city="Cleveland",
6526
- state="OH",
6527
- postal="",
6528
- lat=41.496389,
6529
- lng=-81.688056,
6530
- housenumber="1",
6531
- country="USA",
6532
- ),
6543
+ "Quicken Loans Arena - Cleveland, Ohio - United States": QUICKEN_LOANS_ARENA,
6533
6544
  "Pepsi Center - Denver, Colorado, U.S. - United States": PEPSI_CENTRE,
6534
6545
  "Staples Center": STAPLES_CENTRE,
6535
6546
  "American Airlines Arena": AMERICAN_AIRLINES_ARENA,
@@ -6949,15 +6960,7 @@ _CACHED_GEOCODES: dict[str, Any] = {
6949
6960
  country="USA",
6950
6961
  ),
6951
6962
  "Golden 1 Center, Sacramento, California": GOLDEN_1_CENTER,
6952
- "Kaseya Center, Miami, Florida": SportsballGeocodeTuple(
6953
- city="Miami",
6954
- state="FL",
6955
- postal="",
6956
- lat=25.781389,
6957
- lng=-80.188056,
6958
- housenumber="601",
6959
- country="USA",
6960
- ),
6963
+ "Kaseya Center, Miami, Florida": KASEYA_CENTER,
6961
6964
  "Scotiabank Arena, Toronto, Canada": SportsballGeocodeTuple(
6962
6965
  city="Toronto",
6963
6966
  state="ON",
@@ -6994,6 +6997,33 @@ _CACHED_GEOCODES: dict[str, Any] = {
6994
6997
  "Chesapeake Energy Arena, Oklahoma City, Oklahoma": CHESAPEAKE_ENERGY_ARENA,
6995
6998
  "The Arena, Bay Lake, Florida": ESPN_WIDE_WORLD_OF_SPORTS_COMPLEX,
6996
6999
  "HP Field House, Bay Lake, Florida": ESPN_WIDE_WORLD_OF_SPORTS_COMPLEX,
7000
+ "Mexico City Arena, Mexico City, Mexico": SportsballGeocodeTuple(
7001
+ city="Mexico City",
7002
+ state="",
7003
+ postal="04650",
7004
+ lat=19.496309,
7005
+ lng=-99.175429,
7006
+ housenumber="",
7007
+ country="Mexico",
7008
+ ),
7009
+ "Amway Center, Orlando, Florida": ORLANDO_ARENA,
7010
+ "Phoenix Suns Arena, Phoenix, Arizona": AMERICA_WEST_ARENA,
7011
+ "Quicken Loans Arena, Cleveland, Ohio": QUICKEN_LOANS_ARENA,
7012
+ "STAPLES Center, Los Angeles, California": STAPLES_CENTRE,
7013
+ "Bankers Life Fieldhouse, Indianapolis, Indiana": GAINBRIDGE_FIELDHOUSE,
7014
+ "AmericanAirlines Arena, Miami, Florida": KASEYA_CENTER,
7015
+ "Amalie Arena, Tampa, Florida": SportsballGeocodeTuple(
7016
+ city="Tampa",
7017
+ state="FL",
7018
+ postal="",
7019
+ lat=27.942778,
7020
+ lng=-82.451944,
7021
+ housenumber="401",
7022
+ country="USA",
7023
+ ),
7024
+ "Pepsi Center, Denver, Colorado": PEPSI_CENTRE,
7025
+ "Visa Athletic Center, Bay Lake, Florida": ESPN_WIDE_WORLD_OF_SPORTS_COMPLEX,
7026
+ "Dunn–Oliver Acadome, Montgomery, Alabama": DUNN_OLIVER_ACADOME,
6997
7027
  }
6998
7028
 
6999
7029
 
@@ -38,6 +38,7 @@ def _create_nba_nba_player_model(
38
38
  field_goals_attempted=None,
39
39
  offensive_rebounds=None,
40
40
  assists=None,
41
+ turnovers=None,
41
42
  )
42
43
 
43
44
 
@@ -49,6 +49,7 @@ def _create_nba_nba_team_model(
49
49
  field_goals_attempted=row["FGA" + suffix],
50
50
  offensive_rebounds=row["OREB" + suffix],
51
51
  assists=row["AST" + suffix],
52
+ turnovers=row["TOV" + suffix],
52
53
  )
53
54
 
54
55
 
@@ -14,6 +14,7 @@ FIELD_GOALS_COLUMN: Literal["field_goals"] = "field_goals"
14
14
  FIELD_GOALS_ATTEMPTED_COLUMN: Literal["field_goals_attempted"] = "field_goals_attempted"
15
15
  OFFENSIVE_REBOUNDS_COLUMN: Literal["offensive_rebounds"] = "offensive_rebounds"
16
16
  ASSISTS_COLUMN: Literal["assists"] = "assists"
17
+ TURNOVERS_COLUMN: Literal["turnovers"] = "turnovers"
17
18
 
18
19
 
19
20
  class PlayerModel(BaseModel):
@@ -60,3 +61,8 @@ class PlayerModel(BaseModel):
60
61
  json_schema_extra={TYPE_KEY: FieldType.LOOKAHEAD},
61
62
  alias=ASSISTS_COLUMN,
62
63
  )
64
+ turnovers: int | None = Field(
65
+ ...,
66
+ json_schema_extra={TYPE_KEY: FieldType.LOOKAHEAD},
67
+ alias=TURNOVERS_COLUMN,
68
+ )
@@ -72,6 +72,7 @@ def _create_sportsreference_game_model(
72
72
  fga = {}
73
73
  offensive_rebounds = {}
74
74
  assists = {}
75
+ turnovers = {}
75
76
  for df in dfs:
76
77
  if df.index.nlevels > 1:
77
78
  df.columns = df.columns.get_level_values(1)
@@ -93,6 +94,10 @@ def _create_sportsreference_game_model(
93
94
  asts = df["AST"].tolist()
94
95
  for idx, player in enumerate(players):
95
96
  assists[player] = asts[idx]
97
+ if "TOV" in df.columns.values:
98
+ tovs = df["TOV"].tolist()
99
+ for idx, player in enumerate(players):
100
+ turnovers[player] = tovs[idx]
96
101
 
97
102
  teams: list[TeamModel] = []
98
103
  for a in scorebox_div.find_all("a"):
@@ -110,6 +115,7 @@ def _create_sportsreference_game_model(
110
115
  fga,
111
116
  offensive_rebounds,
112
117
  assists,
118
+ turnovers,
113
119
  )
114
120
  )
115
121
 
@@ -28,6 +28,7 @@ def _create_sportsreference_player_model(
28
28
  fga: dict[str, int],
29
29
  offensive_rebounds: dict[str, int],
30
30
  assists: dict[str, int],
31
+ turnovers: dict[str, int],
31
32
  ) -> PlayerModel | None:
32
33
  """Create a player model from NCAAB sports reference."""
33
34
  player_url = _fix_url(player_url)
@@ -53,6 +54,7 @@ def _create_sportsreference_player_model(
53
54
  field_goals_attempted=fga.get(name),
54
55
  offensive_rebounds=offensive_rebounds.get(name),
55
56
  assists=assists.get(name),
57
+ turnovers=turnovers.get(name),
56
58
  )
57
59
 
58
60
 
@@ -64,9 +66,10 @@ def _cached_create_sportsreference_player_model(
64
66
  fga: dict[str, int],
65
67
  offensive_rebounds: dict[str, int],
66
68
  assists: dict[str, int],
69
+ turnovers: dict[str, int],
67
70
  ) -> PlayerModel | None:
68
71
  return _create_sportsreference_player_model(
69
- session, player_url, fg, fga, offensive_rebounds, assists
72
+ session, player_url, fg, fga, offensive_rebounds, assists, turnovers
70
73
  )
71
74
 
72
75
 
@@ -78,13 +81,14 @@ def create_sportsreference_player_model(
78
81
  fga: dict[str, int],
79
82
  offensive_rebounds: dict[str, int],
80
83
  assists: dict[str, int],
84
+ turnovers: dict[str, int],
81
85
  ) -> PlayerModel | None:
82
86
  """Create a player model from sports reference."""
83
87
  if not pytest_is_running.is_running():
84
88
  return _cached_create_sportsreference_player_model(
85
- session, player_url, fg, fga, offensive_rebounds, assists
89
+ session, player_url, fg, fga, offensive_rebounds, assists, turnovers
86
90
  )
87
91
  with session.cache_disabled():
88
92
  return _create_sportsreference_player_model(
89
- session, player_url, fg, fga, offensive_rebounds, assists
93
+ session, player_url, fg, fga, offensive_rebounds, assists, turnovers
90
94
  )
@@ -1,6 +1,6 @@
1
1
  """Sports Reference team model."""
2
2
 
3
- # pylint: disable=too-many-arguments,too-many-locals
3
+ # pylint: disable=too-many-arguments,too-many-locals,duplicate-code
4
4
  import datetime
5
5
  import json
6
6
  import urllib.parse
@@ -30,6 +30,7 @@ def _create_sportsreference_team_model(
30
30
  fga: dict[str, int],
31
31
  offensive_rebounds: dict[str, int],
32
32
  assists: dict[str, int],
33
+ turnovers: dict[str, int],
33
34
  ) -> TeamModel:
34
35
  response = session.get(url)
35
36
  response.raise_for_status()
@@ -58,7 +59,7 @@ def _create_sportsreference_team_model(
58
59
  y
59
60
  for y in [ # pyright: ignore
60
61
  create_sportsreference_player_model(
61
- session, x, dt, fg, fga, offensive_rebounds, assists
62
+ session, x, dt, fg, fga, offensive_rebounds, assists, turnovers
62
63
  )
63
64
  for x in valid_player_urls
64
65
  ]
@@ -85,6 +86,7 @@ def _cached_create_sportsreference_team_model(
85
86
  fga: dict[str, int],
86
87
  offensive_rebounds: dict[str, int],
87
88
  assists: dict[str, int],
89
+ turnovers: dict[str, int],
88
90
  ) -> TeamModel:
89
91
  return _create_sportsreference_team_model(
90
92
  session,
@@ -97,6 +99,7 @@ def _cached_create_sportsreference_team_model(
97
99
  fga,
98
100
  offensive_rebounds,
99
101
  assists,
102
+ turnovers,
100
103
  )
101
104
 
102
105
 
@@ -111,6 +114,7 @@ def create_sportsreference_team_model(
111
114
  fga: dict[str, int],
112
115
  offensive_rebounds: dict[str, int],
113
116
  assists: dict[str, int],
117
+ turnovers: dict[str, int],
114
118
  ) -> TeamModel:
115
119
  """Create a team model from Sports Reference."""
116
120
  if not pytest_is_running.is_running():
@@ -125,6 +129,7 @@ def create_sportsreference_team_model(
125
129
  fga,
126
130
  offensive_rebounds,
127
131
  assists,
132
+ turnovers,
128
133
  )
129
134
  with session.cache_disabled():
130
135
  return _create_sportsreference_team_model(
@@ -138,4 +143,5 @@ def create_sportsreference_team_model(
138
143
  fga,
139
144
  offensive_rebounds,
140
145
  assists,
146
+ turnovers,
141
147
  )
@@ -1,5 +1,6 @@
1
1
  """The prototype class for a team."""
2
2
 
3
+ # pylint: disable=duplicate-code
3
4
  from typing import Any, Literal
4
5
 
5
6
  from pydantic import BaseModel, Field
@@ -18,6 +19,7 @@ FIELD_GOALS_COLUMN: Literal["field_goals"] = "field_goals"
18
19
  FIELD_GOALS_ATTEMPTED_COLUMN: Literal["field_goals_attempted"] = "field_goals_attempted"
19
20
  OFFENSIVE_REBOUNDS_COLUMN: Literal["offensive_rebounds"] = "offensive_rebounds"
20
21
  ASSISTS_COLUMN: Literal["assists"] = "assists"
22
+ TURNOVERS_COLUMN: Literal["turnovers"] = "turnovers"
21
23
 
22
24
 
23
25
  def _calculate_kicks(data: dict[str, Any]) -> int | None:
@@ -90,6 +92,20 @@ def _calculate_assists(data: dict[str, Any]) -> int | None:
90
92
  return assists
91
93
 
92
94
 
95
+ def _calculate_turnovers(data: dict[str, Any]) -> int | None:
96
+ turnovers = 0
97
+ found_turnovers = False
98
+ for player in data[PLAYER_COLUMN_PREFIX]:
99
+ player_turnovers = player.turnovers
100
+ if player_turnovers is None:
101
+ continue
102
+ found_turnovers = True
103
+ turnovers += player_turnovers
104
+ if not found_turnovers:
105
+ return None
106
+ return turnovers
107
+
108
+
93
109
  class TeamModel(BaseModel):
94
110
  """The serialisable team class."""
95
111
 
@@ -136,3 +152,8 @@ class TeamModel(BaseModel):
136
152
  json_schema_extra={TYPE_KEY: FieldType.LOOKAHEAD},
137
153
  alias=ASSISTS_COLUMN,
138
154
  )
155
+ turnovers: int | None = Field(
156
+ default_factory=_calculate_turnovers,
157
+ json_schema_extra={TYPE_KEY: FieldType.LOOKAHEAD},
158
+ alias=TURNOVERS_COLUMN,
159
+ )
@@ -7,21 +7,21 @@ import json
7
7
  import os
8
8
 
9
9
  import pandas as pd
10
+ import pytest_is_running
10
11
  import pytz
11
12
  import requests
13
+ import requests_cache
12
14
 
13
15
  from ....cache import MEMORY
14
16
  from ...weather_model import WeatherModel
15
17
 
16
18
 
17
- @MEMORY.cache(ignore=["session"])
18
- def create_gribstream_weather_model(
19
- session: requests.Session,
19
+ def _create_gribstream_weather_model(
20
+ session: requests_cache.CachedSession,
20
21
  latitude: float,
21
22
  longitude: float,
22
23
  dt: datetime.datetime,
23
24
  ) -> WeatherModel | None:
24
- """Create a weather model from gribstream."""
25
25
  api_key = os.environ.get("GRIBSTREAM_API_KEY")
26
26
  if api_key is None:
27
27
  return None
@@ -58,3 +58,28 @@ def create_gribstream_weather_model(
58
58
  temperature = df.iloc[idx]["TMP|2 m above ground|"] # type: ignore
59
59
  relative_humidity = df.iloc[idx]["RH|2 m above ground|"] # type: ignore
60
60
  return WeatherModel(temperature=temperature, relative_humidity=relative_humidity)
61
+
62
+
63
+ @MEMORY.cache(ignore=["session"])
64
+ def _cached_create_gribstream_weather_model(
65
+ session: requests_cache.CachedSession,
66
+ latitude: float,
67
+ longitude: float,
68
+ dt: datetime.datetime,
69
+ ) -> WeatherModel | None:
70
+ return _create_gribstream_weather_model(session, latitude, longitude, dt)
71
+
72
+
73
+ def create_gribstream_weather_model(
74
+ session: requests_cache.CachedSession,
75
+ latitude: float,
76
+ longitude: float,
77
+ dt: datetime.datetime,
78
+ ) -> WeatherModel | None:
79
+ """Create a weather model from gribstream."""
80
+ if not pytest_is_running.is_running() and dt < datetime.datetime.now().replace(
81
+ tzinfo=dt.tzinfo
82
+ ) - datetime.timedelta(days=3):
83
+ return _cached_create_gribstream_weather_model(session, latitude, longitude, dt)
84
+ with session.cache_disabled():
85
+ return _create_gribstream_weather_model(session, latitude, longitude, dt)
@@ -2,7 +2,7 @@
2
2
 
3
3
  import datetime
4
4
 
5
- import requests
5
+ import requests_cache
6
6
 
7
7
  from ...cache import MEMORY
8
8
  from ..weather_model import WeatherModel
@@ -13,7 +13,7 @@ from .openmeteo.openmeteo_weather_model import create_openmeteo_weather_model
13
13
 
14
14
  @MEMORY.cache(ignore=["session"])
15
15
  def create_mutli_weather_model(
16
- session: requests.Session,
16
+ session: requests_cache.CachedSession,
17
17
  latitude: float,
18
18
  longitude: float,
19
19
  dt: datetime.datetime,
@@ -4,8 +4,10 @@ import datetime
4
4
 
5
5
  import openmeteo_requests # type: ignore
6
6
  import pandas as pd
7
+ import pytest_is_running
7
8
  import pytz
8
9
  import requests
10
+ import requests_cache
9
11
  from openmeteo_requests.Client import OpenMeteoRequestsError # type: ignore
10
12
  from openmeteo_requests.Client import WeatherApiResponse
11
13
 
@@ -54,15 +56,13 @@ def _parse_openmeteo(
54
56
  return WeatherModel(temperature=temperature, relative_humidity=relative_humidity)
55
57
 
56
58
 
57
- @MEMORY.cache(ignore=["session"])
58
- def create_openmeteo_weather_model(
59
- session: requests.Session,
59
+ def _create_openmeteo_weather_model(
60
+ session: requests_cache.CachedSession,
60
61
  latitude: float,
61
62
  longitude: float,
62
63
  dt: datetime.datetime,
63
64
  tz: str,
64
65
  ) -> WeatherModel | None:
65
- """Create a weather model from openmeteo."""
66
66
  # pylint: disable=broad-exception-caught
67
67
  client = openmeteo_requests.Client(session=session)
68
68
  try:
@@ -138,3 +138,32 @@ def create_openmeteo_weather_model(
138
138
  if "Parameter 'start_date' is out of allowed range from" in e_text:
139
139
  return None
140
140
  raise e
141
+
142
+
143
+ @MEMORY.cache(ignore=["session"])
144
+ def _cached_create_openmeteo_weather_model(
145
+ session: requests_cache.CachedSession,
146
+ latitude: float,
147
+ longitude: float,
148
+ dt: datetime.datetime,
149
+ tz: str,
150
+ ) -> WeatherModel | None:
151
+ return _create_openmeteo_weather_model(session, latitude, longitude, dt, tz)
152
+
153
+
154
+ def create_openmeteo_weather_model(
155
+ session: requests_cache.CachedSession,
156
+ latitude: float,
157
+ longitude: float,
158
+ dt: datetime.datetime,
159
+ tz: str,
160
+ ) -> WeatherModel | None:
161
+ """Create a weather model from openmeteo."""
162
+ if not pytest_is_running.is_running() and dt < datetime.datetime.now().replace(
163
+ tzinfo=dt.tzinfo
164
+ ) - datetime.timedelta(days=3):
165
+ return _cached_create_openmeteo_weather_model(
166
+ session, latitude, longitude, dt, tz
167
+ )
168
+ with session.cache_disabled():
169
+ return _create_openmeteo_weather_model(session, latitude, longitude, dt, tz)