cfb-data 0.4.1__py3-none-any.whl

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 (127) hide show
  1. cfb_data/__init__.py +234 -0
  2. cfb_data/_dataframes.py +279 -0
  3. cfb_data/_executor.py +129 -0
  4. cfb_data/_parquet.py +197 -0
  5. cfb_data/_request_rules.py +41 -0
  6. cfb_data/_requests.py +36 -0
  7. cfb_data/_tabular.py +676 -0
  8. cfb_data/_transport.py +452 -0
  9. cfb_data/adjusted_metrics/__init__.py +29 -0
  10. cfb_data/adjusted_metrics/models/__init__.py +1 -0
  11. cfb_data/adjusted_metrics/models/pydantic/__init__.py +29 -0
  12. cfb_data/adjusted_metrics/models/pydantic/requests.py +45 -0
  13. cfb_data/adjusted_metrics/models/pydantic/responses.py +88 -0
  14. cfb_data/adjusted_metrics/resource.py +220 -0
  15. cfb_data/base/__init__.py +6 -0
  16. cfb_data/base/types.py +112 -0
  17. cfb_data/betting/__init__.py +15 -0
  18. cfb_data/betting/models/__init__.py +1 -0
  19. cfb_data/betting/models/pydantic/__init__.py +6 -0
  20. cfb_data/betting/models/pydantic/requests.py +35 -0
  21. cfb_data/betting/models/pydantic/responses.py +62 -0
  22. cfb_data/betting/resource.py +91 -0
  23. cfb_data/client.py +305 -0
  24. cfb_data/coaches/__init__.py +57 -0
  25. cfb_data/coaches/models/__init__.py +1 -0
  26. cfb_data/coaches/models/pydantic/__init__.py +57 -0
  27. cfb_data/coaches/models/pydantic/requests.py +75 -0
  28. cfb_data/coaches/models/pydantic/responses.py +261 -0
  29. cfb_data/coaches/resource.py +216 -0
  30. cfb_data/conferences/__init__.py +23 -0
  31. cfb_data/conferences/models/__init__.py +1 -0
  32. cfb_data/conferences/models/pydantic/__init__.py +23 -0
  33. cfb_data/conferences/models/pydantic/requests.py +69 -0
  34. cfb_data/conferences/models/pydantic/responses.py +64 -0
  35. cfb_data/conferences/resource.py +175 -0
  36. cfb_data/draft/__init__.py +19 -0
  37. cfb_data/draft/models/__init__.py +1 -0
  38. cfb_data/draft/models/pydantic/__init__.py +12 -0
  39. cfb_data/draft/models/pydantic/requests.py +18 -0
  40. cfb_data/draft/models/pydantic/responses.py +65 -0
  41. cfb_data/draft/resource.py +132 -0
  42. cfb_data/drives/__init__.py +13 -0
  43. cfb_data/drives/models/__init__.py +1 -0
  44. cfb_data/drives/models/pydantic/__init__.py +17 -0
  45. cfb_data/drives/models/pydantic/requests.py +42 -0
  46. cfb_data/drives/models/pydantic/responses.py +46 -0
  47. cfb_data/drives/resource.py +94 -0
  48. cfb_data/enums.py +93 -0
  49. cfb_data/errors.py +234 -0
  50. cfb_data/games/__init__.py +42 -0
  51. cfb_data/games/models/__init__.py +1 -0
  52. cfb_data/games/models/pydantic/__init__.py +106 -0
  53. cfb_data/games/models/pydantic/requests.py +266 -0
  54. cfb_data/games/models/pydantic/responses.py +495 -0
  55. cfb_data/games/resource.py +486 -0
  56. cfb_data/info/__init__.py +25 -0
  57. cfb_data/info/models/__init__.py +1 -0
  58. cfb_data/info/models/pydantic/__init__.py +23 -0
  59. cfb_data/info/models/pydantic/requests.py +18 -0
  60. cfb_data/info/models/pydantic/responses.py +103 -0
  61. cfb_data/info/resource.py +88 -0
  62. cfb_data/metrics/__init__.py +53 -0
  63. cfb_data/metrics/models/__init__.py +1 -0
  64. cfb_data/metrics/models/pydantic/__init__.py +49 -0
  65. cfb_data/metrics/models/pydantic/requests.py +121 -0
  66. cfb_data/metrics/models/pydantic/responses.py +182 -0
  67. cfb_data/metrics/resource.py +371 -0
  68. cfb_data/players/__init__.py +44 -0
  69. cfb_data/players/models/__init__.py +1 -0
  70. cfb_data/players/models/pydantic/__init__.py +41 -0
  71. cfb_data/players/models/pydantic/requests.py +70 -0
  72. cfb_data/players/models/pydantic/responses.py +171 -0
  73. cfb_data/players/resource.py +258 -0
  74. cfb_data/playoffs/__init__.py +41 -0
  75. cfb_data/playoffs/models/__init__.py +1 -0
  76. cfb_data/playoffs/models/pydantic/__init__.py +37 -0
  77. cfb_data/playoffs/models/pydantic/requests.py +30 -0
  78. cfb_data/playoffs/models/pydantic/responses.py +173 -0
  79. cfb_data/playoffs/resource.py +149 -0
  80. cfb_data/plays/__init__.py +43 -0
  81. cfb_data/plays/models/__init__.py +1 -0
  82. cfb_data/plays/models/pydantic/__init__.py +35 -0
  83. cfb_data/plays/models/pydantic/requests.py +85 -0
  84. cfb_data/plays/models/pydantic/responses.py +231 -0
  85. cfb_data/plays/resource.py +249 -0
  86. cfb_data/py.typed +0 -0
  87. cfb_data/rankings/__init__.py +16 -0
  88. cfb_data/rankings/models/__init__.py +1 -0
  89. cfb_data/rankings/models/pydantic/__init__.py +6 -0
  90. cfb_data/rankings/models/pydantic/requests.py +36 -0
  91. cfb_data/rankings/models/pydantic/responses.py +42 -0
  92. cfb_data/rankings/resource.py +89 -0
  93. cfb_data/ratings/__init__.py +59 -0
  94. cfb_data/ratings/models/__init__.py +1 -0
  95. cfb_data/ratings/models/pydantic/__init__.py +55 -0
  96. cfb_data/ratings/models/pydantic/requests.py +87 -0
  97. cfb_data/ratings/models/pydantic/responses.py +215 -0
  98. cfb_data/ratings/resource.py +342 -0
  99. cfb_data/recruiting/__init__.py +26 -0
  100. cfb_data/recruiting/models/__init__.py +1 -0
  101. cfb_data/recruiting/models/pydantic/__init__.py +23 -0
  102. cfb_data/recruiting/models/pydantic/requests.py +69 -0
  103. cfb_data/recruiting/models/pydantic/responses.py +70 -0
  104. cfb_data/recruiting/resource.py +180 -0
  105. cfb_data/retry.py +49 -0
  106. cfb_data/stats/__init__.py +69 -0
  107. cfb_data/stats/models/__init__.py +1 -0
  108. cfb_data/stats/models/pydantic/__init__.py +65 -0
  109. cfb_data/stats/models/pydantic/requests.py +167 -0
  110. cfb_data/stats/models/pydantic/responses.py +291 -0
  111. cfb_data/stats/resource.py +400 -0
  112. cfb_data/teams/__init__.py +40 -0
  113. cfb_data/teams/models/__init__.py +1 -0
  114. cfb_data/teams/models/pydantic/__init__.py +26 -0
  115. cfb_data/teams/models/pydantic/requests.py +96 -0
  116. cfb_data/teams/models/pydantic/responses.py +116 -0
  117. cfb_data/teams/resource.py +270 -0
  118. cfb_data/venues/__init__.py +6 -0
  119. cfb_data/venues/models/__init__.py +1 -0
  120. cfb_data/venues/models/pydantic/__init__.py +5 -0
  121. cfb_data/venues/models/pydantic/responses.py +24 -0
  122. cfb_data/venues/resource.py +51 -0
  123. cfb_data-0.4.1.dist-info/METADATA +414 -0
  124. cfb_data-0.4.1.dist-info/RECORD +127 -0
  125. cfb_data-0.4.1.dist-info/WHEEL +5 -0
  126. cfb_data-0.4.1.dist-info/licenses/LICENSE +21 -0
  127. cfb_data-0.4.1.dist-info/top_level.txt +1 -0
