Changelog
The newest releases. Changes merged since 0.1.5 are under Unreleased; older releases are in the archive.
0.1.5 Release: October 8, 2026
Highlights
- Failed fetches raise instead of returning empty frames:
AssetFetchError(the fetch failed),NoDataError(nothing there) orValueError(bad request), across ESPN, stats.nba.com, the generated flat APIs and HockeyTech. - polars 2.x is supported (
polars>=1.0,<3); the code runs on both polars 1.x and 2.0. - New sources: the official PFF Developer API (
pff_api_*), Formula 1 (f1_*), EuroLeague live data, kloppy soccer event data with SPADL and Expected Threat, Polymarket, Kalshi and more. - Football: one play-by-play shape from Shield, Yahoo, CBS, NCAA and Fox feeds; team and coach tendencies and the usage box; many CFB EPA / WP fixes that need a reprocess.
sdv-docs: an MCP server that answers exact questions about the package from a docs index.
Breaking changes
- Errors: a failed fetch in generated flat-API wrappers (
espn_*,fox_api_*,cbs_*,mlb_api_*, NHL,asa_*) and other getters (mlb_statcast_*,torvik_*,kenpom_*,on3_*,yahoo_*,nfl_api_*, ...) raisesAssetFetchError(400 / 422:ValueError), never "no data". - ESPN (cross-league): the hand-written scrapers (
espn_<league>_schedule/_teams/_pbp,espn_*_player_stats,bref_*,build_nfl_players, ...) raiseAssetFetchErroron a failed fetch andValueErroron 400 / 422 instead of parsing the error body as data. - HockeyTech: season names read as their end year, so
season=can pick another season (WHL / KIJHLseason=2026is now 2025-26); one-year preseasons answer to the next year, exhibitions aregame_type="exhibition", the default is the newest regular season, andseason_yrisInt64. - HockeyTech:
hockeytech_api(PWHL and the 19 other leagues) raisesAssetFetchErroron a failed fetch or HTTP-200 error sentinel andNoDataErroron a 404 instead of returning an empty frame, as do season-defaulting wrappers whose seasons lookup fails. - MLB:
mlb_statcast_search/_search_minors/_search_wbcpin the 14 MLBAM id columns to nullableInt64:on_1b/on_2b/on_3bwere Float64 (660271.0), and pandas output fromparse_mlb_statcast_searchgives nullableInt64instead of numpyint64. - NBA / WNBA:
nba_stats_*/wnba_stats_*raiseAssetFetchErrorinstead of returning{}(404:NoDataError, 400 / 422:ValueError);nba_live_*/nba_l2m*/nba_referee_assignmentsnow raiseValueErroron 400 / 422;wnba_on_court/wnba_possessionsraise on a failed rotation fetch. - NBA / WNBA:
nba_stats_*/wnba_stats_*season arguments default to the latest season with rows and each league's own default ids, so endpoints that summed every season (drafthistory,leaguegamefinder,playergamestreakfinder, ...) return one season. - NFL: the 11 per-type loaders deprecated since 0.0.68 (
load_nfl_ngs_passing/_rushing/_receivingand eightload_nfl_pfr_*per-type and weekly variants) are removed, with theirsportsdataverse.parsed.nflaliases. - NFL: fantasy-football id columns are
Utf8(wereInt64):load_nfl_ff_playerids(mfl_id,fantasypros_id,pff_id,nfl_id, ...),load_nfl_ff_rankings(kind="draft")idandkind="week"fantasypros_id; zero-padded ids such as"0156"keep their padding. - Soccer / EuroLeague: the ASA, FIFA, FotMob, UEFA, MLS, NWSL and EuroLeague frames keep
nullable types: a nullable boolean is
Boolean(was a string with"nan"), a nullable integer isInt64(wasFloat64), and an all-null column isUtf8.
Upgrade notes —
-
Errors: catch
AssetFetchErrorwhere a loop must keep going;except NoDataErrorkeeps skipping absent resources;except SportsDataverseErrorcatches both, timeouts included; aValueErrormeans the call itself needs fixing.EmptyResponseWarningnow fires only for a 2xx with an empty object. Code that caughtrequests.HTTPErrorfromnfl_api_*or readexc.responsemust catch the new types (read the status from the message). HockeyTech wrappers that default the season raise when the seasons lookup fails; passseason_id=to skip it:import sportsdataverse as sdvfrom sportsdataverse.errors import AssetFetchError, NoDataErrortry:df = sdv.ahl_schedule()except NoDataError:df = None # the fetch worked and there is nothing there: skip itexcept AssetFetchError:raise # the fetch failed: retry later, never record it as empty -
HockeyTech seasons: a caller who passed the start year to get a season should pass the end year; preseasons answer to the next year (
resolve_season_id("ohl", season=2027, game_type="preseason")is the "2026 Pre-season"); passseason_id=where divisions listed side by side for one year are not told apart (e.g. BCHL 2024). -
nba_stats / wnba_stats: pass
seasonexplicitly for a lockout or pandemic calendar; for every season pass an empty one (season_year_nullable=""fordrafthistory,season_nullable=""forleaguegamefinder/playergamestreakfinder). -
NFL loaders: replace
load_nfl_ngs_passing,load_nfl_ngs_rushingandload_nfl_ngs_receivingwithload_nfl_nextgen_stats(seasons, stat_type=...), andload_nfl_pfr_pass,load_nfl_pfr_weekly_pass,load_nfl_pfr_rush,load_nfl_pfr_weekly_rush,load_nfl_pfr_rec,load_nfl_pfr_weekly_rec,load_nfl_pfr_defandload_nfl_pfr_weekly_defwithload_nfl_pfr_advstats(seasons, stat_type=..., summary_level=...). -
NFL fantasy ids: code that joined or compared these ids as integers should cast its own side to
pl.Utf8; callsportsdataverse.nfl.clear_cache()after upgrading, since cached frames keep their old dtypes (above all withcache_mode="filesystem").
Added
- Analytics:
rolling_windowscomputes event-count form windows with prev-season, season and career baselines, extended to stats.nba / stats.wnba shot events. (#590, #657) - Analytics:
metric_curvesfits rate curves along a continuous axis (shot distance, field position), binned on the coordinate distance rather than the nominal label. (#652, #658) - Analytics:
defense_vs_positionreports what each defense allowed to QB, RB, WR and TE, filtered by the season-type column. (#659, #660) - Basketball: KenPom, Her Hoop Stats, Basketball-Reference, RealGM and the salary, draft and
injury surfaces (#451), then Bart Torvik's
torvik_game_stats,torvik_player_statsand the publictorvik_game_schedule(#678). - CFB:
paper_indexports Game on Paper's Paper Index and season deserved wins. (#661) - CFB:
CFBPlayProcessfills missingyds_punted,yds_kickoffand bare-puntyds_punt_returnfrom ESPN field position, with newyds_punted_source,yds_kickoff_sourceandyds_punt_return_sourcecolumns ("text","derived"or null); parsed values never change. - CFB:
cfb_drive_summary.create_drive_summary()(StatBroadcast-style drive summary) andcfb_situational_stats.create_situational_stats()(per-team situational block), withCFBPlayProcessdelegates; graduated from Game on Paper. (#470) - ESPN (cross-league): the ESPN CDN family (
cdn.espn.com/core) as generatedespn_<league>_cdn_*wrappers, with a per-endpoint league allowlist from a live probe. (#681) - EuroLeague: 8 new wrappers:
euroleague_game_points()(shot chart),euroleague_game_pbp(),euroleague_game_boxscore(),euroleague_game_header(),euroleague_standings(kind=),euroleague_player_stats(),euroleague_team_stats()andeuroleague_game_report(). - F1:
sportsdataverse.f1wraps the keyless Jolpica (Ergast-compatible) API:f1_schedule,f1_race,f1_results,f1_qualifying,f1_sprint,f1_pitstops, standings, drivers, constructors, circuits and the pagedf1_laps(season, round); data is CC BY-NC-SA 4.0. - Fox:
fox_api_*wrapsapi.foxsports.comdirectly (33 endpoints), beside the per-leaguefox_<league>_*Bifrost wrappers. (#680) - G League: ESPN's G League is a documented league: the universal family (112 wrappers:
espn_nbagl_standings,espn_nbagl_scoreboard,espn_nbagl_summary, ...) is exported fromsportsdataverse.nbagland the top-level package. (#684) - MLB:
load_mlb_park_dimensions()loads one row per MLB venue per season from 2001: fence distances, capacity, turf, roof, elevation and coordinates, withvenue_idas a string. - NBA:
sportsdataverse.nba.nba_officiatingreads official.nba.com:nba_l2m(game_id),nba_l2m_games(season),nba_referee_assignments(date, league=),wnba_referee_assignments();nba_live_pbp()/nba_live_boxscore()and WNBA twins read the cdn liveData feeds. (#592) - NFL: NFL Pro Next Gen Stats: the
pro.nfl.comfamily (nfl_pro_*, 16 endpoints) andload_nfl_ngs(seasons, dataset=)over the SDV-nativenfl_ngs_*releases (12 datasets). (#454, #481, #489) - NFL:
sportsdataverse.nfl.shield_pbpgraduates thenative_pbpparser and adds its live layer (phase, provisional rows, current situation) and theshield_nfl_pbpentry point. (#528, #536) - NFL:
load_nfl_fp_curve()loads the bundled NFL field-position EP curve (2016-2025 fit), andfit_nfl_field_position_ep(pbp)refits it. - NFL / CFB:
NFLPlayProcess/CFBPlayProcessacceptsource=and build the same frame from Shield (#540), Yahoo (#541, #543), CBS (#542, #545), NCAA (#544) and Fox (#548) feeds throughsportsdataverse.football.sources; the dispatch table landed in #525. - NFL / CFB:
football.tendencies(team and coach splits) andfootball.usage_box(usage, situational and special-teams box), with EPA and game-context cuts, read back by 28 loaders such asload_{cfb,nfl}_team_tendenciesandload_{cfb,nfl}_usage_players. (#496, #497, #498, #614) - NFL / CFB:
espn_nfl_pbp(summary=)/espn_cfb_pbp(summary=)process a stored ESPN summary with no network, andNFLPlayProcess(odds_override=)mirrors the CFB contract. (#491) - PFF: the official Developer API: 68
pff_api_*wrappers (sportsdataverse.nfl.pff_api), keyed byapi_key=,PFF_API_KEYorSDV_PY_PFF_API_KEY;strict=True/SDV_PY_PFF_STRICT=1raises on withheld columns. The cookie-authpff_*premium wrappers still work, marked LEGACY. - Providers: 46 wrappers in six new families:
espn_content_*,thesportsdb_*($THESPORTSDB_API_KEY),football_data_*(Football-Data.co.uk),openligadb_*, and the read-only prediction marketspolymarket_*andkalshi_*undersportsdataverse.odds. - Providers: six documented provider APIs, each generated from its own endpoint YAML: CBS NAPI
(
cbs_napi_*), Yahoo Shangrila (yahoo_shangrila_*), Fox, ASA (asa_*), MLS (mls_api_*) and NWSL (nwsl_api_*). (#452) - Reference data: 36 loaders over the
{league}_groupstags for nine leagues:load_<league>_groups(),load_<league>_group_seasons(),load_<league>_group_aliases()andload_<league>_team_group_seasons(seasons); NCAA baseball isload_ncaa_baseball_*. - Registry:
sportsdataverse.registry(metrics.yaml) defines each published football metric once;resolve(column)maps a column to its entry, andpython -m sportsdataverse.registry --ts --target gop|webrenders a TypeScript module. (#645) - sdv-docs:
sdv-docs, a stdio MCP server over a published docs index with six read-only tools (search,get_function,find_columns,find_endpoints,list_datasets,index_info); installsportsdataverse[mcp](Python 3.10+);SDV_DOCS_DB=<file>uses a local index. - Soccer:
XThreatfits an Expected Threat grid andsoccer_xthreat_rate(actions)addsxt_value;load_xthreat_model()loads a bundled 12 x 16 grid fit on StatsBomb open data (research / non-commercial use only). - Soccer:
soccer_spadl(dataset)converts any kloppy event dataset into SPADL actions (a socceraction port);soccer_open_dataset()returns the dataset behindsoccer_open_events(). - Soccer:
asa_players_xpass(league_slug, season_name=...)and thenaslanduslsASA leagues; USL Super League takes split-year labels (season_name="2024-25", not2024). - Soccer: the optional
soccerextra (pip install "sportsdataverse[soccer]", kloppy) addssoccer_open_events("statsbomb", 8658)for open event data andsoccer_events_to_frame(dataset)for any kloppy dataset. - Validation:
sportsdataverse.validationgainsvalidate_game+GameReport, the advBoxScore reconciliation rules, NCAA source column aliases and the football processor invariant sweeps. (#553, #554, #555, #556, #558, #510)
Changed
- CFB: the bundled xQBR model (
cfb/models/qbr_model.ubj) is retrained on the served box score without the spread (qbr_varsis the five EPA aggregates plusera0..era3), behind a publish gate; everyexp_qbrchanges. - CFB: the vendor special-teams name regexes moved into
sportsdataverse.football.espn_text(CLAUSE_NAME,CLAUSE_RETURNER_RE,CLAUSE_FG_KICKER_RE); output is unchanged. - CFB:
cfb_returning_productionmeasures defense from play participants (2014+) or pbp splash plays (2004-13) and weights it intooverall_returning(offense 0.49 / defense 0.51), sooverall_returningvalues change; newdef_basisandoverall_basiscolumns. - Docs:
generate.py --checkfails when a public callable has noReturns:/Yields:section; reference pages show a returns table captured from real data, or say why there is none. - Docs: blank returns-table descriptions are filled only from the league's own sport's R packages, never with R argument text; NFL Pro, On3 and 13 Fox Sports tables gain authored descriptions.
- Docs: league index pages can list companion packages in a "See also" block
(
tools/codegen/companions.yaml); the SOCCER page links kloppy, sdvplot, sdvplotR, itscalledsoccer, soccerdata and mplsoccer. - Docs: the docs site is generated from one league registry: table rows leave the search index,
plain function headings, large reference pages split by family, a
main (latest)label and a codegen-rendered changelog. (#664, #671, #672, #673, #674, #676) - Models: native thread pools default to one:
SDV_XGB_THREADS(default 1) stops xgboost's predict from fanning across every core per request; raise it deliberately. (#563) - NFL / CFB: the situation-neutral split in
football.tendenciesreadswp_before_naive(score, clock and field position) instead ofwp_before, so every*_neutralcolumn andsec_per_play_neutralmove. - NFL / CFB:
tackle_sharecounts only the defense's own scrimmage snaps, with newscrimmage_tackle_pointsandteam_scrimmage_tackle_pointscolumns;tackles,assistsandtackle_pointsstill count every credit. - Packaging: polars 2.x is allowed (
polars>=1.0,<3, mirrored inrecipe/meta.yaml); the lock resolves polars 2.0.0 on Python 3.10+ and 1.36.1 on Python 3.9. - Validation:
tools/validation/source_parity, a nightly harness, compiles the same games from two providers and reports column-level disagreement. (#547)
Fixed
- CFB:
load_cfb_passing,load_cfb_receivingandload_cfb_rushingdeclare the columns the assets gained (dispersion_games,EPAplay_sd,boom_rate,stuff_rate, ...). - CFB: the NCAA mapper fixes quarter markers, the score walk, overtime interception flags, overturned yardage and same-row penalty enforcement; no-play rows carry no yardage, and block-printed tries go to the kicking team. (#557, #550, #560)
- CFB: about 650 plays ESPN scores but no text rule named (frozen-board pick-sixes, fumble returns, field goals) now score; textless copies and untyped admin rows ("Begin Drive", quarter markers, lone try fragments) are dropped.
- CFB: a play that ends a half or a finished game leaves a possession worth nothing (EP_end 0, EPA -EP_start), now also for a finished game's last play and regulation's last play before overtime.
- CFB: a returned kickoff whose end down is outside 1-4 (ESPN's -1 sentinel) ends at down 1, so its EP_end is the next snap's EP_start.
- CFB:
end.TimeSecsRem/end.adj_TimeSecsRemare the next play's start clock (they were the previous play's), and the last play of a half or game ends at 0:00; EPA moves most at period ends. - CFB: 2007-13 touchdowns ESPN filed as their own extra-point kick carry the snap's down and distance (was -1), so the EP model no longer scores them as no down.
- CFB: blocked field goals keep ESPN's type instead of becoming "Penalty", "Extra Point Missed" or a plain "Blocked Field Goal" (sportsdataverse/cfbfastR#175); plays with null join keys are never dropped as copies. (#641)
- CFB: win probability in overtime and the final seconds uses the new
cfb_wp_overtimecorrection, and made field goals, decision surfaces and two-point shootouts are valued correctly; everywp_*/wpamoves, andfg_wp/make_fg_wp/miss_fg_wp/xp_wpare Float64. - CFB: completions written without "complete to ... for N" (ESPN 2024-25) keep their receiving
yards from ESPN's
statYardage, so passing / receiving yards and box scores move. - CFB: a tackle is credited to the tackler's own team from the game roster, so coverage and
post-turnover tackles leave the opponent's tackle table;
def_pos_teamintackles/position_group_tacklesis now the tackler's team. - CFB: plays ESPN files twice under new ids (stub echoes, drive batches at the start clock, copies around a timeout) are dropped before the adjacent-copy dedupe; play counts, EPA/play and success rate move in affected games.
- CFB: losses written "for N yards loss" or "for 1 yard loss" (ESPN 2025) no longer read as
gains in
yds_rushedandyds_receiving. - CFB: fumbles in ESPN's 2025 text format and the new
Fumbletype keep theirrush/passflags, so pass / rush aggregates (havoc, EPA/play, success rate) no longer drop them. - CFB: the usage box no longer glues a two-player assist into one phantom tackler, and
create_usage_box(rosters=)fillsposition_group_usage/position_group_tacklesfor historical games. - CFB: ESPN's 2025 jersey-style kick text fills kick distances, return yards, touchbacks, fair
catches and kicker / returner names, and
st_kickerslists a kicker once per team. - Cache: a scoreboard request whose
dates=include today or a future day now bypasses the response cache (no read, no write); a wholly historical date keeps the 30-day TTL, and an explicitcache_ttl=still wins. - Docs: descriptions mined from hoopR / wehoop no longer say "
team_detail = TRUEonly" (orathlete_detail/position_detail) for columns the Python parsers always return. - Docs: each reference page's Valid URL and docstring
Example URL:is the URL its example call requests (ESPN Core v2 child resources, default params);espn_<lg>_summarydocuments that it returns a dict. - Docs:
nba_stats,wnba_statsandon3return tables are generated from parser output on real captures (e.g.fg3m->fg3_m), and multi-result-set endpoints document their dict; wrapper behaviour is unchanged. - MLB:
mlb_expected_statscounts only plate-appearance-ending rows forpa,aband the wOBA denominator (raw pitch rows had pushedpato ~3,400, deflatingxba/xslg), andintent_walkis no longer an at-bat. - NBA / WNBA / MBB / WBB:
espn_nba_pbp,espn_wnba_pbp,espn_mbb_pbp,espn_wbb_pbpread the spread from a one-provider pickcenter, pair it with the same provider's favorite, flag every team timeout and fix MBB 2OT+ end seconds;helper_<lg>_pickcenterreturns plain floats / bools. - NFL: a strip-sack (type 80) credits the recovery to the defence, not the offence. (#546)
- NFL / CFB: processor bug sweeps: timeouts, roof, spread sign, re-run idempotence, dedupe, yard line and end clock (NFL), and C3-C40 plus the NCAA rounds (CFB). (#503, #504, #506, #514, #517, #519, #526, #530, #532, #533)
- NFL / CFB:
sec_per_playinfootball.tendenciescounts regulation drives only, each for its own offense, so overtime 0:00 drives and drive ids shared by two offenses no longer distort pace. - NFL / CFB:
aggregate_usage_boxkeeps one season row per player, keyed on(team, player_id), instead of splitting a player whose name or position group changed. - NFL / CFB: a pick-six or fumble-return touchdown no longer counts as the offense's conversion
or touchdown in
football.tendencies,football.usage_boxandfit_third_down_curve. - NHL, ESPN, NFL, KenPom: the twelve
nhl_edge_*_top_10boards return data (always empty before);espn_<league>_transactionsusesparse_transactions;load_nfl_ff_rankingsno longer readsrank_deltaas String early in a season; KenPom examples use ids KenPom recognises. - PFF: the legacy
pff_*passing / receiving and thepff_apiposition / team return tables now describeavg_time_to_throw(per dropback),aimed_passesand receivingpositive_epa_percentcorrectly, as already done for the player summaries. (#689) - PFF: 19
pff_api_*per-player and coverage-matrix routes gain their return-table columns, andpff_api_player_rushing_direction()/pff_api_player_snaps_summary()return rows instead of a zero-row frame. - Polars: code polars 2.0 rejects now runs on 1.x and 2.0 with unchanged 1.x output: the
*_pbpclock split,start.down/start.distance/end.down/end.distancecast toInt64, String-to-Date casts andexplode()on empty lists. - Polars: on polars 2.0, a column R's arrow wrote with the
arrow.r.vctrsextension type (such asgame_json_urlin the NHL and PWHL schedules) reads as its storage type, not anExtensioncolumn, which no.strop, comparison or join accepts; importing sportsdataverse registers it. (#723) - Polars: on polars 2.0,
pl.read_parquet(url)gets HTTP 501 from GitHub release URLs; the release loaders read withuse_pyarrow=Trueand work. - Soccer:
soccer_open_events()andsoccer_open_dataset()no longer raiseAttributeErrorin a fresh interpreter. - stats.ncaa.org: the fetch layer passes the new
/stats_termsTerms gate without returning or caching it as content (#568), fits its three-view cap and backs off on refusals (#569), and rotates the proxy when a network error interrupts acceptance (#570).
Security
- HTTP: a credential in a query string (The Odds API
apiKey, HockeyTechkey, Foxapikey, ...) readsREDACTEDin everydl_utils.downloadlog line, error message and chained exception; The Odds API wrappers raiseAssetFetchErroron a non-2xx answer instead of returning it as odds.