cfb-data 0.4.1__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.
- cfb_data-0.4.1/LICENSE +21 -0
- cfb_data-0.4.1/PKG-INFO +414 -0
- cfb_data-0.4.1/README.md +377 -0
- cfb_data-0.4.1/cfb_data/cfb_data/__init__.py +234 -0
- cfb_data-0.4.1/cfb_data/cfb_data/_dataframes.py +279 -0
- cfb_data-0.4.1/cfb_data/cfb_data/_executor.py +129 -0
- cfb_data-0.4.1/cfb_data/cfb_data/_parquet.py +197 -0
- cfb_data-0.4.1/cfb_data/cfb_data/_request_rules.py +41 -0
- cfb_data-0.4.1/cfb_data/cfb_data/_requests.py +36 -0
- cfb_data-0.4.1/cfb_data/cfb_data/_tabular.py +676 -0
- cfb_data-0.4.1/cfb_data/cfb_data/_transport.py +452 -0
- cfb_data-0.4.1/cfb_data/cfb_data/adjusted_metrics/__init__.py +29 -0
- cfb_data-0.4.1/cfb_data/cfb_data/adjusted_metrics/models/__init__.py +1 -0
- cfb_data-0.4.1/cfb_data/cfb_data/adjusted_metrics/models/pydantic/__init__.py +29 -0
- cfb_data-0.4.1/cfb_data/cfb_data/adjusted_metrics/models/pydantic/requests.py +45 -0
- cfb_data-0.4.1/cfb_data/cfb_data/adjusted_metrics/models/pydantic/responses.py +88 -0
- cfb_data-0.4.1/cfb_data/cfb_data/adjusted_metrics/resource.py +220 -0
- cfb_data-0.4.1/cfb_data/cfb_data/base/__init__.py +6 -0
- cfb_data-0.4.1/cfb_data/cfb_data/base/types.py +112 -0
- cfb_data-0.4.1/cfb_data/cfb_data/betting/__init__.py +15 -0
- cfb_data-0.4.1/cfb_data/cfb_data/betting/models/__init__.py +1 -0
- cfb_data-0.4.1/cfb_data/cfb_data/betting/models/pydantic/__init__.py +6 -0
- cfb_data-0.4.1/cfb_data/cfb_data/betting/models/pydantic/requests.py +35 -0
- cfb_data-0.4.1/cfb_data/cfb_data/betting/models/pydantic/responses.py +62 -0
- cfb_data-0.4.1/cfb_data/cfb_data/betting/resource.py +91 -0
- cfb_data-0.4.1/cfb_data/cfb_data/client.py +305 -0
- cfb_data-0.4.1/cfb_data/cfb_data/coaches/__init__.py +57 -0
- cfb_data-0.4.1/cfb_data/cfb_data/coaches/models/__init__.py +1 -0
- cfb_data-0.4.1/cfb_data/cfb_data/coaches/models/pydantic/__init__.py +57 -0
- cfb_data-0.4.1/cfb_data/cfb_data/coaches/models/pydantic/requests.py +75 -0
- cfb_data-0.4.1/cfb_data/cfb_data/coaches/models/pydantic/responses.py +261 -0
- cfb_data-0.4.1/cfb_data/cfb_data/coaches/resource.py +216 -0
- cfb_data-0.4.1/cfb_data/cfb_data/conferences/__init__.py +23 -0
- cfb_data-0.4.1/cfb_data/cfb_data/conferences/models/__init__.py +1 -0
- cfb_data-0.4.1/cfb_data/cfb_data/conferences/models/pydantic/__init__.py +23 -0
- cfb_data-0.4.1/cfb_data/cfb_data/conferences/models/pydantic/requests.py +69 -0
- cfb_data-0.4.1/cfb_data/cfb_data/conferences/models/pydantic/responses.py +64 -0
- cfb_data-0.4.1/cfb_data/cfb_data/conferences/resource.py +175 -0
- cfb_data-0.4.1/cfb_data/cfb_data/draft/__init__.py +19 -0
- cfb_data-0.4.1/cfb_data/cfb_data/draft/models/__init__.py +1 -0
- cfb_data-0.4.1/cfb_data/cfb_data/draft/models/pydantic/__init__.py +12 -0
- cfb_data-0.4.1/cfb_data/cfb_data/draft/models/pydantic/requests.py +18 -0
- cfb_data-0.4.1/cfb_data/cfb_data/draft/models/pydantic/responses.py +65 -0
- cfb_data-0.4.1/cfb_data/cfb_data/draft/resource.py +132 -0
- cfb_data-0.4.1/cfb_data/cfb_data/drives/__init__.py +13 -0
- cfb_data-0.4.1/cfb_data/cfb_data/drives/models/__init__.py +1 -0
- cfb_data-0.4.1/cfb_data/cfb_data/drives/models/pydantic/__init__.py +17 -0
- cfb_data-0.4.1/cfb_data/cfb_data/drives/models/pydantic/requests.py +42 -0
- cfb_data-0.4.1/cfb_data/cfb_data/drives/models/pydantic/responses.py +46 -0
- cfb_data-0.4.1/cfb_data/cfb_data/drives/resource.py +94 -0
- cfb_data-0.4.1/cfb_data/cfb_data/enums.py +93 -0
- cfb_data-0.4.1/cfb_data/cfb_data/errors.py +234 -0
- cfb_data-0.4.1/cfb_data/cfb_data/games/__init__.py +42 -0
- cfb_data-0.4.1/cfb_data/cfb_data/games/models/__init__.py +1 -0
- cfb_data-0.4.1/cfb_data/cfb_data/games/models/pydantic/__init__.py +106 -0
- cfb_data-0.4.1/cfb_data/cfb_data/games/models/pydantic/requests.py +266 -0
- cfb_data-0.4.1/cfb_data/cfb_data/games/models/pydantic/responses.py +495 -0
- cfb_data-0.4.1/cfb_data/cfb_data/games/resource.py +486 -0
- cfb_data-0.4.1/cfb_data/cfb_data/info/__init__.py +25 -0
- cfb_data-0.4.1/cfb_data/cfb_data/info/models/__init__.py +1 -0
- cfb_data-0.4.1/cfb_data/cfb_data/info/models/pydantic/__init__.py +23 -0
- cfb_data-0.4.1/cfb_data/cfb_data/info/models/pydantic/requests.py +18 -0
- cfb_data-0.4.1/cfb_data/cfb_data/info/models/pydantic/responses.py +103 -0
- cfb_data-0.4.1/cfb_data/cfb_data/info/resource.py +88 -0
- cfb_data-0.4.1/cfb_data/cfb_data/metrics/__init__.py +53 -0
- cfb_data-0.4.1/cfb_data/cfb_data/metrics/models/__init__.py +1 -0
- cfb_data-0.4.1/cfb_data/cfb_data/metrics/models/pydantic/__init__.py +49 -0
- cfb_data-0.4.1/cfb_data/cfb_data/metrics/models/pydantic/requests.py +121 -0
- cfb_data-0.4.1/cfb_data/cfb_data/metrics/models/pydantic/responses.py +182 -0
- cfb_data-0.4.1/cfb_data/cfb_data/metrics/resource.py +371 -0
- cfb_data-0.4.1/cfb_data/cfb_data/players/__init__.py +44 -0
- cfb_data-0.4.1/cfb_data/cfb_data/players/models/__init__.py +1 -0
- cfb_data-0.4.1/cfb_data/cfb_data/players/models/pydantic/__init__.py +41 -0
- cfb_data-0.4.1/cfb_data/cfb_data/players/models/pydantic/requests.py +70 -0
- cfb_data-0.4.1/cfb_data/cfb_data/players/models/pydantic/responses.py +171 -0
- cfb_data-0.4.1/cfb_data/cfb_data/players/resource.py +258 -0
- cfb_data-0.4.1/cfb_data/cfb_data/playoffs/__init__.py +41 -0
- cfb_data-0.4.1/cfb_data/cfb_data/playoffs/models/__init__.py +1 -0
- cfb_data-0.4.1/cfb_data/cfb_data/playoffs/models/pydantic/__init__.py +37 -0
- cfb_data-0.4.1/cfb_data/cfb_data/playoffs/models/pydantic/requests.py +30 -0
- cfb_data-0.4.1/cfb_data/cfb_data/playoffs/models/pydantic/responses.py +173 -0
- cfb_data-0.4.1/cfb_data/cfb_data/playoffs/resource.py +149 -0
- cfb_data-0.4.1/cfb_data/cfb_data/plays/__init__.py +43 -0
- cfb_data-0.4.1/cfb_data/cfb_data/plays/models/__init__.py +1 -0
- cfb_data-0.4.1/cfb_data/cfb_data/plays/models/pydantic/__init__.py +35 -0
- cfb_data-0.4.1/cfb_data/cfb_data/plays/models/pydantic/requests.py +85 -0
- cfb_data-0.4.1/cfb_data/cfb_data/plays/models/pydantic/responses.py +231 -0
- cfb_data-0.4.1/cfb_data/cfb_data/plays/resource.py +249 -0
- cfb_data-0.4.1/cfb_data/cfb_data/py.typed +0 -0
- cfb_data-0.4.1/cfb_data/cfb_data/rankings/__init__.py +16 -0
- cfb_data-0.4.1/cfb_data/cfb_data/rankings/models/__init__.py +1 -0
- cfb_data-0.4.1/cfb_data/cfb_data/rankings/models/pydantic/__init__.py +6 -0
- cfb_data-0.4.1/cfb_data/cfb_data/rankings/models/pydantic/requests.py +36 -0
- cfb_data-0.4.1/cfb_data/cfb_data/rankings/models/pydantic/responses.py +42 -0
- cfb_data-0.4.1/cfb_data/cfb_data/rankings/resource.py +89 -0
- cfb_data-0.4.1/cfb_data/cfb_data/ratings/__init__.py +59 -0
- cfb_data-0.4.1/cfb_data/cfb_data/ratings/models/__init__.py +1 -0
- cfb_data-0.4.1/cfb_data/cfb_data/ratings/models/pydantic/__init__.py +55 -0
- cfb_data-0.4.1/cfb_data/cfb_data/ratings/models/pydantic/requests.py +87 -0
- cfb_data-0.4.1/cfb_data/cfb_data/ratings/models/pydantic/responses.py +215 -0
- cfb_data-0.4.1/cfb_data/cfb_data/ratings/resource.py +342 -0
- cfb_data-0.4.1/cfb_data/cfb_data/recruiting/__init__.py +26 -0
- cfb_data-0.4.1/cfb_data/cfb_data/recruiting/models/__init__.py +1 -0
- cfb_data-0.4.1/cfb_data/cfb_data/recruiting/models/pydantic/__init__.py +23 -0
- cfb_data-0.4.1/cfb_data/cfb_data/recruiting/models/pydantic/requests.py +69 -0
- cfb_data-0.4.1/cfb_data/cfb_data/recruiting/models/pydantic/responses.py +70 -0
- cfb_data-0.4.1/cfb_data/cfb_data/recruiting/resource.py +180 -0
- cfb_data-0.4.1/cfb_data/cfb_data/retry.py +49 -0
- cfb_data-0.4.1/cfb_data/cfb_data/stats/__init__.py +69 -0
- cfb_data-0.4.1/cfb_data/cfb_data/stats/models/__init__.py +1 -0
- cfb_data-0.4.1/cfb_data/cfb_data/stats/models/pydantic/__init__.py +65 -0
- cfb_data-0.4.1/cfb_data/cfb_data/stats/models/pydantic/requests.py +167 -0
- cfb_data-0.4.1/cfb_data/cfb_data/stats/models/pydantic/responses.py +291 -0
- cfb_data-0.4.1/cfb_data/cfb_data/stats/resource.py +400 -0
- cfb_data-0.4.1/cfb_data/cfb_data/teams/__init__.py +40 -0
- cfb_data-0.4.1/cfb_data/cfb_data/teams/models/__init__.py +1 -0
- cfb_data-0.4.1/cfb_data/cfb_data/teams/models/pydantic/__init__.py +26 -0
- cfb_data-0.4.1/cfb_data/cfb_data/teams/models/pydantic/requests.py +96 -0
- cfb_data-0.4.1/cfb_data/cfb_data/teams/models/pydantic/responses.py +116 -0
- cfb_data-0.4.1/cfb_data/cfb_data/teams/resource.py +270 -0
- cfb_data-0.4.1/cfb_data/cfb_data/venues/__init__.py +6 -0
- cfb_data-0.4.1/cfb_data/cfb_data/venues/models/__init__.py +1 -0
- cfb_data-0.4.1/cfb_data/cfb_data/venues/models/pydantic/__init__.py +5 -0
- cfb_data-0.4.1/cfb_data/cfb_data/venues/models/pydantic/responses.py +24 -0
- cfb_data-0.4.1/cfb_data/cfb_data/venues/resource.py +51 -0
- cfb_data-0.4.1/cfb_data/cfb_data.egg-info/PKG-INFO +414 -0
- cfb_data-0.4.1/cfb_data/cfb_data.egg-info/SOURCES.txt +130 -0
- cfb_data-0.4.1/cfb_data/cfb_data.egg-info/dependency_links.txt +1 -0
- cfb_data-0.4.1/cfb_data/cfb_data.egg-info/requires.txt +20 -0
- cfb_data-0.4.1/cfb_data/cfb_data.egg-info/top_level.txt +1 -0
- cfb_data-0.4.1/pyproject.toml +115 -0
- cfb_data-0.4.1/setup.cfg +4 -0
cfb_data-0.4.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 Ryan Anderson
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
cfb_data-0.4.1/PKG-INFO
ADDED
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cfb-data
|
|
3
|
+
Version: 0.4.1
|
|
4
|
+
Summary: Async validated CollegeFootballData access for pandas and Polars
|
|
5
|
+
Author: Ryan Anderson
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Documentation, https://ryanpaulanderson.github.io/cfb-data/
|
|
8
|
+
Project-URL: Repository, https://github.com/ryanpaulanderson/cfb-data
|
|
9
|
+
Project-URL: Issues, https://github.com/ryanpaulanderson/cfb-data/issues
|
|
10
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Requires-Python: >=3.12
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: aiohttp<4,>=3.13
|
|
19
|
+
Requires-Dist: pandas<4,>=3.0
|
|
20
|
+
Requires-Dist: pydantic<3,>=2.12
|
|
21
|
+
Requires-Dist: pyarrow<26,>=25
|
|
22
|
+
Provides-Extra: polars
|
|
23
|
+
Requires-Dist: polars<2,>=1.43.2; extra == "polars"
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: build<2,>=1.5; extra == "dev"
|
|
26
|
+
Requires-Dist: furo>=2025.12.19; extra == "dev"
|
|
27
|
+
Requires-Dist: mypy<3,>=2.3; extra == "dev"
|
|
28
|
+
Requires-Dist: myst-parser<6,>=5.1; extra == "dev"
|
|
29
|
+
Requires-Dist: pre-commit<5,>=4.5; extra == "dev"
|
|
30
|
+
Requires-Dist: pyarrow-stubs<21,>=20.0.0.20260625; extra == "dev"
|
|
31
|
+
Requires-Dist: pytest<10,>=9; extra == "dev"
|
|
32
|
+
Requires-Dist: pytest-asyncio<2,>=1.3; extra == "dev"
|
|
33
|
+
Requires-Dist: ruff<0.17,>=0.15.22; extra == "dev"
|
|
34
|
+
Requires-Dist: sphinx<10,>=9.1; extra == "dev"
|
|
35
|
+
Requires-Dist: twine<8,>=7; extra == "dev"
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
|
|
38
|
+
# College Football Data Python Toolkit
|
|
39
|
+
|
|
40
|
+
`cfb-data` 0.4.1 is an asynchronous, validated client for the public
|
|
41
|
+
[CollegeFootballData API](https://collegefootballdata.com/) REST endpoint
|
|
42
|
+
groups. It returns eager pandas DataFrames by default and can return the same
|
|
43
|
+
logical tables as Polars DataFrames. Irreducibly nested analytical responses
|
|
44
|
+
and operational account metadata return validated models instead.
|
|
45
|
+
|
|
46
|
+
Read the complete [documentation](https://ryanpaulanderson.github.io/cfb-data/)
|
|
47
|
+
for the getting-started guide, request rules and allowed values, namespace
|
|
48
|
+
contracts, result schemas, and generated Python API reference.
|
|
49
|
+
|
|
50
|
+
The request path is explicit:
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
HTTP → Pydantic models → logical schema → canonical Arrow table → DataFrame
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Malformed upstream data never reaches a DataFrame. Choosing Polars changes the
|
|
57
|
+
concrete return type and native nested representation, not endpoint names,
|
|
58
|
+
validation, retry behavior, columns, row order, logical values, or the
|
|
59
|
+
canonical storage schema.
|
|
60
|
+
|
|
61
|
+
## Installation
|
|
62
|
+
|
|
63
|
+
pandas and PyArrow are included in the default installation:
|
|
64
|
+
|
|
65
|
+
```sh
|
|
66
|
+
python -m pip install cfb-data
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Install the optional Polars backend with:
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
python -m pip install "cfb-data[polars]"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Python 3.12 and 3.13 are supported. DataFrames are eager; Polars
|
|
76
|
+
`LazyFrame` results are not part of the 0.4.1 contract.
|
|
77
|
+
|
|
78
|
+
## Authentication and lifecycle
|
|
79
|
+
|
|
80
|
+
Set a CollegeFootballData API key in the environment:
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
export CFBD_API_KEY="..."
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Every client is one-shot and must own its reusable HTTP session through
|
|
87
|
+
`async with`:
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
import asyncio
|
|
91
|
+
|
|
92
|
+
from cfb_data import CFBDClient
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
async def main() -> None:
|
|
96
|
+
async with CFBDClient() as client:
|
|
97
|
+
games = await client.games.list(year=2024, team="Michigan")
|
|
98
|
+
drives = await client.drives.list(year=2024, team="Michigan")
|
|
99
|
+
plays = await client.plays.list(year=2024, week=1, team="Michigan")
|
|
100
|
+
stats = await client.stats.team_season(year=2024, team="Michigan")
|
|
101
|
+
ratings = await client.ratings.elo(year=2024, team="Michigan")
|
|
102
|
+
players = await client.players.search(
|
|
103
|
+
search_term="Edwards", year=2024, team="Michigan"
|
|
104
|
+
)
|
|
105
|
+
teams = await client.teams.fbs(year=2024)
|
|
106
|
+
draft_picks = await client.draft.picks(year=2024, school="Michigan")
|
|
107
|
+
playoff = await client.playoffs.cfp(year=2024)
|
|
108
|
+
adjusted = await client.adjusted_metrics.team_season(
|
|
109
|
+
year=2024, team="Michigan"
|
|
110
|
+
)
|
|
111
|
+
account = await client.info.account()
|
|
112
|
+
|
|
113
|
+
print(games.head())
|
|
114
|
+
print(drives.head())
|
|
115
|
+
print(plays.head())
|
|
116
|
+
print(stats.head())
|
|
117
|
+
print(ratings.head())
|
|
118
|
+
print(players.head())
|
|
119
|
+
print(teams.head())
|
|
120
|
+
print(draft_picks.head())
|
|
121
|
+
print(playoff.champion)
|
|
122
|
+
print(adjusted.head())
|
|
123
|
+
print(account.tier_name)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
asyncio.run(main())
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
An explicit non-empty `api_key` takes precedence over `CFBD_API_KEY`. Passing
|
|
130
|
+
an empty explicit value is a configuration error and does not fall back to the
|
|
131
|
+
environment. Calls before context entry, after exit, during a nested entry, or
|
|
132
|
+
after attempted re-entry raise `CFBDClientStateError`.
|
|
133
|
+
|
|
134
|
+
For Polars, select only the backend:
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
from cfb_data import CFBDClient
|
|
138
|
+
|
|
139
|
+
async with CFBDClient(dataframe_backend="polars") as client:
|
|
140
|
+
calendar = await client.games.calendar(year=2024)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Type checkers infer `pandas.DataFrame` for the default client and
|
|
144
|
+
`polars.DataFrame` when the literal backend is `"polars"`.
|
|
145
|
+
|
|
146
|
+
## Endpoints
|
|
147
|
+
|
|
148
|
+
Each method accepts either one positional request model or explicit snake-case
|
|
149
|
+
keyword filters. The styles are mutually exclusive:
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
from cfb_data import CFBDClient, GamesRequest, SeasonType
|
|
153
|
+
|
|
154
|
+
request = GamesRequest(year=2024, season_type=SeasonType.regular)
|
|
155
|
+
|
|
156
|
+
async with CFBDClient() as client:
|
|
157
|
+
by_model = await client.games.list(request)
|
|
158
|
+
by_keywords = await client.games.list(year=2024, season_type="regular")
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Unknown filters and invalid combinations fail before HTTP. The public Python
|
|
162
|
+
name is always `game_id`; request serialization maps it to upstream `id` or
|
|
163
|
+
`gameId` as required.
|
|
164
|
+
|
|
165
|
+
| Method | Request model | Result |
|
|
166
|
+
| --- | --- | --- |
|
|
167
|
+
| `client.games.list` | `GamesRequest` | `Game` rows as selected frame |
|
|
168
|
+
| `client.games.records` | `RecordsRequest` | `TeamRecords` rows as selected frame |
|
|
169
|
+
| `client.games.calendar` | `CalendarRequest` | `CalendarWeek` rows as selected frame |
|
|
170
|
+
| `client.games.scoreboard` | `ScoreboardRequest` | `ScoreboardGame` rows as selected frame |
|
|
171
|
+
| `client.games.media` | `GameMediaRequest` | `GameMedia` rows as selected frame |
|
|
172
|
+
| `client.games.weather` | `GameWeatherRequest` | `GameWeather` rows as selected frame |
|
|
173
|
+
| `client.games.player_stats` | `PlayerGameStatsRequest` | `PlayerGameStats` rows as selected frame |
|
|
174
|
+
| `client.games.team_stats` | `TeamGameStatsRequest` | `TeamGameStats` rows as selected frame |
|
|
175
|
+
| `client.games.advanced_box_score` | `AdvancedBoxScoreRequest` | `AdvancedBoxScore` model |
|
|
176
|
+
| `client.drives.list` | `DrivesRequest` | `Drive` rows as selected frame |
|
|
177
|
+
| `client.plays.list` | `PlaysRequest` | `Play` rows as selected frame |
|
|
178
|
+
| `client.plays.types` | None | `PlayType` rows as selected frame |
|
|
179
|
+
| `client.plays.stats` | `PlayStatsRequest` | `PlayStat` rows as selected frame |
|
|
180
|
+
| `client.plays.stat_types` | None | `PlayStatType` rows as selected frame |
|
|
181
|
+
| `client.plays.live` | `LivePlaysRequest` | `LiveGame` model |
|
|
182
|
+
| `client.venues.list` | None | `Venue` rows as selected frame |
|
|
183
|
+
| `client.conferences.list` | `ConferencesRequest` | `Conference` rows as selected frame |
|
|
184
|
+
| `client.conferences.changes` | `ConferenceChangesRequest` | `TeamConferenceChange` rows as selected frame |
|
|
185
|
+
| `client.conferences.affiliations` | `ConferenceAffiliationsRequest` | `TeamConferenceAffiliation` rows as selected frame |
|
|
186
|
+
| `client.teams.list` | `TeamsRequest` | `Team` rows as selected frame |
|
|
187
|
+
| `client.teams.fbs` | `FBSTeamsRequest` | `Team` rows as selected frame |
|
|
188
|
+
| `client.teams.matchup` | `TeamMatchupRequest` | one `Matchup` row as selected frame |
|
|
189
|
+
| `client.teams.ats` | `TeamATSRequest` | `TeamATS` rows as selected frame |
|
|
190
|
+
| `client.teams.roster` | `RosterRequest` | `RosterPlayer` rows as selected frame |
|
|
191
|
+
| `client.teams.talent` | `TalentRequest` | `TeamTalent` rows as selected frame |
|
|
192
|
+
| `client.stats.player_season` | `PlayerSeasonStatsRequest` | `PlayerStat` rows as selected frame |
|
|
193
|
+
| `client.stats.player_season_success` | `PlayerSeasonSuccessRequest` | `PlayerSeasonSuccessRate` rows as selected frame |
|
|
194
|
+
| `client.stats.player_game_success` | `PlayerGameSuccessRequest` | `PlayerGameSuccessRate` rows as selected frame |
|
|
195
|
+
| `client.stats.team_season` | `TeamSeasonStatsRequest` | `TeamStat` rows as selected frame |
|
|
196
|
+
| `client.stats.categories` | None | `StatCategory` rows as selected frame |
|
|
197
|
+
| `client.stats.advanced_season` | `AdvancedSeasonStatsRequest` | `AdvancedSeasonStat` rows as selected frame |
|
|
198
|
+
| `client.stats.advanced_game` | `AdvancedGameStatsRequest` | `AdvancedGameStat` rows as selected frame |
|
|
199
|
+
| `client.stats.game_havoc` | `GameHavocRequest` | `GameHavocStats` rows as selected frame |
|
|
200
|
+
| `client.metrics.predicted_points` | `PredictedPointsRequest` | `PredictedPointsValue` rows as selected frame |
|
|
201
|
+
| `client.metrics.team_season_ppa` | `TeamSeasonPPARequest` | `TeamSeasonPredictedPointsAdded` rows as selected frame |
|
|
202
|
+
| `client.metrics.team_game_ppa` | `TeamGamePPARequest` | `TeamGamePredictedPointsAdded` rows as selected frame |
|
|
203
|
+
| `client.metrics.player_game_ppa` | `PlayerGamePPARequest` | `PlayerGamePredictedPointsAdded` rows as selected frame |
|
|
204
|
+
| `client.metrics.player_season_ppa` | `PlayerSeasonPPARequest` | `PlayerSeasonPredictedPointsAdded` rows as selected frame |
|
|
205
|
+
| `client.metrics.win_probability` | `WinProbabilityRequest` | `PlayWinProbability` rows as selected frame |
|
|
206
|
+
| `client.metrics.pregame_win_probability` | `PregameWinProbabilityRequest` | `PregameWinProbability` rows as selected frame |
|
|
207
|
+
| `client.metrics.field_goal_expected_points` | None | `FieldGoalExpectedPoints` rows as selected frame |
|
|
208
|
+
| `client.ratings.core` | `CoreRatingsRequest` | `TeamCoreRating` rows as selected frame |
|
|
209
|
+
| `client.ratings.sp` | `SPRatingsRequest` | `TeamSP` rows as selected frame |
|
|
210
|
+
| `client.ratings.conference_sp` | `ConferenceSPRatingsRequest` | `ConferenceSP` rows as selected frame |
|
|
211
|
+
| `client.ratings.srs` | `SRSRatingsRequest` | `TeamSRS` rows as selected frame |
|
|
212
|
+
| `client.ratings.expanded_srs` | `ExpandedSRSRatingsRequest` | `ExpandedTeamSRS` rows as selected frame |
|
|
213
|
+
| `client.ratings.elo` | `EloRatingsRequest` | `TeamElo` rows as selected frame |
|
|
214
|
+
| `client.ratings.fpi` | `FPIRatingsRequest` | `TeamFPI` rows as selected frame |
|
|
215
|
+
| `client.players.search` | `PlayerSearchRequest` | `PlayerSearchResult` rows as selected frame |
|
|
216
|
+
| `client.players.usage` | `PlayerUsageRequest` | `PlayerUsage` rows as selected frame |
|
|
217
|
+
| `client.players.season_overview` | `PlayerSeasonOverviewRequest` | one `PlayerSeasonOverview` row as selected frame |
|
|
218
|
+
| `client.players.returning_production` | `ReturningProductionRequest` | `ReturningProduction` rows as selected frame |
|
|
219
|
+
| `client.players.transfer_portal` | `TransferPortalRequest` | `PlayerTransfer` rows as selected frame |
|
|
220
|
+
| `client.rankings.list` | `RankingsRequest` | `PollWeek` rows as selected frame |
|
|
221
|
+
| `client.betting.lines` | `BettingLinesRequest` | `BettingGame` rows as selected frame |
|
|
222
|
+
| `client.recruiting.players` | `RecruitingPlayersRequest` | `Recruit` rows as selected frame |
|
|
223
|
+
| `client.recruiting.teams` | `RecruitingTeamsRequest` | `TeamRecruitingRanking` rows as selected frame |
|
|
224
|
+
| `client.recruiting.groups` | `RecruitingGroupsRequest` | `AggregatedTeamRecruiting` rows as selected frame |
|
|
225
|
+
| `client.coaches.list` | `CoachesRequest` | `Coach` rows as selected frame |
|
|
226
|
+
| `client.coaches.profile` | `CoachProfileRequest` | one `CoachProfile` row as selected frame |
|
|
227
|
+
| `client.coaches.seasons` | `CoachSeasonsRequest` | `DetailedCoachSeason` rows as selected frame |
|
|
228
|
+
| `client.coaches.tenures` | `CoachTenuresRequest` | `CoachTenure` rows as selected frame |
|
|
229
|
+
| `client.draft.teams` | None | `DraftTeam` rows as selected frame |
|
|
230
|
+
| `client.draft.positions` | None | `DraftPosition` rows as selected frame |
|
|
231
|
+
| `client.draft.picks` | `DraftPicksRequest` | `DraftPick` rows as selected frame |
|
|
232
|
+
| `client.playoffs.cfp` | `CfpPlayoffRequest` | `CfpPlayoff` model |
|
|
233
|
+
| `client.playoffs.participants` | `CfpParticipantsRequest` | `PlayoffParticipant` rows as selected frame |
|
|
234
|
+
| `client.playoffs.games` | `CfpGamesRequest` | `PlayoffMatchup` rows as selected frame |
|
|
235
|
+
| `client.adjusted_metrics.team_season` | `AdjustedTeamMetricsRequest` | `AdjustedTeamMetrics` rows as selected frame |
|
|
236
|
+
| `client.adjusted_metrics.player_passing` | `AdjustedPlayerPassingRequest` | `PlayerWeightedEPA` rows as selected frame |
|
|
237
|
+
| `client.adjusted_metrics.player_rushing` | `AdjustedPlayerRushingRequest` | `PlayerWeightedEPA` rows as selected frame |
|
|
238
|
+
| `client.adjusted_metrics.kicker_paar` | `KickerPAARRequest` | `KickerPAAR` rows as selected frame |
|
|
239
|
+
| `client.info.account` | None | `UserInfo` model |
|
|
240
|
+
| `client.info.usage` | `InfoUsageRequest` | `UserUsage` model |
|
|
241
|
+
|
|
242
|
+
Request models and shared `StrEnum` values are exported from `cfb_data` and
|
|
243
|
+
their supported domain namespaces. Enum fields also accept their documented
|
|
244
|
+
string values.
|
|
245
|
+
|
|
246
|
+
Raw JSON and general validated-model return modes are intentionally excluded.
|
|
247
|
+
Advanced box score, live plays, and the complete CFP bracket return models
|
|
248
|
+
because their nested sections do not form one natural table. Info returns
|
|
249
|
+
models because account and usage metadata are operational objects rather than
|
|
250
|
+
analytical tables. The upstream live-plays route requires Patreon Tier 2
|
|
251
|
+
access; all Adjusted Metrics routes require Patreon Tier 1 access.
|
|
252
|
+
|
|
253
|
+
Team matchup, player season overview, and coach profile are one-row frames
|
|
254
|
+
containing nested columns. Rankings preserve polls and ranks, betting preserves
|
|
255
|
+
provider lines, and coach summaries preserve seasons as nested values. pandas
|
|
256
|
+
represents nested values as `object`; Polars represents them as native `Struct`
|
|
257
|
+
and `List[Struct]` values.
|
|
258
|
+
|
|
259
|
+
## DataFrame contract
|
|
260
|
+
|
|
261
|
+
Response model field order defines exact snake-case column order. API row order
|
|
262
|
+
and row count are preserved. Conversion never flattens, explodes, indexes by
|
|
263
|
+
ID, or drops rows, and an empty response produces a correctly typed empty
|
|
264
|
+
frame.
|
|
265
|
+
|
|
266
|
+
pandas uses:
|
|
267
|
+
|
|
268
|
+
- `int64`, `float64`, and `bool` for required scalars;
|
|
269
|
+
- `Int64`, `Float64`, and `boolean` for nullable scalars;
|
|
270
|
+
- pandas `string` and `datetime64[ns, UTC]` dtypes;
|
|
271
|
+
- `object` columns for nested structs and lists;
|
|
272
|
+
- `object` for the explicitly heterogeneous Stats `stat_value` scalar;
|
|
273
|
+
- a normal `RangeIndex`.
|
|
274
|
+
|
|
275
|
+
Polars uses strict `Int64`, `Float64`, `Boolean`, `String`, UTC `Datetime`,
|
|
276
|
+
`Struct`, `List`, and the explicit heterogeneous `Object` Stats scalar. This
|
|
277
|
+
means nested values have the same logical content while remaining Python
|
|
278
|
+
mappings/lists in pandas and native nested columns in Polars. The
|
|
279
|
+
`client.stats.team_season` `stat_value` column preserves each upstream string,
|
|
280
|
+
integer, or float without coercion and is `object`/`Object` in both backends.
|
|
281
|
+
|
|
282
|
+
All response timestamps must include a timezone. Validation normalizes them to
|
|
283
|
+
UTC before conversion.
|
|
284
|
+
|
|
285
|
+
## Arrow and Parquet contract
|
|
286
|
+
|
|
287
|
+
Every tabular response is represented as one explicit Arrow table before
|
|
288
|
+
pandas or Polars materialization. The Arrow schema is derived from the same
|
|
289
|
+
Pydantic annotations and retains ordered struct fields, typed list elements,
|
|
290
|
+
nullability, and UTC timestamps even for empty or all-null responses.
|
|
291
|
+
|
|
292
|
+
The internal versioned Parquet codec uses that schema directly. It stores
|
|
293
|
+
standard nested Parquet values plus cfb-data storage version, row-model
|
|
294
|
+
identity, logical-schema digest, and writer-version metadata. The heterogeneous
|
|
295
|
+
Stats scalar is stored losslessly as a tagged struct and decoded back to its
|
|
296
|
+
original string, integer, or float value for DataFrames.
|
|
297
|
+
|
|
298
|
+
Direct pandas and Polars Parquet methods are not the cfb-data persistence
|
|
299
|
+
compatibility contract: pandas object inference and Polars `Object` columns do
|
|
300
|
+
not provide identical empty- and mixed-value behavior. Version 0.2.0 keeps the
|
|
301
|
+
codec internal so future caching can use it without prematurely committing to
|
|
302
|
+
a public save/load API. See
|
|
303
|
+
[`ADR 0003`](docs/architecture/0003-canonical-arrow-parquet.md) for the format,
|
|
304
|
+
validation, and compatibility decisions.
|
|
305
|
+
|
|
306
|
+
## Retries and errors
|
|
307
|
+
|
|
308
|
+
The default immutable `RetryPolicy` makes at most three total safe GET
|
|
309
|
+
attempts. It retries connection failures, timeouts, truncated payloads, and
|
|
310
|
+
HTTP `408`, `429`, `500`, `502`, `503`, and `504` with capped exponential
|
|
311
|
+
full-jitter backoff. Set `RetryPolicy(max_attempts=1)` to disable retries.
|
|
312
|
+
|
|
313
|
+
Valid numeric and HTTP-date `Retry-After` values are honored up to 90 seconds.
|
|
314
|
+
A longer requested delay fails immediately and remains available as
|
|
315
|
+
`retry_after_seconds` on the HTTP error. Redirects are disabled, TLS
|
|
316
|
+
verification remains enabled, every attempt has a finite timeout, and
|
|
317
|
+
cancellation is preserved.
|
|
318
|
+
|
|
319
|
+
```python
|
|
320
|
+
from cfb_data import CFBDClient, RetryPolicy
|
|
321
|
+
|
|
322
|
+
policy = RetryPolicy(
|
|
323
|
+
max_attempts=4,
|
|
324
|
+
base_delay_seconds=0.25,
|
|
325
|
+
max_backoff_seconds=4.0,
|
|
326
|
+
max_retry_after_seconds=20.0,
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
async with CFBDClient(retry_policy=policy) as client:
|
|
330
|
+
scoreboard = await client.games.scoreboard()
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
All library exceptions derive from `CFBDError`. Public subclasses distinguish
|
|
334
|
+
configuration, optional dependencies, client state, request validation,
|
|
335
|
+
timeouts and transport, HTTP/authentication/authorization/rate-limit/server
|
|
336
|
+
responses, response decoding and validation, and DataFrame conversion. Error
|
|
337
|
+
text and debug retry events include only safe endpoint/status/attempt metadata,
|
|
338
|
+
never credentials, query parameters, response payloads, or secrets.
|
|
339
|
+
|
|
340
|
+
## Migrating from 0.1.x
|
|
341
|
+
|
|
342
|
+
The inherited raw, validation, and pandas client families were removed rather
|
|
343
|
+
than retained as compatibility wrappers.
|
|
344
|
+
|
|
345
|
+
Raw client calls:
|
|
346
|
+
|
|
347
|
+
```python
|
|
348
|
+
# Before: CFBDGamesAPI(...).make_request("/games", {"year": 2024})
|
|
349
|
+
async with CFBDClient() as client:
|
|
350
|
+
games = await client.games.list(year=2024)
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
Validated-model client calls:
|
|
354
|
+
|
|
355
|
+
```python
|
|
356
|
+
# Before: CFBDGamesValidationAPI(...).make_request("/calendar", {"year": 2024})
|
|
357
|
+
async with CFBDClient() as client:
|
|
358
|
+
calendar_frame = await client.games.calendar(year=2024)
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
pandas client calls:
|
|
362
|
+
|
|
363
|
+
```python
|
|
364
|
+
# Before: CFBDDrivesPandasAPI(...).make_request("/drives", {"year": 2024})
|
|
365
|
+
async with CFBDClient() as client:
|
|
366
|
+
drives_frame = await client.drives.list(year=2024)
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
There is no public generic path router or `make_request(path, params)` method.
|
|
370
|
+
Use the typed namespace method and either its request model or keyword filters.
|
|
371
|
+
|
|
372
|
+
## Datasets and workflows
|
|
373
|
+
|
|
374
|
+
Version 0.4.1 does not expose `client.datasets` or `client.workflows`. The
|
|
375
|
+
accepted architecture reserves two higher layers:
|
|
376
|
+
|
|
377
|
+
- datasets compose validated endpoint results and validated subdatasets
|
|
378
|
+
through joins into one validated tabular row model, converting only the
|
|
379
|
+
final table;
|
|
380
|
+
- workflows orchestrate endpoints, datasets, and broader control flow and may
|
|
381
|
+
return multiple artifacts.
|
|
382
|
+
|
|
383
|
+
See
|
|
384
|
+
[`docs/architecture/0001-validated-models-before-dataframes.md`](docs/architecture/0001-validated-models-before-dataframes.md)
|
|
385
|
+
for the decision and extension boundaries.
|
|
386
|
+
|
|
387
|
+
## Development
|
|
388
|
+
|
|
389
|
+
```sh
|
|
390
|
+
git clone https://github.com/ryanpaulanderson/cfb-data.git
|
|
391
|
+
cd cfb-data
|
|
392
|
+
make install
|
|
393
|
+
make hooks
|
|
394
|
+
make format
|
|
395
|
+
make docs
|
|
396
|
+
make check
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
`make install` creates `.venv` and installs `.[dev,polars]`, giving
|
|
400
|
+
contributors the complete Arrow/Parquet and two-backend test contract.
|
|
401
|
+
`make check` runs Ruff, strict mypy, a warning-free Sphinx build, and pytest
|
|
402
|
+
under the same contract as CI. `make docs` writes the local HTML site to
|
|
403
|
+
`docs/_build/html`. Package metadata and all dependency groups live only in
|
|
404
|
+
`pyproject.toml`.
|
|
405
|
+
|
|
406
|
+
See [`CONTRIBUTING.md`](CONTRIBUTING.md) and
|
|
407
|
+
[`docs/project-status.md`](docs/project-status.md) for repository and release
|
|
408
|
+
status.
|
|
409
|
+
|
|
410
|
+
## License
|
|
411
|
+
|
|
412
|
+
This project is licensed under the MIT License. See [`LICENSE`](LICENSE).
|
|
413
|
+
|
|
414
|
+
This project is not affiliated with CollegeFootballData.com.
|