cfb_data/enums.py ADDED
@@ -0,0 +1,93 @@
1
+ """Define values shared by CFBD requests and responses."""
2
+
3
+ from enum import StrEnum
4
+
5
+
6
+ class SeasonType(StrEnum):
7
+ """Identify the phase of a college football season."""
8
+
9
+ regular = "regular"
10
+ postseason = "postseason"
11
+ both = "both"
12
+ allstar = "allstar"
13
+ spring_regular = "spring_regular"
14
+ spring_postseason = "spring_postseason"
15
+
16
+
17
+ class Classification(StrEnum):
18
+ """Identify a college football division classification."""
19
+
20
+ fbs = "fbs"
21
+ fcs = "fcs"
22
+ ii = "ii"
23
+ iii = "iii"
24
+
25
+
26
+ class RankingPoll(StrEnum):
27
+ """Identify a supported rankings poll selector."""
28
+
29
+ cfp = "cfp"
30
+
31
+
32
+ class RecruitClassification(StrEnum):
33
+ """Identify the source classification of a recruit."""
34
+
35
+ juco = "JUCO"
36
+ prep_school = "PrepSchool"
37
+ high_school = "HighSchool"
38
+
39
+
40
+ class MediaType(StrEnum):
41
+ """Identify a game broadcast medium."""
42
+
43
+ tv = "tv"
44
+ radio = "radio"
45
+ web = "web"
46
+ ppv = "ppv"
47
+ mobile = "mobile"
48
+
49
+
50
+ class PlayoffCompetition(StrEnum):
51
+ """Identify an accepted playoff competition filter."""
52
+
53
+ cfp = "cfp"
54
+
55
+
56
+ class PlayoffRound(StrEnum):
57
+ """Identify an accepted College Football Playoff round filter."""
58
+
59
+ first_round = "first_round"
60
+ quarterfinal = "quarterfinal"
61
+ semifinal = "semifinal"
62
+ championship = "championship"
63
+
64
+
65
+ class UserUsageApi(StrEnum):
66
+ """Identify which product contributes to an account usage summary."""
67
+
68
+ all = "all"
69
+ cfb = "cfb"
70
+ cbb = "cbb"
71
+
72
+
73
+ class TransferEligibility(StrEnum):
74
+ """Identify a transfer player's recorded eligibility status."""
75
+
76
+ withdrawn = "Withdrawn"
77
+ tbd = "TBD"
78
+ pending_appeal = "PendingAppeal"
79
+ sitting_one = "SittingOne"
80
+ immediate = "Immediate"
81
+
82
+
83
+ __all__ = [
84
+ "Classification",
85
+ "MediaType",
86
+ "PlayoffCompetition",
87
+ "PlayoffRound",
88
+ "RankingPoll",
89
+ "RecruitClassification",
90
+ "SeasonType",
91
+ "TransferEligibility",
92
+ "UserUsageApi",
93
+ ]
cfb_data/errors.py ADDED
@@ -0,0 +1,234 @@
1
+ """Define safe, actionable exceptions raised by :mod:`cfb_data`."""
2
+
3
+ from __future__ import annotations
4
+
5
+
6
+ class CFBDError(Exception):
7
+ """Provide the root exception for all library-owned failures."""
8
+
9
+
10
+ class _SanitizedCause(Exception):
11
+ """Retain an exception category without retaining unsafe source data."""
12
+
13
+ category: str
14
+
15
+ def __init__(self, *, category: str) -> None:
16
+ """Initialize a safe diagnostic cause.
17
+
18
+ :param category: Source exception type name without its values or state.
19
+ """
20
+ self.category = category
21
+ super().__init__(category)
22
+
23
+
24
+ def _sanitized_cause(source: BaseException) -> _SanitizedCause:
25
+ """Return a diagnostic cause detached from a potentially unsafe exception.
26
+
27
+ :param source: Exception whose type identifies the failure category.
28
+ :return: New exception retaining only the source type name.
29
+ """
30
+ return _SanitizedCause(category=type(source).__name__)
31
+
32
+
33
+ class CFBDConfigurationError(CFBDError):
34
+ """Report invalid or missing client configuration."""
35
+
36
+
37
+ class CFBDOptionalDependencyError(CFBDError, ImportError):
38
+ """Report that a selected optional feature is not installed."""
39
+
40
+
41
+ class CFBDClientStateError(CFBDError, RuntimeError):
42
+ """Report an operation that violates the one-shot client lifecycle."""
43
+
44
+
45
+ class _EndpointError(CFBDError):
46
+ """Attach a safe endpoint identifier to an operation failure."""
47
+
48
+ endpoint: str
49
+
50
+ def __init__(self, message: str, *, endpoint: str) -> None:
51
+ """Initialize an endpoint-scoped error.
52
+
53
+ :param message: Safe human-readable failure description.
54
+ :param endpoint: Fixed endpoint path without query parameters.
55
+ """
56
+ self.endpoint = endpoint
57
+ super().__init__(f"{message} for endpoint {endpoint}")
58
+
59
+
60
+ class CFBDRequestValidationError(_EndpointError):
61
+ """Report invalid endpoint request parameters."""
62
+
63
+ def __init__(self, *, endpoint: str) -> None:
64
+ """Initialize a request-validation error.
65
+
66
+ :param endpoint: Fixed endpoint path without query parameters.
67
+ """
68
+ super().__init__("Request validation failed", endpoint=endpoint)
69
+
70
+
71
+ class CFBDTransportError(_EndpointError):
72
+ """Report a non-timeout failure while communicating with the API."""
73
+
74
+ attempts: int
75
+ category: str
76
+
77
+ def __init__(self, *, endpoint: str, attempts: int, category: str) -> None:
78
+ """Initialize a transport error.
79
+
80
+ :param endpoint: Fixed endpoint path without query parameters.
81
+ :param attempts: Total attempts made.
82
+ :param category: Safe transport failure category.
83
+ """
84
+ self.attempts = attempts
85
+ self.category = category
86
+ super().__init__(
87
+ f"Transport failed after {attempts} attempt(s) ({category})",
88
+ endpoint=endpoint,
89
+ )
90
+
91
+
92
+ class CFBDTimeoutError(CFBDTransportError, TimeoutError):
93
+ """Report that every permitted request attempt timed out."""
94
+
95
+ def __init__(self, *, endpoint: str, attempts: int) -> None:
96
+ """Initialize a timeout error.
97
+
98
+ :param endpoint: Fixed endpoint path without query parameters.
99
+ :param attempts: Total attempts made.
100
+ """
101
+ super().__init__(
102
+ endpoint=endpoint,
103
+ attempts=attempts,
104
+ category="timeout",
105
+ )
106
+
107
+
108
+ class CFBDTLSError(CFBDTransportError):
109
+ """Report a non-retryable TLS or certificate failure."""
110
+
111
+ def __init__(self, *, endpoint: str, attempts: int) -> None:
112
+ """Initialize a TLS error.
113
+
114
+ :param endpoint: Fixed endpoint path without query parameters.
115
+ :param attempts: Total attempts made.
116
+ """
117
+ super().__init__(endpoint=endpoint, attempts=attempts, category="tls")
118
+
119
+
120
+ class CFBDHTTPError(_EndpointError):
121
+ """Report an unsuccessful HTTP response without exposing its body."""
122
+
123
+ status: int
124
+ attempts: int
125
+ retry_after_seconds: float | None
126
+
127
+ def __init__(
128
+ self,
129
+ *,
130
+ endpoint: str,
131
+ status: int,
132
+ attempts: int,
133
+ retry_after_seconds: float | None = None,
134
+ ) -> None:
135
+ """Initialize an HTTP error.
136
+
137
+ :param endpoint: Fixed endpoint path without query parameters.
138
+ :param status: HTTP response status.
139
+ :param attempts: Total attempts made.
140
+ :param retry_after_seconds: Parsed server-requested delay, if valid.
141
+ """
142
+ self.status = status
143
+ self.attempts = attempts
144
+ self.retry_after_seconds = retry_after_seconds
145
+ retry_detail = ""
146
+ if retry_after_seconds is not None:
147
+ retry_detail = f", Retry-After={retry_after_seconds:g}s"
148
+ super().__init__(
149
+ f"HTTP {status} after {attempts} attempt(s){retry_detail}",
150
+ endpoint=endpoint,
151
+ )
152
+
153
+
154
+ class CFBDAuthenticationError(CFBDHTTPError):
155
+ """Report rejected API authentication."""
156
+
157
+
158
+ class CFBDAuthorizationError(CFBDHTTPError):
159
+ """Report insufficient authorization for an endpoint."""
160
+
161
+
162
+ class CFBDRateLimitError(CFBDHTTPError):
163
+ """Report an API rate-limit response."""
164
+
165
+
166
+ class CFBDServerError(CFBDHTTPError):
167
+ """Report an unsuccessful server response."""
168
+
169
+
170
+ class CFBDResponseDecodeError(_EndpointError):
171
+ """Report a response body that cannot be decoded as JSON."""
172
+
173
+ attempts: int
174
+
175
+ def __init__(self, *, endpoint: str, attempts: int) -> None:
176
+ """Initialize a response-decode error.
177
+
178
+ :param endpoint: Fixed endpoint path without query parameters.
179
+ :param attempts: Total attempts made.
180
+ """
181
+ self.attempts = attempts
182
+ super().__init__(
183
+ f"Response JSON decoding failed after {attempts} attempt(s)",
184
+ endpoint=endpoint,
185
+ )
186
+
187
+
188
+ class CFBDResponseValidationError(_EndpointError):
189
+ """Report a decoded response that violates its Pydantic contract."""
190
+
191
+ def __init__(self, *, endpoint: str) -> None:
192
+ """Initialize a response-validation error.
193
+
194
+ :param endpoint: Fixed endpoint path without query parameters.
195
+ """
196
+ super().__init__("Response validation failed", endpoint=endpoint)
197
+
198
+
199
+ class CFBDDataFrameConversionError(_EndpointError):
200
+ """Report failure to preserve validated rows in a selected DataFrame."""
201
+
202
+ backend: str
203
+
204
+ def __init__(self, *, endpoint: str, backend: str) -> None:
205
+ """Initialize a DataFrame-conversion error.
206
+
207
+ :param endpoint: Fixed endpoint path without query parameters.
208
+ :param backend: Selected DataFrame backend name.
209
+ """
210
+ self.backend = backend
211
+ super().__init__(
212
+ f"{backend} DataFrame conversion failed",
213
+ endpoint=endpoint,
214
+ )
215
+
216
+
217
+ __all__ = [
218
+ "CFBDAuthenticationError",
219
+ "CFBDAuthorizationError",
220
+ "CFBDClientStateError",
221
+ "CFBDConfigurationError",
222
+ "CFBDDataFrameConversionError",
223
+ "CFBDError",
224
+ "CFBDHTTPError",
225
+ "CFBDOptionalDependencyError",
226
+ "CFBDRateLimitError",
227
+ "CFBDRequestValidationError",
228
+ "CFBDResponseDecodeError",
229
+ "CFBDResponseValidationError",
230
+ "CFBDServerError",
231
+ "CFBDTimeoutError",
232
+ "CFBDTLSError",
233
+ "CFBDTransportError",
234
+ ]
@@ -0,0 +1,42 @@
1
+ """Export the supported Games namespace and request contracts."""
2
+
3
+ from cfb_data.enums import (
4
+ Classification,
5
+ MediaType,
6
+ PlayoffCompetition,
7
+ PlayoffRound,
8
+ SeasonType,
9
+ )
10
+
11
+ from .models.pydantic.requests import (
12
+ AdvancedBoxScoreRequest,
13
+ CalendarRequest,
14
+ GameMediaRequest,
15
+ GamesRequest,
16
+ GameWeatherRequest,
17
+ PlayerGameStatsRequest,
18
+ RecordsRequest,
19
+ ScoreboardRequest,
20
+ TeamGameStatsRequest,
21
+ )
22
+ from .models.pydantic.responses import AdvancedBoxScore
23
+ from .resource import GamesResource
24
+
25
+ __all__ = [
26
+ "AdvancedBoxScoreRequest",
27
+ "AdvancedBoxScore",
28
+ "CalendarRequest",
29
+ "Classification",
30
+ "GameMediaRequest",
31
+ "GamesRequest",
32
+ "GamesResource",
33
+ "GameWeatherRequest",
34
+ "MediaType",
35
+ "PlayerGameStatsRequest",
36
+ "PlayoffCompetition",
37
+ "PlayoffRound",
38
+ "RecordsRequest",
39
+ "ScoreboardRequest",
40
+ "SeasonType",
41
+ "TeamGameStatsRequest",
42
+ ]
@@ -0,0 +1 @@
1
+ """Provide authoritative Pydantic models for Games endpoints."""
@@ -0,0 +1,106 @@
1
+ """Pydantic models for game endpoints."""
2
+
3
+ from cfb_data.enums import Classification, MediaType, SeasonType
4
+
5
+ from .requests import (
6
+ AdvancedBoxScoreRequest,
7
+ CalendarRequest,
8
+ GameMediaRequest,
9
+ GamesRequest,
10
+ GameWeatherRequest,
11
+ PlayerGameStatsRequest,
12
+ RecordsRequest,
13
+ ScoreboardRequest,
14
+ TeamGameStatsRequest,
15
+ )
16
+ from .responses import (
17
+ AdvancedBoxScore,
18
+ AdvancedGameInfo,
19
+ AdvancedPlayerStats,
20
+ AdvancedTeamStats,
21
+ CalendarWeek,
22
+ Game,
23
+ GameMedia,
24
+ GamePlayoff,
25
+ GameStatus,
26
+ GameWeather,
27
+ PlayerGameStatCategory,
28
+ PlayerGameStatPlayer,
29
+ PlayerGameStats,
30
+ PlayerGameStatsTeam,
31
+ PlayerGameStatType,
32
+ PlayerGameUsage,
33
+ PlayerPPA,
34
+ PlayerStatsByQuarter,
35
+ ScoreboardBetting,
36
+ ScoreboardGame,
37
+ ScoreboardTeam,
38
+ ScoreboardVenue,
39
+ ScoreboardWeather,
40
+ StatsByQuarter,
41
+ TeamExplosiveness,
42
+ TeamFieldPosition,
43
+ TeamGameStat,
44
+ TeamGameStats,
45
+ TeamGameStatsTeam,
46
+ TeamHavoc,
47
+ TeamPPA,
48
+ TeamRecord,
49
+ TeamRecords,
50
+ TeamRushingStats,
51
+ TeamScoringOpportunities,
52
+ TeamSuccessRates,
53
+ )
54
+
55
+ __all__ = [
56
+ # Request models
57
+ "GamesRequest",
58
+ "CalendarRequest",
59
+ "RecordsRequest",
60
+ "ScoreboardRequest",
61
+ "GameMediaRequest",
62
+ "GameWeatherRequest",
63
+ "PlayerGameStatsRequest",
64
+ "TeamGameStatsRequest",
65
+ "AdvancedBoxScoreRequest",
66
+ # Response models
67
+ "SeasonType",
68
+ "Classification",
69
+ "MediaType",
70
+ "GameStatus",
71
+ "GamePlayoff",
72
+ "Game",
73
+ "CalendarWeek",
74
+ "GameMedia",
75
+ "GameWeather",
76
+ "TeamRecord",
77
+ "TeamRecords",
78
+ "ScoreboardVenue",
79
+ "ScoreboardTeam",
80
+ "ScoreboardWeather",
81
+ "ScoreboardBetting",
82
+ "ScoreboardGame",
83
+ "PlayerGameStatPlayer",
84
+ "PlayerGameStatType",
85
+ "PlayerGameStatCategory",
86
+ "PlayerGameStatsTeam",
87
+ "PlayerGameStats",
88
+ "TeamGameStat",
89
+ "TeamGameStatsTeam",
90
+ "TeamGameStats",
91
+ "StatsByQuarter",
92
+ "TeamPPA",
93
+ "TeamSuccessRates",
94
+ "TeamExplosiveness",
95
+ "TeamRushingStats",
96
+ "TeamHavoc",
97
+ "TeamScoringOpportunities",
98
+ "TeamFieldPosition",
99
+ "PlayerStatsByQuarter",
100
+ "PlayerGameUsage",
101
+ "PlayerPPA",
102
+ "AdvancedGameInfo",
103
+ "AdvancedTeamStats",
104
+ "AdvancedPlayerStats",
105
+ "AdvancedBoxScore",
106
+ ]